/*
 * cstack.c - A stack where all cards are seen.
 */

#include <stdlib.h>

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

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

/* ---------- Macros ---------- */
#define CSTACK_INITSIZE 5
#define CSTACK_STEPSIZE 5

/* ---------------------------------------------------------------------- */
struct cstack *
cstack_create()
{
     struct cstack *ret;
     struct card **cardpp;

     ret = calloc(sizeof(*ret), 1);
     if (ret == NULL) return NULL;
     
     cardpp = calloc(sizeof(*cardpp), CSTACK_INITSIZE);
     if (cardpp == NULL) {
	  free(ret);
	  return NULL;
     }
     ret->ap = NULL;
     ret->cardpp = cardpp;
     ret->num_cards = 0;
     ret->max_cards = CSTACK_INITSIZE;
     ret->invert = FALSE;

     return(ret);
}

/* ---------------------------------------------------------------------- */
int
cstack_addcard(struct cstack *csp, struct card *cdp)
{
     XRectangle trect;
     int max_cards;
     struct card **cardpp;

     if (csp->num_cards == csp->max_cards) {
	  max_cards = csp->max_cards + CSTACK_STEPSIZE;
	  cardpp = realloc(csp->cardpp, sizeof(*cardpp) * max_cards);
	  if (cardpp == NULL) return(ERR_NOMEM);
	  csp->max_cards = max_cards;
	  csp->cardpp = cardpp;
     }

     csp->cardpp[csp->num_cards] = cdp;
     csp->num_cards++;

     if (csp->ap) {
	  cstacka_getcardrect(csp->ap, csp->num_cards - 1, FALSE, &trect);
	  area_clearrect(csp->ap, &trect, TRUE);
     }

     return(0);
}

/* ---------------------------------------------------------------------- */
void
cstack_draw(struct cstack *csp, struct wind *windp, int x, int y)
{
     int curr_y, i;
     
     curr_y = y;
     for (i = 0; i < csp->num_cards; i++) {
	  card_draw(csp->cardpp[i], windp, x, curr_y);
	  curr_y += CSTACK_DRAW_SPACE;
     }
}

/* ---------------------------------------------------------------------- */
void
cstack_draw_card(struct cstack *csp, struct wind *windp, 
		 int cardnum, int x, int y)
{
     card_draw(csp->cardpp[cardnum], windp, x, y);
}

/* ---------------------------------------------------------------------- */
void
cstack_destroy(struct cstack *csp, int everything)
{
     int i;

     if (everything) {
	  for (i = 0; i < csp->num_cards; i++) {
	       card_destroy(csp->cardpp[i]);
	  }
     }
     free(csp->cardpp);
     free(csp);
}

/* ---------------------------------------------------------------------- */
int
cstack_setinvert(struct cstack *csp, int invert)
{
     /* If status is same, then do nothing. */
     if (invert == csp->invert) return(invert);
     
     card_setinvert(csp->cardpp[csp->num_cards - 1], invert);
     csp->invert = invert;

     if (csp->ap) cstacka_setinvert(csp->ap, invert);

     return(!invert);
}

/* ---------------------------------------------------------------------- */
int
cstack_getinvert(struct cstack *csp)
{
     return(csp->invert);
}

/* ---------------------------------------------------------------------- */
void 
cstack_makeempty(struct cstack *csp, int free_cards)
{
     int i;

     if (free_cards) {
	  for (i = 0; i < csp->num_cards; i++) {
	       card_destroy(csp->cardpp[i]);
	  }
     }
     csp->num_cards = 0;
     if (csp->ap) area_clear(csp->ap);
}

/* ------------------------------------------------------------------------ */
int
cstack_getnumcards(struct cstack *csp)
{
     return(csp->num_cards);
}

/* ---------------------------------------------------------------------- */
int 
cstack_isempty(struct cstack *csp)
{
     return(csp->num_cards == 0);
}

/* ---------------------------------------------------------------------- */
struct card *
cstack_removecard(struct cstack *csp)
{
     struct card *cdp;
     XRectangle trect;

     if (csp->ap) {
	  cstacka_getcardrect(csp->ap, csp->num_cards - 1, FALSE, &trect);
	  area_clearrect(csp->ap, &trect, TRUE);
     }
     cdp = csp->cardpp[csp->num_cards - 1];
     csp->num_cards--;
     return(cdp);
}

/* ---------------------------------------------------------------------- */
struct card *
cstack_bottomcard(struct cstack *csp)
{
     if (csp->num_cards == 0) return(NULL);
     
     return(csp->cardpp[csp->num_cards - 1]);
}

/* ---------------------------------------------------------------------- */
int
cstack_join(struct cstack *csp, struct cstack *other)
{
     struct card *cdp;
     int i;

     for (i = 0; i < cstack_getnumcards(other); i++) {
	  cdp = cstack_getcard(other, i);
	  cstack_addcard(csp, cdp);
     }
     cstack_destroy(other, FALSE);

     return(0);
}

/* ---------------------------------------------------------------------- */
struct cstack *
cstack_split(struct cstack *csp, int split)
{
     struct cstack *other;
     int i;

     other = cstack_create();
     if (other == NULL) return NULL;
     
     for (i = split; i < csp->num_cards; i++) {
	  cstack_addcard(other, csp->cardpp[i]);
     }
     for (i = csp->num_cards - 1; i >= split; i--) {
	  cstack_removecard(csp);
     }
     return(other);
}

/* ---------------------------------------------------------------------- */
struct card *
cstack_getcard(struct cstack *csp, int n)
{
     if (n >= csp->num_cards) return NULL;
     return(csp->cardpp[n]);
}

