/*
CLASS {NATIVE_Clipboard|_Cpp}, NATIVE:

IMPORT, ANYWAY: {NATIVE_String_functions} ;

*/
#ifdef SEPARATE_UNITS
    #include "NATIVE_Clipboard.h"
#endif

#ifdef MSWINDOWS
#else
	// linux part based on x11clipboard -- not work???
	#include <string.h> // strlen, strndup
	#include <X11/Xlib.h>
	#include <X11/Xatom.h>
	#include <assert.h>   
	#include <unistd.h>   
	#include <stdio.h>
	#include <stdlib.h>
	#include <X11/extensions/xfixesproto.h>
	
	static Display * display;
	static Window window;
	static Atom targets_atom, text_atom, UTF8;
	
	char * XPasteType(Atom atom) {
		XEvent event;
		int format;
		unsigned long N, size;
		char * data, * s = 0;
		Atom target,
			CLIPBOARD = XInternAtom(display, "CLIPBOARD", 0),
			XSEL_DATA = XInternAtom(display, "XSEL_DATA", 0);
		XConvertSelection(display, CLIPBOARD, atom, XSEL_DATA, window, CurrentTime);
		XSync(display, 0);
		XNextEvent(display, &event);
		
		switch(event.type) {
		case SelectionNotify:
			if(event.xselection.selection != CLIPBOARD) break;
			if(event.xselection.property) {
				XGetWindowProperty(event.xselection.display, event.xselection.requestor,
					event.xselection.property, 0L,(~0L), 0, AnyPropertyType, &target,
					&format, &size, &N,(unsigned char**)&data);
				if(target == UTF8 || target == XA_STRING) {
					s = strndup(data, size);
					XFree(data);
				}
				XDeleteProperty(event.xselection.display, event.xselection.requestor, event.xselection.property);
			}
		}
	  return s;
	}

	char *XPaste() {
		char * c = 0;
		UTF8 = XInternAtom(display, "UTF8_STRING", True);
		if(UTF8 != None) c = XPasteType(UTF8);
		if(!c) c = XPasteType(XA_STRING);
		return c;
	}
	
	static void XCopy(Atom selection, unsigned char * text, int size) {
		XEvent event;
		Window owner;
		XSetSelectionOwner (display, selection, window, 0);
		if (XGetSelectionOwner (display, selection) != window) return;
		while (1) {
			XNextEvent (display, &event);
			if (event.type == SelectionRequest)
			{
				if (event.xselectionrequest.selection != selection) break;
				XSelectionRequestEvent * xsr = &event.xselectionrequest;
				XSelectionEvent ev = {0};
				int R = 0;
				ev.type = SelectionNotify, ev.display = xsr->display, ev.requestor = xsr->requestor,
				ev.selection = xsr->selection, ev.time = xsr->time, ev.target = xsr->target, ev.property = xsr->property;
				if (ev.target == targets_atom) R = XChangeProperty (ev.display, ev.requestor, ev.property, XA_ATOM, 32,
						PropModeReplace, (unsigned char*)&UTF8, 1);
				else if (ev.target == XA_STRING || ev.target == text_atom) 
					R = XChangeProperty(ev.display, ev.requestor, ev.property, XA_STRING, 8, PropModeReplace, text, size);
				else if (ev.target == UTF8)
					R = XChangeProperty(ev.display, ev.requestor, ev.property, UTF8, 8, PropModeReplace, text, size);
				else ev.property = None;
				if ((R & 2) == 0) XSendEvent (display, ev.requestor, 0, 0, (XEvent *)&ev);
			}
			else if (event.type == SelectionClear)
			{
				return;
			}
		}
	}	
	
#endif

std::string AL4_clipboard::Get_text_from_clipboard()
{
    std::string text = std::string("");
#ifdef MSWINDOWS
    if (!OpenClipboard(nullptr)) return std::string("");
    HANDLE hData = GetClipboardData(CF_TEXT);
    if (hData == nullptr) return std::string("");
    
    char* pszText = static_cast<char *>( GlobalLock(hData ) );
    if (pszText != nullptr)
        text = pszText;
    
    GlobalUnlock(hData);
    CloseClipboard();
#else
	display = XOpenDisplay(0);
	int N = DefaultScreen(display);
	window = XCreateSimpleWindow(display, RootWindow(display, N), 0, 0, 1, 1, 0,
		BlackPixel(display, N), WhitePixel(display, N)
	);	
	text = XPaste();
#endif
    return text;
}

bool AL4_clipboard::Clipboard_has_text()
{
	bool RESULT = false;
#ifdef MSWINDOWS
    if (!OpenClipboard(nullptr)) return RESULT;
    HANDLE hData = GetClipboardData(CF_TEXT);
    if (hData != nullptr) RESULT = true;
    CloseClipboard();
#else
	display = XOpenDisplay(0);
	int N = DefaultScreen(display);
	window = XCreateSimpleWindow(display, RootWindow(display, N), 0, 0, 1, 1, 0,
		BlackPixel(display, N), WhitePixel(display, N)
	);	
	RESULT = XPaste() != nullptr;
#endif
    return RESULT;
}

