/* Slang interface to the Midnight Commander
   This emulates some features of ncurses on top of slang
   Copyright (C) 1995 Miguel de Icaza
   
   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.  */
#include <config.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <termios.h>
#include <signal.h>
#include "tty.h"
#include "mad.h"
#include "color.h"
#include "util.h"
#include "mouse.h"		/* Gpm_Event is required in key.h */
#include "key.h"		/* define_sequence */
#include "main.h"		/* extern: force_colors */
#include "win.h"		/* do_exit_ca_mode */

#ifdef HAVE_SLANG

/* Taken from S-Lang's sldisply.c file */
#ifndef USE_TERMCAP
#   define tgetstr(a,b) SLtt_tgetstr (a)
#else
    extern char *tgetstr(char *, char **);
#endif


static struct termios boot_mode;
static struct termios new_mode;
static int Read_FD;

#if DEVELOPERS_ONLY
static void slang_sigterm (int signo)
{
    SLsmg_reset_smg ();
    kill (getpid (), signo);
}
#endif

static int slinterrupt;

static void slang_intr (int signo)
{
    slinterrupt = 1;
}

void enable_interrupt_key(void)
{
#ifndef _OS_NT
    struct sigaction act;
    
#ifdef SIGINT
    act.sa_handler = slang_intr;
    sigemptyset (&act.sa_mask);
    act.sa_flags = 0;
    sigaction (SIGINT, &act, NULL);
#endif
#endif
    slinterrupt = 0;
}

void disable_interrupt_key(void)
{
#ifndef _OS_NT
    struct sigaction act;
    
#ifdef SIGINT
    act.sa_handler = SIG_IGN;
    act.sa_flags = 0;
    sigemptyset (&act.sa_mask);
    sigaction (SIGINT, &act, NULL);
#endif
#endif
}

int got_interrupt ()
{
    int t;

    t = slinterrupt;
    slinterrupt = 0;
    return t;
}

#ifdef _OS_NT
#define tcgetattr(a,b)
#endif

/* Only done the first time */
void slang_init (void)
{
#ifndef _OS_NT
    struct sigaction act, oact;
#endif
    
    Read_FD = fileno (stdin);
    SLtt_get_terminfo ();
    tcgetattr (Read_FD, &boot_mode);
    /* 255 = ignore abort char; XCTRL('g') for abort char = ^g */
    SLang_init_tty (XCTRL('c'), 1, 0);	
    tcgetattr (Read_FD, &new_mode);
    slang_prog_mode ();
    load_terminfo_keys ();
#ifdef SIGINT
    act.sa_handler = slang_intr;
    sigemptyset (&act.sa_mask);
#ifdef SA_RESTART
    act.sa_flags = SA_RESTART;
#endif
    sigaction (SIGINT, &act, &oact);
#endif

#if DEVELOPERS_ONLY
#ifdef SIGHUP
    signal (SIGHUP, slang_sigterm);
#endif    
#ifdef SIGQUIT
    signal (SIGQUIT, slang_sigterm);
#endif    
#ifdef SIGABRT    
    signal (SIGABRT, slang_sigterm);
#endif    
#ifdef SIGBUS    
    signal (SIGBUS, slang_sigterm);
#endif    
#ifdef SIGSEGV    
    signal (SIGSEGV, slang_sigterm);
#endif    
#ifdef SIGTERM    
    signal (SIGTERM, slang_sigterm);
#endif
#endif
}

/* Done each time we come back from done mode */
void slang_prog_mode (void)
{
    tcsetattr (Read_FD, TCSANOW, &new_mode);
    SLsmg_init_smg ();
    SLsmg_touch_lines (0, LINES);
}

/* Called each time we want to shutdown slang screen manager */
void slang_shell_mode (void)
{
    tcsetattr (Read_FD, TCSANOW, &boot_mode);
}

void slang_shutdown ()
{
    char *op_cap;
    
    slang_shell_mode ();
    do_exit_ca_mode ();
    SLang_reset_tty ();

    /* Load the op capability to reset the colors to those that were
     * active when the program was started up
     */
    op_cap = SLtt_tgetstr ("op");
    if (op_cap){
	fprintf (stderr, "%s", op_cap);
	fflush (stderr);
    }
}

/* keypad routines */
void slang_keypad (int set)
{
    char *keypad_string;
    
    keypad_string = (char *) SLtt_tgetstr (set ? "ks" : "ke");
    if (keypad_string)
	SLtt_write_string (keypad_string);
}

static int no_slang_delay;

void set_slang_delay (int v)
{
    no_slang_delay = v;
}

void hline (int ch, int len)
{
    int last_x, last_y;

    last_x = SLsmg_get_column ();
    last_y = SLsmg_get_row ();
    
    if (ch == 0)
	ch = ACS_HLINE;

    if (ch == ACS_HLINE){
	SLsmg_draw_hline (len);
    } else {
	while (len--)
	    addch (ch);
    }
    move (last_y, last_x);
}

