/* 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_cardcell.cc

#include "cardwords_gtk_cardcell.hh"
#include "config.hh"
#include "cardwords_gettext.hh"
#include <gtk--/label.h>

static const gchar cell_attribute_marker[] = {'W','L','C','B'};
static const int   default_values[]        = {1, 1, 0, int(true)};


CardWords_Gtk_CellAttribute::
CardWords_Gtk_CellAttribute(const
                            CardWords_Gtk_Common_Card_Cell_Styles *
                            styles,

                            CardWords_Gtk_CellAttributeType type)
  : cell_attribute_type(type)
{
  assert (styles != 0);

  set_style(*styles->get_attribute_bg_style(type));
  //set_usize(styles->get_attribute_width(), styles->get_attribute_height());
}

CardWords_Gtk_CellAttribute::~CardWords_Gtk_CellAttribute()
{}

CardWords_Gtk_CellAttributeType
CardWords_Gtk_CellAttribute::get_cell_attribute_type(void) const
{
  return cell_attribute_type;
}

CardWords_Gtk_CellAttributeValue::
CardWords_Gtk_CellAttributeValue(const
                                 CardWords_Gtk_Common_Card_Cell_Styles *
                                 styles,
                                 
                                 CardWords_Gtk_CellAttributeType type,
                                 int val)
  : CardWords_Gtk_CellAttribute(styles, type),
    value(val),
    label(0)
{
  assert (styles != 0);
  assert (type != CAT_DEFAULT);
  assert (type != CAT_BLOCKED);
  assert (type == CAT_WORD_FACTOR
          || type == CAT_LETTER_FACTOR
          || type == CAT_CELL_POINTS);

  gchar type_marker = 0;
  if (type == CAT_WORD_FACTOR) {
    type_marker = * gettext("W");
  }
  else if (type == CAT_LETTER_FACTOR) {
    type_marker = * gettext("L");
  }
  else if (type == CAT_CELL_POINTS) {
    type_marker = * gettext("C");
  }
  else {
    assert(0); // invalid type
  }
  
  ostrstream label_text;

  label_text << value
             << type_marker
             << ends;

  label_text.freeze(true);
  label = new Gtk::Label(label_text.str());
  label_text.freeze(false);

  label->set_style(*styles->get_values_font_style());

  add(*label);

  label->show();
}

CardWords_Gtk_CellAttributeValue::~CardWords_Gtk_CellAttributeValue()
{
  label->hide();
  remove(/*label*/);
  delete label;
}

int
CardWords_Gtk_CellAttributeValue::get_value(void) const
{
  return value;
}

CardWords_Gtk_CellAttribute *
make_new_cell_attribute(const
                        CardWords_Gtk_Common_Card_Cell_Styles *
                        styles,

                        CardWords_Gtk_CellAttributeType type,
                        int value = 0)
{
  CardWords_Gtk_CellAttribute * attr;
  
  switch (type) {
  case CAT_DEFAULT:
    attr = new CardWords_Gtk_CellAttributeDefault(styles, type);
    break;
  case CAT_WORD_FACTOR:
    assert (value != DEFAULT_WORD_FACTOR);
    attr = new CardWords_Gtk_CellAttributeValue(styles, type, value);
    break;
  case CAT_LETTER_FACTOR:
    assert (value != DEFAULT_LETTER_FACTOR);
    attr = new CardWords_Gtk_CellAttributeValue(styles, type, value);
    break;
  case CAT_CELL_POINTS:
    assert (value != DEFAULT_CELL_POINTS);
    attr = new CardWords_Gtk_CellAttributeValue(styles, type, value);
    break;
  case CAT_BLOCKED:
    attr = new CardWords_Gtk_CellAttributeBlocked(styles, type);
    break;
  default:
    assert(0);
  }
  assert (attr != 0);
  return attr;
}


