/* tiles.c
 *
 * Copyright (C) 1999 Tom Gilbert
 *
 * 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 "Gnerudite.h"

extern rack_button tile_button[13];
extern grid_button button[15][15];
extern int debug;
extern int tiles_in_rack;
extern GtkWidget *window;
extern GtkWidget *swap_dialog;
extern GtkWidget *swap_tile_button;
extern GtkWidget *deal_button;
extern user_preferences options;
extern grid_button *other_gridbutton;
extern rack_button *other_rackbutton;
extern int grid_selected_count;
extern int rack_selected_count;
extern int scrabble[15][15];
extern int swapping_tiles;

void
grid_square_toggled (grid_button * buttondata)
{

  if (GTK_TOGGLE_BUTTON (buttondata->toggle_button)->active)
    {
      /* If control reaches here, the toggle button is down */
      grid_selected_count++;
      if (grid_selected_count >= 3)
	{
	  reset_grid_buttons ();
	  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON
					(buttondata->toggle_button), TRUE);
	}
      else if (grid_selected_count == 2)
	{
	  if (tiles_can_be_swapped (buttondata, other_gridbutton))
	    {
	      swap_grid_tiles ((buttondata), (other_gridbutton));
	    }
	  reset_grid_buttons ();
	}
      else
	{
	  /* Only one grid-square is currently selected! */

	  if (rack_selected_count == 1)
	    {
	      if (rack_tile_can_be_placed (other_rackbutton, buttondata))
		{
		  place_rack_tile (other_rackbutton, buttondata);
		}
	      reset_rack_buttons ();
	      reset_grid_buttons ();
	    }
	  else
	    {
	      other_gridbutton = buttondata;
	    }
	}
    }

  else
    {
      /* If control reaches here, the toggle button is up */
      grid_selected_count--;
    }
}

void
rack_tile_toggled (rack_button * rackbutton)
{
  if (swapping_tiles)
    {
      TOMTRACE (("Rack tile toggled. Swapping tile mode is active\n"));
      if (GTK_TOGGLE_BUTTON (rackbutton->toggle_button)->active)
	{
	  /* If control reaches here, the toggle button is down */
	  rack_selected_count++;
	}
      else
	{
	  rack_selected_count--;
	}
      if (rack_selected_count == 0)
	gnome_dialog_set_sensitive (GNOME_DIALOG (swap_dialog), 0, FALSE);
      else
	gnome_dialog_set_sensitive (GNOME_DIALOG (swap_dialog), 0, TRUE);
    }
  else if (GTK_TOGGLE_BUTTON (rackbutton->toggle_button)->active)
    {
      /* If control reaches here, the toggle button is down */
      rack_selected_count++;
      if (rack_selected_count >= 2)
	{
	  if (rack_tiles_can_be_swapped (rackbutton, other_rackbutton))
	    {
	      swap_rack_tiles (rackbutton, other_rackbutton);
	      reset_rack_buttons ();
	    }
	}
      else
	{
	  /* Only one selected! */
	  if (grid_selected_count == 1)
	    {
	      if (rack_tile_can_be_placed (rackbutton, other_gridbutton))
		place_rack_tile (rackbutton, other_gridbutton);
	      reset_rack_buttons ();
	      reset_grid_buttons ();
	    }
	  else
	    {
	      other_rackbutton = rackbutton;
	    }
	}
    }
  else
    {
      /* If control reaches here, the toggle button is up */
      rack_selected_count--;
    }
}

void
reset_grid_buttons (void)
{
  int i, j;
  TOMTRACE (("Reseting grid buttons\n"));
  for (i = 0; i < 15; i++)
    for (j = 0; j < 15; j++)
      {
	if (GTK_TOGGLE_BUTTON ((button[j][i]).toggle_button)->active)
	  {
	    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON
					  ((button[j][i]).toggle_button),
					  FALSE);}
      }
}


