/**********************************************************************
 *
 *   FreeDoko a Doppelkopf-Game
 *    
 *   Copyright (C) 2001-2004  by Diether Knof and Borg Enders
 *
 *   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 can find this license in the file 'gpl.txt'.
 *
 *   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
 *
 *  Contact:
 *    Diether Knof dknof@gmx.de
 *    Borg Enders  borg@borgsoft.de
 *
 *********************************************************************/

#include "constants.h"

#ifdef USE_UI_GTKMM

#include "hand.h"
#include "table.h"
#include "ui.h"

#include "cards.h"
#include "icongroup.h"

#include "../../game/game.h"
#include "../../player/player.h"
#include "../../misc/setting.h"

namespace UI_GTKMM_NS {

  /**
   **
   ** Constructor
   **
   ** @param	table	the table
   ** @param	player	the player
   **
   ** @return	-
   ** 
   ** @author	Diether Knof
   **
   ** @version	0.6.1
   **
   **/
  Hand::Hand(Table* const table, Player const* const player) :
    HTIN(table, player)
    {
      DEBUG_CALLING(INFO_GTKMM_HAND && INFO_GTKMM_INIT,
		    "Hand::Hand(table, player)");

      DEBUG_RETURNING(VOID,
		      INFO_GTKMM_HAND && INFO_GTKMM_INIT,
		      "Hand::Hand(table, player)");
    } // Hand::Hand(Table* const table, Player const* const player)

  /**
   **
   ** Destruktor
   **
   ** @param	-
   **
   ** @return	-
   ** 
   ** @author	Diether Knof
   **
   ** @version	0.6.1
   **
   **/
  Hand::~Hand()
  {
    DEBUG_CALLING(INFO_GTKMM_HAND && INFO_GTKMM_INIT,
		  "Hand::~Hand()");

    DEBUG_RETURNING(VOID,
		    INFO_GTKMM_HAND && INFO_GTKMM_INIT,
		    "Hand::~Hand()");
  } // Hand::~Hand()

  /**
   **
   ** draws the hand
   **
   ** @param	update	whether to update the area
   **
   ** @return	-
   ** 
   ** @author	Diether Knof
   **
   ** @version	0.6.1
   **
   **/
  void
    Hand::draw(bool const update)
    {
      DEBUG_CALLING(INFO_GTKMM_HAND && INFO_GTKMM_DRAW,
		    "Hand::draw(update)");

      if ((::game_status >= GAMESTATUS::GAME_INIT)
	  && (::game_status <= GAMESTATUS::GAME_FINISHED)) {
	if (update)
	  this->table().clear(Gdk::Rectangle(this->pos_x(), this->pos_y(),
					     this->width(), this->height()));

	bool const show = ((this->player->type() == Player::HUMAN)
			   || ::setting(Setting::SHOW_ALL_HANDS)
			   || (::game_status == GAMESTATUS::GAME_FINISHED)
			   || ( (::game_status == GAMESTATUS::GAME_REDISTRIBUTE)
				&& (*(this->player)
				    == this->player->game().soloplayer()) )
			  );
	// draw the cards
	for (unsigned c = 0; c < this->player->hand().cardsnumber_all(); c++) {
	  if ( (show
		? !this->player->sorted_hand().played(c)
		: !this->player->hand().played(c) )
	      || (::game_status == GAMESTATUS::GAME_FINISHED)) {

	    Glib::RefPtr<Gdk::Pixbuf> const
	      card = (show
		      ? this->ui->cards->card(this->player->sorted_hand().card_all(c),
					      this->rotation())
		      : this->ui->cards->back(this->rotation())
		     );

	    this->table().pixmap->draw_pixbuf(this->table().gc,
					      card,
					      0, 0,
					      this->start_x() +
					      static_cast<int>(this->cards_step_x() * c),
					      this->start_y() +
					      static_cast<int>(this->cards_step_y() * c),
					      -1, -1,
					      Gdk::RGB_DITHER_NONE,
					      0, 0);
	  } // if (!this->player->hand().played(c))
	} // for (c < this->player->hand().cardsnumber_all()

	if (update)
	  this->table().update(Gdk::Rectangle(this->pos_x(), this->pos_y(),
					      this->width(), this->height()));

      } // if (GAME_RESERVATION <= game_status < GAME_FINISHED)

      DEBUG_RETURNING(VOID,
		      INFO_GTKMM_HAND && INFO_GTKMM_DRAW,
		      "Hand::draw(update)");
    } // void Hand::draw(bool const update = true)

