/*  moko-panel-applet.c
 *
 *  Authored By Michael 'Mickey' Lauer <mlauer@vanille-media.de>
 *
 *  Copyright (C) 2006-2007 OpenMoko Inc.
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser Public License as published by
 *  the Free Software Foundation; version 2 of the license.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser Public License for more details.
 *
 *  Current Version: $Rev$ ($Date$) [$Author: mickey $]
 */

#include "moko-panel-applet.h"

#include <matchbox-panel/mb-panel-scaling-image.h>
#include <gtk/gtkmenu.h>

#undef DEBUG_THIS_FILE
//#define DEBUG_THIS_FILE

#ifdef DEBUG_THIS_FILE
#define moko_debug(fmt,...) g_debug(fmt,##__VA_ARGS__)
#define moko_debug_minder(predicate) moko_debug( __FUNCTION__ ); g_return_if_fail(predicate)
#else
#define moko_debug(...)
#endif

G_DEFINE_TYPE (MokoPanelApplet, moko_panel_applet, GTK_TYPE_ALIGNMENT)

#define MOKO_PANEL_APPLET_GET_PRIVATE(o)   (G_TYPE_INSTANCE_GET_PRIVATE ((o), MOKO_TYPE_PANEL_APPLET, MokoPanelAppletPrivate))
#define MOKO_PANEL_APPLET_TAP_HOLD_TIMEOUT  750

typedef struct _MokoPanelAppletPrivate
{
    gboolean is_initialized;
    gboolean hold_timeout_triggered;
    char* filename_for_icon;
} MokoPanelAppletPrivate;

enum {
    DUMMY_SIGNAL,
    CLICKED,
    TAP_HOLD,
    LAST_SIGNAL,
};

static guint moko_panel_applet_signals[LAST_SIGNAL] = { 0, };

/* forward declarations */
static gboolean cb_moko_panel_applet_button_release_event( GtkWidget* widget, GdkEventButton* event, MokoPanelApplet* self);
void moko_panel_applet_signal_clicked(MokoPanelApplet* self);
void moko_panel_applet_signal_tap_hold(MokoPanelApplet* self);

static void
moko_panel_applet_dispose(GObject* object)
{
    if (G_OBJECT_CLASS (moko_panel_applet_parent_class)->dispose)
        G_OBJECT_CLASS (moko_panel_applet_parent_class)->dispose (object);
}

static void
moko_panel_applet_finalize(GObject* object)
{
    G_OBJECT_CLASS (moko_panel_applet_parent_class)->finalize (object);
}

static void
moko_panel_applet_class_init(MokoPanelAppletClass* klass)
{
    /* default signal handlers */
    klass->clicked = moko_panel_applet_signal_clicked;
    klass->tap_hold = moko_panel_applet_signal_tap_hold;

    /* add private */
    g_type_class_add_private (klass, sizeof(MokoPanelAppletPrivate));

    /* hook destruction */
    GObjectClass* object_class = G_OBJECT_CLASS (klass);
    object_class->dispose = moko_panel_applet_dispose;
    object_class->finalize = moko_panel_applet_finalize;

    /* install properties */

    /* install signals */
    moko_panel_applet_signals[CLICKED] = g_signal_new("clicked",
            G_TYPE_FROM_CLASS (klass),
            G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
            G_STRUCT_OFFSET (MokoPanelAppletClass, clicked),
            NULL,
            NULL,
            g_cclosure_marshal_VOID__VOID,
            G_TYPE_NONE, 0);

    moko_panel_applet_signals[TAP_HOLD] = g_signal_new("tap-hold",
            G_TYPE_FROM_CLASS (klass),
            G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
            G_STRUCT_OFFSET (MokoPanelAppletClass, tap_hold),
            NULL,
            NULL,
            g_cclosure_marshal_VOID__VOID,
            G_TYPE_NONE, 0);
}

GtkWidget*
moko_panel_applet_new()
{
    return GTK_WIDGET (g_object_new(MOKO_TYPE_PANEL_APPLET, NULL));
}