void
reset_rack_buttons (void)
{
  int i;
  TOMTRACE (("Reseting rack buttons\n"));
  for (i = 0; i < 13; i++)
    {
      if (GTK_TOGGLE_BUTTON (tile_button[i].toggle_button)->active)
	{
	  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON
					(tile_button[i].toggle_button),
					FALSE);
	}
      rack_selected_count = 0;
    }
}

int
tiles_can_be_swapped (grid_button * gridbutton1, grid_button * gridbutton2)
{
  if ((gridbutton1->placed_this_go) && (gridbutton2->placed_this_go))
    {
      TOMTRACE (("Tiles can be swapped, both placed this go\n"));
      return TRUE;
    }
  else
    {
      if (((gridbutton1->letter == '\0') && (gridbutton2->letter == '\0')) ||
	  ((gridbutton1->letter == '\0') && (gridbutton2->letter != '\0')
	   && (gridbutton2->placed_this_go)) || ((gridbutton1->letter != '\0')
						 && (gridbutton2->letter ==
						     '\0')
						 &&
						 (gridbutton1->
						  placed_this_go)))
	{
	  TOMTRACE (("Tiles can be swapped\n"));
	  return TRUE;
	}
      else
	{
	  TOMTRACE (("Tiles cannot be swapped\n"));
	  return FALSE;
	}
    }
}

int
swap_grid_tiles (grid_button * gridbutton1, grid_button * gridbutton2)
{
  gchar c;
  gchar d;
  c = gridbutton1->letter;
  d = gridbutton2->letter;

  grid_button_assign_char (gridbutton1, d);
  grid_button_assign_char (gridbutton2, c);

  if ((c == '\0') && (d == '\0'))
    {
      TOMTRACE (("You swapped two blanks!\n"));
    }
  else if ((c != '\0') && (d != '\0'))
    {
      TOMTRACE (("You have swapped two letters\n"));
    }
  else if ((c == '\0') && (d != '\0'))
    {
      TOMTRACE (("You have swapped a grid blank with a grid letter.\n"));
      gridbutton2->placed_this_go = FALSE;
      gridbutton1->placed_this_go = TRUE;
    }
  else if ((d == '\0') && (c != '\0'))
    {
      TOMTRACE (("You have swapped a grid letter with a grid blank.\n"));
      gridbutton1->placed_this_go = FALSE;
      gridbutton2->placed_this_go = TRUE;
    }
  else
    {
      TOMTRACE (("I don't know what to do!\n"));
    }
  return TRUE;
}

int
rack_tiles_can_be_swapped (rack_button * rackbutton1,
			   rack_button * rackbutton2)
{
  /* Hmmm. Now I think about it, would this ever be false? */
  return TRUE;
}

int
place_rack_tile (rack_button * rackbutton, grid_button * gridbutton)
{

  gchar c;
  gchar d;
  c = rackbutton->letter;
  d = gridbutton->letter;

  rack_button_assign_char (rackbutton, d);
  grid_button_assign_char (gridbutton, c);

  if ((c == '\0') && (d == '\0'))
    {
      TOMTRACE (("You swapped a blank rack tile with a blank grid tile\n"));
      gridbutton->placed_this_go = FALSE;
    }
  else if ((c == '\0') && (d != '\0'))
    {
      TOMTRACE (("You returned a grid tile to the rack\n"));
      gridbutton->placed_this_go = FALSE;
      tiles_in_rack++;
    }
  else if ((c != '\0') && (d != '\0'))
    {
      TOMTRACE (("You swapped a grid tile with a rack tile\n"));
    }
  else
    {
      TOMTRACE (("You have placed a tile from the rack\n"));
      gridbutton->placed_this_go = TRUE;
      tiles_in_rack--;
    }
  return TRUE;
}

