/*
 * dml - Dialog Markup Language
 *
 * $Id: slang.c,v 1.10 2003/08/23 14:19:20 malekith Exp $
 * Author: Michal Moskal <malekith@pld-linux.org>
 * include COPYING-GNU
 */

#include "pi.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <slang/slang.h>

#define C_BLACK "black"
#define C_GRAY "gray"
#define C_RED "red" 
#define C_LIGHTRED "brightred"
#define C_GREEN "green"
#define C_LIGHTGREEN "brightgreen"
#define C_BROWN "brown"
#define C_YELLOW "yellow"
#define C_BLUE "blue"
#define C_LIGHTBLUE "brightblue"
#define C_MAGENTA "magenta"
#define C_LIGHTMAGENTA "brightmagenta"
#define C_CYAN "cyan"
#define C_LIGHTCYAN "brightcyan"
#define C_LIGHTGRAY "lightgray"
#define C_WHITE "white"

struct pi_object *_pi_root_object;

char *pi_conf_file = "/etc/dml.conf";
int pi_screen_height, pi_screen_width;
int pi_poor_man_frames = 0;

struct optiondesc {
	char *element_name;
	int element;
	char *default_fg;
	char *default_bg;
};


/*
  I know, the second field could be omitted here, because the table is
  in correct order (like proper enum in pi.h).
  But it is more clear now
*/
struct optiondesc optionlist[] = {
  { "pi_color_bg", pi_color_bg, C_YELLOW, C_BLUE },
  { "pi_color_label", pi_color_label, C_LIGHTGRAY, C_BLACK },
  { "pi_color_window", pi_color_window, C_CYAN, C_BLACK },
  { "pi_color_window_hl", pi_color_window_hl, C_LIGHTCYAN, C_BLACK },
  { "pi_color_button", pi_color_button, C_GREEN, C_BLACK },
  { "pi_color_abutton", pi_color_abutton, C_BLACK, C_GREEN },
  { "pi_color_button_hl", pi_color_button_hl, C_LIGHTGREEN, C_BLACK },
  { "pi_color_abutton_hl", pi_color_abutton_hl, C_LIGHTGREEN, C_GREEN },
  { "pi_color_input", pi_color_input, C_BLACK, C_CYAN },
  { "pi_color_input_ghosted", pi_color_input_ghosted, C_WHITE, C_BLACK },
  { "pi_color_input_hl", pi_color_input_hl, C_WHITE, C_CYAN },
  { "pi_color_input_deadly", pi_color_input_deadly, C_WHITE, C_BLUE },
  { "pi_color_input_arrow", pi_color_input_arrow, C_WHITE, C_GREEN },
  { "pi_color_textarea_c1", pi_color_textarea_c1, C_LIGHTGRAY, C_BLUE },
  { "pi_color_textarea_c2", pi_color_textarea_c2, C_YELLOW, C_BLUE },
  { "pi_color_textarea_c3", pi_color_textarea_c3, C_LIGHTCYAN, C_BLUE },
  { "pi_color_textarea_scrollbar", pi_color_textarea_scrollbar, C_BLUE, C_BLUE },
  { "pi_color_atextarea_scrollbar_marked", pi_color_atextarea_scrollbar_marked, C_GREEN, C_GREEN },
  { "pi_color_atextarea_scrollbar", pi_color_atextarea_scrollbar, C_BLUE, C_BLUE },
  { "pi_color_textarea_scrollbar_marked", pi_color_textarea_scrollbar_marked, C_CYAN, C_CYAN },
  { "pi_color_menu_1", pi_color_menu_1, C_LIGHTGRAY, C_BLUE },
  { "pi_color_menu_2", pi_color_menu_2, C_YELLOW, C_BLUE },
  { "pi_color_menu_hl_1", pi_color_menu_hl_1, C_BLACK, C_CYAN },
  { "pi_color_menu_hl_2", pi_color_menu_hl_2, C_LIGHTCYAN, C_CYAN },
  { "pi_color_menu_hl_active_1", pi_color_menu_hl_active_1, C_BLACK, C_GREEN },
  { "pi_color_menu_hl_active_2", pi_color_menu_hl_active_2, C_LIGHTGREEN, C_GREEN },
  { "pi_color_amenu_scrollbar", pi_color_amenu_scrollbar, C_BLUE, C_BLUE },
  { "pi_color_amenu_scrollbar_marked", pi_color_amenu_scrollbar_marked, C_CYAN, C_CYAN },
  { "pi_color_menu_scrollbar_marked", pi_color_menu_scrollbar_marked, C_GREEN, C_GREEN },
  { "pi_color_menu_scrollbar", pi_color_menu_scrollbar, C_BLUE, C_BLUE },
  { "pi_color_title1", pi_color_title1, C_GREEN, C_BLACK },
  { "pi_color_title2", pi_color_title2, C_LIGHTGREEN, C_BLACK },
  { "pi_color_checkbox", pi_color_checkbox, C_WHITE, C_BLACK },
  { "pi_color_checkbox_hl", pi_color_checkbox_hl, C_LIGHTCYAN, C_BLUE },
  { "pi_color_fileselector_1", pi_color_fileselector_1, C_LIGHTGRAY, C_BLUE },
  { "pi_color_fileselector_2", pi_color_fileselector_2, C_YELLOW, C_BLUE },
  { "pi_color_fileselector_hl_1", pi_color_fileselector_hl_1, C_BLACK, C_CYAN },
  { "pi_color_fileselector_hl_2", pi_color_fileselector_hl_2, C_LIGHTCYAN, C_CYAN },
  { "pi_color_fileselector_hl_active_1", pi_color_fileselector_hl_active_1, C_BLACK, C_GREEN },
  { "pi_color_fileselector_hl_active_2", pi_color_fileselector_hl_active_2, C_LIGHTGREEN, C_GREEN },
  { "pi_color_afileselector_scrollbar", pi_color_afileselector_scrollbar, C_BLUE, C_BLUE },
  { "pi_color_afileselector_scrollbar_marked", pi_color_afileselector_scrollbar_marked, C_CYAN, C_CYAN },
  { "pi_color_fileselector_scrollbar_marked", pi_color_fileselector_scrollbar_marked, C_GREEN, C_GREEN },
  { "pi_color_fileselector_scrollbar", pi_color_fileselector_scrollbar, C_BLUE, C_BLUE },
  { NULL, 0, NULL, NULL }
};

