#ifndef _PLATFORM_H
#define _PLATFORM_H

#include "types.h"
#include "../std_mkncc.h"  // for MKnCC

#include <stdio.h>
#include <stdlib.h>
#ifdef __cplusplus
#include <new>
#else
#include <new.h>
#endif
#include <limits.h>

#ifdef _WIN32
# include "win32.h"

#define OSMODULEHANDLE  HINSTANCE
#define INVALIDOSMODULEHANDLE  ((OSMODULEHANDLE)0)
#define OSWINDOWHANDLE  HWND
#define INVALIDOSWINDOWHANDLE  ((OSWINDOWHANDLE)0)
#define OSICONHANDLE  HICON
#define INVALIDOSICONHANDLE  ((OSICONHANDLE)0)
#define OSCURSORHANDLE  HICON
#define INVALIDOSCURSORHANDLE  ((OSCURSORHANDLE)0)
#define OSTHREADHANDLE  HANDLE
#define INVALIDOSTHREADHANDLE ((OSTHREADHANDLE)0)
#define OSREGIONHANDLE  HRGN
#define INVALIDOSREGIONHANDLE  ((OSREGIONHANDLE)0)
typedef HMENU OSMENUHANDLE;

#define RGBA(r,g,b,a)          ((ARGB32)((uint8_t)(r) | ((uint8_t)(g) << 8) | ((uint8_t)(b) << 16) | ((uint8_t)(a) << 24)))

#ifndef PATH_MAX
#define PATH_MAX MAX_PATH
#endif

#elif defined(LINUX)
# include <bfc/platform/linux.h>
#elif defined(__APPLE__)
#include <Carbon/Carbon.h>

typedef HIShapeRef OSREGIONHANDLE;
typedef int OSCURSOR; // TODO: find a good one for this
typedef int OSCURSORHANDLE; // TODO: find a good one for this
typedef HIWindowRef OSWINDOWHANDLE;
typedef void *OSMODULEHANDLE; // TODO:
typedef CGContextRef HDC; // TODO: find a better name
typedef MenuRef OSMENUHANDLE;
typedef CGImageRef OSICONHANDLE;

#ifdef __LITTLE_ENDIAN__
#define RGBA(r,g,b,a)          ((ARGB32)((uint8_t)(r) | ((uint8_t)(g) << 8) | ((uint8_t)(b) << 16) | ((uint8_t)(a) << 24)))
#elif defined(__BIG_ENDIAN__)
#define RGBA(r,g,b,a)          ((ARGB32)((uint8_t)(a) | ((uint8_t)(r) << 8) | ((uint8_t)(g) << 16) | ((uint8_t)(b) << 24)))
#else
#error endian preprocessor symbol not defined
#endif

#define RGB(r,g,b)          RGBA(r,g,b,0xFF)

static const HIWindowRef INVALIDOSWINDOWHANDLE = 0; // TODO: maybe there's an apple-defined name for this
#define INVALIDOSMODULEHANDLE 0
#define INVALIDOSCURSORHANDLE 0

typedef char OSFNCHAR;
typedef char *OSFNSTR;

typedef const char OSFNCCHAR;
typedef const char *OSFNCSTR;

#define FNT(x) x

typedef struct tagRECT
{
	int left;
	int top;
	int right;
	int bottom;
}
RECT;
typedef RECT * LPRECT;

inline RECT RECTFromHIRect(const HIRect *r)
{
	RECT rect;
	rect.left = r->origin.x;
	rect.right = r->origin.x + r->size.width;
	rect.top = r->origin.y;
	rect.bottom = r->origin.y + r->size.height;
	return rect;
}

inline HIRect HIRectFromRECT(const RECT *r)
{
	HIRect rect;
	rect.origin.x = r->left;
	rect.origin.y = r->top;
	rect.size.width = r->right - r->left;
	rect.size.height = r->bottom - r->top;
	return rect;
}

typedef struct tagPOINT
{
	int x;
	int y;
}
POINT;
typedef struct tagPOINT * LPPOINT;

inline HIPoint HIPointFromPOINT(const POINT *pt)
{
	HIPoint p;
	p.x = pt->x;
	p.y = pt->y;
	return p;
}

inline int MulDiv(int a, int b, int c)
{
	int s;
	int v;

	s = 0;
	if (a < 0)
	{
		s = !s;
		a = -a;
	}
	if (b < 0)
	{
		s = !s;
		b = -b;
	}
	if (c < 0)
	{
		s = !s;
		c = -c;
	}
	double d;
	d = ((double)a * (double)b) / (double)c;
	if (d >= 4294967296.)
		return -1;
	v = d;
	if (s)
		v = -v;
	return v;
}

#else
#error port me
// Windows API dependant definitions for non-windows platforms

