/* -*-c-*- */
/* 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "config.h"

#include "libs/fvwmlib.h"
#include "libs/ColorUtils.h"
#include "libs/Graphics.h"
#include "Tools.h"

#define BdWidth 2               /* Border width */
#define SbWidth 15              /* ScrollBar width */

/*
 * Fonction pour Liste / Functions for the List
 */
void InitList(struct XObj *xobj)
{
  unsigned long mask;
  XSetWindowAttributes Attr;
  int minw,minh,resize=0;
  int NbVisCell,NbCell;

  /* Enregistrement des couleurs et de la police / fonts and colors */
  if (xobj->colorset >= 0) {
    xobj->TabColor[fore] = Colorset[xobj->colorset].fg;
    xobj->TabColor[back] = Colorset[xobj->colorset].bg;
    xobj->TabColor[hili] = Colorset[xobj->colorset].hilite;
    xobj->TabColor[shad] = Colorset[xobj->colorset].shadow;
  } else {
    xobj->TabColor[fore] = GetColor(xobj->forecolor);
    xobj->TabColor[back] = GetColor(xobj->backcolor);
    xobj->TabColor[hili] = GetColor(xobj->hilicolor);
    xobj->TabColor[shad] = GetColor(xobj->shadcolor);
  }

  mask = 0;
  Attr.background_pixel = xobj->TabColor[back];
  mask |= CWBackPixel;
  Attr.cursor = XCreateFontCursor(dpy,XC_hand2);
  mask |= CWCursor;  /* Curseur pour la fenetre / Window cursor */
  xobj->win = XCreateWindow(dpy, *xobj->ParentWin,
			  xobj->x, xobj->y, xobj->width, xobj->height, 0,
			  CopyFromParent, InputOutput, CopyFromParent,
			  mask, &Attr);

  xobj->gc = fvwmlib_XCreateGC(dpy, xobj->win, 0, NULL);
  XSetForeground(dpy, xobj->gc, xobj->TabColor[fore]);
  XSetLineAttributes(dpy, xobj->gc, 1, LineSolid, CapRound, JoinMiter);

  if ((xobj->Ffont = FlocaleLoadFont(dpy, xobj->font, ScriptName)) == NULL)
  {
    fprintf(stderr, "%s: Couldn't load font. Exiting!\n", ScriptName);
    exit(1);
  }
  if (xobj->Ffont->font != NULL)
    XSetFont(dpy, xobj->gc, xobj->Ffont->font->fid);

  /* Calcul de la taille du widget *
   * Taille minimum: une ligne ou ascenseur visible */
  /* Computation of the size of the widget *
   * min size: one line or a visible elevator */
  minh = 8 + 3*BdWidth + 3*(xobj->Ffont->height + 3);
  if (xobj->height<minh)
  {
    xobj->height = minh;
    resize = 1;
  }
  minw = 12 + 3*BdWidth +SbWidth +75;
  if (xobj->width<minw)
  {
    xobj->width = minw;
    resize = 1;
  }
  if (resize)
    XResizeWindow(dpy, xobj->win, xobj->width, xobj->height);
  if (xobj->colorset >= 0)
    SetWindowBackground(dpy, xobj->win, xobj->width, xobj->height,
			&Colorset[xobj->colorset], Pdepth,
			xobj->gc, True);

  /* Calcul de la premiere cellule visible */
  /* Computation of the first visible cell */
  NbVisCell = (xobj->height - 2 - 3*BdWidth) / (xobj->Ffont->height + 3);
  NbCell = CountOption(xobj->title);
  if (NbCell > NbVisCell)
  {
    if (xobj->value2 > (NbCell - NbVisCell + 1))
      xobj->value2 = NbCell - NbVisCell + 1;
    if ((xobj->value2 < 1) || (xobj->value2 < 0))
      xobj->value2 = 1;
  }
  else
    xobj->value2 = 1;
  XSelectInput(dpy, xobj->win, ExposureMask);
}

