#include <config.h>
#ifdef _plan9_
#include <u.h>
#include <libc.h>
#else
#ifndef NO_MALLOC_H
#include <malloc.h>
#endif
#include <string.h>
#endif

#include <fconfig.h>
#include <filter.h>
#include <fractal.h>
#include <ui_helper.h>
#include <ui.h>
#include <xshl.h>
#include <xmenu.h>
#include <grlib.h>
#include <misc-f.h>
#include "uiint.h"
#define HISTORYSIZE 10
static int historypos;
static struct xshl_line *lines;
static int helpwidth, helpheight, helpx, helpy;
static struct uih_window *helpw;
static int textheight;
static char *ui_helppage[HISTORYSIZE];
static int ui_helppos[HISTORYSIZE];
int helpvisible;

static struct xshl_item *presseditem;
static struct xshl_item *selecteditem;
static int pressedline;
static int selectedline;
#define SCROOLSIZE 10
#define XPOS(xp) (2 * BORDERWIDTH + (xp))
#define YPOS(yp) (2*BORDERWIDTH+ (yp)-ui_helppos[historypos]+10)
#define SCROOLSTART (helpx+helpwidth-WBORDERS)
#define WBORDERS (4*BORDERWIDTH+SCROOLSIZE)
#define HBORDERS (xtextheight(uih->font)+8*BORDERHEIGHT)
#define WIDTH  (uih->image->width-WBORDERS)
#define HEIGHT (uih->image->height-HBORDERS)

static int pressedbutton = -1;
static int selectedbutton = -1;

#define NBUTTONS 3
CONST char *CONST names[] = { "OK", "Back", "Main" };

#define BUTTONSTART(i) (helpx+BORDERWIDTH+(helpwidth-2*BORDERWIDTH)/NBUTTONS*(i))
static void ui_build_help(char *name);
static void ui_backhelp(void)
{
    historypos--;
    if (historypos < 0)
	historypos = HISTORYSIZE - 1;
    ui_build_help(ui_helppage[historypos]);
}

static void do_button(int i)
{
    switch (i) {
    case 0:
	ui_close_help();
	break;
    case 1:
	ui_backhelp();
	break;
    case 2:
	ui_help("main");
	break;
    }
}

void ui_close_help(void)
{
    if (helpw != NULL) {
	xshl_free(lines);
	helpvisible = 0;
	uih_removew(uih, helpw);
	uih->display = 1;
	helpw = NULL;
    }
}

static int getwidth(void *data, int flags, CONST char *text)
{
    if (uih->image->flags & AAIMAGE)
	return (xtextwidth(uih->font, text));
    return (xtextwidth(uih->font, text) - 1);
}

static void
helpsize(struct uih_context *c, int *x, int *y, int *width, int *height,
	 void
	 *data)
{
    *x = helpx;
    *y = helpy;
    *width = helpwidth;
    *height = helpheight;
}

