/* Midnight Commander Tk initialization and main loop
   Copyright (C) 1995 Miguel de Icaza
   Copyright (C) 1995 Jakub Jelinek
   
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU 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 General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */

/*
 * The Tk version of the code tries to use as much code as possible
 * from the curses version of the code, so we Tk as barely as possible
 * and manage most of the events ourselves.  This may cause some
 * confusion at the beginning.
 */
 
#include <config.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#include "tkmain.h"
#include "key.h"
#include "global.h"
#include "tty.h"		/* for KEY_BACKSPACE */

/* Tcl interpreter */
Tcl_Interp *interp;

/* if true, it's like mc, otherwise is like mxc */
int use_one_window = 1;

static char *display = NULL;

/* Used to quote the next character, emulates mi_getch () */
static int mi_getch_waiting = 0;
static int mi_getch_value;

static Tk_ArgvInfo arg_table[] = {
{"-display", TK_ARGV_STRING, (char *) NULL, (char *) &display,
             "Display to use"},
{(char *) NULL, TK_ARGV_END, (char *) NULL, (char *) NULL,
             (char *) NULL}
};

static int tkmc_callback (ClientData cd, Tcl_Interp *i, int ac, char *av[]);

int
xtoolkit_init (int *argc, char *argv[])
{
    interp = Tcl_CreateInterp ();
    if (Tk_ParseArgv (interp, (Tk_Window) NULL, argc, argv, arg_table, 0)
	!= TCL_OK) {
	fprintf(stderr, "%s\n", interp->result);
	exit(1);
    }

    /* Pass DISPLAY variable to child procedures */
    if (display != NULL) {
	Tcl_SetVar2 (interp, "env", "DISPLAY", display, TCL_GLOBAL_ONLY);
    }

    Tcl_SetVar(interp, "tcl_interactive", "0", TCL_GLOBAL_ONLY);
    
    Tcl_SetVar(interp, "one_window",
	       use_one_window ? "1" : "0", TCL_GLOBAL_ONLY);

    /*
     * Initialize the Tk application.
     */
#ifdef OLD_VERSION
    tkwin = Tk_CreateMainWindow (interp, display, "Midnight Commander","tkmc");
#endif
    if (Tcl_Init (interp) != TCL_OK){
	fprintf (stderr, "%s\n", interp->result);
	exit (1);
    }
    if (Tk_Init (interp) != TCL_OK){
	fprintf (stderr, "%s\n", interp->result);
	exit (1);
    }
    
    Tcl_CreateCommand (interp, "tkmc", tkmc_callback, 0, 0);
    if (Tcl_EvalFile (interp, LIBDIR "mc.tcl") == TCL_OK)
	return 0;
    else {
	printf ("%s\n", interp->result);
	exit (1);
    }
}

int
xtoolkit_end (void)
{
    /* Cleanup */
    Tcl_Eval (interp, "exit");
    return 1;
}

void
tk_evalf (char *format, ...)
{
    va_list ap;
    char buffer [1024];

    va_start (ap, format);
    vsprintf (buffer, format, ap);
    if (Tcl_Eval (interp, buffer) != TCL_OK){
	fprintf (stderr, "[%s]: %s\n", buffer, interp->result);
    }
    va_end (ap);
}

int
tk_evalf_val (char *format, ...)
{
    va_list ap;
    char buffer [1024];
    int r;

    va_start (ap, format);
    vsprintf (buffer, format, ap);
    r = Tcl_Eval (interp, buffer);
    va_end (ap);
    return r;
}

widget_data
xtoolkit_create_dialog (Dlg_head *h)
{
    char *dialog_name = copy_strings (".", h->name, 0);
    
    tk_evalf ("toplevel %s", dialog_name);
    return (widget_data) dialog_name;
}

void
x_set_dialog_title (Dlg_head *h, char *title)
{
    tk_evalf ("wm title %s {%s}", (char *)(h->wdata), title);
}

widget_data
xtoolkit_get_main_dialog (Dlg_head *h)
{
    return (widget_data) strdup (".");
}

/* Creates the containers */
widget_data
x_create_panel_container (int which)
{
    char *s, *cmd;

    cmd  = use_one_window ? "frame" : "toplevel";
    s   = which ? ".right" : ".left";
    tk_evalf ("%s %s", cmd, s);

    return (widget_data) s;
}

void
x_panel_container_show (widget_data wdata)
{
}

int
do_esc_key (int d)
{
    if (isdigit(d))
	return KEY_F(d-'0');
    if ((d >= 'a' && d <= 'z') || (d >= 'A' && d <= 'Z' )
	|| d == '\n' || d == '\t' || d == XCTRL ('h') || d == '!'
	|| d == KEY_BACKSPACE || d == 127 || d == '\r')
	return ALT(d);
    else {
	return ESC_CHAR;
    }
}

/* This commands has this sintax:
 * [r|a|c] ascii
 *
 * r, a, c, k: regular, alt, control, keysym
 */
 
