// -*- mode:C++; tab-width:2; c-basic-offset:2; indent-tabs-mode:nil -*-
/* Blackjack - chips.cpp
 * Copyright (C) 2003 William Jon McCann <mccann@jhu.edu>
 *
 * This game 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, 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 <stdlib.h>
#include <math.h>

#include "blackjack.h"
#include "chips.h"
#include "draw.h"

GdkPixbuf *chip_pixbuf[4];
GList *chip_stack_list = NULL;

gint
bj_chip_get_width ()
{
  // assume they are all the same size
  return gdk_pixbuf_get_width (bj_chip_get_pixbuf (0));
}

gint
bj_chip_get_id (gfloat value)
{
  gint id;

  if (value == 100)
    id = CHIP_100;
  else if (value == 25)
    id = CHIP_25;
  else if (value == 5)
    id = CHIP_5;
  else if (value == 1)
    id = CHIP_1;
  else
    id = -1;

  return id;
}

GdkPixbuf*
bj_chip_get_pixbuf (gint chip)
{
  if (chip < 0 || chip > 3)
    return NULL;
  return chip_pixbuf[chip];
}

gdouble
bj_chip_get_value (gint chip)
{
  gdouble value;

  switch (chip)
    {
    case CHIP_100: value = 100.0; break;
    case CHIP_25: value = 25.0; break;
    case CHIP_5: value = 5.0; break;
    case CHIP_1: value = 1.0; break;
    default: value = 0;
    }
  return value;
}

void
bj_chip_stack_decompose_value (gfloat value, gint *blacks, 
                               gint *greens, gint *reds, gint *whites)
{
  gfloat remainder = value;
  *blacks = (gint) remainder / 100;
  remainder -= (*blacks * 100);
  *greens = (gint) remainder / 25;
  remainder -= (*greens * 25);
  *reds = (gint) remainder / 5;
  remainder -= (*reds * 5);
  *whites = (gint) remainder / 1;
}

gfloat
bj_chip_stack_get_chips_value (GList *chips)
{
  gfloat value = 0;
  for (GList *tmptr=chips; tmptr; tmptr=tmptr->next)
    {
      value += ((hchip_type)tmptr->data)->value;
    }
  return value;
}

void 
bj_chip_stack_add (gint id, gint x, gint y)
{
  hstack_type hstack = (hstack_type) g_malloc (sizeof (chip_stack_type));

  hstack->id = id;
  hstack->chips = NULL;
  hstack->x = x;
  hstack->y = y;

  hstack->dx = hstack->dy = 0;
  hstack->expansion_depth = 0;

  //hstack->dx = x_expanded_offset;
  hstack->dy = bj_chip_get_width () / 5;
    
  hstack->length = hstack->exposed = 0;
  bj_chip_stack_update_length (hstack);

  chip_stack_list = g_list_append (chip_stack_list, hstack);
}

hchip_type 
bj_chip_new (float value)
{
  hchip_type temp_chip = (hchip_type) g_malloc (sizeof (chip_type));

  temp_chip->value = value;

  return temp_chip;
}

void 
bj_chip_stack_pressed (gint x, gint y, hstack_type *stack, gint *chipid) 
{
  GList *tempptr;

  gint num_chips;
  gboolean got_stack = FALSE;

  *stack = NULL;
  *chipid = -1;

  gint chip_height = bj_chip_get_width ();
  for (tempptr = g_list_last (chip_stack_list); tempptr; tempptr = tempptr->prev)
    {

      hstack_type hstack = (hstack_type) tempptr->data;
      gint bottom_chip_edge = hstack->y + chip_height;
      gint top_chip_edge = bottom_chip_edge - hstack->height;
      /* if point is within our rectangle */
      if (hstack->x < x && x < hstack->x + hstack->width 
          && bottom_chip_edge > y && y > top_chip_edge) 
      {
        num_chips = hstack->length;
        
        if ( got_stack == FALSE || num_chips > 0 )
          {  
            // loop through chips top down (cascade)
            // check if click is within chip radius
            gint x_center, y_center;
            x_center = hstack->x + chip_height / 2;
            gfloat radius, x_diff, y_diff;
            for (gint chip_i = num_chips-1; chip_i >= 0; chip_i--)
              {
                y_center = hstack->y + chip_height / 2 - chip_i * hstack->dy;
                y_diff = ABS ((y - y_center));
                x_diff = ABS ((x - x_center));
                radius = sqrt (x_diff * x_diff + y_diff * y_diff);
                if (radius < chip_height / 2)
                  {
                    *chipid = chip_i;
                    break;
                  }
              }

            *stack = hstack;

            /* this is the topmost stack with a chip */
            /* take it and run*/
            if ( num_chips > 0 )
              break;
            
            got_stack = TRUE;
          }
      }
  }
}

