/* Many part of code are ripped of an example from JX's site */

#include "wconfig.h"

#ifdef XDND

#include <X11/Xlib.h>
#include "WindowMaker.h"
#include "window.h"
#include "dock.h"
#include "xdnd.h"
#include "motif.h"

#include "workspace.h"

#include "stdlib.h"

#include <X11/Xatom.h>


#define XDND_VERSION 3L

Atom _XA_XdndAware;
Atom _XA_XdndEnter;
Atom _XA_XdndLeave;
Atom _XA_XdndDrop;
Atom _XA_XdndPosition;
Atom _XA_XdndStatus;
Atom _XA_XdndActionCopy;
Atom _XA_XdndSelection;
Atom _XA_XdndFinished;
Atom _XA_WINDOWMAKER_XDNDEXCHANGE;

/*
Atom _XA_MOTIF_DRAG_RECEIVER_INFO;
Atom _XA_MOTIF_DRAG_AND_DROP_MESSAGE;
*/

Atom atom_support;

void wXDNDInitializeAtoms()
{

    _XA_XdndAware = XInternAtom(dpy, "XdndAware", False);
    _XA_XdndEnter = XInternAtom(dpy, "XdndEnter", False);
    _XA_XdndLeave = XInternAtom(dpy, "XdndLeave", False);
    _XA_XdndDrop = XInternAtom(dpy, "XdndDrop", False);
    _XA_XdndPosition = XInternAtom(dpy, "XdndPosition", False);
    _XA_XdndStatus = XInternAtom(dpy, "XdndStatus", False);
    _XA_XdndActionCopy = XInternAtom(dpy, "XdndActionCopy", False);
    _XA_XdndSelection = XInternAtom(dpy, "XdndSelection", False);
    _XA_XdndFinished = XInternAtom(dpy, "XdndFinished", False);

    _XA_WINDOWMAKER_XDNDEXCHANGE = XInternAtom(dpy, "_WINDOWMAKER_XDNDEXCHANGE", False);

    /*
    _XA_MOTIF_DRAG_RECEIVER_INFO = XInternAtom(dpy, "_MOTIF_DRAG_RECEIVER_INFO",False);
    _XA_MOTIF_DRAG_AND_DROP_MESSAGE = XInternAtom(dpy, "_MOTIF_DRAG_AND_DROP_MESSAGE", False);
    */
}

void wXDNDMakeAwareness(Window window) {
    long int xdnd_version = 3;
    /*
    MotifDragReceiverInfo info;
    */
    XChangeProperty (dpy, window, _XA_XdndAware, XA_ATOM,
            32, PropModeAppend, (char *)&xdnd_version, 1);

    /*** MOTIF ***
    info.byte_order = '\0';
    info.protocol_version = 0;
    info.protocol_style = XmDRAG_DYNAMIC;
    info.proxy_window = 0;
    info.num_drop_sites = 0;
    info.total_size = sizeof(info);

    XChangeProperty (dpy, window,
                   _XA_MOTIF_DRAG_RECEIVER_INFO,
                   _XA_MOTIF_DRAG_RECEIVER_INFO,
                   8, PropModeReplace,
                   (unsigned char *)&info,
                   sizeof (info));
                   */
}

void wXDNDClearAwareness(Window window) {
    long int xdnd_version = 3;
    XDeleteProperty (dpy, window, _XA_XdndAware);
}

Bool
wXDNDProcessSelection(XEvent *event)
{
	WScreen *scr = wScreenForWindow(event->xselection.requestor);
    char *dropdata;
    char *retain;
    Atom ret_type;
    int ret_format;
    unsigned long ret_item;
    unsigned long remain_byte;
    char * delme;
    XEvent xevent;
    Window selowner = XGetSelectionOwner(dpy,_XA_XdndSelection);
    WMBag *items;


    XGetWindowProperty(dpy, event->xselection.requestor,
            _XA_WINDOWMAKER_XDNDEXCHANGE,
            0, 65536, True, atom_support, &ret_type, &ret_format,
            &ret_item, &remain_byte, (unsigned char **)&delme);
    if (delme){
		scr->xdestring=delme;
    }

    /*send finished*/
    memset (&xevent, 0, sizeof(xevent));
    xevent.xany.type = ClientMessage;
    xevent.xany.display = dpy;
    xevent.xclient.window = selowner;
    xevent.xclient.message_type = _XA_XdndFinished;
    xevent.xclient.format = 32;
    XDND_FINISHED_TARGET_WIN(&xevent) = event->xselection.requestor;
    XSendEvent(dpy, selowner, 0, 0, &xevent);

    /*process dropping*/
    if (scr->xdestring) {
        int length, str_size;
        int total_size = 0;
        char *tmp;

        items = WMCreateBag(1);
        retain = wstrdup(scr->xdestring);
        XFree(scr->xdestring); /* since xdestring was created by Xlib */

        length = strlen(retain);

        /* search in string */
        while (length--) {
            if (retain[length] == '\r') { /* useless char, nuke it */
                retain[length] = 0;
            }
            if (retain[length] == '\n') {
                str_size = strlen(&retain[length + 1]);
                if(str_size) {
                    WMPutInBag(items, wstrdup(&retain[length + 1]));
                    total_size += str_size + 3; /* reserve for " \"\"" */
                    if (length)
                        WMAppendBag(items, WMCreateBag(1));
                }
                retain[length] = 0;
            }
        }
        /* final one */
        WMPutInBag(items, wstrdup(retain));
        total_size += strlen(retain) + 3;
        free(retain);

        /* now pack new string */
        scr->xdestring = wmalloc(total_size);
        scr->xdestring[0]=0; /* empty string */
        for(length = WMGetBagItemCount(items)-1; length >=0; length--) {
            tmp = WMGetFromBag(items, length);
            if (!strncmp(tmp,"file:",5)) {
                /* add more 2 chars while removing 5 is harmless */
                strcat(scr->xdestring, " \"");
                strcat(scr->xdestring, &tmp[5]);
                strcat(scr->xdestring, "\"");
            } else {
                /* unsupport object, still need more " ? tell ]d */
                strcat(scr->xdestring, &tmp[5]);
            }
            free(tmp);
        }
        WMFreeBag(items);
        wDockReceiveDNDDrop(scr,event);
        /*
        printf("free ");
        puts(scr->xdestring);
        */
        free(scr->xdestring); /* this xdestring is not from Xlib (no XFree) */
    }
}