static void init_colors()
{
	FILE *f;
	int i;
	char line[200];
	char element_name[100];
	char fg[30];
	char bg[30];
	struct optiondesc od;

	/* load defaults */

	for (i = 0; od = optionlist[i], od.element_name != NULL; i++ )
		SLtt_set_color(od.element, 0 ,od.default_fg, od.default_bg);

	/* overrwrite by config file if exists */

	f = fopen(pi_conf_file,"r");
	
	if (f == NULL)
		return;
		
	while (fgets(line, sizeof(line), f)) {
		for (i = 0; line[i]; i++)
			if (line[i] == '#')
				break;
		if (line[i])
			continue;
		if (sscanf(line, "%99s%29s%29s", element_name, fg, bg) != 3)
			continue;
			
		for (i = 0; od = optionlist[i], od.element_name != NULL; i++) 
			if (strcmp(od.element_name, element_name) == 0) 
				SLtt_set_color(od.element, 0, fg, bg);
	}
	fclose (f);
}

static void int_handler(int x)
{
	(void)x;
	pi_die("interrupt");
}

void pi_cls()
{
	SLsmg_cls();
}

void pi_addstr_fill_alt(const char *s, int n, int c1, int c2)
{
	pi_color(c1);
	
	while (*s && n--) {
		if (*s == '_' && s[1]) {
			pi_color(c2);
			pi_putch(*++s);
			pi_color(c1);
			s++;
		} else
			pi_putch(*s++);
	}

	pi_color(c1);
	while (n-- > 0)
		pi_putch(' ');
}

