
/**
 * @file
 * All launching of tasks is done there. A task is created by a call to
 * sic_launch with a procedure as argument. It can be a process or a thread. In
 * case of process, the procedure starts an executable by a call to sic_execvp.
 */

/***************************************************************************** 
 *                              Dependencies                                 * 
 *****************************************************************************/

#include "glaunch.h"

#include <stdio.h>
#include <fcntl.h>
#ifndef WIN32
#include <stdlib.h>
#include <unistd.h>
#include <strings.h>
#else
#include "gsys/win32.h"
#endif
#include "gcomm.h"
#include "gerror.h"
#include "gsys/sic_util.h"
#include "gcore-message-c.h"

static sic_task_t _sic_task_null = SIC_TASK_NULL;
static sic_task_t _sic_task_not_null = SIC_TASK_NOT_NULL;

/*****************************************************************************
 *                             Function bodies                               *
 *****************************************************************************/

static int (*s_gtv_window_handler)( void *data) = NULL;

void set_gtv_window_handler( int (*handler)( void *data))
{
    s_gtv_window_handler = handler;
}

static int start_gtv_x11_window( void *data)
{
#ifndef GAG_USE_GTK
    if (s_gtv_window_handler != NULL)
        return s_gtv_window_handler( data);
#endif

    return 0;
}

static int (*s_dialog_handler)( void) = NULL;
static char *(*s_dialog_version_handler)( void) = NULL;

void set_dialog_handler( int (*handler)( void), char *(*version_handler)(void))
{
    s_dialog_handler = handler;
    s_dialog_version_handler = version_handler;
}

char *call_dialog_version_handler()
{
    if (s_dialog_version_handler != NULL) {
        return s_dialog_version_handler();
    } else {
        return "";
    }
}

static int start_dialog( void *data)
{
    if (s_dialog_handler != NULL)
        return !s_dialog_handler( );

    return 0;
}

sic_task_t launch_dialog( )
{
#ifdef GAG_USE_GTK
    if (start_dialog( NULL)) {
        // return not zero
        return _sic_task_not_null;
    } else {
        return _sic_task_null;
    }
#else
    return sic_launch( start_dialog, NULL);
#endif
}

static int (*s_gtv_toolbar_handler)( gtv_toolbar_args_t *args) = NULL;

void set_gtv_toolbar_handler( int (*handler)( gtv_toolbar_args_t *args))
{
    s_gtv_toolbar_handler = handler;
}

static int start_gtv_toolbar( void *data)
{
    if (s_gtv_toolbar_handler != NULL)
      return s_gtv_toolbar_handler( data);

    return 0;
}

sic_task_t launch_gtv_toolbar( gtv_toolbar_args_t *args)
{
    static sic_task_t gtv_toolbar_pid = SIC_TASK_NULL;

#ifndef GAG_USE_GTK
    if (args->cmap == 0) {
#ifndef WIN32
        kill( (pid_t)gtv_toolbar_pid, SIGUSR2);
#endif
    } else
#endif
    {
        gtv_toolbar_pid = sic_launch( start_gtv_toolbar, args);
    }

    return gtv_toolbar_pid;
}

static int (*s_gtv_main_loop_handler)( void *data) = NULL;

void set_gtv_main_loop_handler( int (*handler)( void *data))
{
    s_gtv_main_loop_handler = handler;
}

static int start_gtv_main_loop( void *data)
{
    if (s_gtv_main_loop_handler != NULL)
      return s_gtv_main_loop_handler( data);
    return 1;
}

sic_task_t launch_gtv_main_loop( void *data)
{
    sic_task_t ret = sic_launch( start_gtv_main_loop, data);
    //sic_wait_widget_created( );
    return ret;
}

static void (*s_new_graph_handler)( int, size_t *, char *, int *, int *, int *, int *, int [], int, int) = NULL;

void set_new_graph_handler( void (*handler)( int, size_t *, char *, int *, int *, int *, int *, int [], int, int))
{
    s_new_graph_handler = handler;
}