  /**
   **
   ** -> result
   **
   ** @param	position	Position of the hand
   **
   ** @return	upper left x position of the hand at 'position'
   ** 
   ** @version	0.6.1
   **
   ** @author	Diether Knof
   **
   **/
  int
    Hand::pos_x(Position const position) const
    {
      DEBUG_CALLING(INFO_GTKMM_HAND && INFO_GTKMM_VALUE,
		    "Hand::pos_x(position)");

      int value = 0; // return value

      switch(position) {
      case NORTH:
      case SOUTH:
	value = (this->table().border_x()
		 + this->width(WEST)
		 + this->margin_x(WEST)
		 + this->icongroup().width(WEST)
		 + this->icongroup().margin_x(WEST));
	break;
      case WEST:
	value = this->table().border_x();
	break;
      case EAST:
	value = (this->table().width() - this->table().border_x()
		 - this->width());
	break;
      } // switch(position)

      DEBUG_RETURNING(value,
		      INFO_GTKMM_HAND && INFO_GTKMM_VALUE,
		      "Hand::pos_x(position)");
    } // int Hand::pos_x(Position const position)

  /**
   **
   ** -> result
   **
   ** @param	position	Position of the hand
   **
   ** @return	upper left y position of the hand at 'position'
   ** 
   ** @version	0.6.1
   **
   ** @author	Diether Knof
   **
   **/
  int
    Hand::pos_y(Position const position) const
    {
      DEBUG_CALLING(INFO_GTKMM_HAND && INFO_GTKMM_VALUE,
		    "Hand::pos_y(position)");

      int value = 0; // return value

      switch(position) {
      case NORTH:
	value = this->table().border_y();
	break;
      case SOUTH:
	value = (this->table().height()
		 - this->table().border_y()
		 - this->height());
	break;
      case WEST:
      case EAST:
	value = (this->table().border_y()
		 + this->height(NORTH)
		 + this->margin_y(NORTH)
		 + this->icongroup().height(NORTH)
		 + this->icongroup().margin_y(NORTH));
	break;
      } // switch(position)

      DEBUG_RETURNING(value,
		      INFO_GTKMM_HAND && INFO_GTKMM_VALUE,
		      "Hand::pos_y(position)");
    } // int Hand::pos_y(Position const position)

  /**
   **
   ** -> result
   **
   ** @param	position	Position of the hand
   **
   ** @return	width of the hand at 'position'
   ** 
   ** @version	0.6.1
   **
   ** @author	Diether Knof
   **
   **/
  int
    Hand::width(Position const position) const
    {
      DEBUG_CALLING(INFO_GTKMM_HAND && INFO_GTKMM_VALUE,
		    "Hand::width(position)");

      int value = 0; // return value

      switch(position) {
      case NORTH:
      case SOUTH:
	value = (this->table().width()
		 - this->table().border_x()
		 - this->width(WEST)
		 - this->margin_x(WEST)
		 - this->icongroup().width(WEST)
		 - this->icongroup().margin_x(WEST)
		 - this->table().border_x()
		 - this->width(EAST)
		 - this->margin_x(EAST)
		 - this->icongroup().width(EAST)
		 - this->icongroup().margin_x(EAST));
	break;
      case WEST:
      case EAST:
	value = this->ui->cards->width(this->rotation(position));
	break;
      } // switch(position)

      DEBUG_RETURNING(value,
		      INFO_GTKMM_HAND && INFO_GTKMM_VALUE,
		      "Hand::width(position)");
    } // int Hand::width(Position const position)

  /**
   **
   ** -> result
   **
   ** @param	position	Position of the hand
   **
   ** @return	height of the hand at 'position'
   ** 
   ** @version	0.6.1
   **
   ** @author	Diether Knof
   **
   **/
  int
    Hand::height(Position const position) const
    {
      DEBUG_CALLING(INFO_GTKMM_HAND && INFO_GTKMM_VALUE,
		    "Hand::height(position)");

      int value = 0; // return value

      switch(position) {
      case NORTH:
      case SOUTH:
	value = this->ui->cards->height(this->rotation(position));
	break;
      case WEST:
      case EAST:
	value = (this->table().height()
		 - this->table().border_y()
		 - this->height(NORTH)
		 - this->margin_y(NORTH)
		 - this->icongroup().height(NORTH)
		 - this->icongroup().margin_y(NORTH)
		 - this->table().border_y()
		 - this->height(SOUTH)
		 - this->margin_y(SOUTH)
		 - this->icongroup().height(SOUTH)
		 - this->icongroup().margin_y(SOUTH));
	break;
      } // switch(position)

      DEBUG_RETURNING(value,
		      INFO_GTKMM_HAND && INFO_GTKMM_VALUE,
		      "Hand::height(position)");
    } // int Hand::height(Position const position)