void 
bj_chip_stack_update_length (hstack_type hstack)
{
  gint delta = g_list_length (hstack->chips) - hstack->length;

  hstack->length += delta;
  hstack->exposed += delta;

  if ((hstack->dx == 0 && hstack->dy == 0 && hstack->exposed > 1) 
      || (hstack->length > 0 && hstack->exposed < 1))
    hstack->exposed = 1;

  delta = hstack->exposed ? hstack->exposed - 1 : 0;
  
  hstack->width = bj_chip_get_width () + delta * hstack->dx;
  hstack->height = bj_chip_get_width () + delta * hstack->dy;
}

GList* 
bj_chip_stack_get_list ()
{
  return chip_stack_list;
}

void
bj_chip_stack_add_chips (GList* newchips, hstack_type hstack)
{
  hstack->chips = g_list_concat (hstack->chips, newchips);
  bj_chip_stack_update_length (hstack);
}

void
bj_chip_stack_delete (hstack_type hstack) 
{
  GList* temptr;
  
  for (temptr = hstack->chips; temptr; temptr = temptr->next)
    g_free (temptr->data);
  g_list_free (hstack->chips);
  free (hstack);
}

void
bj_chip_stack_delete_all (void)
{
  GList* temptr;
  
  for (temptr = chip_stack_list; temptr; temptr = temptr->next)
    {
      bj_chip_stack_delete ((hstack_type)temptr->data);
      temptr->data = NULL;
    }
  g_list_free (chip_stack_list);
  chip_stack_list = NULL;
}

void
bj_chip_stack_delete_all_wagers (void)
{
  bj_chip_stack_delete_all ();
  bj_chip_stack_create_sources ();
}

void
bj_chip_stack_create_sources (void)
{
  gint x = CHIP_X_ORIGIN;
  gint y = CHIP_Y_ORIGIN;
  gint x_offset = 0;
  for (int i=0; i < 4; i++)
    {
      bj_chip_stack_new_source_with_value (bj_chip_get_value (i),
                                           x + x_offset, y);
      x_offset += bj_chip_get_width () + 5;
    }
}

void
bj_chip_stack_new_with_id_value (gint id, gfloat value, gint x, gint y)
{
  bj_chip_stack_add (id, x, y);
  GList *chiplist = NULL;

  gint blacks, greens, reds, whites;
  bj_chip_stack_decompose_value (value, &blacks, 
                                 &greens, &reds, &whites);

  // Put higher value chips on bottom
  for (int i=0; i < blacks; i++)
    {
      hchip_type newchip = bj_chip_new (100.0);
      chiplist = g_list_append (chiplist, newchip);
    }
  for (int i=0; i < greens; i++)
    {
      hchip_type newchip = bj_chip_new (25.0);
      chiplist = g_list_append (chiplist, newchip);
    }
  for (int i=0; i < reds; i++)
    {
      hchip_type newchip = bj_chip_new (5.0);
      chiplist = g_list_append (chiplist, newchip);
    }
  for (int i=0; i < whites; i++)
    {
      hchip_type newchip = bj_chip_new (1.0);
      chiplist = g_list_append (chiplist, newchip);
    }
  bj_chip_stack_add_chips (chiplist, 
                           (hstack_type)g_list_last (bj_chip_stack_get_list ())->data);
}

void
bj_chip_stack_new_with_value (gfloat value, gint x, gint y)
{
  // New wager chip stack
  bj_chip_stack_new_with_id_value (1, value, x, y);
}

void
bj_chip_stack_new_source_with_value (gfloat value, gint x, gint y)
{
  // New source chip stack
  bj_chip_stack_new_with_id_value (0, value, x, y);
}

gboolean
bj_chip_stack_is_source (hstack_type hstack)
{
  // return true if stack is a chip source stack
  if (! hstack)
    return FALSE;
  return (hstack->id == 0) ? TRUE : FALSE;
}
