
#include "xml-dialog.h"

#include "service.h"
#include "ggui/dialog.h"
#include "gcore/gcomm.h"
#include "gsys/gag_trace.h"
#include "gcore/glaunch.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <errno.h>
#include <unistd.h>

/****************************************************************************/

#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE 1
#endif
#define BUFSIZE 4048*4
#define WRITE(x,y,z) if (!write(x,y,z)) perror( "socket write")

/****************************************************************************/

static char buffer_out[BUFSIZE];

static char gxml_window_title[TITLELENGTH];
static char gxml_helpfilename[HLPFILELNGTH];
static char gxml_main_command[COMMANDLENGTH];

/****************************************************************************/

/* GTK widget implementation */
static void dialog_info_create_group_box( dialog_info_t *dialog);
static void dialog_separator_add( dialog_info_t *dialog);
static void dialog_chain_add( dialog_info_t *dialog, chain_struct *chain);
static void dialog_slider_add( dialog_info_t *dialog, slider_struct *slider);
static void slider_info_set_value( widget_info_t *widget_info, double value);
static void logic_info_get_value( widget_info_t *widget_info);
static void logic_info_set_value( widget_info_t *widget_info, int value);
static void chain_info_get_value( widget_info_t *widget_info);
static void chain_info_set_value( widget_info_t *widget_info, const char *value);
static void choice_info_get_value( widget_info_t *widget_info);
static void choice_info_set_value( widget_info_t *widget_info, const char *value);
static void file_info_get_value( widget_info_t *widget_info);
static void file_info_set_value( widget_info_t *widget_info, const char *value);
static void dialog_show_add( dialog_info_t *dialog, show_struct *show);
static void dialog_logic_add( dialog_info_t *dialog, logic_struct *logic);
static void dialog_browser_add( dialog_info_t *dialog, file_struct *file);
static void dialog_choice_add( dialog_info_t *dialog, choice_struct *choice);
static void dialog_button_add( dialog_info_t *dialog, button_struct *button);
static void dialog_close( dialog_info_t *dialog);

/* GTK widget interface */
static widget_api_t gxml_widget_api = {
    dialog_info_create_group_box,
    dialog_separator_add,
    dialog_chain_add,
    chain_info_get_value,
    chain_info_set_value,
    dialog_slider_add,
    slider_info_set_value,
    dialog_show_add,
    dialog_logic_add,
    logic_info_get_value,
    logic_info_set_value,
    dialog_browser_add,
    file_info_get_value,
    file_info_set_value,
    dialog_choice_add,
    choice_info_get_value,
    choice_info_set_value,
    dialog_button_add,
    NULL, /* dialog_on_create_item */
    dialog_close,
};

/****************************************************************************/

typedef struct {
    dialog_info_t _herits;
} gxml_dialog_info_t;

typedef struct {
    choice_struct *choice; // herits from widget_info_struct
} gxml_choice_info_t;

typedef struct {
    slider_struct *slider; // herits from widget_info_struct
} gxml_slider_info_t;

typedef struct {
    button_struct *button; // herits from widget_info_struct
    gxml_dialog_info_t *dialog;
} gxml_button_info_t;

typedef struct {
    logic_struct *logic; // herits from widget_info_struct
} gxml_logic_info_t;

typedef struct {
    chain_struct *chain; // herits from widget_info_struct
} gxml_chain_info_t;

typedef struct {
    file_struct *file; // herits from widget_info_struct
} gxml_file_info_t;

/****************************************************************************/


static gxml_dialog_info_t *win_dialog_info_new()
{
    gxml_dialog_info_t *ret;
    ret = calloc( 1, sizeof( *ret));
    return ret;
}

static void gxml_dialog_info_delete( gxml_dialog_info_t *dialog)
{
    free( dialog);
}

static gxml_choice_info_t *gxml_choice_info_new( choice_struct *choice)
{
    gxml_choice_info_t *ret;
    ret = widget_info_new( sizeof( *ret), choice);
    return ret;
}

