#include <stdio.h>
#include <X11/Xmd.h>
#include <X11/Xlib.h>
#include <gdk/gdkx.h>
#include <gtk/gtk.h>

#include "xaux_common.h"
#include "xaux_ext_common.h"
#include "le_aux_protocol.h"

#include "common_aux_methods.h"

/* Define Aux class */
xaux_class_t *xc_ = 0;
int im_ = 0;
int ic_ = 0;

#define ATOM_NUM_COMPOSITEAUX   32

/* Define Aux class */
xaux_class_t xaux_class = {
    COMPOSITE_AUX_CLASS_NAME, 1,
    NULL,
    (Window) 0, (Window) 0, (Window) 0,
    (Atom) 0, (Atom) 0, (Atom) 0, (Atom) 0,
    {(Atom) 0}, ATOM_NUM_COMPOSITEAUX, 0,
    {(Atom) 0}, ATOM_NUM_COMPOSITEAUX, 0,
    NULL,
};

int gLocaleID = 0;
Display *gDisplay = NULL;
Window gWindow = 0;


/*
        Event Handler
*/
GdkFilterReturn xaux_ext_event_handler(GdkXEvent * gdk_xevent,
                                       GdkEvent * event,
                                       gpointer user_data)
{
    XEvent *xevent = (XEvent *) gdk_xevent;

    switch (xevent->type) {
    case ClientMessage:
        xaux_ext_process_client_message((Display *) gDisplay,
                                        (XClientMessageEvent *) xevent);
        break;
    case SelectionClear:
        break;
    }
    return GDK_FILTER_CONTINUE;
}

/*
        xaux_ext_init_classes(): Initialize the Atom of Auxiliary Window.
        It is in ../xaux_common/xaux_ext_common.c
*/
int xaux_ext_register_classes(GdkWindow * window)
{
    char *locale;

    gDisplay = (Display *) GDK_WINDOW_XDISPLAY(window);
    gWindow = (Window) GDK_WINDOW_XWINDOW(window);

    /* Register aux class */
    if (xaux_ext_init_classes(gDisplay, (xaux_class_t *) & xaux_class, gWindow) == False)
        return (False);

    return (True);
}

/*
Note:
     xaux_ext_Start(), xaux_ext_Draw(), xaux_ext_Done()
     These three functions are all called by xaux_ext_process_client_message()

     xaux_ext_SetValue() will send auxiliary window information to language engine;
*/

/* Method - Start */
Bool xaux_ext_Start(xaux_class_t * xc, aux_ext_data_t * aux_ext_data,
                    Atom atom)
{
    DEBUG_printf("ext_Start: im:%d, ic:%d\n", aux_ext_data->im,
                 aux_ext_data->ic);
    im_ = aux_ext_data->im;
    ic_ = aux_ext_data->ic;
    xc_ = xc;

    /* inform Language Engine that PaletteAux has started. */

    return True;
}

/* Method - Draw */
Bool xaux_ext_Draw(xaux_class_t * xc, aux_ext_data_t * aux_ext_data,
                   Atom atom)
{
    DEBUG_printf("ext_Draw == im:0x%x, ic:0x%x\n", aux_ext_data->im,
                 aux_ext_data->ic);
    im_ = aux_ext_data->im;
    ic_ = aux_ext_data->ic;
    xc_ = xc;

    composite_aux_Proc_LE_Notify(aux_ext_data);
    return True;
}

/* Method - Done */
Bool xaux_ext_Done(xaux_class_t * xc, aux_ext_data_t * aux_ext_data,
                   Atom atom)
{
    DEBUG_printf("ext_Done im:0x%x, ic_id:0x%x\n", aux_ext_data->im,
                 aux_ext_data->ic);
    return True;
}

void composite_aux_Set_Selection_Owner()
{
    Atom aux_atom =
        XInternAtom(gDisplay, "CH_PROPERTIES_MODULE_ATOM", False);

    XSetSelectionOwner(gDisplay, aux_atom, gWindow, CurrentTime);
}