  /**
   **
   ** -> result
   **
   ** @param	position	Position of the hand
   **
   ** @return	starting x position of the hand at 'position'
   ** 
   ** @version	0.6.1
   **
   ** @author	Diether Knof
   **
   **/
  int
    Hand::start_x(Position const position) const
    {
      DEBUG_CALLING(INFO_GTKMM_HAND && INFO_GTKMM_VALUE,
		    "Hand::start_x(position)");

      DEBUG_RETURNING(this->pos_x(position),
		      INFO_GTKMM_HAND && INFO_GTKMM_VALUE,
		      "Hand::start_x(position)");
    } // int Hand::start_x(Position const position)

  /**
   **
   ** -> result
   **
   ** @param	position	Position of the hand
   **
   ** @return	starting y position of the hand at 'position'
   ** 
   ** @version	0.6.1
   **
   ** @author	Diether Knof
   **
   **/
  int
    Hand::start_y(Position const position) const
    {
      DEBUG_CALLING(INFO_GTKMM_HAND && INFO_GTKMM_VALUE,
		    "Hand::start_y(position)");

      DEBUG_RETURNING(this->pos_y(position),
		      INFO_GTKMM_HAND && INFO_GTKMM_VALUE,
		      "Hand::start_y(position)");
    } // int Hand::start_y(Position const position)

  /**
   **
   ** -> result
   **
   ** @param	position	Position of the hand
   **
   ** @return	the x margin at 'position
   ** 
   ** @version	0.6.1
   **
   ** @author	Diether Knof
   **
   **/
  int
    Hand::margin_x(Position const position) const
    {
      DEBUG_CALLING(INFO_GTKMM_HAND && INFO_GTKMM_VALUE,
		    "Hand::margin_x(position)");

      int value = 0;

      switch(position) {
      case NORTH:
      case SOUTH:
	value = (this->ui->cards->height() / 20);
	break;
      case WEST:
      case EAST:
	value = (this->ui->cards->height() / 20);
	break;
      } // switch(position)

      DEBUG_RETURNING(value,
		      INFO_GTKMM_HAND && INFO_GTKMM_VALUE,
		      "Hand::margin_x(position)");
    } // int Hand::margin_x(Position const position)

  /**
   **
   ** -> result
   **
   ** @param	position	Position of the hand
   **
   ** @return	the y margin at 'position
   ** 
   ** @version	0.6.1
   **
   ** @author	Diether Knof
   **
   **/
  int
    Hand::margin_y(Position const position) const
    {
      DEBUG_CALLING(INFO_GTKMM_HAND && INFO_GTKMM_VALUE,
		    "Hand::margin_y(position)");

      int value = 0;

      switch(position) {
      case NORTH:
      case SOUTH:
	value = (this->ui->cards->height() / 20);
	break;
      case WEST:
      case EAST:
	value = (this->ui->cards->height() / 20);
	break;
      } // switch(position)

      DEBUG_RETURNING(value,
		      INFO_GTKMM_HAND && INFO_GTKMM_VALUE,
		      "Hand::margin_y(position)");
    } // int Hand::margin_y(Position const position)

  /**
   **
   ** -> result
   **
   ** @param	-
   **
   ** @return	upper left x position of the hand
   ** 
   ** @version	0.6.1
   **
   ** @author	Diether Knof
   **
   **/
  int
    Hand::pos_x() const
    {
      DEBUG_CALLING(INFO_GTKMM_HAND && INFO_GTKMM_VALUE,
		    "Hand::pos_x()");

      DEBUG_RETURNING(this->pos_x(this->position()),
		      INFO_GTKMM_HAND && INFO_GTKMM_VALUE,
		      "Hand::pos_x()");
    } // int Hand::pos_x()

  /**
   **
   ** -> result
   **
   ** @param	-
   **
   ** @return	upper left y position of the hand
   ** 
   ** @version	0.6.1
   **
   ** @author	Diether Knof
   **
   **/
  int
    Hand::pos_y() const
    {
      DEBUG_CALLING(INFO_GTKMM_HAND && INFO_GTKMM_VALUE,
		    "Hand::pos_y()");

      DEBUG_RETURNING(this->pos_y(this->position()),
		      INFO_GTKMM_HAND && INFO_GTKMM_VALUE,
		      "Hand::pos_y()");
    } // int Hand::pos_y()

