/* This file is part of cardwords
   (c) 1999 Tobias Peters
   see file COPYING for the copyright terms.
   
   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
*/

// cardwords_gtk_cardtable.cc

#include "cardwords_gtk_cardtable.hh"
#include <gtk--/label.h>

CardWords_Gtk_CardTable::
CardWords_Gtk_CardTable( const CardWords_CardTable * b,
                   size_t cell_width,
                   size_t cell_height,

                   bool use_digits_for_the_columns,
                   // and chars for the rows, otherwise the other way
                   // round
			  
                   bool column_indices_grow_rightwards,
                   // if true, the rightmost column has the greatest
                   // index
			  
                   bool row_indices_grow_upwards,

                   CardWords_Gtk_CardTableInfo * info)
  : Gtk::Table(b->get_width() + 2, b->get_height() + 2, false),
    card_table(b),
    cells(b->get_width(), b->get_height(), 0),
    styles(new CardWords_Gtk_Common_Card_Cell_Styles(cell_width,
                                                     cell_height)),
    card_table_info(info)
{
  this->use_digits_for_the_columns = use_digits_for_the_columns;
  this->column_indices_grow_rightwards = column_indices_grow_rightwards;
  this->row_indices_grow_upwards = row_indices_grow_upwards;
  
  size_t x, y;

  char text[3] = {0,0,0};

  assert (card_table->get_width() <= 26);
  assert (card_table->get_height() <= 99);

  
  // ********* Fill the card-table table with the labels: ************
  if (use_digits_for_the_columns) {
    for (y = 1; y <= card_table->get_height(); ++y) {
      text[0] = (row_indices_grow_upwards
                 ? (card_table->get_height() - y + 'A')
                 : ('A' + y - 1));

      left_labels.push_back(new Gtk::Label(text));
      attach(*left_labels.back(),
             0, 1,
             y, y+1);
      left_labels.back()->show();
    
      right_labels.push_back(new Gtk::Label(text));
      attach(*right_labels.back(),
             card_table->get_width() + 1, card_table->get_width() + 2,
             y, y+1);
      right_labels.back()->show();
    }

    for (x = 1; x <= card_table->get_width(); ++x) {
      size_t user_coordinate = (column_indices_grow_rightwards
                                ? x
                                : (card_table->get_width() - x + 1));
      if (user_coordinate < 10) {
        text[0] = '0' + user_coordinate;
        text[1] = '\0';
      }
      else {
        text[0] = '0' + user_coordinate / 10;
        text[1] = '0' + user_coordinate % 10;
      }
    
      upper_labels.push_back(new Gtk::Label(text));
      attach(*upper_labels.back(),
             x, x + 1,
             0, 1);
      upper_labels.back()->show();
    
      lower_labels.push_back(new Gtk::Label(text));
      attach(*lower_labels.back(),
             x, x + 1,
             card_table->get_height() + 1, card_table->get_height() + 2);
      lower_labels.back()->show();
    }
  }
  else {
    // !use_digits_for_the_columns
    for (x = 1; x <= card_table->get_width(); ++x) {
      text[0] = (column_indices_grow_rightwards
                 ? ('A' + x - 1)
                 : (card_table->get_width() - x + 'A')
                 );

      upper_labels.push_back(new Gtk::Label(text));
      attach(*upper_labels.back(), x, x+1, 0, 1);
      upper_labels.back()->show();
    
      lower_labels.push_back(new Gtk::Label(text));
      attach(*lower_labels.back(), x, x+1,
             card_table->get_height() + 1, card_table->get_height() + 2);
      lower_labels.back()->show();
    }

    for (y = 1; y <= card_table->get_height(); ++y) {
      size_t user_coordinate = (row_indices_grow_upwards
                                ? (card_table->get_height() - y + 1)
                                : y);
      if (user_coordinate < 10) {
        text[0] = '0' + user_coordinate;
        text[1] = '\0';
      }
      else {
        text[0] = '0' + user_coordinate / 10;
        text[1] = '0' + user_coordinate % 10;
      }
    
      left_labels.push_back(new Gtk::Label(text));
      attach(*left_labels.back(), 0, 1, y, y + 1);
      left_labels.back()->show();
    
      right_labels.push_back(new Gtk::Label(text));
      attach(*right_labels.back(),
             card_table->get_width() + 1, card_table->get_width() + 2,
             y, y + 1);
      right_labels.back()->show();
    }
  }

  // ******** Copy the info from card-table into the table: ***********
  for (x = 0; x < card_table->get_width(); ++x) {
    for (y = 0; y < card_table->get_height(); ++y) {

      cells(x,y) = new CardWords_Gtk_CardCell(styles,
                                              
                                              x
                                              + y * card_table->get_width(),
                                              
                                              card_table->get_word_factor(x,y),
                                              
                                              card_table
                                              ->get_letter_factor(x,y),

                                              card_table->get_cell_points(x,y),

                                              card_table->is_cell_blocked(x,y)
                                              );
      if ((*card_table)(x,y) != 0) { // There is already a card:
        cells(x,y)->set_card((*card_table)(x,y)->get_faceValue(),
                             (*card_table)(x,y)->get_points(),
                             (*card_table)(x,y)->is_wildcard());
      }
      attach(*cells(x,y), x+1, x+2, y+1, y+2, 0, 0, 0, 0);
      cells(x,y)->show();

      if (card_table_info != 0) {
        cells(x,y)->enter_signal.
          connect(SigC::slot(card_table_info,
                       &CardWords_Gtk_CardTableInfo::show_info_about_cell));
      }
      cells(x,y)->clicked_signal.
        connect(SigC::slot(this,
                     &CardWords_Gtk_CardTable::receive_click_on_cell));
    }
  }
}