void AL4_clipboard::Set_text_to_clipboard(std::string Text)
{
#ifdef MSWINDOWS
    int n = Text.length();
    int len = (n+1) * sizeof(char);
    HANDLE hMem = 0;
    if (Text.length() != 0)
    {
        hMem = GlobalAlloc(GMEM_MOVEABLE, len);
        memcpy(GlobalLock(hMem), &Text[0], len);
        GlobalUnlock(hMem);
    }
    //AL4_system.WriteLine(std::string("$$$$$$$$$$$$$$$$ "));
    if (!OpenClipboard(nullptr)) return;
    EmptyClipboard();
    if (Text.length() != 0)
    {
        SetClipboardData(CF_TEXT, hMem);
    }
    CloseClipboard();
#else
	display = XOpenDisplay(0);
	int N = DefaultScreen(display);
	window = XCreateSimpleWindow(display, RootWindow(display, N), 0, 0, 1, 1, 0,
		BlackPixel(display, N), WhitePixel(display, N));	
	targets_atom = XInternAtom(display, "TARGETS", 0);
	text_atom = XInternAtom(display, "TEXT", 0);
	UTF8 = XInternAtom(display, "UTF8_STRING", 1);
	if (UTF8 == None) UTF8 = XA_STRING;
	Atom selection = XInternAtom(display, "CLIPBOARD", 0);
	XCopy(selection, (unsigned char*)&Text[0], Text.length());
#endif
}

int AL4_clipboard::Files_from_clipboard(DynAStr* Paths)
{
    std::string text = Get_text_from_clipboard();
#ifdef MSWINDOWS
    if (!OpenClipboard(nullptr)) return 0;
    if (!IsClipboardFormatAvailable(CF_HDROP)) return 0;
    HDROP f = (HDROP)GetClipboardData(CF_HDROP);
    if (f == nullptr) return 0;
    int RESULT = 0;
    
    int numFiles = DragQueryFile(f, -1, nullptr, 0);
    
    char* buffer = new char[MAX_PATH];
    for (int i=0; i < numFiles; i++) {
    	buffer[0] = (char)0;
    	DragQueryFile(f, i, buffer, sizeof(buffer));
    	Paths->Add(buffer);
    }
    delete[] buffer;
    
    HANDLE deffect = (HANDLE)RegisterClipboardFormat("Preferred DropEffect");
    if (deffect != 0) {
    	HANDLE chandle = GetClipboardData((UINT)deffect);
    	if (chandle != nullptr) {
    		void* Mem = GlobalLock(chandle);
    		if (*(byte*)Mem == 2) RESULT = 1;
    		GlobalUnlock(chandle); 
    	}
    }
    CloseClipboard();
    return RESULT;
#else
	std::string s = Get_text_from_clipboard();
	if (s == "") return 0;
	M__Split_string_native(Paths, s, (char)10);
    return 0;
#endif
}

void AL4_clipboard::Files_to_clipboard(ArrayStr* Paths, byte Op)
{
#ifdef MSWINDOWS
    std::string List = "";
    for (int i = 0; i < Paths->Count(); i++) {
		List += Paths->get(i) + (char)0;
	}
	int iLen = List.length() + 1;
    HANDLE gbl = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE | GMEM_ZEROINIT,
		sizeof(DROPFILES) + iLen);
    if (gbl == nullptr) return;
    int RESULT = 0;
    
    if (OpenClipboard(0)) {
    	EmptyClipboard();
    	DROPFILES* dropFiles = (DROPFILES*)GlobalLock(gbl);
    	memmove(/*dest=*/dropFiles, /*src=*/(void *)List.c_str(), iLen);
    	GlobalUnlock(gbl);
    	
    	SetClipboardData(CF_HDROP, gbl);
    	if (Op == 1) {
    		unsigned int f = RegisterClipboardFormat("Preferred DropEffect");
    		gbl = GlobalAlloc(GMEM_SHARE | GMEM_MOVEABLE | GMEM_ZEROINIT,
    			sizeof(unsigned int));
    		unsigned int * d = (unsigned int*) GlobalLock(gbl);
    		*d = 2;
    		SetClipboardData(f, gbl);
    		GlobalUnlock(gbl);
    	}	
    	CloseClipboard();
    }
#else
	std::string s = "";
	for (int i = 0; i < Paths.Count(); i++) {
		if (s != "") s += (char)10;
		s += Paths.get(i);
	}
	Set_text_to_clipboard(s);
#endif
}

bool AL4_clipboard::Clipboard_has_files()
{
    DynAStr* d = new DynAStr();
    Files_from_clipboard(d);
    bool RESULT = d->Count()  > 0;
    delete d;
    return RESULT;
}


/*
    
CONST STR:
    NATIVE_Import_clipboard = ""

    NATIVE_Text_from_clipboard = @
    "RESULT = AL4_clipboard::Get_text_from_clipboard();"

    NATIVE_Clipboard_has_text = @
    "RESULT = AL4_clipboard::Clipboard_has_text();"

    NATIVE_Text_to_clipboard = @
    "AL4_clipboard::Set_text_to_clipboard(X_Text);"
    
    NATIVE_Files_from_clipboard = @
    "RESULT = AL4_clipboard::Files_from_clipboard((DynAStr*)X_Paths);"     
    
	NATIVE_Files_to_clipboard = @
    "AL4_clipboard::Files_to_clipboard(X_Paths, X_Op);"

    NATIVE_Clipboard_has_files = @
    "RESULT = AL4_clipboard::Clipboard_has_files();"

    .
        

END
*/

