 /*
  * UAE - The Un*x Amiga Emulator
  *
  * ncurses frontend for a text-based user interface.
  *
  * Copyright 1996 Bernd Schmidt
  * If you find the routines in this file useful, you may use them in your
  * programs without restrictions. Essentially, it's in the public domain.
  *
  */


#include "sysconfig.h"
#include "sysdeps.h"

#include <ncurses.h>

#include "config.h"
#include "options.h"
#include "tui.h"

static WINDOW *currwin;

static WINDOW *winstack[10]; /* more than enough */
static int winnr = 0;

void tui_setup(void)
{
    int i;
    
    for (i = 0; i < 10; i++)
	winstack[i] = NULL;
    /* From the ncurses manpage... */
    initscr(); start_color(); cbreak(); noecho(); nonl(); intrflush(stdscr, FALSE); keypad(stdscr, TRUE);
    currwin = stdscr;
    if (has_colors()) {
	init_pair(1, COLOR_WHITE, COLOR_BLUE);
	init_pair(2, COLOR_BLACK, COLOR_WHITE);
	wattron(currwin, COLOR_PAIR(1) | A_BOLD);
	wbkgd(currwin, ' '|COLOR_PAIR(1));
    }
    
    winstack[0] = stdscr;
    winnr = 1;
}

int tui_lines(void)
{
    return LINES;
}

int tui_cols(void)
{
    return COLS;
}

void tui_shutdown(void)
{
    endwin();
}

void tui_refresh(void)
{
    wrefresh(currwin);
}

void tui_puts(const char *s)
{
    waddstr(currwin, s);
}

void tui_cursoff(void)
{
}

void tui_curson(void)
{
}

void tui_putc(char c)
{
    waddch(currwin, c);
}

void tui_cr(void)
{
    waddch(currwin, '\r');
}

char tui_getc(void)
{
    return getch();
}

void tui_gotoxy(int x, int y)
{
    x--; y--;
    wmove(currwin, y, x);
}

void tui_selwin(int w)
{
    currwin = winstack[w];
}

void tui_clrwin(int w)
{
    wclear(winstack[w]);
}

void tui_drawbox(int w)
{
    wborder(winstack[w], 0, 0, 0, 0, 0, 0, 0, 0);
}

void tui_hline(int x1, int y1, int x2)
{
    wmove(currwin, y1-1, x1-1);
    whline(currwin, 0, x2-x1+1);
}

int tui_dlog(int x1, int y1, int x2, int y2)
{
    x1--; y1--;
    winstack[winnr] = newwin(y2 - y1, x2 - x1, y1, x1);
    return winnr++;
}

void tui_dlogdie(int w)
{
    if (currwin == winstack[w])
	currwin = stdscr;
    delwin(winstack[w]);
    winstack[w] = NULL;
    while (winstack[winnr-1] == NULL)
	winnr--;
    
    for (w = 0; w < winnr; w++)
	redrawwin(winstack[w]), wrefresh(winstack[w]);
}

int tui_gets(char *buf, int x, int y, int n)
{
    int i = 0;
    for (;;) {
	int c = getch();
	int j;
	wmove(currwin, y, x);
	for (j = 0; j < i; j++)
	    waddch(currwin, buf[j]);
	for (; j < n; j++)
	    waddch(currwin, ' ');
	wmove(currwin, y, x + i);
	wrefresh(currwin);
	buf[i] = 0;
	if (c == 13)
	    return 1;
	else if (c == 27)
	    return 0;
	else if (i + 1 < n)
	    buf[i++] = c;
    }
}

int tui_wgets(char *buf, const char *title, int n)
{
    int l = strlen(title);
    int ww = l > n ? l : n;
    int w = tui_dlog((tui_cols()-ww-2)/2, tui_lines()/2-1, (tui_cols()+ww+2)/2, tui_lines()/2+1);
    tui_selwin(w); tui_drawbox(w);
    wmove(currwin, 0, (ww-l)/2);
    waddstr(currwin, title);
    return tui_gets(buf, 1, 1, n);
}


static char *pattern;
static int maxlen;

static void put_filename(char *s, int x, int y, attr_t a)
{
    char buf[256];
    int i;

    tui_gotoxy(x,y);
    if (strcmp(s, ".") == 0)
	strcpy(buf, "(none)");
    else
	strcpy(buf, s);
    buf[maxlen] = 0;
    for (i = 0; i < strlen(buf); i++)
	waddch(currwin, buf[i] | a);
    for (; i < maxlen; i++)
	waddch(currwin, ' ' | a);
}