static void drawhelp(struct uih_context *c, void *data)
{
    int i = 0;
    int y;
    int percentx, percenty;
    struct xshl_item *curritem;
    uih_drawborder(uih, helpx + BORDERWIDTH, helpy + BORDERHEIGHT,
		   helpwidth - WBORDERS + SCROOLSIZE,
		   helpheight - HBORDERS, BORDER_PRESSED);

    if (ui_helppos[historypos] > textheight - helpheight / 2 + HBORDERS)
	ui_helppos[historypos] = textheight - helpheight / 2 + HBORDERS;
    if (ui_helppos[historypos] < 0)
	ui_helppos[historypos] = 0;

    /*draw scroolbar */
    percentx =
	(helpheight - HBORDERS) * ui_helppos[historypos] / textheight;
    percenty =
	(helpheight - HBORDERS) * (ui_helppos[historypos] + helpheight -
				   HBORDERS) / textheight;
    if (percentx < BORDERHEIGHT)
	percentx = BORDERHEIGHT;
    if (percenty < BORDERHEIGHT)
	percenty = BORDERHEIGHT;
    if (percentx > helpheight - HBORDERS - BORDERHEIGHT)
	percentx = helpheight - HBORDERS - BORDERHEIGHT;
    if (percenty > helpheight - HBORDERS - BORDERHEIGHT)
	percenty = helpheight - HBORDERS - BORDERHEIGHT;
    uih_drawborder(uih, SCROOLSTART, helpy + BORDERHEIGHT + percentx,
		   SCROOLSIZE - 1, percenty - percentx, 0);
    for (i = 0; i < NBUTTONS; i++) {
	ui_drawbutton(names[i], pressedbutton == i, selectedbutton == i,
		      BUTTONSTART(i) + BORDERWIDTH,
		      BUTTONSTART(i + 1) - BORDERWIDTH,
		      helpy + helpheight - BUTTONHEIGHT - BORDERHEIGHT);
    }


    i = 0;
    while (YPOS(lines[i].y) < 2 * BORDERWIDTH) {
	i++;
	if (lines[i].y < 0)
	    return;
    }
    while ((y =
	    YPOS(lines[i].y)) <
	   helpheight - HBORDERS - xtextheight(uih->font)
	   && lines[i].y >= 0) {
	curritem = lines[i].first;
	while (curritem != NULL) {
	    unsigned int bgcolor = BGCOLOR(uih);
	    unsigned int fgcolor = /*FGCOLOR (uih) */ LIGHTGRAYCOLOR2(uih);
	    int flags = 0;
	    int x = XPOS(curritem->x);

	    if (curritem->c.flags & (XSHL_BIG | XSHL_RED))
		fgcolor = SELCOLOR(uih);
	    else if (curritem->c.flags & (XSHL_EMPH | XSHL_MONOSPACE))
		fgcolor =
		    uih->image->
		    flags & AAIMAGE ? SELCOLOR(uih) : FGCOLOR(uih);
	    else if (curritem->c.flags & (XSHL_BLACK))
		bgcolor = fgcolor = BGCOLOR(uih), flags = TEXT_PRESSED;
	    else
		bgcolor = fgcolor, flags |= TEXT_PRESSED;
	    if (uih->palette->type & BITMAPS) {
		flags = TEXT_PRESSED;
		fgcolor = BGCOLOR(uih);
	    }
	    if (curritem->c.linktext != NULL) {
		if (uih->palette->type & BITMAPS) {
		    if (curritem == presseditem
			|| curritem == selecteditem)
			fgcolor =
			    FGCOLOR(uih), xrectangle(uih->image, x + helpx,
						     y + helpy,
						     curritem->width,
						     xtextheight(uih->
								 font),
						     BGCOLOR(uih));
		    else
			xhline(uih->image, x + helpx,
			       y + helpy + xtextheight(uih->font) - 1,
			       curritem->width, BGCOLOR(uih));
		} else {
		    if (uih->image->flags & AAIMAGE)
			fgcolor = curritem == presseditem
			    || curritem ==
			    selecteditem ? SELCOLOR(uih) : BGCOLOR(uih);
		    else {
			int i;
			i = strlen(curritem->c.linktext);
			if (i > 3
			    && !strcmp(".xaf",
				       curritem->c.linktext + i - 4))
			    xhline(uih->image, x + helpx,
				   y + helpy + xtextheight(uih->font) - 1,
				   curritem->width, curritem == presseditem
				   || curritem ==
				   selecteditem ? SELCOLOR(uih) :
				   SELCOLOR(uih));
			else
			    xhline(uih->image, x + helpx,
				   y + helpy + xtextheight(uih->font) - 1,
				   curritem->width, curritem == presseditem
				   || curritem ==
				   selecteditem ? SELCOLOR(uih) :
				   LIGHTGRAYCOLOR2(uih));
			xhline(uih->image, x + helpx + 1,
			       y + helpy + xtextheight(uih->font) - 0,
			       curritem->width, BGCOLOR(uih));
		    }
		    flags = 0;
		    bgcolor = BGCOLOR(uih);
		    if (fgcolor == LIGHTGRAYCOLOR2(uih))
			fgcolor = FGCOLOR(uih);
		    if (curritem == presseditem
			|| curritem == selecteditem)
			fgcolor = SELCOLOR(uih);
		}
	    }
	    xprint(uih->image, uih->font, x + helpx, y + helpy,
		   curritem->text, 0, fgcolor, bgcolor, flags);
	    curritem = curritem->next;
	}
	i++;
    }
}