int
swap_rack_tiles (rack_button * rackbutton1, rack_button * rackbutton2)
{
  gchar c;
  gchar d;

  c = rackbutton1->letter;
  d = rackbutton2->letter;

  rack_button_assign_char (rackbutton1, d);
  rack_button_assign_char (rackbutton2, c);

  if (rackbutton1->letter == '\0')
    gtk_widget_set_name (rackbutton1->toggle_button, "rack");
  else
    gtk_widget_set_name (rackbutton1->toggle_button, "tile");

  if (rackbutton2->letter == '\0')
    gtk_widget_set_name (rackbutton2->toggle_button, "rack");
  else
    gtk_widget_set_name (rackbutton2->toggle_button, "tile");

  return TRUE;
}

int
rack_tile_can_be_placed (rack_button * rackbutton, grid_button * gridbutton)
{
  if ((gridbutton->placed_this_go) || (gridbutton->letter == '\0'))
    {
      TOMTRACE (("Rack tile may be placed\n"));
      return TRUE;
    }
  else
    {
      TOMTRACE (("Rack tile may not be placed\n"));
      return FALSE;
    }
  return FALSE;
}

int
grid_show_label_hide_pixmap (grid_button * gridbutton)
{
  TOMTRACE (("\nShowing Label, hiding pixmap\n"));
  return TRUE;
}

int
grid_show_pixmap_hide_label (grid_button * gridbutton)
{
  TOMTRACE (("\nShowing pixmap, hiding label\n"));
  return TRUE;
}

void
cb_deal_button (void)
{
  deal_seven_letters ();
  gtk_widget_set_sensitive (deal_button, FALSE);
}

int
clear_grid_button_validations (void)
{
  int i, j;
  for (i = 0; i < 15; i++)
    for (j = 0; j < 15; j++)
      {
	button[j][i].placed_this_go = FALSE;
      }
  return TRUE;
}

int
cb_skip_go_pressed (void)
{
  /* Offer a confirmation dialog to confirm go_skip (if user has not deselected
   * options.confirm_skip_go) */

  if (options.confirm_skip_go)
    {
      GtkWidget *dialog;
      GtkWidget *label;
      int reply;
      /* Ask for confirmation */
      /* TODO Use meaningful buttons, (skip) and (don't skip) instead of
       * yes and no */
      TOMTRACE (("About to ask for confirmation\n"));
      dialog = gnome_dialog_new (_ ("Skip go confirmation"),
				 GNOME_STOCK_BUTTON_YES,
				 GNOME_STOCK_BUTTON_NO, NULL);
      gnome_dialog_set_parent (GNOME_DIALOG (dialog), GTK_WINDOW (window));
      label = gtk_label_new ("Are you sure you wish to skip your go?");
      gnome_dialog_set_default (GNOME_DIALOG (dialog), GNOME_OK);
      gtk_box_pack_start (GTK_BOX (GNOME_DIALOG (dialog)->vbox),
			  label, TRUE, TRUE, GNOME_PAD);
      gtk_widget_show_all (dialog);

      reply = gnome_dialog_run (GNOME_DIALOG (dialog));

      if (!reply == GNOME_OK)
	{
	  gtk_widget_destroy (dialog);
	  return FALSE;
	}
      gtk_widget_destroy (dialog);
    }

  start_next_go ();

  /* TODO */

  return TRUE;
}

void
set_tile_status (grid_button * gridbutton)
{
  gtk_widget_set_name (gridbutton->toggle_button, "tile");
}

void
reset_tile_status (grid_button * gridbutton)
{
  switch (gridbutton->score)
    {
    case SCORE_NONE:
      {
	gtk_widget_set_name (gridbutton->toggle_button, "blank");
	break;
      }
    case SCORE_DOUBLE_LETTER:
      {
	gtk_widget_set_name (gridbutton->toggle_button, "2l");
	break;
      }
    case SCORE_TRIPLE_LETTER:
      {
	gtk_widget_set_name (gridbutton->toggle_button, "3l");
	break;
      }
    case SCORE_DOUBLE_WORD:
      {
	gtk_widget_set_name (gridbutton->toggle_button, "2w");
	break;
      }
    case SCORE_TRIPLE_WORD:
      {
	gtk_widget_set_name (gridbutton->toggle_button, "3w");
	break;
      }
    default:
      {
	TOMTRACE (("Error setting togglebutton class\n"));
      }
    }
}