Bool
isAwareXDND(Window window)
{
    Atom actual;
    int format;
    unsigned long count, remaining;
    unsigned char *data=0;
    Atom *types, *t;

    if (!window) return False;
    XGetWindowProperty (dpy, window, _XA_XdndAware,
                    0, 0x8000000L, False, XA_ATOM,
                    &actual, &format,
                    &count, &remaining, &data);
    if (actual != XA_ATOM || format != 32 || count == 0 || !data) {
        if (data)
            XFree (data);
        return False;
    }
    if (data)
        XFree (data);
    return True;
}

Bool
acceptXDND(Window window)
{
	WScreen *scr = wScreenForWindow(window);
    WWindow *wwin = wWindowFor(window);
    WDock *dock;
    int icon_pos,i;
    
    icon_pos = -1;
    if ((dock = scr->dock)!=NULL) {
        for (i=0; i<dock->max_icons; i++) {
            if (dock->icon_array[i]
                && dock->icon_array[i]->icon->core->window==window) {
                icon_pos = i;
                break;
            }
        }
    }
    if (icon_pos<0 && (dock = scr->workspaces[scr->current_workspace]->clip)!=NULL) {
        for (i=0; i<dock->max_icons; i++) {
            if (dock->icon_array[i]
                && dock->icon_array[i]->icon->core->window==window) {
                icon_pos = i;
                break;
            }
        }
    }
    if (icon_pos<0) return False;
    if (!dock) return False;
    if (isAwareXDND(dock->icon_array[icon_pos]->icon->icon_win)) return False;
    
    if (dock->icon_array[icon_pos]->dnd_command!=NULL) return True;
    
    return False;
}

Bool
wXDNDProcessClientMessage(XClientMessageEvent *event)
{
    /* test */
    {
    char * name = XGetAtomName(dpy, event->message_type);
    /*
    printf("Get %s\n",name);
    */
    XFree(name);
    }

    /*
    if (event->message_type == _XA_MOTIF_DRAG_AND_DROP_MESSAGE) {
        printf("motif dnd msg %d\n",event->data.b[0]);
        if (event->data.b[0] == XmDROP_START){
            unsigned x_root, y_root, flags;
            unsigned char reason;
            unsigned long timestamp;
            Atom atom;
            Window source_window;
            MotifDragInitiatorInfo *initiator_info;
            Atom ret_type;
            int ret_format;
            unsigned long ret_item;
            unsigned long remain_byte;

            reason = event->data.b[0];
            flags = event->data.s[1];
            timestamp = event->data.l[1];
            x_root = event->data.s[4];
            y_root = event->data.s[5];
            atom = event->data.l[3];
            source_window = event->data.l[4];

    XGetWindowProperty(dpy, source_window, atom,
            0, sizeof(*initiator_info), True, atom_support,
            &ret_type, &ret_format,
            &ret_item, &remain_byte, (unsigned char **)&initiator_info);
        }
    }
    else */
    if (event->message_type == _XA_XdndEnter) {
        if ((event->data.l[1] & 1) == 0){
            atom_support = event->data.l[2];
        }
        /*
        else puts("enter more than 3 types");
        */
        return True;
    } else if (event->message_type == _XA_XdndLeave) {
        return True;
    } else if (event->message_type == _XA_XdndDrop) {
        if (event->data.l[0] == XGetSelectionOwner(dpy, _XA_XdndSelection)){
            XConvertSelection(dpy, _XA_XdndSelection, atom_support,
                    _XA_WINDOWMAKER_XDNDEXCHANGE, event->window, CurrentTime);
        }
        else {
            puts("wierd selection owner? QT?");
            XConvertSelection(dpy, _XA_XdndSelection, atom_support,
                    _XA_WINDOWMAKER_XDNDEXCHANGE, event->window, CurrentTime);
        }
        return True;
    } else if (event->message_type == _XA_XdndPosition) {
        XEvent xevent;
        Window srcwin = event->data.l[0];
        if (atom_support != XInternAtom(dpy, "text/uri-list", False)) {
            return True;
        }
        {
            memset (&xevent, 0, sizeof(xevent));
            xevent.xany.type = ClientMessage;
            xevent.xany.display = dpy;
            xevent.xclient.window = srcwin;
            xevent.xclient.message_type = _XA_XdndStatus;
            xevent.xclient.format = 32; 

            XDND_STATUS_TARGET_WIN (&xevent) = event->window;
            XDND_STATUS_WILL_ACCEPT_SET (&xevent, acceptXDND(event->window));
            XDND_STATUS_WANT_POSITION_SET(&xevent, True);
            XDND_STATUS_RECT_SET(&xevent, 0, 0, 1024,768);
            XDND_STATUS_ACTION(&xevent) = _XA_XdndActionCopy;

            XSendEvent(dpy, srcwin, 0, 0, &xevent);
        }
        return True;
    }
    return False;
}

#endif
