#include "win32\win32guts.h"
#ifndef _APRICOT_H_
#include "apricot.h"
#endif
#include "guts.h"
#include "Window.h"
#include "Icon.h"
#include "Application.h"

#ifdef __cplusplus
extern "C" {
#endif


#define  sys (( PDrawableData)(( PComponent) self)-> sysData)->
#define  dsys( view) (( PDrawableData)(( PComponent) view)-> sysData)->
#define var (( PWidget) self)->
#define HANDLE sys handle
#define DHANDLE(x) dsys(x) handle

static unsigned char cursor_dnd_move[] = {
0x00,0x00,0x00,0x00,0x28,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x40,0x00,0x00,0x00,
0x01,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x15,0x54,0x00,0x00,0x2A,0xAA,0x00,0x00,0x10,0x04,0x00,0x00,0x20,0x02,0x00,0x00,
0x10,0x04,0x00,0x00,0x20,0x02,0x00,0x00,0x10,0x04,0x00,0x00,0x29,0xAA,0x00,0x00,
0x15,0x94,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x06,0x00,0x00,0x00,
0x46,0x00,0x00,0x00,0x6C,0x00,0x00,0x00,0x7C,0x00,0x00,0x00,0x7F,0x80,0x00,0x00,
0x7F,0x00,0x00,0x00,0x7E,0x00,0x00,0x00,0x7C,0x00,0x00,0x00,0x78,0x00,0x00,0x00,
0x70,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xC0,0x01,0xFF,0xFF,0xC0,0x01,0xFF,0xFF,0xCF,0xF9,0xFF,0xFF,0xCF,0xF9,0xFF,0xFF,
0xCF,0xF9,0xFF,0xFF,0xCF,0xF9,0xFF,0xFF,0xCE,0x39,0xFF,0xFF,0xC0,0x01,0xFF,0xFF,
0xC0,0x01,0xFF,0xFF,0xF8,0x7F,0xFF,0xFF,0x78,0x7F,0xFF,0xFF,0x30,0xFF,0xFF,0xFF,
0x10,0xFF,0xFF,0xFF,0x01,0xFF,0xFF,0xFF,0x00,0x1F,0xFF,0xFF,0x00,0x3F,0xFF,0xFF,
0x00,0x7F,0xFF,0xFF,0x00,0xFF,0xFF,0xFF,0x01,0xFF,0xFF,0xFF,0x03,0xFF,0xFF,0xFF,
0x07,0xFF,0xFF,0xFF,0x0F,0xFF,0xFF,0xFF,0x1F,0xFF,0xFF,0xFF,0x3F,0xFF,0xFF,0xFF,
0x7F,0xFF,0xFF,0xFF
};

static unsigned char cursor_dnd_copy[] = {
0x00,0x00,0x00,0x00,0x28,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x40,0x00,0x00,0x00,
0x01,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0xF0,0x00,
0x00,0x1F,0xF0,0x00,0x00,0x1E,0xF0,0x00,0x00,0x1E,0xF0,0x00,0x00,0x18,0x30,0x00,
0x15,0x5E,0xF0,0x00,0x2A,0x9E,0xF0,0x00,0x10,0x1F,0xF0,0x00,0x20,0x1F,0xF0,0x00,
0x10,0x00,0x00,0x00,0x20,0x02,0x00,0x00,0x10,0x04,0x00,0x00,0x29,0xAA,0x00,0x00,
0x15,0x94,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x06,0x00,0x00,0x00,
0x46,0x00,0x00,0x00,0x6C,0x00,0x00,0x00,0x7C,0x00,0x00,0x00,0x7F,0x80,0x00,0x00,
0x7F,0x00,0x00,0x00,0x7E,0x00,0x00,0x00,0x7C,0x00,0x00,0x00,0x78,0x00,0x00,0x00,
0x70,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xC0,0x07,0xFF,0xFF,0xC0,0x07,0xFF,
0xFF,0xC0,0x07,0xFF,0xFF,0xC0,0x07,0xFF,0xFF,0xC0,0x07,0xFF,0xFF,0xC0,0x07,0xFF,
0xC0,0x00,0x07,0xFF,0xC0,0x00,0x07,0xFF,0xCF,0xC0,0x07,0xFF,0xCF,0xC0,0x07,0xFF,
0xCF,0xC0,0x07,0xFF,0xCF,0xF9,0xFF,0xFF,0xCE,0x39,0xFF,0xFF,0xC0,0x01,0xFF,0xFF,
0xC0,0x01,0xFF,0xFF,0xF8,0x7F,0xFF,0xFF,0x78,0x7F,0xFF,0xFF,0x30,0xFF,0xFF,0xFF,
0x10,0xFF,0xFF,0xFF,0x01,0xFF,0xFF,0xFF,0x00,0x1F,0xFF,0xFF,0x00,0x3F,0xFF,0xFF,
0x00,0x7F,0xFF,0xFF,0x00,0xFF,0xFF,0xFF,0x01,0xFF,0xFF,0xFF,0x03,0xFF,0xFF,0xFF,
0x07,0xFF,0xFF,0xFF,0x0F,0xFF,0xFF,0xFF,0x1F,0xFF,0xFF,0xFF,0x3F,0xFF,0xFF,0xFF,
0x7F,0xFF,0xFF,0xFF
};

static unsigned char cursor_dnd_link[] = {
0x00,0x00,0x00,0x00,0x28,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x40,0x00,0x00,0x00,
0x01,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0xF0,0x00,
0x00,0x1D,0xF0,0x00,0x00,0x1B,0xF0,0x00,0x00,0x19,0xF0,0x00,0x00,0x18,0xB0,0x00,
0x15,0x5C,0x30,0x00,0x2A,0x9E,0x30,0x00,0x10,0x1C,0x30,0x00,0x20,0x1F,0xF0,0x00,
0x10,0x00,0x00,0x00,0x20,0x02,0x00,0x00,0x10,0x04,0x00,0x00,0x29,0xAA,0x00,0x00,
0x15,0x94,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x06,0x00,0x00,0x00,
0x46,0x00,0x00,0x00,0x6C,0x00,0x00,0x00,0x7C,0x00,0x00,0x00,0x7F,0x80,0x00,0x00,
0x7F,0x00,0x00,0x00,0x7E,0x00,0x00,0x00,0x7C,0x00,0x00,0x00,0x78,0x00,0x00,0x00,
0x70,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xC0,0x07,0xFF,0xFF,0xC0,0x07,0xFF,
0xFF,0xC0,0x07,0xFF,0xFF,0xC0,0x07,0xFF,0xFF,0xC0,0x07,0xFF,0xFF,0xC0,0x07,0xFF,
0xC0,0x00,0x07,0xFF,0xC0,0x00,0x07,0xFF,0xCF,0xC0,0x07,0xFF,0xCF,0xC0,0x07,0xFF,
0xCF,0xC0,0x07,0xFF,0xCF,0xF9,0xFF,0xFF,0xCE,0x39,0xFF,0xFF,0xC0,0x01,0xFF,0xFF,
0xC0,0x01,0xFF,0xFF,0xF8,0x7F,0xFF,0xFF,0x78,0x7F,0xFF,0xFF,0x30,0xFF,0xFF,0xFF,
0x10,0xFF,0xFF,0xFF,0x01,0xFF,0xFF,0xFF,0x00,0x1F,0xFF,0xFF,0x00,0x3F,0xFF,0xFF,
0x00,0x7F,0xFF,0xFF,0x00,0xFF,0xFF,0xFF,0x01,0xFF,0xFF,0xFF,0x03,0xFF,0xFF,0xFF,
0x07,0xFF,0xFF,0xFF,0x0F,0xFF,0xFF,0xFF,0x1F,0xFF,0xFF,0xFF,0x3F,0xFF,0xFF,0xFF,
0x7F,0xFF,0xFF,0xFF
};

static HCURSOR drag_cursors[crDragLink - crDragCopy + 1] = { NULL, NULL, NULL };

static HCURSOR
create_drag_cursor( int cr )
{
	unsigned char * bits = NULL;
	unsigned int size = 0;
	int index = cr - crDragCopy;

	if ( cr < crDragCopy || cr > crDragLink)
		return NULL;

	if ( drag_cursors[index] != NULL )
		return drag_cursors[index];

	switch (cr) {
	case crDragCopy:
		bits = cursor_dnd_copy;
		size = sizeof(cursor_dnd_copy);
		break;
	case crDragMove:
		bits = cursor_dnd_move;
		size = sizeof(cursor_dnd_move);
		break;
	case crDragLink:
		bits = cursor_dnd_link;
		size = sizeof(cursor_dnd_link);
		break;
	}

	if (( drag_cursors[index] = CreateIconFromResourceEx(
		bits, size,
		false, 0x30000,
		32, 32,
		LR_MONOCHROME | LR_SHARED /* LR_SHARED to release these automatically */
	)) == NULL )
		apiErr;

	return drag_cursors[index];
}

Bool
cursor_update( Handle self)
{
	if ( !is_apt( aptFocused))
		return true;
	DestroyCaret();
	if ( is_apt( aptCursorVis)) {
		if ( !CreateCaret(( HWND) var handle, NULL, sys cursorSize. x, sys cursorSize. y)) apiErrRet;
		if ( !SetCaretPos( sys cursorPos. x, sys lastSize. y - sys cursorPos. y - sys cursorSize. y)) apiErrRet;
		if ( !ShowCaret(( HWND) var handle)) apiErrRet;
	}
	return true;
}

Bool
apc_cursor_set_pos( Handle self, int x, int y)
{
	objCheck false;
	if ( !hwnd_check_limits( x, y, true)) apcErrRet( errInvParams);
	sys cursorPos. x = x;
	sys cursorPos. y = y;
	return cursor_update( self);
}

Bool
apc_cursor_set_size( Handle self, int x, int y)
{
	objCheck false;
	if ( !hwnd_check_limits( x, y, false)) apcErrRet( errInvParams);
	sys cursorSize. x = x;
	sys cursorSize. y = y;
	return cursor_update( self);
}

Bool
apc_cursor_set_visible( Handle self, Bool visible)
{
	objCheck false;
	apt_assign( aptCursorVis, visible);
	return cursor_update( self);
}

Point
apc_cursor_get_pos( Handle self)
{
	Point p = {0,0};
	objCheck p;
	return sys cursorPos;
}

Point
apc_cursor_get_size( Handle self)
{
	Point p = {0,0};
	objCheck p;
	return sys cursorSize;
}

Bool
apc_cursor_get_visible( Handle self)
{
	objCheck false;
	return is_apt( aptCursorVis);
}

Point
apc_pointer_get_hot_spot( Handle self)
{
	Point         r = {0,0};
	ICONINFO      ii;
	objCheck r;
	if ( !GetIconInfo( sys pointer, &ii))
		apiErr
	else {
		int y;
		BITMAP bitmap;
		if ( ii.hbmColor && GetObject( ii.hbmColor, sizeof( BITMAP), ( LPSTR) &bitmap))
			y = bitmap.bmHeight;
		else if ( GetObject( ii.hbmMask, sizeof( BITMAP), ( LPSTR) &bitmap))
			y = bitmap.bmHeight / 2;
		else
			y = guts. pointerSize. y;
		r. x = ii. xHotspot;
		r. y = y - ii. yHotspot - 1;
		DeleteObject( ii. hbmMask);
		DeleteObject( ii. hbmColor);
	}
	return r;
}

Point
apc_pointer_get_pos( Handle self)
{
	Point p = {0,0};
	RECT r;
	objCheck p;
	if ( !GetCursorPos(( POINT*) &p)) apiErr;
	GetWindowRect( HWND_DESKTOP, &r);
	p. y = r. bottom - p. y - 1;
	return p;
}

int
apc_pointer_get_shape( Handle self)
{
	objCheck 0;
	return sys pointerId;
}

Point
apc_pointer_get_size( Handle self)
{
	return guts. pointerSize;
}

Bool
apc_pointer_get_bitmap( Handle self, Handle icon)
{
	ICONINFO  ii;
	PIcon     i = ( PIcon) icon;
	HDC dc;
	XBITMAPINFO bi = {{
		sizeof( BITMAPINFOHEADER), 0, 0, 1, 1
	}};
	BITMAP bitmap;

	bi. bmiHeader. biWidth = guts. pointerSize. x;
	bi. bmiHeader. biHeight = guts. pointerSize. y;

	if ( icon == NULL_HANDLE)
		apcErrRet( errInvParams);
	objCheck false;
	dobjCheck( icon) false;
	if ( !GetIconInfo( sys pointer, &ii))
		apiErrRet;
	if ( ii.hbmColor && GetObject( ii.hbmColor, sizeof( BITMAP), ( LPSTR) &bitmap))
		i-> self-> create_empty( icon, bitmap.bmWidth, bitmap.bmHeight, 1);
	else if ( GetObject( ii.hbmMask, sizeof( BITMAP), ( LPSTR) &bitmap))
		i-> self-> create_empty( icon, bitmap.bmWidth, bitmap.bmHeight / 2, 1);
	else
		i-> self-> create_empty( icon, guts. pointerSize. x, guts. pointerSize. y, 1);
	if (!( dc = dc_alloc())) return false;
	if ( ii. hbmColor) {
		HDC ops = dsys( icon) ps;
		HBITMAP obm = dsys( icon) bm;
		dsys( icon) ps = dc;
		dsys( icon) bm = ii. hbmColor;
		image_query_bits( icon, false);
		if ( !GetDIBits( dc, ii. hbmMask, 0, i-> h, i-> mask, ( BITMAPINFO*) &bi, DIB_RGB_COLORS)) apiErr;
		dsys( icon) ps = ops;
		dsys( icon) bm = obm;
	} else {
		bi. bmiHeader. biHeight *= 2;
		if ( !GetDIBits( dc, ii. hbmMask, 0, i-> h, i-> data, ( BITMAPINFO*) &bi, DIB_RGB_COLORS)) apiErr;
		if ( !GetDIBits( dc, ii. hbmMask, i-> h, i-> h, i-> mask, ( BITMAPINFO*) &bi, DIB_RGB_COLORS)) apiErr;
	}
	dc_free();
	DeleteObject( ii. hbmMask);
	DeleteObject( ii. hbmColor);
	return true;
}

Bool
apc_pointer_get_visible( Handle self)
{
	objCheck false;
	return !guts. pointerInvisible;
}

Bool
apc_pointer_set_pos( Handle self, int x, int y)
{
	RECT r;
	if ( !hwnd_check_limits( x, y, true)) apcErrRet( errInvParams);
	GetWindowRect( HWND_DESKTOP, &r);
	if ( !SetCursorPos( x, r. bottom - y - 1)) apiErrRet;
	return true;
}

Handle ctx_cr2IDC[] =
{
	crArrow,        ( Handle) IDC_ARROW,
	crText,         ( Handle) IDC_IBEAM,
	crWait,         ( Handle) IDC_WAIT,
	crSize,         ( Handle) IDC_SIZEALL,
	crMove,         ( Handle) IDC_SIZEALL,
	crSizeWest,     ( Handle) IDC_SIZEWE,
	crSizeEast,     ( Handle) IDC_SIZEWE,
	crSizeWE,       ( Handle) IDC_SIZEWE,
	crSizeNorth,    ( Handle) IDC_SIZENS,
	crSizeSouth,    ( Handle) IDC_SIZENS,
	crSizeNS,       ( Handle) IDC_SIZENS,
	crSizeNW,       ( Handle) IDC_SIZENWSE,
	crSizeSE,       ( Handle) IDC_SIZENWSE,
	crSizeNE,       ( Handle) IDC_SIZENESW,
	crSizeSW,       ( Handle) IDC_SIZENESW,
	crInvalid,      ( Handle) IDC_NO,
        crDragNone,     ( Handle) IDC_NO,
        crDragCopy,     ( Handle) IDC_HAND,
        crDragMove,     ( Handle) IDC_HAND,
        crDragLink,     ( Handle) IDC_HAND,
	crCrosshair,    ( Handle) IDC_CROSS,
	crUpArrow,      ( Handle) IDC_UPARROW,
	crQuestionArrow,( Handle) IDC_HELP,
	crHand,         ( Handle) IDC_HAND,
	endCtx
};

static Bool
direct_pointer_change( Handle self)
{
	Point p;
	if ( var stage != csNormal) return false;
	if ( guts.dragSource != NULL ) return true;
	if ( !IsWindowVisible( HANDLE)) return false;
	p = apc_pointer_get_pos( application);
	return self == apc_application_get_widget_from_point( application, p);
}

Bool
apc_pointer_set_shape( Handle self, int sysPtrId)
{
	HCURSOR user;

	objCheck false;
	user = sys pointer2;
	if ( sysPtrId < crDefault || sysPtrId > crUser) return false;
	sys pointerId = sysPtrId;
	if ( sysPtrId == crDefault)
	{
		Handle owner = var owner;
		while( owner)
		{
			sysPtrId = dsys( owner) pointerId;
			if ( sysPtrId != crDefault) break;
			owner = (( PComponent) owner)-> owner;
		}
		if ( sysPtrId == crDefault) sysPtrId = crArrow;
		if ( sysPtrId == crUser) user = dsys( owner) pointer2;
	}
	sys pointer = ( sysPtrId == crUser) ? user :
		LoadCursor( NULL, MAKEINTRESOURCE(
		ctx_remap_def( sysPtrId, ctx_cr2IDC, true, ( Handle)IDC_ARROW)));

	if ( sysPtrId >= crDragCopy && sysPtrId <= crDragLink) {
		HCURSOR cursor = create_drag_cursor(sysPtrId);
		if ( cursor != NULL ) sys pointer = cursor;
	}

	if ( direct_pointer_change( self)) {
		SetCursor( sys pointer);
	}
	return true;
}

Bool
apc_pointer_set_user( Handle self, Handle icon, Point hotSpot)
{
	Bool direct;
	HCURSOR cursor;
	objCheck false;

	apcErrClear;
	direct = direct_pointer_change( self);
	if (icon) {
		Point sz = { PImage(icon)->w, PImage(icon)-> h };
		hotSpot. y = sz.y - hotSpot. y - 1;
		cursor = image_make_icon_handle( icon, sz, &hotSpot);
		if ( guts.apcError) return false;
	} else
		cursor = NULL;

	if ( sys pointer2) {
		if ( direct) SetCursor( NULL);
		if ( !DestroyCursor( sys pointer2)) apiErr;
	}
	sys pointer2 = cursor;

	if ( sys pointerId == crUser)
	{
		sys pointer = sys pointer2;
		if ( direct) SetCursor( sys pointer);
	}
	return true;
}

Bool
apc_pointer_set_visible( Handle self, Bool visible)
{
	if ( var stage == csNormal) {
		guts. pointerInvisible = !visible;
		ShowCursor( visible);
		guts. pointerLock += visible ? 1 : -1;
	}
	return true;
}

int
apc_pointer_get_state( Handle self)
{
	return
		(( GetKeyState( VK_LBUTTON)  < 0) ? mbLeft     : 0) |
		(( GetKeyState( VK_RBUTTON)  < 0) ? mbRight    : 0) |
		(( GetKeyState( VK_MBUTTON)  < 0) ? mbMiddle   : 0) |
		(( GetKeyState( VK_XBUTTON1) < 0) ? mb4        : 0) |
		(( GetKeyState( VK_XBUTTON2) < 0) ? mb5        : 0);
}

#ifdef __cplusplus
}
#endif