/*
This source file is part of Scol
For the latest info, see http://www.scolring.org

Copyright (c) 2010 Stephane Bisaro, aka Iri <iri@irizone.net>

This program is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.

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 General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place - Suite 330, Boston, MA 02111-1307, USA, or go to
http://www.gnu.org/copyleft/lesser.txt

For others informations, please contact us from http://www.scolring.org/
*/

#include "../include/scol_gtk_button.h"


/* Flags : creation */
int SCOL_GTK_BUTTON_EMPTY (mmachine m) { MMpush (m, ITOM (BUTTON_EMPTY)); return 0; }
int SCOL_GTK_BUTTON_LABEL (mmachine m) { MMpush (m, ITOM (BUTTON_LABEL)); return 0; }
int SCOL_GTK_BUTTON_MNEMONIC (mmachine m) { MMpush (m, ITOM (BUTTON_MNEMONIC)); return 0; }
int SCOL_GTK_BUTTON_STOCKITEM (mmachine m) { MMpush (m, ITOM (BUTTON_STOCKITEM)); return 0; }
int SCOL_GTK_BUTTON_LINK (mmachine m) { MMpush (m, ITOM (BUTTON_LINK)); return 0; }
int SCOL_GTK_BUTTON_CHECK (mmachine m) { MMpush (m, ITOM (BUTTON_CHECK)); return 0; }
int SCOL_GTK_BUTTON_TOGGLE (mmachine m) { MMpush (m, ITOM (BUTTON_TOGGLE)); return 0; }
int SCOL_GTK_BUTTON_SWITCH (mmachine m) { MMpush (m, ITOM (BUTTON_SWITCH)); return 0; }
int SCOL_GTK_BUTTON_RADIO (mmachine m) { MMpush (m, ITOM (BUTTON_RADIO)); return 0; }

/* Flags : reflexes */
int SCOL_GTK_BUTTON_CB_CLICKED (mmachine m) { MMpush (m, ITOM (BUTTON_CB_CLICKED)); return 0; }
int SCOL_GTK_BUTTON_CB_TOGGLED (mmachine m) { MMpush (m, ITOM (BUTTON_CB_TOGGLED)); return 0; }
int SCOL_GTK_BUTTON_CB_LINKED (mmachine m) { MMpush (m, ITOM (BUTTON_CB_LINKED)); return 0; }
int SCOL_GTK_BUTTON_CB_RADIO_CHANGED (mmachine m) { MMpush (m, ITOM (BUTTON_CB_RADIO_CHANGED)); return 0; }



static void scol_gtk_button_create (GtkWidget **button, GtkWidget * child, const gchar *label, const gchar *label2, gboolean state, int subtype)
{
    switch (subtype)
    {
        case (SCOL_WIDGET_SUBTYPE_BUTTONEMPTY) :  /* empty button */
            *button = gtk_button_new();
            if (child != NULL)
                gtk_container_add (GTK_CONTAINER (button), child);
            break;

        case (SCOL_WIDGET_SUBTYPE_BUTTONLABEL) :  /* button with simple label */
            *button = gtk_button_new_with_label (label);
            break;

        case (SCOL_WIDGET_SUBTYPE_BUTTONMNEMO) :  /* button with mnemonic */
            *button = gtk_button_new_with_mnemonic (label);
            break;

        case (SCOL_WIDGET_SUBTYPE_BUTTONSTOCK) :  /* button with stock item */
            *button = gtk_button_new_from_stock (label);
            break;

        case (SCOL_WIDGET_SUBTYPE_BUTTONLINK) :     /* button with an url */
            *button = gtk_link_button_new_with_label (label2, label);
            break;

        case (SCOL_WIDGET_SUBTYPE_BUTTONCHECK) :    /* check button */
            *button = gtk_check_button_new_with_mnemonic (label);
            gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (*button), state);
            break;

        case (SCOL_WIDGET_SUBTYPE_BUTTONTOGGLE) : /* toggled button */
            *button = gtk_toggle_button_new_with_mnemonic (label);
            gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (*button), state);
            break;

        case (SCOL_WIDGET_SUBTYPE_BUTTONSWITCH) :   /* Switch button */
            #ifndef SCOL_GTK_2
            *button = gtk_switch_new ();
            gtk_switch_set_active (GTK_SWITCH (*button), state);
            #else
            *button = gtk_toggle_button_new_with_mnemonic (DEFAULT_STRING);
            gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (*button), state);
            g_message ("scol_gtk_button_create : a switch button can not create with your GTK+ version");
            #endif
            break;

        case (SCOL_WIDGET_SUBTYPE_BUTTONRADIO) :    /* radio button */
            *button = gtk_radio_button_new_with_label_from_widget (GTK_RADIO_BUTTON (child), label);
            gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (*button), state);
            break;

        default :
            g_message ("scol_gtk_button_create : invalid subtype, button not created");
    }
    /*if (button->parent != NULL)
        gtk_container_add (GTK_CONTAINER (button->parent->widget), button->widget);*/
    /*gtk_widget_realize (button->widget);*/
    return;
}