static gxml_slider_info_t *gxml_slider_info_new( slider_struct *slider)
{
    gxml_slider_info_t *ret;
    ret = widget_info_new( sizeof( *ret), slider);
    return ret;
}

static gxml_button_info_t *gxml_button_info_new( button_struct *button)
{
    gxml_button_info_t *ret;
    ret = widget_info_new( sizeof( *ret), button);
    return ret;
}

static gxml_logic_info_t *gxml_logic_info_new( logic_struct *logic)
{
    gxml_logic_info_t *ret;
    ret = widget_info_new( sizeof( *ret), logic);
    return ret;
}

static gxml_chain_info_t *gxml_chain_info_new( chain_struct *chain)
{
    gxml_chain_info_t *ret;
    ret = widget_info_new( sizeof( *ret), chain);
    return ret;
}

static gxml_file_info_t *gxml_file_info_new( file_struct *file)
{
    gxml_file_info_t *ret;
    ret = widget_info_new( sizeof( *ret), file);
    return ret;
}

/****************************************************************************/

static int panel_block = 0;		/* inform if there is a panel which is described */

static gxml_dialog_info_t *gxml_dialog_create( int dialog_id)
{
    gxml_dialog_info_t *dialog;

    dialog = win_dialog_info_new();

    /* there is no extended button yet... */
    panel_block = 0;

    dialog_info_prepare( (dialog_info_t *)dialog, dialog_id);
    dialog_info_build( &gxml_widget_api, (dialog_info_t *)dialog, dialog_id);

    /* if the memory contains block ends the last block */
    if (panel_block != 0) {
        strcpy( buffer_out, "\n</PANEL>");
        WRITE( sockfd, buffer_out, strlen( buffer_out));
    }

    return dialog;
}

static void close_moreoption_dialog( widget_info_struct *widget_info)
{
    if (widget_info->generic->type == BUTTON) {
        gxml_button_info_t *button_info = (gxml_button_info_t *)widget_info;
        if (button_info->dialog != NULL) {
            gxml_dialog_info_delete( button_info->dialog);
        }
    }
}

/****************************************************************************/
/* Widget API implementation for XML **************************************/

static void dialog_info_create_group_box( dialog_info_t *dialog)
{
    //gxml_dialog_info_t *gxml_dialog = (gxml_dialog_info_t *)dialog;
}

static void dialog_separator_add( dialog_info_t *dialog)
{
}

static char *display_help( char *help_file, char *variable_name)
{
    static char text[BUFSIZE];
    int nrows, ncols;

    gdialog_build_help( help_file, variable_name, text, &ncols, &nrows);
    
    return text;
}

char *widget_info_get_help( widget_info_t *widget_info)
{
    static char helptxt[BUFSIZE];
    generic_struct *generic = ((widget_info_struct *)widget_info)->generic;
    char *help;

    if (!generic->window_id) {
        help = display_help( gxml_helpfilename, generic->variable);
    } else {
        button_struct *b;

        b = widget_find_button_from_window_id( generic->window_id);
        if (b != NULL) {
            help = display_help( b->helptxt, generic->variable);
        } else {
            help = NULL;
        }
    }
    if (help != NULL && help[0])
        sprintf( helptxt, " help=\"%s\"", xmlAttributeFilter( help));
    else
        helptxt[0] = '\0';
    return helptxt;
}

static char *widget_info_set_value( widget_info_t *widget_info)
{
    static char buf[BUFSIZE];
    generic_struct *widget = ((widget_info_struct *)widget_info)->generic;

    if (widget->label[0])
        sprintf( buf, " label=\"%s\"", xmlAttributeFilter( widget->label));
    else
        buf[0] = '\0';
    if (widget->variable[0])
        sprintf( buf + strlen( buf), " variable=\"%s\"", unblank( widget->variable));
    return buf;
}