CardWords_Gtk_EmptyCell::
CardWords_Gtk_EmptyCell (const CardWords_Gtk_Common_Card_Cell_Styles * styles,
                         int new_word_factor   = DEFAULT_WORD_FACTOR,
                         int new_letter_factor = DEFAULT_LETTER_FACTOR,
                         int new_cell_points   = DEFAULT_CELL_POINTS,
                         bool new_cell_blocked = false)
  : word_factor  (new_word_factor),
    letter_factor(new_letter_factor),
    cell_points  (new_cell_points),
    cell_blocked (new_cell_blocked)
{
  assert (styles != 0);

  attribute[0] = 0;
  attribute[1] = 0;

  set_homogeneous(true);
    

  size_t attribute_counter = 0U;

  if (is_cell_blocked() == true) {
    attribute[0] =
      make_new_cell_attribute(styles, CAT_BLOCKED);
    attribute_counter = 1U;
  }
  else {
    if (get_word_factor() != DEFAULT_WORD_FACTOR) {
      attribute[attribute_counter] =
        make_new_cell_attribute(styles,
                                CAT_WORD_FACTOR,
                                get_word_factor());
      ++attribute_counter;
    }
    if (get_cell_points() != DEFAULT_CELL_POINTS) {
      attribute[attribute_counter] =
        make_new_cell_attribute(styles,
                                CAT_CELL_POINTS,
                                get_cell_points());
      ++attribute_counter;
    }
    if (get_letter_factor() != DEFAULT_LETTER_FACTOR) {
      assert (attribute_counter < 2U); // only 2 non-default
      //                                  attributes allowed.

      attribute[attribute_counter] =
        make_new_cell_attribute(styles,
                                CAT_LETTER_FACTOR,
                                get_letter_factor());
      ++attribute_counter;
    }
    if (attribute_counter == 0U
        || attribute_counter == 1U) {
      // add a default attribute indicator:
      attribute[attribute_counter] =
        make_new_cell_attribute(styles,
                                CAT_DEFAULT);
      ++attribute_counter;
    }
  }

  size_t index;
  for (index = 0; index < attribute_counter; ++index) {
    pack_end(*attribute[index]);
    attribute[index]->show();
  }
}
CardWords_Gtk_EmptyCell::~CardWords_Gtk_EmptyCell ()
{
  size_t index;
  for (index = 0;
       index < 2
         && attribute[index] != 0;
       ++index) {
    attribute[index]->hide();
    remove(*attribute[index]);
    delete attribute[index];
  }
}

int
CardWords_Gtk_EmptyCell::get_word_factor(void) const
{
  return word_factor;
}

int
CardWords_Gtk_EmptyCell::get_letter_factor(void) const
{
  return letter_factor;
}

int
CardWords_Gtk_EmptyCell::get_cell_points(void) const
{
  return cell_points;
}
bool
CardWords_Gtk_EmptyCell::is_cell_blocked(void) const
{
  return cell_blocked;
}

CardWords_Gtk_CellCard::
CardWords_Gtk_CellCard (const CardWords_Gtk_Common_Card_Cell_Styles * styles,
                        gchar face,
                        gint  pts,
                        bool  wild = false,
                        bool  s_recent = false,
                        bool  s_pre    = false)
  : int_points(pts), wildcard(wild), recent(s_recent), pre(s_pre)
{
  visible[0] = face;
  visible[1] = '\0';

  hbox = new Gtk::HBox;
  points_box = new Gtk::VBox;
      
  if (recent == true) {
    set_style(*styles->get_card_recent_bg_style());
  }
  else if (pre == true) {
    set_style(*styles->get_card_pre_bg_style());
  }
  else {
    set_style(*styles->get_card_bg_style());
  }

  assert (pts >= -9); // only 2 digits!
  assert (pts <= 99);

  points[2] = '\0';
  if (pts < 0) {
    points[0] = '-';
    points[1] = '0' + ((-pts) % 10);
  }
  else if (pts < 10) {
    points[0] = '0' + pts;
    points[1] = '\0';
  }
  else {
    points[0] = '0' + ( (pts / 10) % 10);
    points[1] = '0' + (pts % 10);
  }

  c_label = new Gtk::Label(visible);
  p_label = new Gtk::Label(points);

  if (wildcard == true) {
    c_label->set_style(*styles->get_card_wildcard_meaning_style());
  }
  else {
    c_label->set_style(*styles->get_card_face_value_style());
  }

  if (points[1] == '\0') {
    p_label->set_style(*styles->get_card_points_wide_style());
  }
  else {
    p_label->set_style(*styles->get_card_points_narrow_style());
  }

  points_box->pack_start(*p_label, false, false);

  hbox->pack_end(*points_box);
  hbox->pack_end(*c_label);

  c_label->show();
  p_label->show();
  points_box->show();

  add(*hbox);
  hbox->show();
}
CardWords_Gtk_CellCard::~CardWords_Gtk_CellCard()
{
  c_label->hide();
  p_label->hide();
  points_box->hide();
  hbox->hide();
    
  points_box->remove(*p_label);
  hbox->remove(*c_label);
  hbox->remove(*points_box);
  remove(/*hbox*/);
    
  delete c_label;
  delete p_label;
  delete points_box;
  delete hbox;
}

gchar
CardWords_Gtk_CellCard::get_visible(void) const
{
  return visible[0];
}

int
CardWords_Gtk_CellCard::get_points(void) const
{
  return int_points;
}

bool
CardWords_Gtk_CellCard::is_wildcard(void) const
{
  return wildcard;
}

bool
CardWords_Gtk_CellCard::is_recent(void) const
{
  return recent;
}

bool
CardWords_Gtk_CellCard::is_pre(void) const
{
  return pre;
}


void
CardWords_Gtk_CardCell::activate(bool make_active)
{
  if (active != make_active) {
    set_style((active = make_active)
              ? *styles->get_frame_active_style()
              : *styles->get_frame_normal_style());
  }
}
  
