#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]);
}
