#include "win32\win32guts.h"
#ifndef _APRICOT_H_
#include "apricot.h"
#endif
#include "guts.h"
#include "Window.h"
#include "Application.h"
#include "Clipboard.h"
#include "Icon.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

PList
apc_get_standard_clipboards( void)
{
	PList l = plist_create( 1, 1);
	if (!l) return nil;
	list_add( l, (Handle)duplicate_string( "Clipboard"));
	return l;
}

Bool
apc_clipboard_create( Handle self)
{
	if ( !((PClipboard)self)-> name
		|| strlen(((PClipboard)self)-> name) != 9
		|| ((PClipboard)self)-> name[0] != 'C'
		|| strcmp(((PClipboard)self)-> name, "Clipboard") != 0) {
		return false;
	}
	return true;
}

Bool
apc_clipboard_destroy( Handle self)
{
	return true;
}


Bool
apc_clipboard_open( Handle self)
{
	if ( !OpenClipboard( nil)) apiErrRet;
	return true;
}

Bool
apc_clipboard_close( Handle self)
{
	if ( !CloseClipboard()) apiErrRet;
	return true;
}

Bool
apc_clipboard_clear( Handle self)
{
	if ( !EmptyClipboard()) apiErrRet;
	return true;
}

static Handle cf2CF( Handle id)
{
	if ( id == cfText)   return CF_TEXT;
	if ( id == cfUTF8)   return CF_UNICODETEXT;
	if ( id == cfBitmap) return CF_BITMAP;
	return id - cfCustom;
}

Bool
apc_clipboard_has_format( Handle self, Handle id)
{
	id = cf2CF( id);
	return IsClipboardFormatAvailable( id) ||
		(( id == CF_TEXT) && IsClipboardFormatAvailable( CF_UNICODETEXT));
}

Bool
apc_clipboard_get_data( Handle self, Handle id, PClipboardDataRec c)
{
	id = cf2CF( id);
	switch( id)
	{
		case CF_BITMAP:
			{
				Handle self  = c-> image;
				HBITMAP b = GetClipboardData( CF_BITMAP);
				HPALETTE op = nil, p = GetClipboardData( CF_PALETTE);
				HBITMAP obm = sys bm;
				HDC dc, ops;

				if ( b == nil) {
					apcErr( errInvClipboardData);
					return false;
				}
				sys bm = b;
				apcErrClear;
				if (!( dc = CreateCompatibleDC( dc_alloc()))) return false;
				ops = sys ps;
				sys ps = dc;

				if ( p) {
					op = SelectPalette( dc, p, 1);
					RealizePalette( dc);
				}
				image_query_bits( self, true);
				if ( p)
					SelectPalette( dc, op, 1);
				DeleteDC( dc);
				dc_free();
				sys ps = ops;
				sys bm = obm;
				return apcError ? 0 : 1;
			}
			break;
		case CF_UNICODETEXT:
			{
				WCHAR *ptr;
				Bool ret = false;
				void *ph;

				ph = GetClipboardData( CF_UNICODETEXT);
				if ( ph == nil) {
					apcErr( errInvClipboardData);
					return false;
				}
				if ( !( ptr = ( WCHAR*) GlobalLock( ph)))
					apiErrRet;
				apcErrClear;
				c->length = WideCharToMultiByte(CP_UTF8, 0, ptr, -1, NULL, 0, NULL, 0);
				if (( c->data = malloc( c-> length ) )) {
					WideCharToMultiByte(CP_UTF8, 0, ptr, -1, (LPSTR)c->data, c->length, NULL, 0);
					if ( c->length > 0) c->length--; // terminating 0
					ret = true;
				} else {
					c->length = 0;
				}
				GlobalUnlock( ph);
				return ret;
			}
			break;
		case CF_TEXT:
			{
				Byte *ptr;
				int i, len, ret = false;
				void *ph = GetClipboardData( CF_TEXT);

				if ( ph == nil) {
					apcErr( errInvClipboardData);
					return false;
				}
				if ( !( ptr = ( Byte*) GlobalLock( ph)))
					apiErrRet;
				apcErrClear;
				len = strlen(( char*) ptr);
				c-> length = 0;
				if ((c-> data = ( Byte *) malloc( len))) {
					for ( i = 0; i < len; i++)
						if ( ptr[i] != '\r' || (( i < len) && (ptr[i+1] != '\n')))
							c-> data[c-> length++] = ptr[i];
					ret = true;
				}
				GlobalUnlock( ph);
				return ret;
			}
			break;
		default:
			{
				char *ptr;
				void *ph = GetClipboardData( id);

				if ( ph == nil) {
					apcErr( errInvClipboardData);
					return false;
				}
				if (( c-> length = GlobalSize( ph)) == 0)
					return true; /* not an error */
				if ( !( ptr = ( char*) GlobalLock( ph)))
					apiErrRet;
				c-> length = *(( int*) ptr);
				ptr += sizeof( int);
				if (( c-> data = malloc( c-> length)))
					memcpy( c-> data, ptr, c-> length);
				GlobalUnlock( ph);
				return true;
			}
	}
	return false;
}

