
#include "gtk-local.h"

#include "zoom-tool.h"
#include "gtk-graph.h"
#include "gtk-toolbar.h"
#include <gdk/gdkkeysyms.h>

#ifdef GAG_USE_GRAB
static int _use_grab_pointer = 1;
static int _use_grab_keyboard = 1;
#else
static int _use_grab_pointer = 0;
static int _use_grab_keyboard = 0;
#endif

#ifdef GAG_USE_CAIRO
    static cairo_t *_zoom_cr;
#else
    static GdkGC *_zoom_gc;
#endif
static GdkCursor *_zoom_cursor;

typedef enum _zoom_drawing_mode {
    _ZOOM_FIRST, _ZOOM_INTERMEDIATE, _ZOOM_LAST, _ZOOM_DRAW
} _zoom_drawing_mode_t;

static void _draw_zoom_cursor( gtv_zoom_data_t *data, gint x, gint y,
 _zoom_drawing_mode_t mode)
{
    GdkWindow *w;

    if (mode == _ZOOM_INTERMEDIATE) {
        // "undo" draw on last position
        _draw_zoom_cursor( data, *data->xpos, *data->ypos, _ZOOM_DRAW);
    }

    //printf("_draw_zoom_cursor: %d %d %d\n", mode, x, y);
#ifdef GAG_USE_CAIRO
    cairo_move_to(_zoom_cr, x, 0);
    cairo_line_to (_zoom_cr, x, data->env->Height_graphique);
    cairo_stroke(_zoom_cr);
    cairo_move_to(_zoom_cr, 0, y);
    cairo_line_to (_zoom_cr, data->env->Width_graphique, y);
    cairo_stroke(_zoom_cr);
	// not drawing the rectangle for now because it's too slow
/*
    if (data->width && data->height ) {
        cairo_rectangle(_zoom_cr, x - data->width, y - data->height, 
        data->width * 2, data->height * 2);
        cairo_stroke(_zoom_cr);
    }
*/
#else
    w = ((ggtk_env_t *)data->env)->win_graph;
    gdk_draw_line( w, _zoom_gc, x, 0, x, data->env->Height_graphique);
    gdk_draw_line( w, _zoom_gc, 0, y, data->env->Width_graphique, y);
    if (data->width && data->height ) {
        gdk_draw_rectangle( w, _zoom_gc, FALSE, x - data->width, y -
         data->height, data->width * 2, data->height * 2);
    }
#endif

    if (mode != _ZOOM_DRAW) {
        /* save values */
        *data->xpos = x;
        *data->ypos = y;
    }
}

static void _draw_zoom_cursor_handler( gpointer user_data)
{
    gtv_zoom_data_t *data = (gtv_zoom_data_t *)user_data;
    _draw_zoom_cursor( data, *data->xpos, *data->ypos, _ZOOM_DRAW);
}

static void ggtk_ungrab( ggtk_env_t *genv)
{
    if (_use_grab_pointer && gdk_pointer_is_grabbed()) {
        gdk_pointer_ungrab( GDK_CURRENT_TIME);
        gdk_window_set_cursor( genv->win_graph, _zoom_cursor);
        gdk_cursor_unref( _zoom_cursor);
    }
    if (_use_grab_keyboard) {
        gdk_keyboard_ungrab( GDK_CURRENT_TIME);
    }
#if 0 && !defined(darwin)
    /* menu don't work on mac with this setting */
    gtk_window_set_accept_focus( GTK_WINDOW(genv->main_widget), FALSE);
#endif
}

void ggtk_deactivate_zoom( gtv_zoom_data_t *data)
{
    ggtk_env_t *genv = (ggtk_env_t *)data->env;

    //printf( "ggtk_deactivate_zoom\n");
    if (data->command) {
        _draw_zoom_cursor( data, *data->xpos, *data->ypos, _ZOOM_LAST);
    }
    ggtk_set_pointer_event_handler( NULL, NULL);
    ggtk_set_post_refresh_handler( (ggtk_env_t *)data->env, NULL, NULL);
#ifdef GAG_USE_CAIRO
    cairo_destroy( _zoom_cr);
#else
    g_object_unref( _zoom_gc);
#endif
    ggtk_ungrab( genv);
#ifndef GGTK_USE_GRAB_KEYBOARD
    //_gtk_widget_remove_events( ((ggtk_env_t *)data->env)->drawing_area,
     //GDK_POINTER_MOTION_MASK);
#endif
    sic_post_widget_created();
}