static void
moko_panel_applet_init(MokoPanelApplet* self)
{
    moko_debug( "moko_panel_applet_init" );

    /* MokoPanelAppletClass* klass = MOKO_PANEL_APPLET_GET_CLASS(self); */
    MokoPanelAppletPrivate* priv = MOKO_PANEL_APPLET_GET_PRIVATE( self );
    priv->hold_timeout_triggered = FALSE;

    self->eventbox = gtk_event_box_new();
    gtk_event_box_set_visible_window( GTK_EVENT_BOX (self->eventbox), FALSE );
    gtk_container_add( GTK_CONTAINER(self), self->eventbox );
    gtk_widget_show( self->eventbox );

    g_signal_connect( G_OBJECT(self->eventbox), "button-release-event", (GCallback) cb_moko_panel_applet_button_release_event, self );
}

static gboolean _moko_panel_applet_window_clicked(GtkWidget* widget, GdkEventButton* event, MokoPanelApplet* self)
{
    gdk_pointer_ungrab( event->time );
    gtk_widget_hide( self->toplevelwindow );

    return FALSE;
}

void moko_panel_applet_get_positioning_hint(MokoPanelApplet* self, GtkWidget* popup, int* x, int* y)
{
    int win_w;
    int win_h;
    gdk_window_get_geometry( self->toplevelwindow->window, NULL, NULL, &win_w, &win_h, NULL );
    moko_debug( "-- popup geom = %d, %d", win_w, win_h );

#ifdef DEBUG_THIS_FILE
    GtkAllocation* allocation = &self->toplevelwindow->allocation;
    moko_debug( "-- popup alloc = %d, %d", allocation->width, allocation->height );
#endif

    GtkAllocation* applet_alloc = &GTK_WIDGET(self)->allocation;
    moko_debug( "-- applet alloc = %d, %d", applet_alloc->width, applet_alloc->height );

    int x_abs;
    int y_abs;

    //FIXME this doesn't work w/ matchbox-panel 2 yet
    gdk_window_get_root_origin( self->eventbox->window, &x_abs, &y_abs );

    moko_debug( "-- abs position = %d, %d", x_abs, y_abs );

    *x = x_abs;
    *y = y_abs + applet_alloc->height + 4;

    if ( *x + win_w > gdk_screen_width() )
            *x = gdk_screen_width() - win_w - 2;
    if ( *y + win_h > gdk_screen_height() )
            *y = gdk_screen_height() - win_h - applet_alloc->height - 2;

    moko_debug( "-- final position = %d, %d", *x, *y );
}

gboolean cb_moko_panel_applet_button_release_event( GtkWidget* widget, GdkEventButton* event, MokoPanelApplet* self)
{
    moko_debug( "cb_moko_panel_applet_button_release_event" );
    if ( event->button == 1 )
        g_signal_emit( G_OBJECT(self), moko_panel_applet_signals[CLICKED], 0, NULL );
    else if ( event->button == 3 )
        g_signal_emit( G_OBJECT(self), moko_panel_applet_signals[TAP_HOLD], 0, NULL );
    return TRUE;
}

void moko_panel_applet_signal_clicked(MokoPanelApplet* self)
{
    moko_debug( __FUNCTION__ );
    if ( self->toplevelwindow && GTK_WIDGET_VISIBLE( self->toplevelwindow ) )
        moko_panel_applet_close_popup( self );
    else
        moko_panel_applet_open_popup( self, MOKO_PANEL_APPLET_CLICK_POPUP );
}

void moko_panel_applet_signal_tap_hold(MokoPanelApplet* self)
{
    moko_debug( __FUNCTION__ );
    moko_panel_applet_open_popup( self, MOKO_PANEL_APPLET_TAP_HOLD_POPUP );
}

gboolean moko_panel_applet_iconadd_cb(MokoPanelApplet* self)
{
    MokoPanelAppletPrivate* priv = MOKO_PANEL_APPLET_GET_PRIVATE( self );

    if ( priv->filename_for_icon )
    {
        moko_debug( "moko_panel_applet_iconadd_cb:'%s' (%p)", priv->filename_for_icon, priv->filename_for_icon );
        mb_panel_scaling_image_set_icon( MB_PANEL_SCALING_IMAGE(self->icon), priv->filename_for_icon );
        g_free( priv->filename_for_icon );
        priv->filename_for_icon = 0;
    }
    return FALSE;
}