static void dialog_chain_add( dialog_info_t *dialog, chain_struct *chain)
{
    //gxml_dialog_info_t *gxml_dialog = (gxml_dialog_info_t *)dialog;
    gxml_chain_info_t *chain_info;

    chain_info = gxml_chain_info_new( chain);
    
    sprintf( buffer_out, "<CHAIN%s userchain=\"%s\" editable=\"%s\"%s>\n</CHAIN>",
        widget_info_set_value( chain_info), xmlAttributeFilter(
        chain->userchain), chain->editable ? "true" : "false",
        widget_info_get_help( chain_info));
    WRITE( sockfd, buffer_out, strlen( buffer_out));
}

static void dialog_slider_add( dialog_info_t *dialog, slider_struct *slider)
{
    //gxml_dialog_info_t *gxml_dialog = (gxml_dialog_info_t *)dialog;
    gxml_slider_info_t *slider_info;

    slider_info = gxml_slider_info_new( slider);
    sprintf( buffer_out, "<SLIDER%s uservalue=\"%f\" width=\"%f\" min=\"%f\"%s>\n</SLIDER>",
        widget_info_set_value( slider_info), slider->uservalue, slider->width,
        slider->min, widget_info_get_help( slider_info));
    WRITE( sockfd, buffer_out, strlen( buffer_out));
}


static void slider_info_set_value( widget_info_t *widget_info, double value)
{
    gxml_slider_info_t *slider_info = (gxml_slider_info_t *)widget_info;
    slider_struct *slider;
    double corrected_value;
    double eps;

    slider = slider_info->slider;
    eps = slider->width / 1e5;
    corrected_value = MINI(MAXI(slider->min, value), slider->min + slider->width);
    if (fabs( corrected_value - value) > eps || fabs( corrected_value - slider->uservalue) > eps) {
        slider->uservalue = (float)corrected_value;
        sprintf( buffer_out, "<SLIDER%s uservalue=\"%f\">\n</SLIDER>",
            widget_info_set_value( slider_info), slider->uservalue);
        WRITE( sockfd, buffer_out, strlen( buffer_out));
    }
}

static void logic_info_get_value( widget_info_t *widget_info)
{
    //gxml_logic_info_t *logic_info = (gxml_logic_info_t *)widget_info;
}

static void logic_info_set_value( widget_info_t *widget_info, int value)
{
    gxml_logic_info_t *logic_info = (gxml_logic_info_t *)widget_info;
    logic_struct *logic;

    logic = logic_info->logic;
    logic->userlogic = value;
    sprintf( buffer_out, "<LOGIC%s userlogic=\"%d\">\n</LOGIC>",
        widget_info_set_value( logic_info), logic->userlogic);
    WRITE( sockfd, buffer_out, strlen( buffer_out));
}

static void chain_info_get_value( widget_info_t *widget_info)
{
    //gxml_chain_info_t *chain_info = (gxml_chain_info_t *)widget_info;
}

static void chain_info_set_value( widget_info_t *widget_info, const char *value)
{
    gxml_chain_info_t *chain_info = (gxml_chain_info_t *)widget_info;
    chain_struct *chain;

    chain = chain_info->chain;
    strcpy( chain->userchain, value);
    sprintf( buffer_out, "<CHAIN%s userchain=\"%s\">\n</CHAIN>",
        widget_info_set_value( chain_info), xmlAttributeFilter( chain->userchain));
    WRITE( sockfd, buffer_out, strlen( buffer_out));
}

static void choice_info_get_value( widget_info_t *widget_info)
{
    //gxml_choice_info_t *choice_info = (gxml_choice_info_t *)widget_info;
}

static void choice_info_set_value( widget_info_t *widget_info, const char *value)
{
    gxml_choice_info_t *choice_info = (gxml_choice_info_t *)widget_info;
    choice_struct *choice;

    choice = choice_info->choice;
    strcpy( choice->userchoice, value);
    if (choice->userchoice[0]) {
        sprintf( buffer_out, "<CHOICE%s userchoice=\"%s\">\n</CHOICE>",
            widget_info_set_value( choice_info), choice->userchoice);
        WRITE( sockfd, buffer_out, strlen( buffer_out));
    }
}