void DrawVSbList(struct XObj *xobj, int NbCell, int NbVisCell, int press)
{
  XRectangle r;
  int PosTh,SizeTh;

  r.y = 2+BdWidth;
  r.x = xobj->width - (6+BdWidth) -SbWidth;
  r.height = xobj->height - r.y - 2*BdWidth;
  r.width = SbWidth + 4;
  DrawReliefRect(r.x, r.y, r.width, r.height, xobj, shad, hili);

  /* Calcul du rectangle pour les fleches *
   * Compute the rectangle for the arrows */
  r.x = r.x + 2;
  r.y = r.y + 2;
  r.width = r.width - 4;
  r.height = r.height - 4;

  /* Dessin de la fleche haute / Draw the up arrow */
  DrawArrowN(xobj, r.x + 1, r.y + 1, press==1);
  DrawArrowS(xobj, r.x + 1, r.y + r.height - 14, press==2);

  /* Calcul du rectangle pour le pouce*/
  r.y = r.y + 13;
  r.height = r.height - 26;

  /* Effacement */
  XClearArea(dpy, xobj->win, r.x, r.y+1, r.width, r.height-2, False);

  /* Dessin du pouce */
  if (NbVisCell < NbCell)
    SizeTh = (NbVisCell * (r.height-8) / NbCell) + 8;
 else
   SizeTh = r.height;
  PosTh = (xobj->value2 - 1) * (r.height - 8) / NbCell;
  DrawReliefRect(r.x, r.y + PosTh, r.width, SizeTh, xobj, hili, shad);
}

void DrawCellule(
	struct XObj *xobj, int NbCell, int NbVisCell, int HeightCell,
	int asc, XEvent *evp)
{
  XRectangle r,inter;
  char *Title;
  int i;
  int do_draw = True;

  /* text clipping */
  r.x = 4 + BdWidth + 4;
  r.y = 4 + BdWidth;
  r.width =  xobj->width - 16 - SbWidth - BdWidth - 6;
  r.height = xobj->height - r.y - 4 - 2*BdWidth;

  for (i = xobj->value2; i < xobj->value2 + NbVisCell; i++)
  {
	  Title = (char*)GetMenuTitle(xobj->title, i);
	  do_draw = True;
	  if (evp)
	  {
		  if (!frect_get_intersection(
			  r.x - 2, r.y + (i - xobj->value2)*HeightCell + 2,
			  r.width + 4, HeightCell-2,
			  evp->xexpose.x, evp->xexpose.y,
			  evp->xexpose.width, evp->xexpose.height,
			  &inter))
		  {
			  do_draw = False;
		  }
	  }
	  else
	  {
		  inter.x = r.x - 2; /* r.x */
		  inter.y = r.y + (i-xobj->value2)*HeightCell + 2;
		  inter.width = r.width + 4;
		  inter.height = HeightCell-2;
	  }
	  if (!do_draw)
	  {
		  continue;
	  }
	  if (strlen(Title)!=0)
	  {
		  int x = GetXTextPosition(
			  xobj, r.width,
			  FlocaleTextWidth(xobj->Ffont,Title,strlen(Title)),
			  r.x, 0, -r.x);
		  int y = (i - xobj->value2) * HeightCell + asc + 2 + r.y;

		  if (xobj->value == i)
		  {
			  /* hili is better than shad.*/
			  XSetForeground(dpy, xobj->gc, xobj->TabColor[hili]);
			  XFillRectangle(
				  dpy, xobj->win, xobj->gc,
				  inter.x, inter.y, inter.width, inter.height);
			  MyDrawString(
				  dpy, xobj, xobj->win, x, y, Title, fore, back,
				  shad, !xobj->flags[1], &r, evp);
		  }
		  else
		  {
			  XClearArea(
				  dpy, xobj->win,
				  inter.x, inter.y, inter.width, inter.height,
				  False);
			  MyDrawString(
				  dpy, xobj, xobj->win, x, y, Title, fore, hili,
				  back, !xobj->flags[1], &r, evp);
		  }
	  }
	  else
	  {
		  XClearArea(
			  dpy, xobj->win,
			  inter.x, inter.y, inter.width, inter.height,
			  False);
	  }
	  if (Title != NULL)
		  free(Title);
  }
}