int ui_helpkeys(int key)
{
    int i;
    if (helpw == NULL)
	return 0;
    switch (key) {
    case 'h':
	ui_close_help();
	ui_menu("tutor");
	return 1;
    case 'm':
	ui_help("main");
	return 1;
    case UIKEY_DOWN:
    case 'j':
	ui_helppos[historypos] += 8, uih->display = 1;
	presseditem = NULL;
	selecteditem = NULL;
	break;
    case UIKEY_UP:
    case 'k':
	ui_helppos[historypos] -= 8, uih->display = 1;
	presseditem = NULL;
	selecteditem = NULL;
	break;
    case UIKEY_PGDOWN:
    case '+':
    case 'f':
    case ' ':
	ui_helppos[historypos] +=
	    helpheight - HBORDERS - 32, uih->display = 1;
	presseditem = NULL;
	selecteditem = NULL;
	break;
    case UIKEY_PGUP:
    case '-':
	ui_helppos[historypos] -=
	    helpheight - HBORDERS - 32, uih->display = 1;
	presseditem = NULL;
	selecteditem = NULL;
	break;
    case 'b':
    case 1:
	ui_backhelp();
	break;
    case UIKEY_ESC:
    case 'q':
    case 'c':
    case 'o':
	ui_close_help();
	break;
    case UIKEY_TAB:
    case UIKEY_RIGHT:
	uih->display = 1;
	if (selectedbutton < 0 || selectedbutton == NBUTTONS - 1) {
	    if (selecteditem == NULL) {
		i = 0;
		while (YPOS(lines[i].y) < 2 * BORDERWIDTH) {
		    i++;
		    if (lines[i].y < 0)
			break;
		}
		selecteditem = lines[i].first;
	    } else
		i = selectedline, selecteditem = selecteditem->next;
	    for (;
		 lines[i].y >= 0
		 && YPOS(lines[i].y) < helpheight - HBORDERS; i++) {
		selectedline = i;
		while (selecteditem != NULL) {
		    if (selecteditem->c.linktext != NULL) {
			selectedbutton = -1;
			return 0;
		    }
		    selecteditem = selecteditem->next;
		}
		selecteditem = lines[i + 1].first;
	    }
	    selecteditem = NULL;
	    selectedbutton = 0;
	} else
	    selectedbutton++;
	break;
    case 13:
    case '\n':
	if (selecteditem != NULL) {
	    ui_help(selecteditem->c.linktext);
	    return 1;
	}
	if (selectedbutton >= 0)
	    do_button(selectedbutton);
    }
    return 1;
}