static void file_info_get_value( widget_info_t *widget_info)
{
    //gxml_file_info_t *file_info = (gxml_file_info_t *)widget_info;
}

static void file_info_set_value( widget_info_t *widget_info, const char *value)
{
    gxml_file_info_t *file_info = (gxml_file_info_t *)widget_info;
    file_struct *file;

    file = file_info->file;
    strcpy( file->userchain, value);
    if (file->userchain[0]) {
        sprintf( buffer_out, "<BROWSER%s userchain=\"%s\">\n</BROWSER>",
            widget_info_set_value( file_info), xmlAttributeFilter( file->userchain));
        WRITE( sockfd, buffer_out, strlen( buffer_out));
    }
}

static void dialog_show_add( dialog_info_t *dialog, show_struct *show)
{
    //gxml_dialog_info_t *gxml_dialog = (gxml_dialog_info_t *)dialog;

    sprintf( buffer_out, "<SHOW label=\"%s\">\n</SHOW>",
        xmlAttributeFilter( show->text));
    WRITE( sockfd, buffer_out, strlen( buffer_out));
}

static void dialog_logic_add( dialog_info_t *dialog, logic_struct *logic)
{
    //gxml_dialog_info_t *gxml_dialog = (gxml_dialog_info_t *)dialog;
    gxml_logic_info_t *logic_info;

    logic_info = gxml_logic_info_new( logic);

    sprintf( buffer_out, "<LOGIC%s userlogic=\"%d\"%s>\n</LOGIC>",
        widget_info_set_value( logic_info), logic->userlogic,
        widget_info_get_help( logic_info));
    WRITE( sockfd, buffer_out, strlen( buffer_out));
}

static void dialog_browser_add( dialog_info_t *dialog, file_struct *file)
{
    //gxml_dialog_info_t *gxml_dialog = (gxml_dialog_info_t *)dialog;
    gxml_file_info_t *file_info;

    file_info = gxml_file_info_new( file);

    sprintf( buffer_out, "<BROWSER%s",
        widget_info_set_value( file_info));
    if (file->userchain[0]) {
        sprintf( buffer_out + strlen( buffer_out), " userchain=\"%s\"",
            xmlAttributeFilter( file->userchain));
    }
    if (file->filter[0]) {
        sprintf( buffer_out + strlen( buffer_out), " filter=\"%s\"",
            xmlAttributeFilter( file->filter));
    }
    sprintf( buffer_out + strlen( buffer_out), "%s>\n</BROWSER>",
        widget_info_get_help( file_info));
    WRITE( sockfd, buffer_out, strlen( buffer_out));
}

/* mode value of choices */
#define FREECHOICE 0
#define FIXEDCHOICE -1
#define INDEXCHOICE 1

static void dialog_choice_add( dialog_info_t *dialog, choice_struct *choice)
{
    //gxml_dialog_info_t *gxml_dialog = (gxml_dialog_info_t *)dialog;
    gxml_choice_info_t *choice_info;
    int k;

    choice_info = gxml_choice_info_new( choice);

    sprintf( buffer_out, "<CHOICE%s",
        widget_info_set_value( choice_info));
    if (choice->userchoice[0]) {
        sprintf( buffer_out + strlen( buffer_out), " userchoice=\"%s\"",
            xmlAttributeFilter( choice->userchoice));
    }
    if (choice->mode == FREECHOICE && (choice->nchoices > 0))
        sprintf( buffer_out + strlen( buffer_out),
            " editable=\"true\" index=\"false\">");
    else if (choice->mode == INDEXCHOICE)
        sprintf( buffer_out + strlen( buffer_out),
            " editable=\"false\" index=\"true\">");
    else
        sprintf( buffer_out + strlen( buffer_out),
            " editable=\"false\" index=\"false\">");
    for (k = 0; k < choice->nchoices; k++) {
        if (choice->choices[k][0])
            sprintf( buffer_out + strlen( buffer_out),
                "\n<ITEM value=\"%s\"></ITEM>", choice->choices[k]);
    }
    sprintf( buffer_out + strlen( buffer_out), "%s>\n</CHOICE>",
        widget_info_get_help( choice_info));
    WRITE( sockfd, buffer_out, strlen( buffer_out));
}