#define __cdecl
#define __stdcall
#define WINAPI
#define WINBASEAPI
#define WINUSERAPI
#define WINGDIAPI
#define WINOLEAPI
#define CALLBACK
#define FARPROC void *

#define FALSE  0
#define TRUE  1

#define ERROR  0

#define CONST const
#define VOID void

typedef unsigned long DWORD;
typedef unsigned short WORD;
typedef unsigned char BYTE;
typedef long LONG;
typedef int INT;
typedef int BOOL;
typedef short SHORT;
typedef void * PVOID;
typedef void * LPVOID;

typedef char CHAR;
typedef unsigned short WCHAR;
typedef char * LPSTR;
typedef WCHAR * LPWSTR;
typedef const char * LPCSTR;
typedef const WCHAR * LPCWSTR;
typedef LPWSTR PTSTR, LPTSTR;
typedef LPCWSTR LPCTSTR;
typedef char TCHAR;
typedef WCHAR OLECHAR;

typedef void * HANDLE;
typedef void * HWND;
typedef void * HDC;
typedef void * HFONT;
typedef void * HBITMAP;
typedef void * HINSTANCE;
typedef void * HICON;
typedef void * HRGN;
typedef void * HPEN;
typedef void * HBRUSH;
typedef void * HRSRC;
typedef void * HGLOBAL;
typedef void * HACCEL;
typedef void * HMODULE;
typedef void * HMENU;
typedef void * HGDIOBJ;

typedef void * ATOM;
typedef void * CRITICAL_SECTION;
typedef void * LPCRITICAL_SECTION;

typedef UINT WPARAM;
typedef UINT LPARAM;
typedef LONG LRESULT;
typedef UINT COLORREF;

typedef LRESULT(*WNDPROC)(HWND, UINT, WPARAM, LPARAM);
typedef BOOL CALLBACK WNDENUMPROC(HWND, LPARAM);
typedef VOID CALLBACK *TIMERPROC(HWND, UINT, UINT, DWORD);

typedef struct tagPOINT
{
	LONG x;
	LONG y;
}
POINT;
typedef struct tagPOINT * LPPOINT;

typedef struct tagSIZE
{
	LONG cx;
	LONG cy;
}
SIZE;


typedef struct tagRECT
{
	LONG left;
	LONG top;
	LONG right;
	LONG bottom;
}
RECT;
typedef RECT * LPRECT;

typedef struct _COORD
{
	SHORT X;
	SHORT Y;
}
COORD, *PCOORD;

typedef struct tagPAINTSTRUCT
{
	HDC hdc;
	BOOL fErase;
	RECT rcPaint;
	BOOL fRestore;
	BOOL fIncUpdate;
	BYTE rgbReserved[32];
}
PAINTSTRUCT;

typedef struct tagBITMAP
{  /* bm */
	int     bmType;
	int     bmWidth;
	int     bmHeight;
	int     bmWidthBytes;
	BYTE    bmPlanes;
	BYTE    bmBitsPixel;
	LPVOID  bmBits;
}
BITMAP;

typedef struct tagRGBQUAD
{
	BYTE rgbRed;
	BYTE rgbGreen;
	BYTE rgbBlue;
	BYTE rgbReserved;
}
RGBQUAD;

typedef struct tagBITMAPINFOHEADER
{
	DWORD      biSize;
	LONG       biWidth;
	LONG       biHeight;
	WORD       biPlanes;
	WORD       biBitCount;
	DWORD      biCompression;
	DWORD      biSizeImage;
	LONG       biXPelsPerMeter;
	LONG       biYPelsPerMeter;
	DWORD      biClrUsed;
	DWORD      biClrImportant;
}
BITMAPINFOHEADER;

typedef struct tagBITMAPINFO
{
	BITMAPINFOHEADER bmiHeader;
	RGBQUAD     bmiColors[1];
}
BITMAPINFO, *LPBITMAPINFO;

typedef struct tagMSG
{
	HWND        hwnd;
	UINT        message;
	WPARAM      wParam;
	LPARAM      lParam;
	DWORD       time;
	POINT       pt;
}
MSG;

typedef MSG * LPMSG;

typedef struct _RGNDATAHEADER
{
	DWORD   dwSize;
	DWORD   iType;
	DWORD   nCount;
	DWORD   nRgnSize;
	RECT    rcBound;
}
RGNDATAHEADER, *PRGNDATAHEADER;

typedef struct _RGNDATA
{
	RGNDATAHEADER   rdh;
	char            Buffer[1];
}
RGNDATA, *PRGNDATA;

// Windows messages

#define WM_SYSCOMMAND 0x112
#define WM_LBUTTONDOWN 0x201
#define WM_LBUTTONUP 0x202
#define WM_RBUTTONDOWN 0x204
#define WM_RBUTTONUP 0x205