void pi_addstr_alt(const char *s, int n, int c1, int c2)
{
	pi_color(c1);
	
	while (*s && n--) {
		if (*s == '_' && s[1]) {
			pi_color(c2);
			pi_putch(*++s);
			pi_color(c1);
			s++;
		} else
			pi_putch(*s++);
	}
	
	pi_color(c1);
}

int pi_strlen_alt(const char *s)
{
	int n;
	
	for (n = 0; *s; s++, n++) 
		if (*s == '_' && s[1])
			s++;
	return n;
}

void pi_init()
{
	SLtt_get_terminfo();
	if (SLkp_init() == -1)
		pi_die("Unable to initialize SLkp.");
		
	if (SLang_init_tty(-1, 0, 0) == -1)
		pi_die("Unable to initialize SLang terminal.");
	SLsmg_init_smg();
	
	SLang_set_abort_signal(int_handler);

	init_colors();

	_pi_root_object = pi_new_object(0);

	pi_screen_height = SLtt_Screen_Rows;
	pi_screen_width = SLtt_Screen_Cols;
}

void pi_goto(int x, int y)
{
	SLsmg_gotorc(y, x);
}

void pi_frame(int x, int y, int w, int h)
{
	if (pi_poor_man_frames) {
		int n;
		
		pi_goto(x, y);
		pi_putch('+');
		n = w - 2;
		while (n-- > 0)
			pi_putch('-');
		pi_putch('+');

		for (n = y + 1; n < y + h; n++) {
			pi_goto(x, n);
			pi_putch('|');
			pi_goto(x + w - 1, n);
			pi_putch('|');
		}
		
		pi_goto(x, y + h - 1);
		pi_putch('+');
		n = w - 2;
		while (n-- > 0)
			pi_putch('-');
		pi_putch('+');

	} else {
		SLsmg_draw_box(y, x, h, w);
	}
}

void pi_putch(int c)
{
	SLsmg_write_char((unsigned)c & 0xff);
}

void pi_addstr(const char *c)
{
	SLsmg_write_string((char*)c);
}

void pi_addstrn(const char *c, int n)
{
	SLsmg_write_nstring((char*)c, n);
}

void pi_addstrn_fill(const char *c, int n)
{
	int k;
	
	if ((k = strlen(c)) > n)
		SLsmg_write_nchars((char*)c, n);
	else {
		SLsmg_write_string((char*)c);
		SLsmg_write_nstring(0, n - k);
	}
}

void pi_color(int c)
{
	SLsmg_set_color(c);
}

void pi_refresh()
{
	SLsmg_refresh();
}

void pi_fini()
{
	SLsmg_reset_smg();
	SLang_reset_tty();
}

void pi_die(const char *msg)
{
	pi_fini();
	fprintf(stderr, "%s\n", msg);
	exit(1);
}

void pi_fill(int c, int x, int y, int w, int h)
{
	SLsmg_fill_region(y, x, h, w, c);
}

int pi_getch()
{
	int k;

	if (SLang_input_pending(0) <= 0)
		return 0;
	
	k = SLkp_getkey();

	switch (k) {
	case SL_KEY_ERR:
		return 0;
	case SL_KEY_UP:
		return pi_key_up;
	case SL_KEY_DOWN:
		return pi_key_down;
	case SL_KEY_LEFT:
		return pi_key_left;
	case SL_KEY_RIGHT:
		return pi_key_right;
	case SL_KEY_PPAGE:
		return pi_key_pgup;
	case SL_KEY_NPAGE:
		return pi_key_pgdn;
	case 0x7f:
	case SL_KEY_BACKSPACE:
		return '\b';
	case '\r':
	case SL_KEY_ENTER:
		return '\n';
	case SL_KEY_DELETE:
		return pi_key_del;
	case SL_KEY_HOME:
		return pi_key_home;
	case SL_KEY_END:
		return pi_key_end;
	default:
		if (k < 256)
			return k;
		if (k > SL_KEY_F0 && k < SL_KEY_F0 + 24)
			return pi_key_f(k - SL_KEY_F0);
		return 0;
	}
}