  /**
   **
   ** -> result
   **
   ** @param	-
   **
   ** @return	width of the hand
   ** 
   ** @version	0.6.1
   **
   ** @author	Diether Knof
   **
   **/
  int
    Hand::width() const
    {
      DEBUG_CALLING(INFO_GTKMM_HAND && INFO_GTKMM_VALUE,
		    "Hand::width()");

      DEBUG_RETURNING(this->width(this->position()),
		      INFO_GTKMM_HAND && INFO_GTKMM_VALUE,
		      "Hand::width()");
    } // int Hand::width()

  /**
   **
   ** -> result
   **
   ** @param	-
   **
   ** @return	height of the hand
   ** 
   ** @version	0.6.1
   **
   ** @author	Diether Knof
   **
   **/
  int
    Hand::height() const
    {
      DEBUG_CALLING(INFO_GTKMM_HAND && INFO_GTKMM_VALUE,
		    "Hand::height()");

      DEBUG_RETURNING(this->height(this->position()),
		      INFO_GTKMM_HAND && INFO_GTKMM_VALUE,
		      "Hand::height()");
    } // int Hand::height()

  /**
   **
   ** -> result
   **
   ** @param	-
   **
   ** @return	starting x position of the hand
   ** 
   ** @version	0.6.1
   **
   ** @author	Diether Knof
   **
   **/
  int
    Hand::start_x() const
    {
      DEBUG_CALLING(INFO_GTKMM_HAND && INFO_GTKMM_VALUE,
		    "Hand::start_x()");

      DEBUG_RETURNING(this->start_x(this->position()),
		      INFO_GTKMM_HAND && INFO_GTKMM_VALUE,
		      "Hand::start_x()");
    } // int Hand::start_x()

  /**
   **
   ** -> result
   **
   ** @param	-
   **
   ** @return	starting y position of the hand
   ** 
   ** @version	0.6.1
   **
   ** @author	Diether Knof
   **
   **/
  int
    Hand::start_y() const
    {
      DEBUG_CALLING(INFO_GTKMM_HAND && INFO_GTKMM_VALUE,
		    "Hand::start_y()");

      DEBUG_RETURNING(this->start_y(this->position()),
		      INFO_GTKMM_HAND && INFO_GTKMM_VALUE,
		      "Hand::start_y()");
    } // int Hand::start_y()

  /**
   **
   ** -> result
   **
   ** @param	-
   **
   ** @return	x step of the cards
   ** 
   ** @version	0.6.1
   **
   ** @author	Diether Knof
   **
   **/
  double
    Hand::cards_step_x() const
    {
      DEBUG_CALLING(INFO_GTKMM_HAND && INFO_GTKMM_VALUE,
		    "Hand::cards_step_x()");

      if (this->player->hand().cardsnumber_all() == 0)
	DEBUG_RETURNING(0,
			INFO_GTKMM_HAND && INFO_GTKMM_VALUE,
			"Hand::cards_step_x()");

      double value = 0;

      switch(this->position()) {
      case NORTH:
      case SOUTH:
	value = ((this->width(this->position())
		  - this->ui->cards->width(this->rotation(this->position())))
		 / static_cast<double>(this->player->hand().cardsnumber_all()
				       - 1));
	break;
      case WEST:
      case EAST:
	value = 0;
	break;
      } // switch(this->position())

      DEBUG_RETURNING(value,
		      INFO_GTKMM_HAND && INFO_GTKMM_VALUE,
		      "Hand::cards_step_x()");
    } // double Hand::cards_step_x()

  /**
   **
   ** -> result
   **
   ** @param	-
   **
   ** @return	y step of the cards
   ** 
   ** @version	0.6.1
   **
   ** @author	Diether Knof
   **
   **/
  double
    Hand::cards_step_y() const
    {
      DEBUG_CALLING(INFO_GTKMM_HAND && INFO_GTKMM_VALUE,
		    "Hand::cards_step_y()");

      if (this->player->hand().cardsnumber_all() <= 1)
	DEBUG_RETURNING(0,
			INFO_GTKMM_HAND && INFO_GTKMM_VALUE,
			"Hand::cards_step_y()");

      double value = 0;

      switch(this->position()) {
      case NORTH:
      case SOUTH:
	value = 0;
	break;
      case WEST:
      case EAST:
	value = ((this->height(this->position())
		  - this->ui->cards->height(this->rotation(this->position())))
		 / static_cast<double>(this->player->hand().cardsnumber_all()
				       - 1));
	break;
      } // switch(this->position())

      DEBUG_RETURNING(value,
		      INFO_GTKMM_HAND && INFO_GTKMM_VALUE,
		      "Hand::cards_step_y()");
    } // double Hand::cards_step_y()