static void dialog_button_add( dialog_info_t *dialog, button_struct *button)
{
    //gxml_dialog_info_t *gxml_dialog = (gxml_dialog_info_t *)dialog;
    gxml_button_info_t *button_info;

    button_info = gxml_button_info_new( button);

    if (button->moretxt[0]) {
        /* case of a SUBPANEL */
        char *previous;

        /* if this widget marks the end of the previous block ends the previous and begin the next */
        if (panel_block) {
            previous = "</PANEL>\n";
         } else {
            previous = "";
            panel_block = 1;
        }
        sprintf( buffer_out, "%s<PANEL moretxt=\"%s\"", previous, button->moretxt);

    } else {
        /* case of a SIMPLE BUTTON */
        sprintf( buffer_out, "<BUTTON group=\"true\"");
    }

    sprintf( buffer_out + strlen( buffer_out), " command=\"%s\"", button->command);
    sprintf( buffer_out + strlen( buffer_out), " title=\"%s\"", button->title);
    sprintf( buffer_out + strlen( buffer_out), " showlength=\"%d\"", button->showlength);
    if (button->moretxt[0])
        sprintf( buffer_out + strlen( buffer_out), ">\n");
    else
        sprintf( buffer_out + strlen( buffer_out), ">\n</BUTTON>");
}

static void dialog_close( dialog_info_t *dialog)
{
    //gxml_dialog_info_t *dialog_info = (gxml_dialog_info_t *)dialog;
}

/****************************************************************************/

static void close_dialog( gxml_dialog_info_t *dialog, int tag)
{
    char return_command[COMMANDLENGTH];

    //printf( "close_dialog( %d)\n", tag);
    if (tag == GGUI_OK)
        strcpy( return_command, gxml_main_command);
    else
        return_command[0] = '\0';

    if (on_close_dialog( &gxml_widget_api, (dialog_info_t *)dialog, return_command, tag) == -1)
        ;//gdk_display_beep( gdk_display_get_default( ));
}

static void close_dialog_ok( gxml_dialog_info_t *dialog)
{
    close_dialog( dialog, GGUI_OK);
}

static void close_dialog_abort( gxml_dialog_info_t *dialog)
{
    close_dialog( dialog, GGUI_ABORT);
}

static void destroy_widgets( void* dialog)
{
    //gxml_dialog_info_t *dialog_info = dialog;
}

static void gxml_update_variable( sic_widget_def_t *widget, void *display)
{
    sprintf( buffer_out, "<gui_update>\n");
    WRITE( sockfd, buffer_out, strlen( buffer_out));
    widget_update_variable( &gxml_widget_api, widget);
    sprintf( buffer_out, "</gui_update>\n");
    WRITE( sockfd, buffer_out, strlen( buffer_out));
    fflush( NULL);
}

void create_widgets( int argc, char **argv)
{
    gxml_dialog_info_t *dialog;

    widget_info_open( );

    on_run_dialog( gxml_update_variable, NULL);

#if 0 /* not implemented */
    /* Create command bar */
    iter = parse_menu_button_begin( );
    while ((b = parse_menu_button_next( iter)) != NULL) {
    }
#endif

    dialog = gxml_dialog_create( 0);

    set_close_dialog_handler( destroy_widgets, dialog);

    sic_post_widget_created( );

    /* TODO: why sleeping ? */
    while (1) {
        sleep( 1);
    }

    widget_info_close( close_moreoption_dialog);
    gxml_dialog_info_delete( dialog);
}

int run_dialog_args( int argc, char **argv)
{
    int nb_widgets;

    nb_widgets = sic_open_widget_board( );

    sic_get_widget_global_infos( gxml_window_title, gxml_helpfilename, gxml_main_command);

    sic_close_widget_board( );

    create_widgets( argc, argv);

    return 0;
}

int run_dialog( )
{
     return run_dialog_args( 0, NULL);
}