void
initialise_tile_scores (void)
{
  int i = 0, j = 0;
  TOMTRACE (("About to initialise tile_score values for the grid\n"));
  for (i = 0; i < 15; i++)
    for (j = 0; j < 15; j++)
      {
	switch (scrabble[j][i])
	  {
	  case 0:
	    {
	      button[j][i].score = SCORE_NONE;
	      break;
	    }
	  case 1:
	    {
	      button[j][i].score = SCORE_DOUBLE_LETTER;
	      break;
	    }
	  case 2:
	    {
	      button[j][i].score = SCORE_DOUBLE_WORD;
	      break;
	    }
	  case 3:
	    {
	      button[j][i].score = SCORE_TRIPLE_LETTER;
	      break;
	    }
	  case 4:
	    {
	      button[j][i].score = SCORE_TRIPLE_WORD;
	      break;
	    }
	  default:
	    {
	      TOMTRACE (("Error!"));
	      exit (2);
	    }
	  }
      }
}

void
rack_button_assign_char (rack_button * rackbutton, gchar c)
{
  gchar d[2] = { '\0', '\0' };

  if (c == '@')
    c = '*';

  rackbutton->letter = c;
  d[0] = c;
  if (c == '\0')
    {
      gtk_widget_set_name (rackbutton->toggle_button, "rack");
      gtk_label_set (GTK_LABEL (rackbutton->label), "");
    }
  else
    {
      gtk_widget_set_name (rackbutton->toggle_button, "tile");
      gtk_label_set (GTK_LABEL (rackbutton->label), d);
    }
}

void
grid_button_assign_char (grid_button * gridbutton, gchar c)
{
  gchar d[2] = { '\0', '\0' };

  if (c == '@')
    c = '*';

  gridbutton->letter = c;
  d[0] = c;
  if (c == '\0')
    {
      reset_tile_status (gridbutton);
      gtk_label_set (GTK_LABEL (gridbutton->label), "");
    }
  else
    {
      set_tile_status (gridbutton);
      gtk_label_set (GTK_LABEL (gridbutton->label), d);
    }
}

void
cb_swap_tile_button (void)
{
  GtkWidget *label = NULL;
  TOMTRACE (("About to offer choice of tiles to swap\n"));
  swapping_tiles = TRUE;
  if (swap_dialog != NULL)
    {
      TOMTRACE (("Swap window already open. I am raising it\n"));
      gdk_window_show (swap_dialog->window);
      gdk_window_raise (swap_dialog->window);
      return;
    }
  else
    {
      TOMTRACE (("Swap window not open. I am creating one\n"));
      gtk_widget_set_sensitive (swap_tile_button, FALSE);
      swap_dialog = gnome_dialog_new (_ ("Swap Tiles"),
				      "Swap selected tiles",
				      "Swap all tiles",
				      GNOME_STOCK_BUTTON_CANCEL, NULL);
      gnome_dialog_set_parent (GNOME_DIALOG (swap_dialog),
			       GTK_WINDOW (window));
      gnome_dialog_set_close (GNOME_DIALOG (swap_dialog), TRUE);
      gtk_signal_connect (GTK_OBJECT (swap_dialog), "close",
			  (gpointer) cb_swap_dialog_closed, &swap_dialog);
      gtk_signal_connect (GTK_OBJECT (swap_dialog), "destroy",
			  GTK_SIGNAL_FUNC (gtk_widget_destroyed),
			  &swap_dialog);
      gtk_signal_connect (GTK_OBJECT (swap_dialog), "clicked",
			  (gpointer) cb_swap_dialog_clicked, &swap_dialog);
      label =
	gtk_label_new
	("Select tiles in your rack to return them to the bag.\n"
	 "Press \"Swap selected\" when you are finished, press cancel to "
	 "leave your rack as it is.\n\nBe aware that swapping some or all "
	 "of your tiles will cost you your turn.");
      gnome_dialog_set_default (GNOME_DIALOG (swap_dialog), 2);
      gtk_box_pack_start (GTK_BOX (GNOME_DIALOG (swap_dialog)->vbox),
			  label, TRUE, TRUE, GNOME_PAD);
      gnome_dialog_set_sensitive (GNOME_DIALOG (swap_dialog), 0, FALSE);
      gtk_widget_show_all (swap_dialog);
    }
}