int ui_helpmouse(int x, int y, int buttons, int flags)
{
    static int grabbed = 0;
    int atpressed = 0;
    if (helpw == NULL)
	return 0;
    if (x < helpx || y < helpy || x > helpx + helpwidth
	|| y > helpy + helpheight) {
	if (flags & MOUSE_PRESS)
	    ui_close_help();
	pressedbutton = -1;
	if (pressedbutton != -1)
	    pressedbutton = -1, uih->display = 1;
	return 1;
    } else {
	if (y > helpy + helpheight - BUTTONHEIGHT - 2 * BORDERHEIGHT) {
	    int button;
	    int i;
	    for (i = 0; i <= NBUTTONS; i++)
		if (x < BUTTONSTART(i))
		    break;
	    button = i - 1;
	    if (flags & MOUSE_DRAG) {
		if (pressedbutton != selectedbutton
		    || pressedbutton != button)
		    pressedbutton = selectedbutton = button, uih->display =
			1;
	    } else {
		if (pressedbutton != -1)
		    pressedbutton = -1, uih->display = 1;
		if (flags & MOUSE_RELEASE)
		    do_button(button);
	    }
	    return 1;
	}
	if (pressedbutton != -1)
	    pressedbutton = -1, uih->display = 1;
	if (buttons
	    && ((x > SCROOLSTART && y < helpy + helpheight - HBORDERS)
		|| grabbed)) {
	    /*we are in scroolbar */
	    int pos = (y - helpy) * textheight / (helpheight - HBORDERS);
	    if (pos != ui_helppos[historypos])
		ui_helppos[historypos] = pos, uih->display = 1;
	    grabbed = 1;
	    return 1;
	} else
	    grabbed = 0;
	y -= helpy + xtextheight(uih->font);
	x -= 2 * BORDERWIDTH + helpx;
	pressedbutton = -1;
	if (presseditem != NULL) {
	    if (YPOS(lines[pressedline].y) + 1 >= y
		&& YPOS(lines[pressedline].y) <= y + xtextheight(uih->font)
		&& presseditem->x <= x
		&& presseditem->x + presseditem->width >= x)
		atpressed = 1;
	}
	if (flags & MOUSE_PRESS || ((flags & MOUSE_DRAG) && !atpressed)) {
	    int i = 0;
	    for (i = 0;
		 lines[i].y >= 0 && (YPOS(lines[i].y) + 1 <= y
				     || YPOS(lines[i].y) >=
				     y + xtextheight(uih->font)); i++);
	    if (lines[i].y >= 0) {
		struct xshl_item *item = lines[i].first;
		while (item != NULL) {
		    if (item->c.linktext != NULL && item->x <= x
			&& item->x + item->width >= x)
			break;
		    item = item->next;
		}
		if (item != NULL) {
		    uih->display = 1;
		    presseditem = item;
		    pressedline = i;
		}
	    }
	} else if (flags & MOUSE_MOVE) {
	    if (!atpressed && presseditem != NULL)
		uih->display = 1, presseditem = 0;
	} else if ((flags & MOUSE_RELEASE)) {
	    if (atpressed) {
		ui_help(presseditem->c.linktext);
		return 1;
	    }
	    if (presseditem != NULL)
		presseditem = NULL, uih->display = 1;
	    /*odfajruj to! */
	}
    }
    return 1;
}

static void ui_build_help(char *name)
{
    int i;
    int width;
    if (ui_nogui) {
	printf("help \"%s\"\n", name);
	return;
    }
    if (driver->gui_driver && driver->gui_driver->help) {
	driver->gui_driver->help(uih, name);
	return;
    }
    if (helpw != NULL)
	ui_close_help();
    pressedbutton = -1;
    helpvisible = 1;
    width = 80 * xtextwidth(uih->font, "w");
    if (width > WIDTH)
	width = WIDTH;
    lines =
	help_make(name ? name : "main", getwidth, width - 2,
		  xtextheight(uih->font), xtextheight(uih->font));
    if (lines == NULL) {
	lines =
	    help_make("main", getwidth, width - 2, xtextheight(uih->font),
		      xtextheight(uih->font));
	if (lines == NULL) {
	    helpvisible = 0;
	    uih_message(uih, "Help file not found");
	    return;
	}
    }
    width += WBORDERS;
    uih->display = 1;
    presseditem = selecteditem = NULL;
    helpwidth = width;
    helpx = (uih->image->width - width) / 2;
    for (i = 0; lines[i].y >= 0; i++);
    textheight = lines[i - 1].y + 4 * xtextheight(uih->font);
    if (textheight < HEIGHT)
	helpheight = textheight;
    else
	helpheight = HEIGHT;
    helpheight += HBORDERS;
    helpy = (uih->image->height - helpheight) / 2;
    helpw = uih_registerw(uih, helpsize, drawhelp, 0, DRAWBORDER);
}

void ui_help(CONST char *name)
{
    if (strlen(name) > 4 && !strcmp(name + strlen(name) - 4, ".xaf")) {
	uih_playtutorial(uih, name);
	if (helpw != NULL)
	    ui_close_help();
	/*FIXME!!!!!!! This needs to be queued! */
	return;
    }
    historypos++;
    historypos %= HISTORYSIZE;
    ui_helppage[historypos] = mystrdup(name);	/* NOTE we are not freeing this memory. I believe it is not problem. */
    ui_helppos[historypos] = 0;
    ui_build_help(ui_helppage[historypos]);
}
