/*
 * cstacka.c - An area which displays a cstack.
 */

#include <stdlib.h>

#include "fc.h"
#include "area.h"
#include "err.h"

#include "card.h"
#include "cstack.h"
#include "cstacka.h"
#include "ticker.h"

/* ---------- Method declarations ---------- */
void cstacka_term(struct area *);
int cstacka_mouse(struct area *, XButtonEvent *);
int cstacka_draw(struct area *, Region);
int cstacka_resize(struct area *, XConfigureEvent *);
int cstacka_key(struct area *, XKeyEvent *);
int cstacka_activate(struct area *, XMapEvent *);
int cstacka_deactivate(struct area *, XUnmapEvent *);

/* ---------- Ops structure ---------- */
struct area_ops cstacka_ops = {
     cstacka_term,
     cstacka_mouse,
     cstacka_draw,
     cstacka_resize,
     cstacka_key,
     cstacka_activate,
     cstacka_deactivate
};

/* ---------------------------------------------------------------------- */
struct area *
cstacka_create(struct cstack *csp, struct aop *aop)
{
     struct area *ret;
     struct cstacka_data *csdp;

     aop->aops = &cstacka_ops;

     ret = area_create(aop, sizeof(struct cstacka_data));
     if (!ret) return ret;
     
     csdp = ret->data;
     csdp->csp = csp;

     cstack_setarea(csp, ret);

     return ret;
}

/* ---------------------------------------------------------------------- */
void cstacka_term(struct area *ap)
{
     struct cstacka_data *csdp = ap->data;

     if (csdp->csp) cstack_destroy(csdp->csp, TRUE);
}

/* ---------------------------------------------------------------------- */
int cstacka_mouse(struct area *ap, XButtonEvent *xevp)
{
     struct cstacka_data *csdp = ap->data;
     struct cstack *csp = csdp->csp;
     
     /* Ignore button up events for now. */
     if (xevp->type == ButtonRelease) return(0);

     if (cstack_getnumcards(csp) > 0) {
	  cstacka_setinvert(ap, !cstack_getinvert(csp));
     }

     return(0);
}

/* ---------------------------------------------------------------------- */
int
cstacka_setinvert(struct area *ap, int invert)
{
     struct cstacka_data *csdp = ap->data;
     struct cstack *csp = csdp->csp;
     XRectangle trect;

     if (invert) ap->click_ticks = get_tick_count();
     cstacka_getcardrect(ap, cstack_getnumcards(csp) - 1,
			 TRUE, &trect);
     clear_rect(dpy, ap->owner, &trect, TRUE);
     return(0);
}

/* ---------------------------------------------------------------------- */
int cstacka_draw(struct area *ap, Region rgn)
{
     struct cstacka_data *csdp = ap->data;
     struct cstack *csp;
     XRectangle trect;
     int i, doneone = FALSE;

     if (!csdp->csp) return(0);

     csp = csdp->csp;

     for (i = 0; i < cstack_getnumcards(csp); i++) {
	  cstacka_getcardrect(ap, i, TRUE, &trect);
	  if (rect_in_rgn(&trect, rgn) || doneone) {
	       cstack_draw_card(csdp->csp, ap->owner, 
				i, trect.x, trect.y);
	       doneone = TRUE;
	  }
     }

     return(0);
}

/* ---------------------------------------------------------------------- */
int cstacka_resize(struct area *ap, XConfigureEvent *xevp)
{
     return(0);
}

/* ---------------------------------------------------------------------- */
int cstacka_key(struct area *ap, XKeyEvent *xevp)
{
     return(0);
}

/* ---------------------------------------------------------------------- */
int cstacka_activate(struct area *ap, XMapEvent *xevp)
{
     return(0);
}

/* ---------------------------------------------------------------------- */
int cstacka_deactivate(struct area *ap, XUnmapEvent *xevp)
{
     return(0);
}

/* ---------------------------------------------------------------------- */
int
cstacka_getcardrect(struct area *ap, int cardnum, int clipped,  
		    XRectangle *rectp)  
{
     struct cstacka_data *csdp = ap->data;
     struct cstack *csp = csdp->csp;

     *rectp = ap->bounds;
     if (cardnum >= cstack_getnumcards(csp)) {
	  rectp->x = rectp->y = rectp->width =
	       rectp->height = 0;
	  return(0);
     }

     rectp->y += CSTACK_DRAW_SPACE * cardnum;
     if (clipped && cardnum < cstack_getnumcards(csp) - 1) {
	  rectp->height = CSTACK_DRAW_SPACE + ROUND_H;
     }
     else {
	  rectp->height = CARD_HEIGHT;
     }
     rectp->height++;
     rectp->width++;

     return(0);
}

/* ---------------------------------------------------------------------- */
struct cstack *
cstacka_getcstack(struct area *ap)
{
     return(((struct cstacka_data *)ap->data)->csp);
}

/* ---------------------------------------------------------------------- */
int
cstacka_findcard(struct area *ap, int x, int y)
{
     struct cstacka_data *csdp = ap->data;
     struct cstack *csp;
     int diff, cardnum;

     if (!area_containspoint(ap, x, y)) return(-1);

     diff = y - ap->bounds.y;
     if (diff < 0) return(-1);

     csp = csdp->csp;
     cardnum = diff / CSTACK_DRAW_SPACE;
     
     if (cardnum > cstack_getnumcards(csp)) {
	  if (y > ((cstack_getnumcards(csp) - 1) * CSTACK_DRAW_SPACE + 
		   ap->bounds.y + CARD_HEIGHT)) {
	       return(-1);
	  }
	  else {
	       return(cstack_getnumcards(csp) - 1);
	  }
     }
     return(cardnum);
}