static int
tkmc_callback (ClientData cd, Tcl_Interp *i, int ac, char *av[])
{
    Dlg_head *h = current_dlg;
    int key;
    static int got_esc;

    key = av [2][0];

    if (av [1][0] == 'c' || av [1][0] == 'a'){
	if (!key)
	    return TCL_OK;
	
	/* Regular? */
	
	if (!isascii (key)){
	    return TCL_OK;
	} else { 
	    key = tolower (key);
	}
    }
    
    switch (av [1][0]){
    case 'a':
	key = ALT(key);
	break;

    case 'c':
	key = XCTRL(key);
	break;

    case 'r':
	if (!key)
	    return TCL_OK;
	break;
	
    case 'k':
	if (!(key = lookup_keysym (av [2])))
	    return TCL_OK;
	break;
    }
    
    if (key == '\r')
	key = '\n';

    if (key == ESC_CHAR){
	if (!got_esc){
	    got_esc = 1;
	    return TCL_OK;
	}
	got_esc = 0;
    }

    if (got_esc){
	key = do_esc_key (key);
	got_esc = 0;
    }

    if (mi_getch_waiting && key){
	mi_getch_waiting = 0;
	mi_getch_value = key;
	return TCL_OK;
    }
    dlg_key_event (h, key);
    update_cursor (h);
    return TCL_OK;
}

void
tk_focus_widget (Widget_Item *p)
{
    char *wname;

    if (!p->widget)
	return;
    
    wname = (char *) p->widget->wdata;

    if (!wname)
	return;

    tk_evalf ("focus %s", wname+1);
}

/* This routine uses the grid geometry manager to layout
 * the widgets inside the dialog.  This is called if no
 * layout routine has been defined for the window
 * it also calls a post layout routine to spice up the dialog
 */
void
do_grid_layout (Dlg_head *h, char *wname)
{
    const int cols  = h->cols;
    const int lines = h->lines;
    const int widgets = h->count;
    const int wherex = h->x;
    const int wherey = h->y;
    Widget_Item *h_track;
    int i, height, width;

#if 0
    for (i = 0; i < cols; i++){
	int j;

	for (j = 0; j < lines; j++){
	    tk_evalf ("frame %s.f%d-%d -height 18 -width 10", wname, i, j);
	    tk_evalf ("grid configure %s.f%d-%d -row %d -column %d", wname, i, j, j, i);
	}
    }
#endif
    tk_evalf_val ("set $setup(heightc)");
    height = atoi (interp->result) * 2;
    tk_evalf_val ("set $setup(widthc)");
    width = atoi (interp->result) *2;

    if (height == 0 || width == 0){
	fprintf (stderr, "valiste verga\n");
	height = 30;
	width = 20;
    }
    h_track = h->current;
    for (i = 0; i < widgets; i++){
	fprintf (stderr, "%s goes to: %d %d\n\r", (char *) h_track->widget->wdata,
		  h_track->widget->x - wherex, h_track->widget->y-wherey);
	tk_evalf ("place configure %s -x %d -y %d ",
		  ((char *) (h_track->widget->wdata))+1, 
		  (h_track->widget->x - wherex) * width,
		  (h_track->widget->y - wherey) * height);
	h_track = h_track->prev;
    }
}

/* Setup done before using tkrundlg_event */
void
tk_init_dlg (Dlg_head *h)
{
    Widget_Item *h_track;
    char *wname;
    int i;

    /* Set wlist to hold all the widget names that will be ran */
    tk_evalf ("set wlist {}");
    h_track = h->current;
    for (i = 0; i < h->count; i++){
	char *wname = (char *)h_track->widget->wdata;
	if (wname)
	    tk_evalf ("set wlist \"%s $wlist\"", wname+1);
	h_track = h_track->prev;
    }

    wname = (char *) h->wdata;
    
    /* Layout the window, if no layout routine is defined, use grided layout */
    if (tk_evalf_val ("layout_%s", h->name) != TCL_OK)
	do_grid_layout (h, wname);

    /* setup window bindings */
    tk_evalf ("bind_setup %s", wname);

    /* If this is not the main window, center it */
    if (wname [0] && wname [1]){
	tk_evalf ("center_win %s", wname);
    }
}

int
tkrundlg_event (Dlg_head *h)
{
    /* Run the dialog */
    while (h->running){
	if (h->send_idle_msg){
	    if (Tcl_DoOneEvent (TCL_DONT_WAIT))
		if (idle_hook)
		    execute_hooks (idle_hook);
		
	    while (Tcl_DoOneEvent (TCL_DONT_WAIT) &&
		   h->running && h->send_idle_msg){
		(*h->callback) (h, 0, DLG_IDLE);
	    }
	} else 
	    Tcl_DoOneEvent (TCL_ALL_EVENTS); 
    }

    return 1;
}

int
Tcl_AppInit (Tcl_Interp *interp)
{
    return TCL_OK;
}

void
x_interactive_display ()
{
}

int
tk_getch ()
{
    mi_getch_waiting = 1;
    
    while (mi_getch_waiting)
	Tk_DoOneEvent (TK_ALL_EVENTS);
    
    return mi_getch_value;
}

void
tk_dispatch_all (void)
{
    while (Tk_DoOneEvent (TK_DONT_WAIT))
	;
}