void DestroyList(struct XObj *xobj)
{
  XFreeGC(dpy, xobj->gc);
  XDestroyWindow(dpy, xobj->win);
}

void DrawList(struct XObj *xobj, XEvent *evp)
{
  int NbVisCell,NbCell;
  int HeightCell;
  XRectangle r;

  /* Dessin du contour / */
  DrawReliefRect(0, 0, xobj->width, xobj->height, xobj, hili, shad);

  /* Dessin du contour de la liste */
  r.x = 2 + BdWidth;
  r.y = r.x;
  r.width = xobj->width - r.x - 4 - 2*BdWidth - SbWidth;
  r.height = xobj->height - r.y - 2*BdWidth;
  DrawReliefRect(r.x, r.y, r.width, r.height, xobj, shad, hili);

  /* Calcul du nombre de cellules visibles */
  HeightCell = xobj->Ffont->height + 3;
  NbVisCell = r.height/HeightCell;
  NbCell = CountOption(xobj->title);
  if (NbCell > NbVisCell)
  {
    if (xobj->value2 > (NbCell - NbVisCell + 1))
      xobj->value2 = NbCell - NbVisCell + 1;
    if ((xobj->value2 < 1) || (xobj->value2 < 0))
      xobj->value2 = 1;
  }
  else
    xobj->value2 = 1;


  /* Dessin des cellules */
  DrawCellule(
	  xobj, NbCell, NbVisCell, HeightCell,
	  /*FlocaleGetMinOffset(xobj->Ffont, ROTATION_0)*/
	  xobj->Ffont->ascent,
	  evp);

  /* Dessin de l'ascenseur vertical */
  DrawVSbList(xobj, NbCell, NbVisCell, 0);

}