/* GTK+ callback : a button has been clicked */
static gboolean scol_gtk_button_cb_clicked (GtkWidget *p_widget, gpointer m2m)
{
    int cb;
    mmachine m;

    m = (mmachine) m2m;

    cb = OBJbeginreflex (m, ObjGtkWidgetType, (int) p_widget, OBJ2DGTK_BUTTON_CB_CLICKED);
    if (cb)
    {
        g_message ("scol_gtk_button_cb_clicked error : no callback defined ! errcode = %d", cb);
        return FALSE;
    }

    if (OBJcallreflex (m, 0)) return TRUE;
    return FALSE;
}

/* GTK+ callback : a button has taggled */
static gboolean scol_gtk_button_cb_toggled (GtkToggleButton *button, gpointer m2m)
{
    int cb, r = 0;
    mmachine m;

    m = (mmachine) m2m;

    cb = OBJbeginreflex (m, ObjGtkWidgetType, (int) button, OBJ2DGTK_BUTTON_CB_TOGGLED);
    if (cb)
    {
        g_message ("scol_gtk_button_cb_toggled error : no callback defined ! errcode = %d", cb);
        return FALSE;
    }

    if (gtk_toggle_button_get_active (button) == TRUE)
        r = 1;

    MMpush (m, ITOM (r));
    if (OBJcallreflex (m, 1)) return TRUE;
    return FALSE;
}

/* GTK+ callback : a button with a url has been activated */
static gboolean scol_gtk_button_cb_linked (GtkLinkButton *button, gpointer m2m)
{
    int cb;
    mmachine m;
    gchar *r;

    m = (mmachine) m2m;

    cb = OBJbeginreflex (m, ObjGtkWidgetType, (int) button, OBJ2DGTK_BUTTON_CB_LINK);
    if (cb)
    {
        g_message ("scol_gtk_button_cb_toggled error : no callback defined ! errcode = %d", cb);
        return FALSE;
    }

    g_object_get (GTK_LINK_BUTTON (button), "uri", &r, NULL);

    Mpushstrbloc (m, r);
    OBJcallreflex (m, 1);
    g_free (r);
    return TRUE;
}

/* GTK+ callback : a radio button has changed */
static gboolean scol_gtk_button_cb_radio (GtkRadioButton *button, gpointer m2m)
{
    int cb, r = 0;
    mmachine m;

    m = (mmachine) m2m;

    cb = OBJbeginreflex (m, ObjGtkWidgetType, (int) button, OBJ2DGTK_BUTTON_CB_RADIO);
    if (cb)
    {
        g_message ("scol_gtk_button_cb_toggled error : no callback defined ! errcode = %d", cb);
        return FALSE;
    }

    if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)) == TRUE)
        r = 1;

    MMpush (m, ITOM (r));
    OBJcallreflex (m, 1);
    return TRUE;
}


/**
 * \brief Create a button : fun [Chn ObjGtkWidget S I u0] ObjGtkWidget
 *
 * Stack :
 * Stage 0 : ObjGtkWidget : child. If Type is SCOL_GTK_BUTTON_EMPTY only , child will be displayed into the new button.
 *         : S : url if type set to SCOL_GTK_BUTTON_LINK only
 *         : I : active (1), inactive (0) if flag is SCOL_GTK_BUTTON_CHECK, SCOL_GTK_BUTTON_TOGGLE or SCOL_GTK_BUTTON_SWITCH
 *         Otherwise, should be nil.
 * Stage 1 : I : type. Type should be one of these values :
 *              - SCOL_GTK_BUTTON_EMPTY : empty button. Cf 'child'.
 *              - SCOL_GTK_BUTTON_LABEL : classical button with the label 'label'.
 *              - SCOL_GTK_BUTTON_MNEMONIC : a button with a mnemonic (can be activate with ALT + key).
 *              - SCOL_GTK_BUTTON_STOCKITEM : a button with a standard stock item.
 *              - SCOL_GTK_BUTTON_LINK : button with a link (uri).
 *              - SCOL_GTK_BUTTON_CHECK : check button (with mnemonic) with a short label
 *              - SCOL_GTK_BUTTON_TOGGLE : toggle button
 *              - SCOL_GTK_BUTTON_SWITCH : switch button (GTK+ 3.x only)
 * Stage 2 : S : label. Can be any label (with SCOL_GTK_BUTTON_LABEL), a mnemonic label (with SCOL_GTK_BUTTON_MNEMONIC)
 *              or a stock item name (with SCOL_GTK_BUTTON_STOCKITEM). Should be nil with SCOL_GTK_BUTTON_EMPTY.
 * Stage 3 : Chn : channel. The channel
 *
 * \return : ObjGtkWidget : a new button or nil if error.
 */