#define WM_USER 0x400

#define WS_EX_TOOLWINDOW 0x00000080L

#define WS_OVERLAPPED 0x00000000L
#define WS_MAXIMIZEBOX 0x00010000L
#define WS_MINIMIZEBOX 0x00020000L
#define WS_SYSMENU 0x00080000L
#define WS_CAPTION 0x00C00000L
#define WS_CLIPCHILDREN 0x02000000L
#define WS_CLIPSIBLINGS 0x04000000L
#define WS_VISIBLE 0x10000000L
#define WS_CHILD 0x40000000L
#define WS_POPUP 0x80000000L

#define HWND_TOP ((HWND)0)
#define HWND_TOPMOST ((HWND)-1)
#define HWND_NOTOPMOST ((HWND)-2)

#define GWL_STYLE  (-16)

#define GW_HWNDFIRST  0
#define GW_HWNDNEXT  2

#define SWP_NOMOVE 0x0002
#define SWP_NOSIZE 0x0001
#define SWP_SHOWWINDOW 0x0040
#define SWP_DEFERERASE 0x2000
#define SWP_NOZORDER 0x0004
#define SWP_NOACTIVATE 0x0010

#define SW_SHOW 5

#define SC_MINIMIZE 0xF020
#define SC_MAXIMIZE 0xF030
#define SC_RESTORE 0xF120

#define GCL_HICONSM (-34)
#define GCL_HICON (-14)

#define MB_OK    0
#define MB_OKCANCEL   1
#define MB_TASKMODAL  0x2000L

#define IDOK    1
#define IDCANCEL  2

#define VK_SHIFT   0x10
#define VK_CONTROL   0x11
#define VK_MENU    0x12

#define RT_RCDATA  10

#define IMAGE_BITMAP  0

#define LR_LOADFROMFILE  0x0010

#define DIB_RGB_COLORS  0

#define MAX_PATH  1024
#define _MAX_PATH  MAX_PATH
#define _MAX_DRIVE  3
#define _MAX_DIR  256
#define _MAX_FNAME  256
#define _MAX_EXT  256

#define GMEM_FIXED  0x0
#define GMEM_ZEROINIT  0x40
#define GPTR    (GMEM_FIXED | GMEM_ZEROINIT)

#define SPI_GETWORKAREA  48

#define SM_CXDOUBLECLK  36
#define SM_CYDOUBLECLK  37

#define COLORONCOLOR  3

#define SRCCOPY    (DWORD)0x00CC0020

#define BI_RGB    0L

#define NULLREGION  1

#define DT_LEFT    0x00000000
#define DT_CENTER  0x00000001
#define DT_RIGHT  0x00000002
#define DT_VCENTER  0x00000004
#define DT_WORDBREAK  0x00000010
#define DT_SINGLELINE  0x00000020
#define DT_CALCRECT  0x00000400
#define DT_NOPREFIX  0x00000800
#define DT_PATH_ELLIPSIS  0x00004000
#define DT_END_ELLIPSIS  0x00008000
#define DT_MODIFYSTRING  0x00010000

#define FW_NORMAL  400
#define FW_BOLD    700

#define FF_DONTCARE  (0<<4)

#define BLACK_BRUSH  4
#define NULL_BRUSH  5

#define PS_SOLID  0
#define PS_DOT    2

#define TRANSPARENT  1
#define OPAQUE    2

#define ANSI_CHARSET  0
#define ANSI_VAR_FONT  12

#define OUT_DEFAULT_PRECIS  0
#define CLIP_DEFAULT_PRECIS  0

#define PROOF_QUALITY  2

#define VARIABLE_PITCH  2

#define RGN_AND    1
#define RGN_OR    2
#define RGN_DIFF  4
#define RGN_COPY  5

#define RDH_RECTANGLES  1

#define MAXLONG    0x7fffffff

// define GUID
#include <bfc/platform/guid.h>

#endif /* not WIN32 */


#ifdef _WIN32
#define OSPIPE HANDLE
#define OSPROCESSID int
#endif

// Ode macro keyworkds
#define DISPATCH_   // makes a method dispatchable, automatically assigns a free ID (requires Interface)
#define DISPATCH(x) // makes a method dispatchable and specifies its ID (not duplicate check, requires Interface)
#define NODISPATCH  // prevents a method from being dispatched if the class is marked for dispatching by default
#define EVENT       // marks a method as being an event to which other classes can connect to receive notification (used by Script and DependentItem helpers)
#define SCRIPT      // exposes a method to script interfaces (requires Script helper)
#define IN          // Input parameter
#define OUT         // Output parameter
#define INOUT       // Input/Output parameter

#endif