void vline (int character, int len)
{
    if (!slow_terminal){
	SLsmg_draw_vline (len);
    } else {
	int last_x, last_y, pos = 0;

	last_x = SLsmg_get_column ();
	last_y = SLsmg_get_row ();

	while (len--){
	    move (last_y + pos++, last_x);
	    addch (' ');
	}
	move (last_x, last_y);
    }
}

void init_pair (int index, char *foreground, char *background)
{
    SLtt_set_color (index, "", foreground, background);
}

char *color_terminals [] = {
#ifdef linux
    "console",
#endif
    "linux",
    "xterm-color",
    "color-xterm",
    "xtermc",
    "ansi",
    0
};

int has_colors ()
{
    char *terminal = getenv ("TERM");
    int  i;

    SLtt_Use_Ansi_Colors = force_colors;
    if (NULL != getenv ("COLORTERM"))
	SLtt_Use_Ansi_Colors = 1;

    /* We want to allow overwriding */
    if (!disable_colors){
	for (i = 0; color_terminals [i]; i++)
	    if (strcmp (color_terminals [i], terminal) == 0)
		SLtt_Use_Ansi_Colors = 1;
    }
    
    /* Setup emulated colors */
    if (SLtt_Use_Ansi_Colors){
	init_pair (A_REVERSE, "black", "white");
    } else {
	SLtt_set_mono (A_BOLD,    NULL, SLTT_BOLD_MASK);
	SLtt_set_mono (A_REVERSE, NULL, SLTT_REV_MASK);
	SLtt_set_mono (A_BOLD|A_REVERSE, NULL, SLTT_BOLD_MASK | SLTT_REV_MASK);
    }
    return SLtt_Use_Ansi_Colors;
}

void attrset (int color)
{
    if (!SLtt_Use_Ansi_Colors){
	SLsmg_set_color (color);
	return;
    }
    
    if (color & A_BOLD){
	if (color == A_BOLD)
	    SLsmg_set_color (A_BOLD);
	else
	    SLsmg_set_color ((color & (~A_BOLD)) + 8);
	return;
    }

    if (color == A_REVERSE)
	SLsmg_set_color (A_REVERSE);
    else
	SLsmg_set_color (color);
}

/* This table describes which capabilities we want and which values we
 * assign to them.
 */
struct {
    int  key_code;
    char *key_name;
} key_table [] = {
    { KEY_F(0),  "k0" },
    { KEY_F(1),  "k1" },
    { KEY_F(2),  "k2" },
    { KEY_F(3),  "k3" },
    { KEY_F(4),  "k4" },
    { KEY_F(5),  "k5" },
    { KEY_F(6),  "k6" },
    { KEY_F(7),  "k7" },
    { KEY_F(8),  "k8" },
    { KEY_F(9),  "k9" },
    { KEY_F(10), "k;" },
    { KEY_F(11), "F1" },
    { KEY_F(12), "F2" },
    { KEY_F(13), "F3" },
    { KEY_F(14), "F4" },
    { KEY_F(15), "F5" },
    { KEY_F(16), "F6" },
    { KEY_F(17), "F7" },
    { KEY_F(18), "F8" },
    { KEY_F(19), "F9" },
    { KEY_F(20), "FA" },	
    { KEY_IC,    "kI" },
    { KEY_NPAGE, "kN" },
    { KEY_PPAGE, "kP" },
    { KEY_LEFT,  "kl" },
    { KEY_RIGHT, "kr" },
    { KEY_UP,    "ku" },
    { KEY_DOWN,  "kd" },
    { KEY_DC,    "kD" },
    { KEY_BACKSPACE, "kb" },
    { KEY_HOME,  "kh" },
    { KEY_END,	 "@7" },
    { 0, 0}
};
	
void do_define_key (int code, char *strcap)
{
    char    *seq;

    seq = (char *) SLtt_tgetstr (strcap);
    if (seq)
	define_sequence (code, seq, MCKEY_NOACTION);
}

void load_terminfo_keys ()
{
    int i;

    for (i = 0; key_table [i].key_code; i++)
	do_define_key (key_table [i].key_code, key_table [i].key_name);
}

int getch ()
{
    unsigned int ch;

    if (no_slang_delay)
	if (SLang_input_pending (0) == 0)
	    return -1;

    ch = SLang_getkey ();

#ifndef __GO32__
#define DEC_8BIT_HACK 64

   /* This has the effect of mapping all characters in the range 128-159 to
    * ESC [ something 
    */
   if ( (use_8th_bit_as_meta == 1) && (ch & 0x80) )
     {
	unsigned char i;
	i = (unsigned char) (ch & 0x7F);
	if (i < ' ')
	  {
	     i += DEC_8BIT_HACK;
	     SLang_ungetkey (i);
	     ch = 27;
	  }
     }

#endif    

   return (ch);
}

extern int slow_terminal;

#else

/* Non slang builds do not understand got_interrupt */
int got_interrupt ()
{
    return 0;
}
#endif /* HAVE_SLANG */