static int _zoom_handler( GdkEvent *event, gpointer event_data, gpointer user_data)
{
    gtv_zoom_data_t *zoom_data = (gtv_zoom_data_t *)user_data;
    if (event->type == GDK_BUTTON_PRESS) {
        ggtk_env_t *genv = (ggtk_env_t *)zoom_data->env;
        GdkEventButton *e = (GdkEventButton *)event;
        gint win_x;
        gint win_y;

        if (gdk_window_at_pointer( &win_x, &win_y) == genv->win_graph) {
            switch (e->button) {
            case 1:
                *zoom_data->command = '^';
                break;
            case 2:
                *zoom_data->command = '&';
                break;
            case 3:
                *zoom_data->command = '*';
                break;
            }
            ggtk_deactivate_zoom( zoom_data);
        } else {
            ggtk_ungrab( genv);
            ggtk_set_post_refresh_handler( genv, NULL, NULL);
            gtk_widget_add_events( genv->drawing_area, GDK_POINTER_MOTION_MASK);
        }
        return 1;
    } else if (event->type == GDK_MOTION_NOTIFY) {
        GdkEventMotion *e = (GdkEventMotion *)event;

        _draw_zoom_cursor( zoom_data, e->x, e->y, _ZOOM_INTERMEDIATE);
        return 1;
    } else if (event->type == GDK_KEY_PRESS) {
        GdkEventKey *e = (GdkEventKey *)event;
        int xo = 0;
        int yo = 0;

        switch (e->keyval) {
        case GDK_Left:
            xo = -1;
            break;
        case GDK_Right:
            xo = 1;
            break;
        case GDK_Up:
            yo = -1;
            break;
        case GDK_Down:
            yo = 1;
            break;
        }
        if (xo || yo) {
            ggtk_env_t *genv = (ggtk_env_t *)zoom_data->env;
            GdkDisplay *display;
            gint root_x;
            gint root_y;

            display = gdk_display_get_default();
#if defined(BUG_GTK_WINDOWS) && GTK_CHECK_VERSION(2,18,0)
            gdk_window_get_root_coords( genv->drawing_area->window,
             *zoom_data->xpos, *zoom_data->ypos, &root_x, &root_y);
#else
            gdk_window_get_origin( genv->drawing_area->window, &root_x,
             &root_y);
            root_x += *zoom_data->xpos;
            root_y += *zoom_data->ypos;
#endif
#if GTK_CHECK_VERSION(2,8,0)
            gdk_display_warp_pointer( display, gdk_display_get_default_screen(
             display), root_x + xo, root_y + yo);
#endif
            return 1;
        } else {
            *zoom_data->command = (char)gdk_keyval_to_unicode( e->keyval);
            if (e->keyval == GDK_dead_circumflex)
                *zoom_data->command = '^';
            //printf("%d (%s): %d\n", e->keyval, gdk_keyval_name( e->keyval), *zoom_data->command);
            ggtk_deactivate_zoom( zoom_data);
            return 1;
        }
    }
    return 0;
}

void ggtk_activate_zoom( gtv_zoom_data_t *data)
{
    ggtk_env_t *genv = (ggtk_env_t *)data->env;
    GdkGrabStatus status;
    GdkColor *color;
    GdkColor zoom_color;

    if (data->called_from_main_thread)
        return;
    //printf( "ggtk_activate_zoom: %d %d\n", *data->command, genv->herit.fen_num);
#ifndef GAG_USE_GRAB
#ifndef WIN32
    //if (getenv( "KDE_FULL_SESSION") != NULL)
    {
        _use_grab_pointer = 1;
        _use_grab_keyboard = 1;
    }
#endif
#endif
    *data->command = 0;
    ggtk_set_pointer_event_handler( _zoom_handler, data);
#ifdef GAG_USE_CAIRO
    _zoom_cr = gdk_cairo_create(genv->win_graph);
    cairo_set_source_rgb(_zoom_cr, 1., 1., 1.);
    // CAIRO_OPERATOR_DIFFERENCE requires cairo >= 1.9.2
    cairo_set_operator(_zoom_cr, CAIRO_OPERATOR_DIFFERENCE);
#else
    _zoom_gc = gdk_gc_new( genv->win_graph);
    gdk_gc_set_function( _zoom_gc, GDK_INVERT);
#endif
    if (_use_grab_pointer) {
        _zoom_cursor = gdk_cursor_new( GDK_LEFT_PTR);
        status = gdk_pointer_grab( genv->win_graph, FALSE,
         GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK,
#if defined(GAG_SYSV) || defined(darwin)
         /* same test as sic_sem_timed_wait */
         //genv->win_graph,
         NULL,
#else
         NULL,
#endif
         _zoom_cursor, GDK_CURRENT_TIME);
        if (status != GDK_GRAB_SUCCESS) {
            fprintf( stderr, "gdk_pointer_grab error\n");
            ggtk_deactivate_zoom( data);
            return;
        }
    } else {
        gtk_widget_add_events( genv->drawing_area, GDK_POINTER_MOTION_MASK);
    }
    {
        gint x;
        gint y;
        GdkModifierType mask;

        gdk_window_get_pointer(genv->win_graph, &x, &y, &mask);
        _draw_zoom_cursor( data, x, y, _ZOOM_FIRST);
        ggtk_set_post_refresh_handler( genv, _draw_zoom_cursor_handler, data);
#if 0 && !defined(darwin)
        /* menu don't work on mac with this setting */
        gtk_window_set_accept_focus( GTK_WINDOW(genv->main_widget), TRUE);
#endif
        if (_use_grab_keyboard) {
            if (gdk_keyboard_grab(genv->win_graph, FALSE, GDK_CURRENT_TIME) !=
             GDK_GRAB_SUCCESS)
                fprintf( stderr, "gdk_keyboard_grab error\n");
        } else {
#ifdef WIN32
            gtk_window_present(GTK_WINDOW(genv->main_widget));
#else
            gdk_window_focus( genv->main_widget->window, GDK_CURRENT_TIME);
#endif
        }
    }
}