  /**
   **
   ** -> result
   **
   ** @param	-
   **
   ** @return	the horizontal margin of the hand (to the center of the table)
   ** 
   ** @version	0.6.1
   **
   ** @author	Diether Knof
   **
   **/
  int
    Hand::margin_x() const
    {
      DEBUG_CALLING(INFO_GTKMM_HAND && INFO_GTKMM_VALUE,
		    "Hand::margin_x()");

      DEBUG_RETURNING(this->margin_x(this->position()),
		      INFO_GTKMM_HAND && INFO_GTKMM_VALUE,
		      "Hand::margin_x()");
    } // int Hand::margin_x()

  /**
   **
   ** -> result
   **
   ** @param	-
   **
   ** @return	the vertical margin of the hand (to the center of the table)
   ** 
   ** @version	0.6.1
   **
   ** @author	Diether Knof
   **
   **/
  int
    Hand::margin_y() const
    {
      DEBUG_CALLING(INFO_GTKMM_HAND && INFO_GTKMM_VALUE,
		    "Hand::margin_y()");

      DEBUG_RETURNING(this->margin_y(this->position()),
		      INFO_GTKMM_HAND && INFO_GTKMM_VALUE,
		      "Hand::margin_y()");
    } // int Hand::margin_y()

  /**
   **
   ** -> result
   **
   ** @param	x	x position
   ** @param	y	y position
   **
   ** @return	the number of the card at the given position,
   **		UINT_MAX, if there is no card
   ** 
   ** @version	0.6.1
   **
   ** @author	Diether Knof
   **
   ** @todo	check for transparency
   **
   **/
  unsigned
    Hand::cardno_at_position(int const x, int const y) const
    {
      DEBUG_CALLING(INFO_GTKMM_HAND && INFO_GTKMM_VALUE,
		    "Hand::cardno_at_position(x, y)");

      if ((x >= this->start_x())
	  && (x < this->start_x() + this->width())
	  && (y >= this->start_y())
	  && (y < this->start_y() + this->height())
	 ) {
	for (unsigned cb = this->player->sorted_hand().cardsnumber_all();
	     cb > 0;
	     cb--) {
	  unsigned const c = cb - 1;
	  if (!this->player->sorted_hand().played(c))
	    if ((x >= this->start_x() + c * this->cards_step_x())
		&& (x < (this->start_x() + c * this->cards_step_x()
			 + this->ui->cards->width(this->rotation())))
		&& (y >= this->start_y() + c * this->cards_step_y())
		&& (y < (this->start_y() + c * this->cards_step_y()
			 + this->ui->cards->height(this->rotation())))
	       )
	      // the position is over the card
	      // ToDo: check for transparency
	      DEBUG_RETURNING(c,
			      INFO_GTKMM_HAND && INFO_GTKMM_VALUE,
			      "Hand::cardno_at_position(x, y)");
	}
      } // if (position over hand)

      DEBUG_RETURNING(UINT_MAX,
		      INFO_GTKMM_HAND && INFO_GTKMM_VALUE,
		      "Hand::cardno_at_position(x, y)");
    } // unsigned Hand::cardno_at_position(int const x, int const y) const

  /**
   **
   ** -> result
   **
   ** @param	x	x position
   ** @param	y	y position
   **
   ** @return	the card at the given position
   **		Card(), if there is no card
   ** 
   ** @version	0.6.5
   **
   ** @author	Diether Knof
   **
   **/
  Card
    Hand::card_at_position(int const x, int const y) const
    {
      DEBUG_CALLING(INFO_GTKMM_HAND && INFO_GTKMM_VALUE,
		    "Hand::card_at_position(x, y)");

      unsigned const cardno = this->cardno_at_position(x, y);

      if (cardno == UINT_MAX)
	DEBUG_RETURNING(Card(),
			INFO_GTKMM_HAND && INFO_GTKMM_VALUE,
			"Hand::card_at_position(x, y)");

      DEBUG_RETURNING(this->player->sorted_hand().card_all(cardno),
		      INFO_GTKMM_HAND && INFO_GTKMM_VALUE,
		      "Hand::card_at_position(x, y)");
    } // Card Hand::card_at_position(int const x, int const y) const

} // namespace UI_GTKMM_NS

#endif // #ifdef USE_UI_GTKMM