void composite_aux_get_cursor_rect(aux_ext_data_t *aux_ext_data, int *pos_x, int *pos_y, int *caret_w, int* caret_h)
{
    int win_x = 0, win_y = 0;

    Window w_none;
    Window clientwindow;
    XWindowAttributes attr;

    clientwindow = aux_ext_data->clientwin;
    if (clientwindow && gDisplay) {
        XGetWindowAttributes(gDisplay, clientwindow, &attr);
        if (attr.root)
            XTranslateCoordinates(gDisplay, clientwindow, attr.root, -(attr.border_width), -(attr.border_width), &win_x, &win_y, &w_none );
    }

    /*
    if ((win_x == 0 && win_y == 0) || (aux_ext_data->point.x == 0 && aux_ext_data->point.y == 0)) {
        win_x =  (gdk_screen_width () > 640)?200:100;
        win_y = (gdk_screen_height () - 200);
    } else {
    */
        win_x += aux_ext_data->point.x;
        win_y += aux_ext_data->point.y;
    //}

    *pos_x = win_x;
    *pos_y = win_y-20;
    *caret_w = 1;
    *caret_h = 25;
}

void composite_aux_get_cursor_position(aux_ext_data_t *aux_ext_data, int *pos_x, int *pos_y)
{
    int win_x = 0, win_y = 0;

    Window w_none;
    Window clientwindow;
    XWindowAttributes attr;

    clientwindow = aux_ext_data->clientwin;
    if (clientwindow && gDisplay) {
        XGetWindowAttributes(gDisplay, clientwindow, &attr);
        if (attr.root)
            XTranslateCoordinates(gDisplay, clientwindow, attr.root, -(attr.border_width), -(attr.border_width), &win_x, &win_y, &w_none );
    }

    /*
    if ((win_x == 0 && win_y == 0) || (aux_ext_data->point.x == 0 && aux_ext_data->point.y == 0)) {
        win_x =  (gdk_screen_width () > 640)?200:100;
        win_y = (gdk_screen_height () - 200);
    } else {
    */
        win_x += aux_ext_data->point.x;
        win_y += aux_ext_data->point.y + 22;
    //}

    *pos_x = win_x;
    *pos_y = win_y;
}

/* ================================================================= */
/*             Send information to Language Engine                   */
/* ================================================================= */
void composite_aux_Connect_To_LE_Request(int locale_id)
{
    int nIntegerCount, pIntegerList[2];

    nIntegerCount = 2;
    pIntegerList[0] = SELECTAUX_CONNECT;
    pIntegerList[1] = locale_id;
    NotifyIntegerListDataToLanguageEngine(gDisplay, nIntegerCount,
                                          pIntegerList);
}

NotifyIntegerListDataToLanguageEngine(Display * display,
                                      int nIntegerCount, int *pIntegerList)
{
    aux_ext_data_t aux_ext_data;

    aux_ext_data.im = im_;
    aux_ext_data.ic = ic_;
    aux_ext_data.integer_count = nIntegerCount;
    aux_ext_data.integer_list = pIntegerList;
    aux_ext_data.string_count = 0;
    aux_ext_data.string_list = NULL;
    aux_ext_data.string_ptr = NULL;
    aux_ext_data.point.x = 0;
    aux_ext_data.point.y = 0;

    xaux_ext_SetValue(display, xc_, &aux_ext_data);
    XFlush(display);
}

NotifyStringListDataToLanguageEngine(Display * display,
                                     int nIntegerCount, int *pIntegerList,
                                     int nStringCount, int *pStringLen,
                                     char **pStringList)
{
    int i;

    aux_ext_data_t aux_ext_data;
    aux_ext_string_t *p;

    aux_ext_data.im = im_;
    aux_ext_data.ic = ic_;
    aux_ext_data.integer_count = nIntegerCount;
    aux_ext_data.integer_list = pIntegerList;
    aux_ext_data.point.x = 0;
    aux_ext_data.point.y = 0;

    aux_ext_data.string_count = nStringCount;
    aux_ext_data.string_ptr = NULL;

    if (nStringCount > 0) {
        aux_ext_data.string_list =
            (aux_ext_string_t *) calloc(nStringCount,
                                        sizeof(aux_ext_string_t));
        for (i = 0; i < nStringCount; i++) {
            aux_ext_string_t *p = &aux_ext_data.string_list[i];
            p->length = pStringLen[i];
            p->ptr = (unsigned char *) (pStringList[i]);
        }
    }

    xaux_ext_SetValue(display, xc_, &aux_ext_data);
    XFlush(display);

    free(aux_ext_data.string_list);
}
