/**********************************************************************
 *
 *   FreeDoko a Doppelkopf-Game
 *    
 *   Copyright (C) 2001-2006  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 "poverty.h"

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

#include "../../game/game.h"
#include "../../party/rule.h"
#include "../../player/player.h"
#include "../../card/hand.h"

#include <gtkmm/main.h>

namespace UI_GTKMM_NS {
  /**
   **
   ** Constructor
   **
   ** @param	-
   **
   ** @return	-
   ** 
   ** @author	Diether Knof
   **
   ** @version	0.6.2
   **
   **/
  Poverty::Poverty(Table* const table, Game& game) :
    Base(table),
    table(table),
    game(&game),
    player(NULL),
    cards(),
    status(INVALID),
    shift_cards(false),
    accept_cards(false)
  {
    return ;
  } // Poverty::Poverty(Table* const table, Game& game)

  /**
   **
   ** Destructor
   **
   ** @param	-
   **
   ** @return	-
   ** 
   ** @author	Diether Knof
   **
   ** @version	0.6.2
   **
   **/
  Poverty::~Poverty()
  {
    return ;
  } // Poverty::~Poverty()

  /**
   **
   ** -> result
   **
   ** @param	-
   **
   ** @return	whether the active player can shift
   ** 
   ** @version	0.6.2
   **
   ** @author	Diether Knof
   **
   **/
  bool
    Poverty::middle_full() const
    {
      for (HandCards::const_iterator card = this->cards.begin();
	   card != this->cards.end();
	   card++)
	if (*card == Card())
	  return false;

      return true;
    } // bool Poverty::middle_full() const

  /**
   **
   ** -> result
   **
   ** @param	-
   **
   ** @return	whether the active player can shift
   ** 
   ** @version	0.6.2
   **
   ** @author	Diether Knof
   **
   **/
  bool
    Poverty::shifting_valid() const
    {
      if (this->player->type() != Player::HUMAN)
	return false;

      bool valid = false;

      switch (this->status) {
      case INVALID:
	valid = false;
	break;
      case ASKING:
	valid = true;
	break;
      case SHIFTING:
      case SHIFTING_BACK:
	valid = this->middle_full();
	break;
      case GETTING_BACK:
	valid = false;
	break;
      case ACCEPTED:
      case DENIED_BY_ALL:
      case FINISHED:
	valid = false;
	break;
      } // switch (this->status)

      return valid;
    } // bool Poverty::shifting_valid() const

  /**
   **
   ** 'player' shifts 'cardno' cards
   **
   ** @param	player	the player who shifts the cards
   ** @param	cardno	the number of cards that are shifted
   **
   ** @return	-
   **
   ** @version	0.6.2
   **
   ** @author	Diether Knof
   **
   **/
  void
    Poverty::shift(Player const& player, unsigned const cardno)
    { 
      this->status = ASKING;
      this->table->draw_all();

      return ;
    } // void Poverty::shift(Player const& player, unsigned const cardno)

  /**
   **
   ** 'player' denied to take the shifted cards
   **
   ** @param	player	the player who has denied to take the cards
   **
   ** @return	-
   **
   ** @version	0.6.2
   **
   ** @author	Diether Knof
   **
   **/
  void
    Poverty::take_denied(Player const& player)
    { 
      return ;
    } // void Poverty::take_denied(Player const& player)

  /**
   **
   ** all players have denied to take the cards
   **
   ** @param	-
   **
   ** @return	-
   **
   ** @version	0.6.4
   **
   ** @author	Diether Knof
   **
   **/
  void
    Poverty::take_denied_by_all()
    { 
      this->player = &(this->player->game().soloplayer());
      this->status = DENIED_BY_ALL;

      return ;
    } // void Poverty::take_denied_by_all()

  /**
   **
   ** 'player' accepts to take the shifted cards
   ** and returns 'cardno' cards with 'trumpno' trumps
   ** show the cards and wait for a click
   **
   ** @param	player	the player who has denied to take the cards
   ** @param	cardno	number of cards that are given back
   ** @param	trumpno	number of trumps of the cards
   **
   ** @return	-
   **
   ** @version	0.6.2
   **
   ** @author	Diether Knof
   **
   **/
  void
    Poverty::take_accepted(Player const& player,
			   unsigned const cardno, unsigned const trumpno)
    { 
      this->status = ACCEPTED;

      return ;
    } // void Poverty::take_accepted(Player const& player, unsigned const cardno, unsigned const trumpno)

  /**
   **
   ** returns which cards the player shifts
   **
   ** @param	player	the player who shifts the cards (the soloplayer)
   **
   ** @return	the cards that are to be shifted
   **
   ** @version	0.6.2
   **
   ** @author	Diether Knof
   **
   **/
  HandCards
    Poverty::shift(Player& player)
    { 
      this->status = SHIFTING;

      this->cards = HandCards(player.game().poverty_cardno());
      this->player = &player;

      this->shift_cards = false;

      // put all trump in the middle
      unsigned j = 0;
      for (unsigned i = 0; i < player.sorted_hand().cardsnumber_all(); i++)
	if (player.sorted_hand().card_all(i).istrump()) {
	  this->cards[j] = player.sorted_hand().card_all(i);
	  player.sorted_hand().playcard(i - j);
	  j += 1;
	}

      this->draw();
      this->table->hand(player).draw();
      this->table->icongroup(player).draw();

      while (!this->ui->thrower
	     && (::game_status == GAMESTATUS::GAME_POVERTY_SHIFT)
	     && (this->shift_cards == false))
	Gtk::Main::iteration();
      if (this->ui->thrower)
	return HandCards();

      if (::game_status != GAMESTATUS::GAME_POVERTY_SHIFT)
	return this->cards;

      // remove the cards to shift from the hand of the player
      player.sorted_hand().remove(this->cards);

      return this->cards;
    } // HandCards Poverty::shift(Player& player)

  /**
   **
   ** ask 'player' whether to accept the poverty
   **
   ** @param	player	the player who is asked
   ** @param	cardno	the number of shifted cards
   **
   ** @return	-
   **
   ** @version	0.6.2
   **
   ** @author	Diether Knof
   **
   **/
  void
    Poverty::ask(Player const& player, unsigned const cardno)
    { 
      this->cards = HandCards(cardno);
      this->player = &player;

      this->table->draw_all();

      return ;
    } // void Poverty::ask(Player const& player, unsigned const cardno)

  /**
   **
   ** returns whether 'player' accepts the shifted cards
   **
   ** @param	player	the player who shifts the cards
   ** @param	cardno	the number of shifted cards
   **
   ** @return	whether to accept the cards
   **
   ** @version	0.6.2
   **
   ** @author	Diether Knof
   **
   **/
  bool
    Poverty::take_accept(Player& player, unsigned const cardno)
    { 
      this->status = ASKING;

      this->cards = HandCards(cardno);
      this->player = &player;

      this->accept_cards = false;
      this->shift_cards = false;

      this->draw();
      this->table->hand(player).draw();

      while (!this->ui->thrower
	     && (::game_status == GAMESTATUS::GAME_POVERTY_SHIFT)
	     && (this->accept_cards == false)
	     && (this->shift_cards == false))
	Gtk::Main::iteration();
      if (this->ui->thrower)
	return false;

#ifdef WORKAROUND
      // without this there is a graphic bug
      this->status = ACCEPTED;
#endif

      return this->accept_cards;
    } // bool Poverty::take_accept(Player& player, unsigned const cardno)

  /**
   **
   ** changes the cards from the poverty-player
   **
   ** @param	player		the player who has accepted the cards
   ** @param	card_shifted	the cards that are given to the player
   **
   ** @return	the cards that are returned to the poverty-player
   **
   ** @version	0.6.2
   **
   ** @author	Diether Knof
   **
   **/
  HandCards
    Poverty::cards_change(Player& player, HandCards const& cards_shifted)
    { 
      this->status = SHIFTING_BACK;

      this->player = &player;

      this->accept_cards = false;
      this->shift_cards = false;

      // add the cards to the hand, but mark all cards in the middle as played
      this->cards.clear();
      for (HandCards::const_iterator c = cards_shifted.begin();
	   c != cards_shifted.end();
	   ++c)
	this->cards.push_back(HandCard(player.hand(), *c));
      player.sorted_hand().add(cards_shifted);
      player.hand_sort();
      for (HandCards::const_iterator
	   card = this->cards.begin();
	   card != this->cards.end();
	   ++card)
	player.sorted_hand().playcard(*card);

      this->draw();
      this->table->hand(player).draw();

      while (!this->ui->thrower
	     && (::game_status == GAMESTATUS::GAME_POVERTY_SHIFT)
	     && (this->shift_cards == false))
	Gtk::Main::iteration();
      if (this->ui->thrower)
	return HandCards();

      // remove the cards to shift from the hand of the player
      player.sorted_hand().remove(this->cards);

      return this->cards;
    } // HandCards Poverty::cards_change(Player& player, HandCards cards_shifted)


  /**
   **
   ** changes the cards from the poverty-player
   **
   ** @param	player		the player who has accepted the cards
   ** @param	cards_returned	the cards that are given to the player
   **
   ** @return	the cards that are returned to the poverty-player
   **
   ** @version	0.6.3
   **
   ** @author	Diether Knof
   **
   **/
  void
    Poverty::cards_get_back(Player& player,
			    HandCards const& cards_returned)
    { 
      if (player.type() != Player::HUMAN)
	return ;

      this->status = GETTING_BACK;

      this->player = &player;

      this->cards.clear();
      for (HandCards::const_iterator c = cards_returned.begin();
	   c != cards_returned.end();
	   ++c)
	this->cards.push_back(HandCard(player.hand(), *c));

      this->accept_cards = false;

      // add the cards to the hand, but mark all cards in the middle as played
      player.sorted_hand().add(cards_returned);
      player.hand_sort();
      for (HandCards::const_iterator
	   card = this->cards.begin();
	   card != this->cards.end();
	   ++card)
	player.sorted_hand().playcard(*card);

      this->table->draw_all();

      while (!this->ui->thrower
	     && (::game_status == GAMESTATUS::GAME_POVERTY_SHIFT)
	     && (this->accept_cards == false))
	Gtk::Main::iteration();
      if (this->ui->thrower)
	return ;

      for (HandCards::const_iterator
	   card = this->cards.begin();
	   card != this->cards.end();
	   ++card)
	player.sorted_hand().unplaycard(*card);

      this->status = FINISHED;

      return ;
    } // void Poverty::cards_get_back(Player& player, HandCards cards_returned)

  /**
   **
   ** -> result
   **
   ** @param	player	the player, whose arrow is requested
   **
   ** @return	outline rectangle of the arrow
   ** 
   ** @version	0.6.2
   **
   ** @author	Diether Knof
   **
   **/
  Gdk::Point
    Poverty::card_pos(unsigned const cardno) const
    {
      DEBUG_ASSERTION((cardno <= Rule::MAX_NUMBER_OF_POVERTY_TRUMPS),
		      "Poverty::card_pos(player, cardno):\n"
		      "  `cardno` not valid");

      Gdk::Point pos;
      Gdk::Rectangle const arrow_outline = this->arrow_outline();
      Player const& player = *(this->player);

      switch (this->table->position(player)) {
      case SOUTH: // player.no
	switch(this->game->poverty_cardno()) {
	case 0: // this->game->poverty_cardno()
	  pos.set_x(this->table->hand(player).start_x()
		    + this->table->hand(player).width() / 2
		    - this->ui->cards->height() / 2);
	  pos.set_y(arrow_outline.get_y() - arrow_outline.get_height() / 2
		    - this->ui->cards->width());
	  break;
	case 1: // this->game->poverty_cardno()
	  switch(cardno) {
	  case 0:
	    pos.set_x(this->table->hand(player).start_x()
		      + this->table->hand(player).width() / 2
		      - this->ui->cards->width() / 2);
	    pos.set_y(arrow_outline.get_y() - arrow_outline.get_height() / 2
		      - this->ui->cards->height());
	    break;
	  default:
	    break;
	  } // switch(cardno)
	  break;
	case 2: // this->game->poverty_cardno()
	  switch(cardno) {
	  case 0:
	    pos.set_x(this->table->hand(player).start_x()
		      + this->table->hand(player).width() / 4);
	    pos.set_y(arrow_outline.get_y() - arrow_outline.get_height() / 2
		      - this->ui->cards->height());
	    break;
	  case 1:
	    pos.set_x(this->table->hand(player).start_x()
		      + this->table->hand(player).width()
		      - this->table->hand(player).width() / 4
		      - this->ui->cards->width());
	    pos.set_y(arrow_outline.get_y() - arrow_outline.get_height() / 2
		      - this->ui->cards->height());
	    break;
	  default:
	    break;
	  } // switch(cardno)
	  break;
	case 3: // this->game->poverty_cardno()
	  switch(cardno) {
	  case 0:
	    pos.set_x(this->table->hand(player).start_x()
		      + this->table->hand(player).width() / 8);
	    pos.set_y(arrow_outline.get_y() - arrow_outline.get_height() / 2
		      - this->ui->cards->height());
	    break;
	  case 1:
	    pos.set_x(this->table->hand(player).start_x()
		      + this->table->hand(player).width() / 2
		      - this->ui->cards->width() / 2);
	    pos.set_y(arrow_outline.get_y() - arrow_outline.get_height() / 2
		      - this->ui->cards->height() / 3
		      - this->ui->cards->height());
	    break;
	  case 2:
	    pos.set_x(this->table->hand(player).start_x()
		      + this->table->hand(player).width()
		      - this->table->hand(player).width() / 8
		      - this->ui->cards->width());
	    pos.set_y(arrow_outline.get_y() - arrow_outline.get_height() / 2
		      - this->ui->cards->height());
	    break;
	  default:
	    break;
	  } // switch(cardno)
	  break;
	default: // this->game->poverty_cardno()
	  break;
	} // switch(this->game->poverty_cardno())
	break;
      case NORTH: // player.no()
	switch(this->game->poverty_cardno()) {
	case 0: // this->game->poverty_cardno()
	  pos.set_x(this->table->hand(player).start_x()
		    + this->table->hand(player).width() / 2
		    - this->ui->cards->height() / 2);
	  pos.set_y(arrow_outline.get_y() + arrow_outline.get_height() * 3 / 2);
	  break;
	case 1: // this->game->poverty_cardno()
	  switch(cardno) {
	  case 0:
	    pos.set_x(this->table->hand(player).start_x()
		      + this->table->hand(player).width() / 2
		      - this->ui->cards->width() / 2);
	    pos.set_y(arrow_outline.get_y() + arrow_outline.get_height() * 3 / 2);
	    break;
	  default:
	    break;
	  } // switch(cardno)
	  break;
	case 2: // this->game->poverty_cardno()
	  switch(cardno) {
	  case 0:
	    pos.set_x(this->table->hand(player).start_x()
		      + this->table->hand(player).width()
		      - this->table->hand(player).width() / 4
		      - this->ui->cards->width());
	    pos.set_y(arrow_outline.get_y() + arrow_outline.get_height() * 3 / 2);
	    break;
	  case 1:
	    pos.set_x(this->table->hand(player).start_x()
		      + this->table->hand(player).width() / 4);
	    pos.set_y(arrow_outline.get_y() + arrow_outline.get_height() * 3 / 2);
	    break;
	  default:
	    break;
	  } // switch(cardno)
	  break;
	case 3: // this->game->poverty_cardno()
	  switch(cardno) {
	  case 0:
	    pos.set_x(this->table->hand(player).start_x()
		      + this->table->hand(player).width()
		      - this->table->hand(player).width() / 8
		      - this->ui->cards->width());
	    pos.set_y(arrow_outline.get_y() + arrow_outline.get_height() * 3 / 2);
	    break;
	  case 1:
	    pos.set_x(this->table->hand(player).start_x()
		      + this->table->hand(player).width() / 2
		      - this->ui->cards->width() / 2);
	    pos.set_y(arrow_outline.get_y() + arrow_outline.get_height() * 3 / 2
		      + this->ui->cards->height() / 3);
	    break;
	  case 2:
	    pos.set_x(this->table->hand(player).start_x()
		      + this->table->hand(player).width() / 8);
	    pos.set_y(arrow_outline.get_y() + arrow_outline.get_height() * 3 / 2);
	    break;
	  default:
	    break;
	  } // switch(cardno)
	  break;
	default: // this->game->poverty_cardno()
	  break;
	} // switch(this->game->poverty_cardno())
	break;
      case WEST: // player.no()
	switch(this->game->poverty_cardno()) {
	case 0: // this->game->poverty_cardno()
	  pos.set_x(arrow_outline.get_x() + arrow_outline.get_width() * 3 / 2);
	  pos.set_y(this->table->hand(player).start_y()
		    + this->table->hand(player).height() / 2
		    - this->ui->cards->height() / 2);
	  break;
	case 1: // this->game->poverty_cardno()
	  switch(cardno) {
	  case 0:
	    pos.set_x(arrow_outline.get_x() + arrow_outline.get_width() * 3 / 2);
	    pos.set_y(this->table->hand(player).start_y()
		      + this->table->hand(player).height() / 2
		      - this->ui->cards->width() / 2);
	    break;
	  default:
	    break;
	  } // switch(cardno)
	  break;
	case 2: // this->game->poverty_cardno()
	  switch(cardno) {
	  case 0:
	    pos.set_x(arrow_outline.get_x() + arrow_outline.get_width() * 3 / 2);
	    pos.set_y(this->table->hand(player).start_y()
		      + this->table->hand(player).height()
		      - this->table->hand(player).height() / 4
		      - this->ui->cards->width());
	    break;
	  case 1:
	    pos.set_x(arrow_outline.get_x() + arrow_outline.get_width() * 3 / 2);
	    pos.set_y(this->table->hand(player).start_y()
		      + this->table->hand(player).height() / 4);
	    break;
	  default:
	    break;
	  } // switch(cardno)
	  break;
	case 3: // this->game->poverty_cardno()
	  switch(cardno) {
	  case 0:
	    pos.set_x(arrow_outline.get_x() + arrow_outline.get_width() * 3 / 2);
	    pos.set_y(this->table->hand(player).start_y()
		      + this->table->hand(player).height()
		      - this->table->hand(player).height() / 8
		      - this->ui->cards->width());
	    break;
	  case 1:
	    pos.set_x(arrow_outline.get_x() + arrow_outline.get_width() * 3 / 2
		      + this->ui->cards->height() / 3);
	    pos.set_y(this->table->hand(player).start_y()
		      + this->table->hand(player).height() / 2
		      - this->ui->cards->width() / 2);
	    break;
	  case 2:
	    pos.set_x(arrow_outline.get_x() + arrow_outline.get_width() * 3 / 2);
	    pos.set_y(this->table->hand(player).start_y()
		      + this->table->hand(player).height() / 8);
	    break;
	  default:
	    break;
	  } // switch(cardno)
	  break;
	default: // this->game->poverty_cardno()
	  break;
	} // switch(this->game->poverty_cardno())
	break;
      case EAST: // player.no()
	switch(this->game->poverty_cardno()) {
	case 0: // this->game->poverty_cardno()
	  pos.set_x(arrow_outline.get_x() - arrow_outline.get_width() / 2
		    - this->ui->cards->width());
	  pos.set_y(this->table->hand(player).start_y()
		    + this->table->hand(player).height() / 2
		    - this->ui->cards->height() / 2);
	  break;
	case 1: // this->game->poverty_cardno()
	  switch(cardno) {
	  case 0:
	    pos.set_x(arrow_outline.get_x() - arrow_outline.get_width() / 2
		      - this->ui->cards->height());
	    pos.set_y(this->table->hand(player).start_y()
		      + this->table->hand(player).height() / 2
		      - this->ui->cards->width() / 2);
	    break;
	  default:
	    break;
	  } // switch(cardno)
	  break;
	case 2: // this->game->poverty_cardno()
	  switch(cardno) {
	  case 0:
	    pos.set_x(arrow_outline.get_x() - arrow_outline.get_width() / 2
		      - this->ui->cards->height());
	    pos.set_y(this->table->hand(player).start_y()
		      + this->table->hand(player).height()
		      - this->table->hand(player).height() / 4
		      - this->ui->cards->width());
	    break;
	  case 1:
	    pos.set_x(arrow_outline.get_x() - arrow_outline.get_width() / 2
		      - this->ui->cards->height());
	    pos.set_y(this->table->hand(player).start_y()
		      + this->table->hand(player).height() / 4);
	    break;
	  default:
	    break;
	  } // switch(cardno)
	  break;
	case 3: // this->game->poverty_cardno()
	  switch(cardno) {
	  case 0:
	    pos.set_x(arrow_outline.get_x() - arrow_outline.get_width() / 2
		      - this->ui->cards->height());
	    pos.set_y(this->table->hand(player).start_y()
		      + this->table->hand(player).height() / 8);
	    break;
	  case 1:
	    pos.set_x(arrow_outline.get_x() - arrow_outline.get_width() / 2
		      - this->ui->cards->height()
		      - this->ui->cards->height() / 3);
	    pos.set_y(this->table->hand(player).start_y()
		      + this->table->hand(player).height() / 2
		      - this->ui->cards->width() / 2);
	    break;
	  case 2:
	    pos.set_x(arrow_outline.get_x() - arrow_outline.get_width() / 2
		      - this->ui->cards->height());
	    pos.set_y(this->table->hand(player).start_y()
		      + this->table->hand(player).height()
		      - this->table->hand(player).height() / 8
		      - this->ui->cards->width());
	    break;
	  default:
	    break;
	  } // switch(cardno)
	  break;
	default: // this->game->poverty_cardno()
	  break;
	} // switch(this->game->poverty_cardno())
	break;
      } // switch (player->no())

      return pos;
    } // Gdk::Pos Poverty::card_pos(unsigned const cardno) const

  /**
   **
   ** -> result
   **
   ** @param	player	the player, whose arrow is requested
   **
   ** @return	outline rectangle of the arrow
   ** 
   ** @version	0.6.2
   **
   ** @author	Diether Knof
   **
   **/
  Gdk::Rectangle
    Poverty::arrow_outline() const
    {
      Gdk::Rectangle rectangle;
      Player const& player = *(this->player);

      switch (this->table->position(player)) {
      case SOUTH:
	rectangle.set_width(this->table->hand(player).width() / 2);
	rectangle.set_height(this->ui->cards->height() / 5);
	rectangle.set_x(this->table->hand(player).start_x()
			+ this->table->hand(player).width() / 4);
	rectangle.set_y(this->table->hand(player).start_y()
			- this->table->icongroup(player).margin_y()
			- this->table->icongroup(player).height()
			- rectangle.get_height()
			- rectangle.get_height() / 2);
	break;
      case NORTH:
	rectangle.set_width(this->table->hand(player).width() / 2);
	rectangle.set_height(this->ui->cards->height() / 5);
	rectangle.set_x(this->table->hand(player).start_x()
			+ this->table->hand(player).width() / 4);
	rectangle.set_y(this->table->hand(player).start_y()
			+ this->table->hand(player).height()
			+ this->table->icongroup(player).margin_y()
			+ this->table->icongroup(player).height()
			+ rectangle.get_height() / 2);
	break;
      case WEST:
	rectangle.set_width(this->ui->cards->height() / 5);
	rectangle.set_height(this->table->hand(player).height() / 2);
	rectangle.set_x(this->table->hand(player).start_x()
			+ this->table->hand(player).width()
			+ this->table->icongroup(player).margin_x()
			+ this->table->icongroup(player).width()
			+ rectangle.get_width() / 2);
	rectangle.set_y(this->table->hand(player).start_y()
			+ this->table->hand(player).height() / 4);
	break;
      case EAST:
	rectangle.set_width(this->ui->cards->height() / 5);
	rectangle.set_height(this->table->hand(player).height() / 2);
	rectangle.set_x(this->table->hand(player).start_x()
			- this->table->icongroup(player).margin_x()
			- this->table->icongroup(player).width()
			- rectangle.get_width()
			- rectangle.get_width() / 2);
	rectangle.set_y(this->table->hand(player).start_y()
			+ this->table->hand(player).height() / 4);
	break;
      } // switch (player->no())

      return rectangle;
    } // Gdk::Rectangle Poverty::arrow_outline() const

  /**
   **
   ** draws the poverty elements in the table
   **
   ** @param	player	the acting player
   ** @param	update	whether the window should be updated (default: true)
   **
   ** @return	-
   ** 
   ** @version	0.6.2
   **
   ** @author	Diether Knof
   **
   **/
  void
    Poverty::draw(bool const update)
    {
      if (this->player == NULL)
	return ;

      if ((this->status == INVALID)
	  || (this->status == ACCEPTED)
	  || (this->status == FINISHED))
	return ;

      Player const& player = *(this->player);

      { // draw the arrow
	Gdk::Rectangle outline = this->arrow_outline();

	this->table->clear(outline);

	if (this->shifting_valid()) {

	  int x, y, width, height;
	  vector<Gdk::Point> points;

	  bool const mirror = (this->status == SHIFTING_BACK);

	  switch(this->table->position(player)) {
	  case SOUTH:
	    x = outline.get_x() + (mirror ? 0 : outline.get_width() / 6);
	    y = outline.get_y() + outline.get_height() / 4;
	    width = outline.get_width() * 5 / 6;
	    height = outline.get_height() / 2;
	    points.push_back(Gdk::Point(x + (mirror ? width : 0),
					outline.get_y()));
	    points.push_back(Gdk::Point(points[0].get_x(),
					outline.get_y() + outline.get_height()));
	    points.push_back(Gdk::Point(outline.get_x() + (mirror ? outline.get_width() : 0),
					outline.get_y() + outline.get_height() / 2));
	    break;
	  case NORTH:
	    x = outline.get_x() + (mirror ? outline.get_width() / 6 : 0);
	    y = outline.get_y() + outline.get_height() / 4;
	    width = outline.get_width() * 5 / 6;
	    height = outline.get_height() / 2;
	    points.push_back(Gdk::Point(x + (mirror ? 0 : width),
					outline.get_y()));
	    points.push_back(Gdk::Point(points[0].get_x(),
					outline.get_y() + outline.get_height()));
	    points.push_back(Gdk::Point(outline.get_x() + (mirror ? 0 : outline.get_width()),
					outline.get_y() + outline.get_height() / 2));
	    break;
	  case WEST:
	    x = outline.get_x() + outline.get_width() / 4;
	    y = outline.get_y() + (mirror ? 0 : outline.get_height() / 6);
	    width = outline.get_width() / 2;
	    height = outline.get_height() * 5 / 6;
	    points.push_back(Gdk::Point(outline.get_x(),
					y + (mirror ? height : 0)));
	    points.push_back(Gdk::Point(outline.get_x() + outline.get_width(),
					points[0].get_y()));
	    points.push_back(Gdk::Point(outline.get_x() + outline.get_width() / 2,
					outline.get_y() + (mirror ? outline.get_height() : 0)));
	    break;
	  case EAST:
	    x = outline.get_x() + outline.get_width() / 4;
	    y = outline.get_y() + (mirror ? outline.get_height() / 6 : 0);
	    width = outline.get_width() / 2;
	    height = outline.get_height() * 5 / 6;
	    points.push_back(Gdk::Point(outline.get_x(),
					y + (mirror ? 0 : height)));
	    points.push_back(Gdk::Point(outline.get_x() + outline.get_width(),
					points[0].get_y()));
	    points.push_back(Gdk::Point(outline.get_x() + outline.get_width() / 2,
					outline.get_y() + (mirror ? 0 : outline.get_height())));
	    break;
	  default:
	    DEBUG_ASSERTION(false,
			    "Poverty::draw():\n"
			    "  `player.no()` not valid (not 0, 1, 2, 3)");
	    x = y = width = height = 0;
	    break;
	  } // switch(player->no())

	  // draw the arrow
	  this->table->pixmap->draw_rectangle(this->table->poverty_shift_arrow_gc,
					      true,
					      x, y, width, height);
	  this->table->pixmap->draw_polygon(this->table->poverty_shift_arrow_gc,
					    true,
					    points);
	  this->table->pixmap->draw_polygon(this->table->poverty_shift_arrow_gc,
					    false,
					    points);
	} // if (this->shifting_valid())

	// update the DrawingArea
	if (update)
	  this->table->update(outline);
      } // draw the arrow

      { // draw the cards
	unsigned const cardno = this->cards.size();

	if (cardno == 0) {
	  Gdk::Point const pos = this->card_pos(0);
	  Glib::RefPtr<Gdk::Pixbuf> card_pixbuf
	    = this->ui->cards->back(this->table->rotation(player));
	  this->table->pixmap->draw_pixbuf(this->table->poverty_shift_arrow_gc,
					   card_pixbuf,
					   0, 0,
					   pos.get_x(), pos.get_y(),
					   -1, -1,
					   Gdk::RGB_DITHER_NONE,
					   0, 0);
	  if (update)
	    this->table->update(Gdk::Rectangle(pos.get_x(), pos.get_y(),
					       card_pixbuf->get_width(),
					       card_pixbuf->get_height()));
	} else { // if !(cardno == 0)
	  for (unsigned i = 0; i < cardno; i++) {
	    Gdk::Point const pos = this->card_pos(i);
	    Glib::RefPtr<Gdk::Pixbuf> card_pixbuf
	      = this->ui->cards->card(this->cards[i],
				      this->table->rotation(player));
	    if ( ( (this->status == ASKING)
		   && this->game->rule()(Rule::SHOW_ALL_HANDS)
		   && ::setting(Setting::SHOW_ALL_HANDS))
		 || (this->status == DENIED_BY_ALL) )
	      card_pixbuf
		= this->ui->cards->card((*this->game->poverty_cards())[i],
					this->table->rotation(player));

	    this->table->pixmap->draw_pixbuf(this->table->poverty_shift_arrow_gc,
					     card_pixbuf,
					     0, 0,
					     pos.get_x(), pos.get_y(),
					     -1, -1,
					     Gdk::RGB_DITHER_NONE,
					     0, 0);
	    if (update)
	      this->table->update(Gdk::Rectangle(pos.get_x(), pos.get_y(),
						 card_pixbuf->get_width(),
						 card_pixbuf->get_height()));
	  } // for (i < cardno)
	} // if !(cardno == 0)
      } // draw the cards

      return ;
    } // void Poverty::draw(bool const update)

  /**
   **
   ** if the arrow is clicked, shift the cards
   ** if a card in the hand is clicked, move it in the cards-to-be-shifted
   ** if a card in the middle is clicked, move it in the hand
   **
   ** @param	button_event	data of the button event
   **
   ** @return	whether the click has been accepted
   ** 
   ** @version	0.6.2
   **
   ** @author	Diether Knof
   **
   **/
  bool
    Poverty::button_press_event(GdkEventButton* button_event)
    {
      // whether the mouse click leads to an action
      bool accepted = false;

      switch (this->possible_action(static_cast<int>(button_event->x),
				    static_cast<int>(button_event->y))) {
      case NONE:
	accepted = false;
	break;
      case SHIFT_CARDS:
	switch (button_event->button) {
	case 1: // left mouse button
	  this->shift_cards = true;
	  accepted = true;
	  break;
	default:
	  break;
	} // switch (button_event->button)
	break;
      case ACCEPT_CARDS:
	switch (button_event->button) {
	case 1: // left mouse button
	  this->accept_cards = true;
	  accepted = true;
	  break;
	default:
	  break;
	} // switch (button_event->button)
	break;
      case TAKE_CARD:
	{
	  Player& player = const_cast<Player&>(*(this->player));

	  // test whether a card in the middle is clicked
	  unsigned cardno = UINT_MAX;
	  for (unsigned i = 0; i < player.game().poverty_cardno(); ++i) {
	    Gdk::Point const pos = this->card_pos(i);
	    if ((button_event->x >= pos.get_x())
		&& (button_event->x
		    < (pos.get_x()
		       + this->ui->cards->card(this->cards[i],
					       this->table->rotation(player)
					      ).get_width()))
		&& (button_event->y >= pos.get_y())
		&& (button_event->y
		    < (pos.get_y()
		       + this->ui->cards->card(this->cards[i],
					       this->table->rotation(player)
					      ).get_height()))

		// ToDo: check for transparency
#ifdef POSTPHONED
		&& !(this->ui->cards->card(cards_drawn[i],
					   this->table->rotation(player))
		     .is_transparent(unsigned(button_event->x - pos.get_x()),
				     unsigned(button_event->y - pos.get_y())))
#endif
	       ) {
	      cardno = i;
	      break;
	    } // if ()
	  } // for (i)
	  DEBUG_ASSERTION((cardno != UINT_MAX),
			  "Poverty::button_press_event():\n"
			  "  no card under the mouse");

	  // move a card in the hand
	  switch (button_event->button) {
	  case 1: // left mouse button
	    player.sorted_hand().unplaycard(this->cards[cardno]);
	    this->cards[cardno] = Card();
	    accepted = true;
	    break;
	  case 3: // right mouse button
	    // right click -- put all cards in the hand
	    for (HandCards::iterator c = this->cards.begin();
		 c != this->cards.end();
		 ++c)
	      if (*c)
		if ((status != SHIFTING)
		    || (!c->istrump())) {
		  player.sorted_hand().unplaycard(*c);
		  *c = Card();
		} // if (card not trump when soloplayer)
	    accepted = true;
	  default:
	    break;
	  } // switch (button_event->button)
	  this->draw();
	  this->table->hand(player).draw();
	}
	break;
      case PUT_CARD:
	switch (button_event->button) {
	case 1: // left mouse button
	  {
	    unsigned const cardno
	      = this->table->hand(*(this->player)).cardno_at_position(static_cast<int>(button_event->x), static_cast<int>(button_event->y));
	    DEBUG_ASSERTION((cardno != UINT_MAX),
			    "Poverty::button_press_event():\n"
			    "  no card under the mouse");
	    this->add_card_to_shift(cardno);
	  }
	  break;
	default:
	  break;
	} // switch (button_event->button)
	break;
      case RETURN_CARDS:
	switch (button_event->button) {
	case 1: // left mouse button
	  this->shift_cards = true;
	  accepted = true;
	  break;
	default:
	  break;
	} // switch (button_event->button)
	break;
      case GET_CARDS_BACK:
	switch (button_event->button) {
	case 1: // left mouse button
	  this->accept_cards = true;
	  accepted = true;
	  break;
	default:
	  break;
	} // switch (button_event->button)
	break;
      }; // switch (this->possible_actions(button_event->x, button_event->y)) {

      return accepted;
    } // bool Poverty::button_press_event(GdkEventButton* button_event)

    /**
     **
     ** -> result
     **
     ** @param	x	x position
     ** @param	y	y position
     **
     ** @return	what action a can be made at the position (for the mouse)
     ** 
     ** @version	0.6.6
     **
     ** @author	Diether Knof
     **
     **/
    Poverty::Action
      Poverty::possible_action(int const x, int const y) const
      {
	if ((this->status == INVALID)
	    || (this->status == FINISHED))
	  return NONE;

	if (this->player == NULL)
	  return NONE;

	Player const& player = *this->player;

	if (player.type() != Player::HUMAN)
	  return NONE;

	// whether the mouse click leads to an action
	bool accepted = false;

	if (this->shifting_valid()) {
	  // test whether mouse is over the arrow
	  Gdk::Rectangle outline = this->arrow_outline();
	  if ((x >= outline.get_x())
	      && (x <= outline.get_x() + outline.get_width())
	      && (y >= outline.get_y())
	      && (y <= outline.get_y() + outline.get_height())
	     ) {
	    switch(this->status) {
	    case NONE:
	      return NONE;
	      break;
	    case SHIFTING:
	      return SHIFT_CARDS;
	      break;
	    case SHIFTING_BACK:
	      return RETURN_CARDS;
	      break;
	    case ASKING:
	      return SHIFT_CARDS;
	      break;
	    case GETTING_BACK:
	    case ACCEPTED:
	    case DENIED_BY_ALL:
	    case FINISHED:
	      return NONE;
	      break;
	    } // switch(this->status)
	  } // if (arrow clicked)
	} // test whether the arrow is clicked

	if (!accepted) {
	  // test whether a card in the middle is clicked
	  unsigned cardno = UINT_MAX;
	  for (unsigned i = 0; i < player.game().poverty_cardno(); ++i) {
	    Gdk::Point const pos = this->card_pos(i);
	    if ((x >= pos.get_x())
		&& (x < (pos.get_x()
			 + this->ui->cards->card(this->cards[i],
						 this->table->rotation(player)
						).get_width()))
		&& (y >= pos.get_y())
		&& (y < (pos.get_y()
			 + this->ui->cards->card(this->cards[i],
						 this->table->rotation(player)
						).get_height()))

		// ToDo: check for transparency
#ifdef POSTPHONED
		&& !(this->ui->cards->card(cards_drawn[i],
					   this->table->rotation(player))
		     .is_transparent(unsigned(x - pos.get_x()),
				     unsigned(y - pos.get_y())))
#endif
	       ) {
	      cardno = i;
	      break;
	    } // if ()
	  } // for (i)


	  if (cardno != UINT_MAX) {
	    switch(this->status) {
	    case INVALID:
	      DEBUG_ASSERTION(false,
			      "Poverty::possible_action():\n"
			      "  'this->status' == INVALID");
	      break;
	    case SHIFTING:
	      // move a card in the hand
	      if (this->cards[cardno] == Card())
		return NONE;

	      if (this->cards[cardno].istrump())
		return NONE;

	      return TAKE_CARD;
	      break;

	    case ASKING:
	      return ACCEPT_CARDS;
	      break;

	    case SHIFTING_BACK:
	      if (this->cards[cardno] == Card())
		return NONE;

	      return TAKE_CARD;
	      break;

	    case GETTING_BACK:
	      return GET_CARDS_BACK;
	      break;

	    case ACCEPTED:
	    case DENIED_BY_ALL:
	    case FINISHED:
	      break;
	    } // switch(this->status)
	  } // if (cardno != UINT_MAX)
	} // test whether a card in the middle is clicked

	if (!accepted) {
	  // test whether the player wants to move a card from the hand
	  // into the middle
	  if ((this->status == SHIFTING)
	      || (this->status == SHIFTING_BACK))
	    if (!(this->middle_full())) {
	      unsigned const cardno
		= this->table->hand(player).cardno_at_position(x, y);
	      if (cardno != UINT_MAX)
		return PUT_CARD;
	    } // if (middle has a free place)

	  // look, whether there is space
	} // if (!accepted)

	return NONE;
      } // Poverty::Action Poverty::possible_action(int const x, int const y) const

    /**
     **
     ** moves the card at 'pos' in the middle
     **
     ** @param	pos	position of the card
     **
     ** @return	-
     ** 
     ** @version	0.6.2
     **
     ** @author	Diether Knof
     **
     **/
    void
      Poverty::add_card_to_shift(unsigned const cardno)
      {
	Player& player = const_cast<Player&>(*(this->player));

	// search the first free card in the middle
	HandCards::iterator c;
	for (c = this->cards.begin(); c != this->cards.end(); ++c)
	  if (*c == Card())
	    break;

	if (c == this->cards.end())
	  // no free card found - ignore the taking of the card
	  return ;

	DEBUG_ASSERTION((player.sorted_hand().played(cardno) == false),
			"Poverty::add_card_to_shift(cardno):\n"
			"  card number '" << cardno << "' is already played:\n"
			"Hand:\n"
			<< player.sorted_hand());

	// move the card in the middle
	*c = player.sorted_hand().card_all(cardno);
	player.sorted_hand().playcard(player.sorted_hand().pos_all_to_pos(cardno));

	this->draw();
	this->table->hand(player).draw();

#ifdef WORKAROUND
	{ // just testing
	  unsigned selected_cards = 0;
	  for (HandCards::const_iterator c = this->cards.begin();
	       c != this->cards.end();
	       ++c)
	    if (*c)
	      selected_cards += 1;

	  DEBUG_ASSERTION((player.sorted_hand().cardsnumber() + selected_cards
			   == player.sorted_hand().cardsnumber_all()),
			  "Poverty::add_card_to_shift(cardno = " << cardno
			  << ")\n"
			  "  'player.sorted_hand().cardsnumber() + this->cards.size()' "
			  " = " << player.sorted_hand().cardsnumber() + this->cards.size()
			  << " != " << player.sorted_hand().cardsnumber_all()
			  << " = player.sorted_hand().cardsnumber_all()\n"
			  << "  shifted cards: " << this->cards << '\n'
			  << " Hand: " << player.sorted_hand());
	}
#endif // #ifdef WORKAROUND

	return ;
      } // void Poverty::add_card_to_shift(unsigned const cardno)

    } // namespace UI_GTKMM_NS

#endif // #ifdef USE_UI_GTKMM