static char fsbuf[256];

static int selectfn(const struct dirent *de)
{
    int l1, l2;

/*    l1 = strlen(pattern + 1);*/
    l2 = strlen(de->d_name);

    if (l2 >= tui_cols()-10) /* Restrict length of filenames so we won't mess up the display */
	return 0;

    /* No pattern matching for now. But we don't show hidden files. */
    if (strcmp(de->d_name, ".") != 0 && strcmp(de->d_name, "..") != 0
	&& de->d_name[0] == '.')
	return 0;
    if (l2 > maxlen)
	maxlen = l2;
    return 1;
}

char *tui_filereq(char *s, char *oldfile)
{
    char cwd[256];
    char *retval = fsbuf;
    char *tmp;
    int fin = 0;

    /* Save wd */
    if (getcwd(cwd, 256) == NULL)
	return NULL;

    /* Change into directory of old file */
    strcpy(fsbuf, oldfile);
    tmp = strrchr(fsbuf, '/');
    if (tmp != NULL) {
	*tmp = 0;
	if (strlen(fsbuf) > 0)
	    chdir(fsbuf);
    }
    
    pattern = s;
    if (s[0] != '*')
	fprintf(stderr, "Can't handle wildcard %s\n", s);
    if (s[1] != 0 && strchr(s+1, '*') != NULL)
	fprintf(stderr, "Can't handle wildcard %s\n", s);
    for (;!fin;) {
	struct dirent **names;
	int i, w, n, l, yp, oldyp, s;
	
	maxlen = 0;
	n = scandir(".", &names, selectfn, alphasort);
	
	if (n <= 0)
	    return NULL;
	l = n;
	if (l > 15)
	    l = 15;
	yp = s = 0; oldyp = -1;
	w = tui_dlog(5, 5, 5 + maxlen + 3, 5 + l + 1);
	tui_selwin(w); tui_drawbox(w);
	for (;;) {
	    int c;
	    char tmp[256];
	    while (s < yp)
		yp--;
	    while (s >= yp + l)
		yp++;
	    if (oldyp != yp) {
		oldyp = yp;
		for (i = 0; i < l; i++) {
		    put_filename(names[i + yp]->d_name, 3, 2 + i, 0);
		}
	    }
	    put_filename(names[s]->d_name, 3, 2 + s - yp, A_STANDOUT);
	    tui_refresh();
	    c = getch();
	    put_filename(names[s]->d_name, 3, 2 + s - yp, 0);
	    if (c == 27) {
		retval = NULL; fin = 1;
		break;
	    } else if (c == KEY_ENTER || c == 13 || c == ' ') {
		int err;
		
		if (strcmp(names[s]->d_name, ".") == 0) {
		    fin = 1;
		    strcpy(fsbuf, "");
		    break;
		}
		err = chdir(names[s]->d_name);
		
		if (err == 0)
		    break;
		else if (errno == ENOTDIR) {
		    fin = 1;
		    if (getcwd(fsbuf, 256) == NULL)
			retval = NULL;
		    if (strlen(fsbuf) + strlen(names[s]->d_name) + 2 >= 256)
			retval = NULL;
		    else {
			strcat(fsbuf, "/");
			strcat(fsbuf, names[s]->d_name);
		    }
		    break;
		} /* else what? */
	    }
	    switch (c) {
	     case KEY_UP:
		if (s > 0)
		    s--;
		break;
	     case KEY_DOWN:
		if (s + 1 < n)
		    s++;
		break;
	     case KEY_PPAGE:
		if (s > l)
		    s -= l;
		else
		    s = 0;
		break;
	     case KEY_NPAGE:
		if (s + l < n)
		    s += l;
		else
		    s = n - 1;
		break;
	     default:
		for (i = 0; i < n; i++)
		    if (names[i]->d_name[0] == c) {
			s = i;
			break;
		    }
	    }
	}
#if 0
	/* @@@ is this right? */
	for (i = 0; i < n; i++)
	    free(names[i]->d_name);
	free(names);
#endif
	tui_dlogdie(w);
    }
    chdir(cwd);
    return retval;
}

int tui_backup_optionsfile(void)
{
    char tmp[257];
    strcpy(tmp, optionsfile);
    strcat(tmp, "~");
    return rename(optionsfile, tmp);
}