void EvtMouseList(struct XObj *xobj, XButtonEvent *EvtButton)
{
  XRectangle rect,rectT;
  XPoint pt;
  int x1,y1,x2,y2;
  Window Win1,Win2;
  unsigned int modif;
  int In = 1;
  static XEvent event;
  int NbVisCell,NbCell,HeightCell,NPosCell,PosMouse;
  fd_set in_fdset;

  pt.x = EvtButton->x-xobj->x;
  pt.y = EvtButton->y-xobj->y;

  HeightCell = xobj->Ffont->height + 3;
  NbVisCell = (xobj->height-6-BdWidth)/HeightCell;
  NbCell = CountOption(xobj->title);

  /* Clic dans une cellule */
  rect.x = 4 + BdWidth;
  rect.y = rect.x;
  rect.width = xobj->width - rect.x - 10 - 2*BdWidth - SbWidth;
  rect.height = xobj->height -rect.y - 4 - 2*BdWidth;
  if(PtInRect(pt,rect))
  {
    /* Determination de la cellule */
    pt.y = pt.y - rect.y;
    NPosCell = xobj->value2 + (pt.y/(xobj->Ffont->height+3));
    if (NPosCell > CountOption(xobj->title))
      NPosCell = 0;
    else if (NPosCell >= xobj->value2 + NbVisCell)
    {
      NPosCell--;
    }
    if (NPosCell != xobj->value)
    {
      xobj->value = NPosCell;
      DrawList(xobj,NULL);
    }
    SendMsg(xobj, SingleClic);
    return ;
  }

  /* Clic fleche haute asc vertical */
  rect.y = 5 + BdWidth;
  rect.x = xobj->width - (6+BdWidth) - SbWidth+3;
  rect.height = 12;
  rect.width = 12;
  if(PtInRect(pt,rect))
  {
    DrawVSbList(xobj, NbCell, NbVisCell, 1);
    do
    {
      FQueryPointer(dpy, *xobj->ParentWin, &Win1, &Win2,
		    &x1, &y1, &x2, &y2, &modif);
      pt.y = y2- xobj->y;
      pt.x = x2- xobj->x;
      if (PtInRect(pt,rect))
      {
	if (In)
	{
	  Wait(8);
	  xobj->value2--;
	  if (xobj->value2 < 1)
	    xobj->value2 = 1;
	  else
	  {
	    DrawCellule(xobj, NbCell, NbVisCell, HeightCell,
			xobj->Ffont->ascent, NULL);
	    DrawVSbList(xobj, NbCell, NbVisCell, 1);
	  }
	}
	else
	{
	  In = 1;
	  DrawVSbList(xobj, NbCell, NbVisCell, 1);
	  xobj->value2--;
	  if (xobj->value2 < 1)
	    xobj->value2 = 1;
	  else
	    DrawCellule(xobj, NbCell, NbVisCell, HeightCell,
			xobj->Ffont->ascent, NULL);
	}
      }
      else
      {
	if (In)
	{
	  In = 0;
	  DrawVSbList(xobj, NbCell, NbVisCell, 0);
	}
      }
      FD_ZERO(&in_fdset);
      FD_SET(x_fd, &in_fdset);
      select(32, SELECT_FD_SET_CAST &in_fdset, NULL, NULL, NULL);
    }
    while (!FCheckTypedEvent(dpy, ButtonRelease, &event));
    DrawVSbList(xobj, NbCell, NbVisCell, 0);
    return;
  }

  /* Clic flache basse asc vertical */
  rect.y = xobj->height - 2*BdWidth -16;
  if(PtInRect(pt,rect))
  {
    DrawVSbList(xobj, NbCell, NbVisCell, 2);
    do
    {
      FQueryPointer(dpy, *xobj->ParentWin, &Win1, &Win2,
		    &x1, &y1, &x2, &y2, &modif);
      pt.y = y2 - xobj->y;
      pt.x = x2 - xobj->x;
      if (PtInRect(pt, rect))
      {
	if (In)
	{
	  Wait(8);
	  if (xobj->value2 <= NbCell-NbVisCell)
	  {
	    xobj->value2++;
	    DrawCellule(xobj, NbCell, NbVisCell, HeightCell,
			xobj->Ffont->ascent, NULL);
	    DrawVSbList(xobj, NbCell, NbVisCell, 2);
	  }
	}
	else
	{
	  In = 1;
	  DrawVSbList(xobj, NbCell, NbVisCell, 2);
	  if (xobj->value2 <= NbCell-NbVisCell)
	  {
	    xobj->value2++;
	    DrawCellule(xobj, NbCell, NbVisCell, HeightCell,
			xobj->Ffont->ascent, NULL);
	  }
	}
      }
      else
      {
	if (In)
	{
	  In = 0;
	  DrawVSbList(xobj, NbCell, NbVisCell, 0);
	}
      }
      FD_ZERO(&in_fdset);
      FD_SET(x_fd, &in_fdset);
      select(32, SELECT_FD_SET_CAST &in_fdset, NULL, NULL, NULL);
    }
    while (!FCheckTypedEvent(dpy, ButtonRelease, &event));
    DrawVSbList(xobj, NbCell, NbVisCell, 0);
    return;
  }

  /* clic sur la zone pouce de l'ascenseur de l'ascenseur */
  rect.y = 17 + BdWidth;
  rect.x = xobj->width - (6+BdWidth) - SbWidth + 2;
  rect.height = xobj->height - rect.y - 19 - 2*BdWidth;
  rect.width = SbWidth;
  if(PtInRect(pt,rect))
  {
    /* Clic dans le pouce */
    rectT.x = rect.x;
    rectT.y = rect.y + (xobj->value2 - 1) * (rect.height - 8) / NbCell;
    if (NbVisCell<NbCell)
      rectT.height = NbVisCell * (rect.height-8) / NbCell+8;
    else
      rectT.height = rect.height;
    rectT.width = rect.width;
    if(PtInRect(pt,rectT))
    {
      PosMouse = pt.y - rectT.y - HeightCell / 2 + 2;
      do
      {
	FQueryPointer(dpy, *xobj->ParentWin, &Win1, &Win2,
		      &x1, &y1, &x2, &y2, &modif);
	/* Calcul de l'id de la premiere cellule */
	pt.y = y2-xobj->y - PosMouse;
	NPosCell = (pt.y - rect.y)*NbCell / (rect.height);

	if (NPosCell < 1) NPosCell = 1;
	if (NbCell > NbVisCell)
	{
	  if (NPosCell > (NbCell - NbVisCell + 1))
	    NPosCell = NbCell - NbVisCell + 1;
	}
	else
	  NPosCell = 1;
	if (xobj->value2 != NPosCell)
	{
	  xobj->value2 = NPosCell;
	  DrawCellule(
		  xobj, NbCell, NbVisCell, HeightCell, xobj->Ffont->ascent,
		  NULL);
	  DrawVSbList(xobj, NbCell, NbVisCell, 0);
	}
	FD_ZERO(&in_fdset);
	FD_SET(x_fd, &in_fdset);
	select(32, SELECT_FD_SET_CAST &in_fdset, NULL, NULL, NULL);
      }
      while (!FCheckTypedEvent(dpy, ButtonRelease, &event));
    }
    else if (pt.y < rectT.y)
    {
      NPosCell = xobj->value2 - NbVisCell;
      if (NPosCell < 1)
	NPosCell = 1;
      if (xobj->value2 != NPosCell)
      {
	xobj->value2 = NPosCell;
	DrawCellule(
		xobj, NbCell, NbVisCell, HeightCell, xobj->Ffont->ascent, NULL);
	DrawVSbList(xobj, NbCell, NbVisCell, 0);
      }
    }
    else if (pt.y > rectT.y + rectT.height)
    {
      NPosCell = xobj->value2+NbVisCell;
      if (NbCell>NbVisCell)
      {
	if (NPosCell > (NbCell - NbVisCell + 1))
	  NPosCell = NbCell - NbVisCell + 1;
      }
      else
	NPosCell = 1;
      if (xobj->value2 != NPosCell)
      {
	xobj->value2 = NPosCell;
	DrawCellule(
		xobj, NbCell, NbVisCell, HeightCell, xobj->Ffont->ascent, NULL);
	DrawVSbList(xobj, NbCell, NbVisCell, 0);
      }
    }
  }
}