CardWords_Gtk_CardTable::~CardWords_Gtk_CardTable()
{
  size_t x, y;
  // ********* Delete the labels: ************
  for (x = 1; x <= card_table->get_width(); ++x) {
    upper_labels[x]->hide();
    remove(*upper_labels[x]);
    delete(upper_labels[x]);
    upper_labels[x] = 0;
    
    lower_labels[x]->hide();
    remove(*lower_labels[x]);
    delete(lower_labels[x]);
    lower_labels[x] = 0;
  }

  for (y = 1; y <= card_table->get_height(); ++y) {
    left_labels[y]->hide();
    remove(*left_labels[y]);
    delete(left_labels[x]);
    left_labels[y] = 0;
    
    right_labels[y]->hide();
    remove(*right_labels[y]);
    delete(right_labels[y]);
    right_labels[y] = 0;
  }


  // ******** Delete the cells: ***********
  for (x = 0; x < card_table->get_width(); ++x) {
    for (y = 0; y < card_table->get_height(); ++y) {

      cells(x,y)->hide();
      remove(*cells(x,y));
      delete(cells(x,y));
      cells(x,y) = 0;
    }
  }
}

// When this method is called, the move has already been added to the
// CardWords_CardTable. The info is for the display:
// Automatically calls unpre(). New Cards will be displayed in recent
// style.
void
CardWords_Gtk_CardTable::show_move(const CardWords_Move &move)
{
  unpre();
  
  CardWords_CardTableLocation loc = move.location;
  size_t & var = (move.direction == horizontal) ? loc.first : loc.second;

  size_t used_cards = 0;
  
  while (used_cards < move.size()) {
    if (cells[loc]->get_cellcard() == 0) {
      cells[loc]->set_card (move[used_cards].get_meaning(),
                            move[used_cards].get_points(),
                            move[used_cards].is_wildcard(),
                            /*recent*/ true);
      recent_locations.push_front(loc);
      ++used_cards;
    }
    ++var;
  }
}

// When unrecent() is called, all cards displayed in the special way for
// recently added cards are converted to be displayed normally:
void
CardWords_Gtk_CardTable::unrecent(void)
{
  CardWords_CardTableLocation loc;
  while (! recent_locations.empty()) {
    loc = recent_locations.front();

    recent_locations.pop_front();

    cells[loc]->set_card (cells[loc]->get_cellcard()->get_visible(),
                          cells[loc]->get_cellcard()->get_points(),
                          cells[loc]->get_cellcard()->is_wildcard());
  }
}

// unpre() without args removes all cards that are currently being dis-
// played but are not yet really on the card-table. This is for the user to
// try moves out.
void
CardWords_Gtk_CardTable::unpre(void)
{
  CardWords_CardTableLocation loc;
  while (! pre_locations.empty()) {
    loc = pre_locations.front();

    pre_locations.pop_front();

    cells[loc]->set_card(static_cast<CardWords_Gtk_CellCard *>(0));
  }
}

// pre (const CardWords_Move &) displays this move, but it is not really on
// the card-table. Calls unpre() to delete previous pre() moves.
void
CardWords_Gtk_CardTable::pre (const CardWords_Move & move)
{
  unpre();
  
  CardWords_CardTableLocation loc = move.location;
  size_t & var = (move.direction == horizontal) ? loc.first : loc.second;

  size_t used_cards = 0;
  
  while (used_cards < move.size()) {
    if (cells[loc]->get_cellcard() == 0) {
      cells[loc]->set_card (move[used_cards].get_faceValue(),
                            move[used_cards].get_points(),
                            move[used_cards].is_wildcard(),
                            /*recent*/ false,
                            /*pre*/    true);
      pre_locations.push_front(loc);
      ++used_cards;
    }
    ++var;
  }
}

const CardWords_Gtk_Common_Card_Cell_Styles *
CardWords_Gtk_CardTable::get_styles(void) const
{
  return styles;
}
  
bool
CardWords_Gtk_CardTable::uses_digits_for_the_columns(void) const
  // and chars for the rows, otherwise the other way
  // round
{
  return use_digits_for_the_columns;
}
bool
CardWords_Gtk_CardTable::do_column_indices_grow_rightwards(void) const
  // if true, the rightmost column has the greatest
  // index
{
  return column_indices_grow_rightwards;
}
bool
CardWords_Gtk_CardTable::do_row_indices_grow_upwards(void) const
{
  return row_indices_grow_upwards;
}

void
CardWords_Gtk_CardTable::
receive_click_on_cell(const CardWords_Gtk_CardCell * cell)
{
  CardWords_CardTableLocation loc;

  loc.first  = cell->get_coordinate() % card_table->get_width();
  loc.second = cell->get_coordinate() / card_table->get_width();

  cell_clicked(loc);
}