void
cb_swap_dialog_clicked (GtkWidget * dialog, int button, gpointer * data)
{
  int i = 0;
  int swap_all = FALSE;
  TOMTRACE (("In swap_dialog_clicked callback\n"));

  if (button == 2)
    {
      TOMTRACE (("Swap dialog cancelled\n"));
      return;
    }
  else if (button == 1)
    {
      TOMTRACE (("Swap all tiles was pressed\n"));
      swap_all = TRUE;
      /* Continue into rest of function */
    }

  TOMTRACE (("Swap selected was pressed\n"));
  TOMTRACE (("Number of tiles to swap : %d\n", rack_selected_count));
  for (i = 0; i < 13; i++)
    {
      if (
	  ((GTK_TOGGLE_BUTTON (tile_button[i].toggle_button)->active)
	   || (swap_all)) && (tile_button[i].letter != '\0'))
	{
	  letter_bag_push (tile_button[i].letter);
	  rack_button_assign_char (&tile_button[i], '\0');
	  tiles_in_rack--;
	}
    }
  letter_bag_mix ();
  deal_seven_letters ();
  start_next_go ();
}

int
cb_swap_dialog_closed (GtkWidget * dialog)
{
  TOMTRACE (("In swap_dialog_closed_cb\n"));
  swapping_tiles = FALSE;
  reset_rack_buttons ();
  gtk_widget_set_sensitive (swap_tile_button, TRUE);
  return FALSE;
}

gchar
ask_user_for_wildcard_char (int row, int col)
{
  GtkWidget *dialog, *label, *entry;
  gchar buffer[120];
  gchar d[2] = { '\0', '\0' };

  TOMTRACE (("About to ask user to specify wildcard character\n"));

  snprintf (buffer, 120, "The letter placed at row %d, col %d "
	    "is a wildcard\n"
	    "Please enter the letter you wish the wildcard to represent.",
	    row + 1, col + 1);

  dialog = gnome_dialog_new ("Wildcard Letter", GNOME_STOCK_BUTTON_OK, NULL);
  gnome_dialog_set_parent (GNOME_DIALOG (dialog), GTK_WINDOW (window));
  label = gtk_label_new (buffer);
  entry = gtk_entry_new_with_max_length (1);
  gnome_dialog_set_default (GNOME_DIALOG (dialog), GNOME_OK);
  gtk_box_pack_start (GTK_BOX (GNOME_DIALOG (dialog)->vbox),
		      label, TRUE, TRUE, GNOME_PAD);
  gtk_box_pack_start (GTK_BOX (GNOME_DIALOG (dialog)->vbox),
		      entry, TRUE, TRUE, GNOME_PAD);
  gtk_widget_show_all (dialog);
  gtk_widget_grab_focus (entry);

  while (!isalpha (d[0]))
    {
      gnome_dialog_run (GNOME_DIALOG (dialog));
      strncpy (d, gtk_entry_get_text (GTK_ENTRY (entry)), 1);
    }

  gtk_widget_destroy (dialog);
  d[0] = toupper (d[0]);
  return d[0];
}