int SCOL_gtkButtonNew (mmachine m)
{
    int mchannel, ms, mtyp, mchild;
    int subtype;
    gboolean state = FALSE;
    GtkWidget *button = NULL, *child;
    gchar *label, *label2;

    g_message ("SCOL_gtkButtonNew : entering");

    mchild = MTOP (MMpull (m));
    mtyp = MTOI (MMpull (m));
    ms = MTOP (MMpull (m));
    mchannel = MMget (m, 0);

    if (mchannel == NIL)
    {
        g_warning ("SCOL_gtkButtonNew error : channel is nil");
        MMpull (m);
        MMpush (m, NIL);
        return 0;
    }

    if (ms == NIL)
    {
        label = (gchar *) g_malloc (sizeof (gchar) * (strlen (DEFAULT_STRING) + 1));
        strcpy (label, DEFAULT_STRING);
    }
    else
    {
        label = (gchar *) g_malloc (sizeof (gchar) * (MMsizestr (m, ms) + 1));
        strcpy (label, (gchar *) MMstartstr (m, ms));
    }
    /* TODO to redo .. :) */
    if (mchild == NIL)
        {
            child = NULL;
            label2 = (gchar *) g_malloc (sizeof (gchar) * 2);
            label2[0] = '\0';
        }
    else
        if (BUTTON_LINK == mtyp)
        {
            label2 = (gchar *) g_malloc (sizeof (gchar) * (MMsizestr (m, mchild) + 1));
            strcpy (label2, MMstartstr (m, mchild));
            child = NULL;
        }
        else if (BUTTON_RADIO == mtyp)
        {
            child = (GtkWidget *) MMfetch (m, MMfetch (m, mchild, 0)>>1, OBJ2DGTK_WIDGET_HANDLE);
            state = MMfetch (m, mchild, 0)>>1;
            if (state != TRUE) state = FALSE;
            label2 = (gchar *) g_malloc (sizeof (gchar) * 2);
            label2[0] = '\0';
        }
        else
        {
            child = (GtkWidget *) MMfetch (m, mchild, OBJ2DGTK_WIDGET_HANDLE);
            label2 = (gchar *) g_malloc (sizeof (gchar) * 2);
            label2[0] = '\0';
        }

    switch (mtyp)
    {
        case (BUTTON_EMPTY) :
            subtype = SCOL_WIDGET_SUBTYPE_BUTTONEMPTY;
            break;
        case (BUTTON_LABEL) :
            subtype = SCOL_WIDGET_SUBTYPE_BUTTONLABEL;
            break;
        case (BUTTON_MNEMONIC) :
            subtype = SCOL_WIDGET_SUBTYPE_BUTTONMNEMO;
            break;
        case (BUTTON_STOCKITEM) :
            subtype = SCOL_WIDGET_SUBTYPE_BUTTONSTOCK;
            break;
        case (BUTTON_LINK) :
            subtype = SCOL_WIDGET_SUBTYPE_BUTTONLINK;
            break;
        case (BUTTON_CHECK) :
            subtype = SCOL_WIDGET_SUBTYPE_BUTTONCHECK;
            if (mchild == 1)
                state = TRUE;
            break;
        case (BUTTON_TOGGLE) :
            subtype = SCOL_WIDGET_SUBTYPE_BUTTONTOGGLE;
            if (mchild == 1)
                state = TRUE;
            break;
        case (BUTTON_SWITCH) :
            subtype = SCOL_WIDGET_SUBTYPE_BUTTONSWITCH;
            if (mchild == 1)
                state = TRUE;
            break;
        case (BUTTON_RADIO) :
            subtype = SCOL_WIDGET_SUBTYPE_BUTTONRADIO;
            break;
        default :
            subtype = SCOL_WIDGET_SUBTYPE_UNKNOWN;
    }
    scol_gtk_button_create (&button, child, label, label2, state, subtype);
    g_free (label);
    g_free (label2);
    return SCOL_gtk_memory_createObjectTAB (m, button, ObjGtkWidgetType, OBJ2DGTK_WIDGET_HANDLE);
}