Bool
apc_clipboard_set_data( Handle self, Handle id, PClipboardDataRec c)
{
	id = cf2CF( id);
	switch ( id)
	{
		case CF_BITMAP:
			{
				HPALETTE p = palette_create( c-> image);
				HBITMAP b = ( HBITMAP) image_create_bitmap( c-> image, p, NULL, BM_AUTO);

				if ( b == nil) {
					if ( p) DeleteObject( p);
					apiErrRet;
				}
				if ( !SetClipboardData( CF_BITMAP,  b)) apiErr;
				if ( p)
					if ( !SetClipboardData( CF_PALETTE, p)) apiErr;
			}
			return true;
		case CF_UNICODETEXT:
			{
				int ulen = MultiByteToWideChar(CP_UTF8, 0, (char*) c-> data, c-> length, NULL, 0) + 1;
				void *ptr = nil;
				HGLOBAL glob;

				if (( glob = GlobalAlloc( GMEM_DDESHARE, ( ulen + 0) * sizeof( WCHAR)))) {
					if (( ptr = GlobalLock( glob))) {
						MultiByteToWideChar(CP_UTF8, 0, (LPSTR)c-> data, c-> length, ptr, ulen);
						GlobalUnlock( glob);
						if ( !SetClipboardData( CF_UNICODETEXT, glob)) apiErr;
					} else {
						GlobalFree( glob);
						apiErr;
					}
				} else apiErr;
			}
			return true;
		case CF_TEXT:
			{
				int ulen = c-> length;
				int i, cr = 0;
				void *ptr = nil, *oemptr = nil;
				char *dst;
				HGLOBAL glob, oemglob;

				for ( i = 0; i < c-> length; i++)
					if (c-> data[i] == '\n' && ( i == 0 || c-> data[i-1] != '\r'))
						cr++;

				glob    = GlobalAlloc( GMEM_DDESHARE, ulen + cr + 1);
				oemglob = GlobalAlloc( GMEM_DDESHARE, ulen + cr + 1);
				if ( glob)    ptr    = GlobalLock( glob);
				if ( oemglob) oemptr = GlobalLock( oemglob);

				if ( ptr && oemptr) {
					dst = ( char *) ptr;
					for ( i = 0; i < c-> length; i++) {
						if ( c-> data[i] == '\n' && ( i == 0 || c-> data[i-1] != '\r'))
							*(dst++) = '\r';
						*(dst++) = c-> data[i];
					}
					*dst = 0;
					CharToOemBuff(( LPCTSTR) ptr, ( LPTSTR) oemptr, ulen + cr + 1);
					GlobalUnlock( oemptr);
					GlobalUnlock( ptr);
					if ( !SetClipboardData( CF_TEXT, glob)) apiErr;
					if ( !SetClipboardData( CF_OEMTEXT, oemglob)) apiErr;
				} else {
					apiErr;
					if ( ptr) GlobalUnlock( ptr);
					if ( oemptr) GlobalUnlock( oemptr);
					if ( glob) GlobalFree( glob);
					if ( oemglob) GlobalFree( oemglob);
				}
			}
			return true;
		default:
			{
				char* ptr;
				HGLOBAL glob = GlobalAlloc( GMEM_DDESHARE, c-> length + sizeof( int));
				if ( !glob) apiErrRet;
				if ( !( ptr = ( char *) GlobalLock( glob))) {
					apiErr;
					GlobalFree( glob);
					return false;
				}
				memcpy( ptr + sizeof( int), c-> data, c-> length);
				memcpy( ptr, &c-> length, sizeof( int));
				GlobalUnlock( glob);
				if ( !SetClipboardData( id, glob)) apiErrRet;
				return true;
			}
	}
	return false;
}

Handle
apc_clipboard_register_format( Handle self, const char * format)
{
	UINT r;
	if ( !( r = RegisterClipboardFormat( format))) apiErrRet;
	return r + cfCustom;
}

Bool
apc_clipboard_deregister_format( Handle self, Handle id)
{
	// Windows doesn't have such functionality. Such a strange malfunction
	return true;
}

ApiHandle
apc_clipboard_get_handle( Handle self)
{
	return nilHandle;
}

#ifdef __cplusplus
}
#endif