void EvtKeyList(struct XObj *xobj, XKeyEvent *EvtKey)
{
  KeySym ks;
  unsigned char buf[10];
  int NbVisCell,NbCell,HeightCell,NPosCell;
  Window Win1,Win2;
  int x1,y1,x2,y2;
  unsigned int modif;
  XRectangle rect;
  XPoint pt;

  HeightCell = xobj->Ffont->height + 3;
  NbVisCell = (xobj->height - 6 - BdWidth) / HeightCell;
  NbCell = CountOption(xobj->title);
  FQueryPointer(dpy, xobj->win, &Win1, &Win2, &x1, &y1, &x2, &y2, &modif);
  pt.x = x2;
  pt.y = y2;
  rect.x = 4 + BdWidth;
  rect.y = rect.x;
  rect.width = xobj->width - rect.x -10 - 2*BdWidth - SbWidth;
  rect.height= xobj->height - rect.y - 4 - 2*BdWidth;

  /* Recherche du charactere */
  XLookupString(EvtKey, (char *)buf, sizeof(buf), &ks, NULL);

  if (ks == XK_Return)
  {
    if(PtInRect(pt,rect))
    {
      /* Determination de la cellule */
      pt.y =  pt.y - rect.y;
      NPosCell = xobj->value2 + (pt.y/(xobj->Ffont->height + 3));
      if (NPosCell > CountOption(xobj->title))
	NPosCell = 0;
      else if (NPosCell >= xobj->value2 + NbVisCell)
      {
	NPosCell--;
      }
      if (NPosCell != xobj->value)
      {
	xobj->value = NPosCell;
	DrawList(xobj,NULL);
      }
      SendMsg(xobj, SingleClic);
    }
  }
  else if (ks == XK_Up)
  {
    if (xobj->value2 == 1)
    {
      if(PtInRect(pt,rect))
      {
	/* Determination de la cellule */
	pt.y= pt.y - rect.y;
	NPosCell = xobj->value2+(pt.y/(xobj->Ffont->height + 3));
	if (NPosCell > CountOption(xobj->title))
	  NPosCell = 0;
	if (NPosCell > 1)
	{
	  FWarpPointer(dpy, None, None, 0, 0, 0, 0, 0, -HeightCell);
	}
      }
    }
    else
    {
      xobj->value2--;
      DrawCellule(
	      xobj, NbCell, NbVisCell, HeightCell, xobj->Ffont->ascent, NULL);
      DrawVSbList(xobj, NbCell, NbVisCell, 0);
    }
  }
  else if (ks == XK_Down)
  {
    if (xobj->value2 > NbCell-NbVisCell)
    {
      if(PtInRect(pt,rect))
      {
	/* Determination de la cellule */
	pt.y =  pt.y - rect.y;
	NPosCell =  xobj->value2 + (pt.y/(xobj->Ffont->height + 3));
	if (NPosCell > CountOption(xobj->title))
	  NPosCell = 0;
	if (NPosCell < NbCell && NPosCell > 0)
	{
	  FWarpPointer(dpy, None, None, 0, 0, 0, 0, 0, HeightCell);
	}
      }
    }
    else
    {
      xobj->value2++;
      DrawCellule(
	      xobj, NbCell, NbVisCell, HeightCell, xobj->Ffont->ascent, NULL);
      DrawVSbList(xobj, NbCell, NbVisCell, 0);
    }
  }
  else if (ks == XK_Prior && xobj->value2 > 1)
  {
    xobj->value2 = xobj->value2 - NbVisCell;
    if (xobj->value2 < 1)
      xobj->value2 = 1;
    DrawCellule(
	    xobj, NbCell, NbVisCell, HeightCell, xobj->Ffont->ascent, NULL);
    DrawVSbList(xobj, NbCell, NbVisCell, 0);
  }
  else if (ks == XK_Next && xobj->value2 <= NbCell-NbVisCell)
  {
    xobj->value2 = xobj->value2 + NbVisCell;
    if (xobj->value2 > NbCell - NbVisCell + 1)
      xobj->value2 = NbCell - NbVisCell + 1;
    DrawCellule(
	    xobj, NbCell, NbVisCell, HeightCell, xobj->Ffont->ascent, NULL);
    DrawVSbList(xobj, NbCell, NbVisCell, 0);
  }
  else if (ks == XK_Home)
  {
    if (xobj->value2 > 1)
    {
      xobj->value2 = 1;
      DrawCellule(
	      xobj, NbCell, NbVisCell, HeightCell, xobj->Ffont->ascent, NULL);
      DrawVSbList(xobj, NbCell, NbVisCell, 0);
    }
  }
  else if (ks == XK_End)
  {
    if (xobj->value2 < NbCell - NbVisCell + 1)
    {
      xobj->value2 = NbCell - NbVisCell + 1;
      DrawCellule(
	      xobj, NbCell, NbVisCell, HeightCell, xobj->Ffont->ascent, NULL);
      DrawVSbList(xobj, NbCell, NbVisCell, 0);
    }
  }
}


void ProcessMsgList(struct XObj *xobj, unsigned long type, unsigned long *body)
{
}