int SCOL_gtkButtonCB (mmachine m)
{
    int mbutton, mflag;
    GtkWidget *button;

    g_message ("SCOL_gtkButtonCB : entering");

    mflag = MTOI (MMpull (m));
    mbutton = MTOP (MMget (m, 2));
    if (mbutton == NIL)
    {
        g_warning ("SCOL_gtkButtonCB error : object is nil");
        MMpush (m, NIL);
        return -1;
    }

    button = (GtkWidget*) MMfetch (m, mbutton, OBJ2DGTK_WIDGET_HANDLE);

    switch (mflag)
    {
        case (BUTTON_CB_CLICKED) :
            OBJaddreflex (m, ObjGtkWidgetType, OBJ2DGTK_BUTTON_CB_CLICKED);
            g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (scol_gtk_button_cb_clicked), (gpointer) m);
            break;

        case (BUTTON_CB_TOGGLED) :
            OBJaddreflex (m, ObjGtkWidgetType, OBJ2DGTK_BUTTON_CB_TOGGLED);
            g_signal_connect (G_OBJECT (button), "toggled", G_CALLBACK (scol_gtk_button_cb_toggled), (gpointer) m);
            break;

        case (BUTTON_CB_LINKED) :
            OBJaddreflex (m, ObjGtkWidgetType, OBJ2DGTK_BUTTON_CB_LINK);
            g_signal_connect (G_OBJECT (button), "activate-link", G_CALLBACK (scol_gtk_button_cb_linked), (gpointer) m);
            break;

        case (BUTTON_CB_RADIO_CHANGED) :
            OBJaddreflex (m, ObjGtkWidgetType, OBJ2DGTK_BUTTON_CB_RADIO);
            g_signal_connect (G_OBJECT (button), "group-changed", G_CALLBACK (scol_gtk_button_cb_radio), (gpointer) m);
            break;

        default :
            g_warning ("SCOL_gtkButtonCB : flag is not valid");
    }
    return 0;
}






/* API definitions : */

char* gtk_but_name[GTK_BUTTON_PKG_NB]=
{
    "SCOL_GTK_BUTTON_EMPTY", "SCOL_GTK_BUTTON_LABEL", "SCOL_GTK_BUTTON_MNEMONIC",
    "SCOL_GTK_BUTTON_STOCKITEM", "SCOL_GTK_BUTTON_LINK", "SCOL_GTK_BUTTON_CHECK",
    "SCOL_GTK_BUTTON_TOGGLE", "SCOL_GTK_BUTTON_SWITCH", "SCOL_GTK_BUTTON_RADIO",

    "SCOL_GTK_BUTTON_CB_CLICKED", "SCOL_GTK_BUTTON_CB_TOGGLED", "SCOL_GTK_BUTTON_CB_LINKED",
    "SCOL_GTK_BUTTON_CB_RADIO_CHANGED",

    "_gtkButtonNew",
    "_gtkButtonCB"
};

int (*gtk_but_fun[GTK_BUTTON_PKG_NB])(mmachine m)=
{
    SCOL_GTK_BUTTON_EMPTY, SCOL_GTK_BUTTON_LABEL, SCOL_GTK_BUTTON_MNEMONIC,
    SCOL_GTK_BUTTON_STOCKITEM, SCOL_GTK_BUTTON_LINK, SCOL_GTK_BUTTON_CHECK,
    SCOL_GTK_BUTTON_TOGGLE, SCOL_GTK_BUTTON_SWITCH, SCOL_GTK_BUTTON_RADIO,

    SCOL_GTK_BUTTON_CB_CLICKED, SCOL_GTK_BUTTON_CB_TOGGLED, SCOL_GTK_BUTTON_CB_LINKED,
    SCOL_GTK_BUTTON_CB_RADIO_CHANGED,

    SCOL_gtkButtonNew,
    SCOL_gtkButtonCB
};

int gtk_but_narg[GTK_BUTTON_PKG_NB]=
{
    0, 0, 0,
    0, 0, 0,
    0, 0, 0,

    0, 0, 0,
    0,

    4,
    4
};

char* gtk_but_type[GTK_BUTTON_PKG_NB]=
{
    "fun [] I", "fun [] I", "fun [] I",
    "fun [] I", "fun [] I", "fun [] I",
    "fun [] I", "fun [] I", "fun [] I",

    "fun [] I", "fun [] I", "fun [] I",
    "fun [] I",

    "fun [Chn S I u0] ObjGtkWidget",
    "fun [ObjGtkWidget u1 u0 I] ObjGtkWidget"
};

int SCOLloadGTKbutton (mmachine m)
{
    int k;

    MMechostr (0, "SCOLloadGTKbutton : entering\n");

    k = PKhardpak (m, "GTK2DbuttonEngine", GTK_BUTTON_PKG_NB, gtk_but_name, gtk_but_fun, gtk_but_narg, gtk_but_type);
    return k;
}