int launch_new_graph(
    int backg,
    size_t *graph_env,
    char *dirname,
    int *x1, int *x2, int *y1, int *y2,
    int dir_cour[],
    int ldir, int reuse)
{
    if (s_new_graph_handler == NULL)
        return 0;
    s_new_graph_handler( backg, graph_env, dirname, x1, x2, y1, y2, dir_cour, ldir, reuse);
    return 1;
}

static void (*s_menu_start_handler)( const char *) = NULL;
static void (*s_menu_kill_handler)() = NULL;

void set_menu_handlers( void (*start_handler)( const char *), void (*kill_handler)())
{
    s_menu_start_handler = start_handler;
    s_menu_kill_handler = kill_handler;
}

/* Create the detached X-Window process */
static int start_menu( void *data)
{
    const char *temporary_file = data;

    if (s_menu_start_handler != NULL)
        s_menu_start_handler( temporary_file);

    return 0;
}

static sic_task_t s_menu_pid = SIC_TASK_NULL;

/**
 * Create the detached X-Window process
 */
void launch_menu( const char *temporary_file)
{
#ifdef GAG_USE_GTK
    s_menu_pid = _sic_task_null;
    start_menu((void *)temporary_file);
#else
    s_menu_pid = sic_launch( start_menu, (void *)temporary_file);
#endif
}

void kill_menu()
{
    if (sic_get_task_id(s_menu_pid) != sic_get_task_id(_sic_task_null)) {
        if (s_menu_kill_handler != NULL)
            s_menu_kill_handler();
        else
            sic_terminate( s_menu_pid);
        s_menu_pid = _sic_task_null;
    }
}

static int (*s_keyboard_handler)( void *data) = NULL;
static void *s_keyboard_handler_data = NULL;

void set_keyboard_handler( int (*handler)( void *), void *data)
{
    s_keyboard_handler = handler;
    s_keyboard_handler_data = data;
}

static int start_keyboard( void *data)
{
    if (s_keyboard_handler != NULL)
        return s_keyboard_handler( s_keyboard_handler_data);

    return 0;
}

sic_task_t launch_keyboard( )
{
    static sic_task_t keyboard_pid = SIC_TASK_NULL;

    /* we pass NULL just to flag the use of a separate thread */
    keyboard_pid = sic_create_thread( start_keyboard, NULL);

    return keyboard_pid;
}

void run_xremote( )
{
    int i;
    char **argv = sic_get_static_argv( );

    i = 0;
    sprintf( argv[i++], "sic_xremote");
#ifdef cygwin
    strcat( argv[i - 1], ".exe");
#endif
    sprintf( argv[i++], "%d", sic_get_comm_id( ));
    argv[i] = NULL;

    if (sic_execvp( argv) == -1) {  /* never returns */
        sic_perror( "sic_execvp");
    }
}

static void (*s_close_dialog_handler)( void *) = NULL;
static void *s_close_dialog_handler_data = NULL;

void set_close_dialog_handler( void (*handler)( void *), void *data)
{
    s_close_dialog_handler = handler;
    s_close_dialog_handler_data = data;
}

void call_close_dialog_handler( )
{
    if (s_close_dialog_handler != NULL) {
        s_close_dialog_handler( s_close_dialog_handler_data);
        s_close_dialog_handler = NULL;
        s_close_dialog_handler_data = NULL;
    }
}

static void (*s_on_end_dialog_handler)( void) = NULL;

void set_on_end_dialog_handler( void (*handler)( void))
{
    s_on_end_dialog_handler = handler;
}

void call_on_end_dialog_handler( )
{
    if (s_on_end_dialog_handler != NULL)
        s_on_end_dialog_handler( );
}

static void (*s_on_open_dialog_handler)( const char *helpfilename) = NULL;

void set_on_open_dialog_handler( void (*handler)( const char *helpfilename))
{
    s_on_open_dialog_handler = handler;
}

void call_on_open_dialog_handler( const char *helpfilename)
{
    if (s_on_open_dialog_handler != NULL)
        s_on_open_dialog_handler( helpfilename);
}