////////////////
// PUBLIC API //
////////////////
void moko_panel_applet_set_icon(MokoPanelApplet* self, const gchar* filename)
{
    moko_debug( "moko_panel_applet_set_icon:'%s' (%p)", filename, filename );
    MokoPanelAppletPrivate* priv = MOKO_PANEL_APPLET_GET_PRIVATE( self );
    if ( !self->icon )
    {
        self->icon = mb_panel_scaling_image_new( GTK_ORIENTATION_HORIZONTAL, NULL );
        mb_panel_scaling_image_set_caching( MB_PANEL_SCALING_IMAGE(self->icon), TRUE );
        gtk_container_add( GTK_CONTAINER(self->eventbox), self->icon );
        gtk_event_box_set_visible_window( GTK_EVENT_BOX(self->eventbox), FALSE );
        gtk_widget_show_all( self->eventbox );
    }
    priv->filename_for_icon = g_strdup( filename );
    g_idle_add( (GSourceFunc) moko_panel_applet_iconadd_cb, self );
}

void moko_panel_applet_set_pixbuf(MokoPanelApplet* self, GdkPixbuf* pixbuf)
{
    if ( !self->icon )
    {
        self->icon = gtk_image_new_from_pixbuf( pixbuf );
        g_return_if_fail( self->icon );
        gtk_container_add( GTK_CONTAINER(self->eventbox), self->icon );
        gtk_event_box_set_visible_window( GTK_EVENT_BOX(self->eventbox), FALSE );
        gtk_widget_show_all( self->eventbox );
    }
    else
        gtk_image_set_from_pixbuf( GTK_IMAGE (self->icon), pixbuf );
}

void moko_panel_applet_set_widget(MokoPanelApplet* self, GtkWidget* widget)
{
    gtk_container_add( GTK_CONTAINER(self->eventbox), GTK_WIDGET(widget) );
}

void moko_panel_applet_set_popup(MokoPanelApplet* self, GtkWidget* popup, MokoPanelAppletPopupType type)
{
    if ( popup == self->popup[type] )
        return;
    if ( self->popup[type] )
    {
        gtk_widget_destroy( self->popup[type] );
        //FIXME necessary here or does gtk_widget_destroy removes all references?
        g_object_unref( self->popup[type] );
    }
    self->popup[type] = popup;
    g_object_ref( popup );
}

void moko_panel_applet_open_popup(MokoPanelApplet* self, MokoPanelAppletPopupType type)
{
    moko_debug( "moko_panel_applet_open_popup [type=%d]", type );
    GtkWidget* popup = self->popup[type];
    if ( !popup )
    {
        moko_debug( "-- no popup for type %d : return", type );
        return;
    }

    if ( self->toplevelwindow && GTK_WIDGET_VISIBLE( self->toplevelwindow ) )
        moko_panel_applet_close_popup( self );

    if ( GTK_IS_MENU(self->popup[type]) )
    {
        self->toplevelwindow = self->popup[type];
        gtk_menu_popup( GTK_MENU( self->toplevelwindow ), NULL, NULL, NULL, NULL, 0, CurrentTime );
    }
    else
    {
        self->toplevelwindow = gtk_window_new( GTK_WINDOW_POPUP );
        gtk_container_add( GTK_CONTAINER(self->toplevelwindow), self->popup[type] );
        g_signal_connect( G_OBJECT(self->toplevelwindow), "button-press-event", G_CALLBACK(_moko_panel_applet_window_clicked), self );
        gtk_widget_add_events( self->toplevelwindow, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK );
        gtk_widget_realize( self->toplevelwindow );
        gtk_widget_show_all( self->toplevelwindow );
        int x = 0;
        int y = 0;
        moko_panel_applet_get_positioning_hint( self, self->popup[type], &x, &y );
        gtk_window_move( GTK_WINDOW (self->toplevelwindow), x, y );
        gdk_pointer_grab( self->toplevelwindow->window, TRUE, GDK_BUTTON_PRESS_MASK, NULL, NULL, CurrentTime );
    }
}

void moko_panel_applet_close_popup(MokoPanelApplet* self)
{
    g_return_if_fail( self->toplevelwindow || !GTK_WIDGET_VISIBLE(self->toplevelwindow) );
    moko_debug( "moko_panel_applet_close_popup" );

    if ( GTK_IS_MENU( self->toplevelwindow ) )
    {
        gtk_menu_popdown( GTK_MENU( self->toplevelwindow) );
    }
    else
    {
        gdk_pointer_ungrab( CurrentTime );
        gtk_widget_hide( self->toplevelwindow );
        gtk_container_remove( GTK_CONTAINER(self->toplevelwindow), gtk_bin_get_child( GTK_BIN(self->toplevelwindow) ) );
        gtk_widget_destroy( self->toplevelwindow );
        self->toplevelwindow = 0L;
    }
}