CardWords_Gtk_CardCell::
CardWords_Gtk_CardCell(const CardWords_Gtk_Common_Card_Cell_Styles * styles,
                       size_t coordinate,
                       int word_factor   = DEFAULT_WORD_FACTOR,
                       int letter_factor = DEFAULT_LETTER_FACTOR,
                       int cell_points   = DEFAULT_CELL_POINTS,
                       bool cell_blocked = false)
  : ct(0), active(false), mouse_button_is_pressed(false)
{
  this->styles = styles;
  assert(styles != 0);
  set_style(*styles->get_frame_normal_style());

  inner_box = new Gtk::EventBox;
  inner_box->set_border_width(styles->get_frame_thickness());

  ec = new CardWords_Gtk_EmptyCell (styles,
                                    word_factor,
                                    letter_factor,
                                    cell_points,
                                    cell_blocked);
  inner_box->add(*ec);
  ec->show();
  add(*inner_box);
  inner_box->show();
  set_usize(styles->get_cell_width(),styles->get_cell_height());
    
  button_press_event.
    connect(SigC::slot(this, &CardWords_Gtk_CardCell::button_pressed));

  button_release_event.
    connect(SigC::slot(this, &CardWords_Gtk_CardCell::button_released));

  leave_notify_event.
    connect(SigC::slot(this, &CardWords_Gtk_CardCell::pointer_leaves));

  this->coordinate = coordinate;

  enter_notify_event.
    connect(SigC::slot(this, &CardWords_Gtk_CardCell::send_enter_signal));
}

void
CardWords_Gtk_CardCell::set_card (CardWords_Gtk_CellCard  * cellcard) {
  if (ct != 0) {
    ct->hide();
    inner_box->remove(/*ct*/);
    delete ct;
    ct = 0;
  }
  else {
    ec->hide();
    inner_box->remove(/*ec*/);
  }
  ct = cellcard;
  if (ct == 0) {
    inner_box->add(*ec);
    ec->show();
  }
  else {
    inner_box->add (*ct);
    ct->show();
  }
  // Now, this is possibly a bug in gtk+: The cards or empty card cells will
  // not be redrawn.
  queue_resize();
}   
CardWords_Gtk_CardCell::~CardWords_Gtk_CardCell() {
  delete ec;
  delete ct;
  delete inner_box;
}

int
CardWords_Gtk_CardCell::get_word_factor(void) const
{
  return ec->get_word_factor();
}

int
CardWords_Gtk_CardCell::get_letter_factor(void) const
{
  return ec->get_letter_factor();
}

int
CardWords_Gtk_CardCell::get_cell_points(void) const
{
  return ec->get_cell_points();
}
bool
CardWords_Gtk_CardCell::is_cell_blocked(void) const
{
  return ec->is_cell_blocked();
}

const CardWords_Gtk_CellCard *
CardWords_Gtk_CardCell::get_cellcard(void) const
{
  return ct;
}

size_t
CardWords_Gtk_CardCell::get_coordinate(void) const
{
  return coordinate;
}

int
CardWords_Gtk_CardCell::send_enter_signal(GdkEventCrossing *)
{
  enter_signal(this);
  return true;
}

/*
Signal1<const CardWords_Gtk_CardCell *>
CardWords_Gtk_CardCell::get_enter_signal(void) const
{
  return enter_signal;
}
*/

void
CardWords_Gtk_CardCell::set_card (gchar face,
                                gint  pts,
                                bool  wild = false,
                                bool  s_recent = false,
                                bool  s_pre    = false)
{
  set_card(new CardWords_Gtk_CellCard(styles,
                                    face,
                                    pts,
                                    wild,
                                    s_recent,
                                    s_pre));
}
void
CardWords_Gtk_CardCell::set_card (const CardWords_CardBase * tb,
                                bool  s_recent = false,
                                bool  s_pre    = false)
{
  if (tb == 0) {
    set_card(static_cast<CardWords_Gtk_CellCard *>(0));
  }
  else {
    set_card(new CardWords_Gtk_CellCard(styles,
                                      tb->get_meaning(),
                                      tb->get_points(),
                                      tb->is_wildcard(),
                                      s_recent,
                                      s_pre
                                      )
             );
  }
}
                                    
int
CardWords_Gtk_CardCell::button_pressed(GdkEventButton * event)
{
  if (event->button == 1) {
    // first button pressed
    mouse_button_is_pressed = true;
    return true;
  }
  return false;
}
int
CardWords_Gtk_CardCell::button_released(GdkEventButton * event)
{
  if (event->button == 1 && mouse_button_is_pressed == true) {
    mouse_button_is_pressed = false;
    clicked_signal(this);
    return true;
  }
  return false;
}
int
CardWords_Gtk_CardCell::pointer_leaves(GdkEventCrossing*)
{
  if (mouse_button_is_pressed == true) {
    mouse_button_is_pressed = false;
    return true;
  }
  return false;
}

