/**********************************************************************
 *
 *   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 "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()
  {
    DEBUG_CALLING(INFO_GTKMM_POVERTY && INFO_GTKMM_INIT,
		  "Poverty::Poverty(table, game)");

    DEBUG_RETURNING(VOID,
		    INFO_GTKMM_POVERTY && INFO_GTKMM_INIT,
		    "Poverty::Poverty(table, game)");
  } // Poverty::Poverty(Table* const table, Game& game)

  /**
   **
   ** Destructor
   **
   ** @param	-
   **
   ** @return	-
   ** 
   ** @author	Diether Knof
   **
   ** @version	0.6.2
   **
   **/
  Poverty::~Poverty()
  {
    DEBUG_CALLING(INFO_GTKMM_POVERTY && INFO_GTKMM_INIT,
		  "Poverty::~Poverty()");

    DEBUG_RETURNING(VOID,
		    INFO_GTKMM_POVERTY && INFO_GTKMM_INIT,
		    "Poverty::~Poverty()");
  } // Poverty::~Poverty()

  /**
   **
   ** -> result
   **
   ** @param	-
   **
   ** @return	whether the active player can shift
   ** 
   ** @version	0.6.2
   **
   ** @author	Diether Knof
   **
   **/
  bool
    Poverty::middle_full() const
    {
      DEBUG_CALLING(INFO_GTKMM_POVERTY && INFO_GTKMM_VALUE,
		    "Poverty::middle_full()");

      for (vector<Card>::const_iterator card = this->cards.begin();
	   card != this->cards.end();
	   card++)
	if (*card == Card())
	  DEBUG_RETURNING(false,
			  INFO_GTKMM_POVERTY && INFO_GTKMM_VALUE,
			  "Poverty::middle_full()");

      DEBUG_RETURNING(true,
		      INFO_GTKMM_POVERTY && INFO_GTKMM_VALUE,
		      "Poverty::middle_full()");
    } // 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
    {
      DEBUG_CALLING(INFO_GTKMM_POVERTY && INFO_GTKMM_VALUE,
		    "Poverty::shifting_valid()");

      if (this->player->type() != Player::HUMAN)
	DEBUG_RETURNING(false,
			INFO_GTKMM_POVERTY && INFO_GTKMM_VALUE,
			"Poverty::shifting_valid()"
			" = false");

      bool valid = false;

      switch (this->status) {
      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)

      DEBUG_RETURNING(valid,
		      INFO_GTKMM_POVERTY && INFO_GTKMM_VALUE,
		      "Poverty::shifting_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
   **
   ** @todo	all (what?)
   **
   **/
  void
    Poverty::shift(Player const& player, unsigned const cardno)
    { 
      DEBUG_CALLING(INFO_GTKMM_POVERTY && INFO_GTKMM_GAMEPLAY,
		    "Poverty::shift(player, cardno)");

      this->table->draw_all();

      DEBUG_RETURNING(VOID,
		      INFO_GTKMM_POVERTY && INFO_GTKMM_GAMEPLAY,
		      "Poverty::shift(player, cardno)");
    } // 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
   **
   ** @todo	all (what?)
   **
   **/
  void
    Poverty::take_denied(Player const& player)
    { 
      DEBUG_CALLING(INFO_GTKMM_POVERTY && INFO_GTKMM_GAMEPLAY,
		    "Poverty::take_denied(player)");

      DEBUG_RETURNING(VOID,
		      INFO_GTKMM_POVERTY && INFO_GTKMM_GAMEPLAY,
		      "Poverty::take_denied(player)");
    } // void Poverty::take_denied(Player const& player)

  /**
   **
   ** all players have denied to take the cards
   **
   ** @param	-
   **
   ** @return	-
   **
   ** @version	0.6.4
   **
   ** @author	Diether Knof
   **
   ** @todo	all (what?)
   **
   **/
  void
    Poverty::take_denied_by_all()
    { 
      DEBUG_CALLING(INFO_GTKMM_POVERTY && INFO_GTKMM_GAMEPLAY,
		    "Poverty::take_denied_by_all()");

      this->player = &(this->player->game().soloplayer());
      this->status = DENIED_BY_ALL;

      DEBUG_RETURNING(VOID,
		      INFO_GTKMM_POVERTY && INFO_GTKMM_GAMEPLAY,
		      "Poverty::take_denied_by_all()");
    } // 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
   **
   ** @todo	all (what?)
   **
   **/
  void
    Poverty::take_accepted(Player const& player,
			   unsigned const cardno, unsigned const trumpno)
    { 
      DEBUG_CALLING(INFO_GTKMM_POVERTY && INFO_GTKMM_GAMEPLAY,
		    "Poverty::take_accepted(player, cardno, trumpno)");

      this->status = ACCEPTED;

      DEBUG_RETURNING(VOID,
		      INFO_GTKMM_POVERTY && INFO_GTKMM_GAMEPLAY,
		      "Poverty::take_accepted(player, cardno, trumpno)");
    } // 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
   **
   **/
  ::Hand
    Poverty::shift(Player& player)
    { 
      DEBUG_CALLING(INFO_GTKMM_POVERTY && INFO_GTKMM_GAMEPLAY,
		    "Poverty::shift(player)");

      this->status = SHIFTING;

      this->cards = vector<Card>(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 ((::game_status == GAMESTATUS::GAME_POVERTY_SHIFT)
	     && (this->shift_cards == false))
	Gtk::Main::iteration();

      if (::game_status != GAMESTATUS::GAME_POVERTY_SHIFT)
	DEBUG_RETURNING(::Hand(this->cards),
			INFO_GTKMM_POVERTY && INFO_GTKMM_GAMEPLAY,
			"Poverty::shift(player)");

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

      DEBUG_RETURNING(::Hand(this->cards),
		      INFO_GTKMM_POVERTY && INFO_GTKMM_GAMEPLAY,
		      "Poverty::shift(player)");
    } // ::Hand 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)
    { 
      DEBUG_CALLING(INFO_GTKMM_POVERTY && INFO_GTKMM_GAMEPLAY,
		    "Poverty::ask(player, cardno)");

      this->cards = vector<Card>(cardno);
      this->player = &player;

      this->table->draw_all();

      DEBUG_RETURNING(VOID,
		      INFO_GTKMM_POVERTY && INFO_GTKMM_GAMEPLAY,
		      "Poverty::ask(player, cardno)");
    } // 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)
    { 
      DEBUG_CALLING(INFO_GTKMM_POVERTY && INFO_GTKMM_GAMEPLAY,
		    "Poverty::take_accept(player, cardno)");

      this->status = ASKING;

      this->cards = vector<Card>(cardno);
      this->player = &player;

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

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

      while ((::game_status == GAMESTATUS::GAME_POVERTY_SHIFT)
	     && (this->accept_cards == false)
	     && (this->shift_cards == false))
	Gtk::Main::iteration();

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

      DEBUG_RETURNING(this->accept_cards,
		      INFO_GTKMM_POVERTY && INFO_GTKMM_GAMEPLAY,
		      "Poverty::take_accept(player, cardno)");
    } // 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
   **
   **/
  ::Hand
    Poverty::cards_change(Player& player, ::Hand const& cards_shifted)
    { 
      DEBUG_CALLING(INFO_GTKMM_POVERTY && INFO_GTKMM_GAMEPLAY,
		    "Poverty::cards_change(player, 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 = cards_shifted.cards();
      player.sorted_hand().add(cards_shifted);
      player.hand_sort();
      for (vector<Card>::const_iterator card = cards_shifted.cards().begin();
	   card != cards_shifted.cards().end();
	   ++card)
	player.sorted_hand().playcard(*card);

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

      while ((::game_status == GAMESTATUS::GAME_POVERTY_SHIFT)
	     && (this->shift_cards == false))
	Gtk::Main::iteration();

      if (::game_status != GAMESTATUS::GAME_POVERTY_SHIFT)
	DEBUG_RETURNING(::Hand(),
			INFO_GTKMM_POVERTY && INFO_GTKMM_GAMEPLAY,
			"Poverty::cards_change(player, cards_shifted)");

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

      DEBUG_RETURNING(this->cards,
		      INFO_GTKMM_POVERTY && INFO_GTKMM_GAMEPLAY,
		      "Poverty::cards_change(player, cards_shifted)");
    } // ::Hand Poverty::cards_change(Player& player, ::Hand const& 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, ::Hand const& cards_returned)
    { 
      DEBUG_CALLING(INFO_GTKMM_POVERTY && INFO_GTKMM_GAMEPLAY,
		    "Poverty::cards_get_back(player, cards_returned)");

      if (player.type() != Player::HUMAN)
	DEBUG_RETURNING(VOID,
			INFO_GTKMM_POVERTY && INFO_GTKMM_GAMEPLAY,
			"Poverty::cards_get_back(player, cards_returned)");

      this->status = GETTING_BACK;

      this->player = &player;

      this->cards = cards_returned.cards();

      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 (vector<Card>::const_iterator card = cards_returned.cards().begin();
	   card != cards_returned.cards().end();
	   ++card)
	player.sorted_hand().playcard(*card);

      this->table->draw_all();

      while ((::game_status == GAMESTATUS::GAME_POVERTY_SHIFT)
	     && (this->accept_cards == false))
	Gtk::Main::iteration();

      for (vector<Card>::const_iterator card = cards_returned.cards().begin();
	   card != cards_returned.cards().end();
	   ++card)
	player.sorted_hand().unplaycard(*card);

      this->status = FINISHED;

      DEBUG_RETURNING(VOID,
		      INFO_GTKMM_POVERTY && INFO_GTKMM_GAMEPLAY,
		      "Poverty::cards_get_back(player, cards_returned)");
    } // void Poverty::cards_get_back(Player& player, ::Hand const& 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)
    {
      DEBUG_CALLING(INFO_GTKMM_POVERTY && INFO_GTKMM_VALUE,
		    "Poverty::card_pos(player, cardno)");

      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())

      DEBUG_RETURNING(pos,
		      INFO_GTKMM_POVERTY && INFO_GTKMM_VALUE,
		      "Poverty::card_pos(player, cardno)");
    } // Gdk::Pos Poverty::card_pos(unsigned const cardno)

  /**
   **
   ** -> 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()
    {
      DEBUG_CALLING(INFO_GTKMM_POVERTY && INFO_GTKMM_VALUE,
		    "Poverty::arrow_outline()");

      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())

      DEBUG_RETURNING(rectangle,
		      INFO_GTKMM_POVERTY && INFO_GTKMM_VALUE,
		      "Poverty::arrow_outline()");
    } // Gdk::Rectangle Poverty::arrow_outline()

  /**
   **
   ** 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)
    {
      DEBUG_CALLING(INFO_GTKMM_POVERTY && INFO_GTKMM_DRAW,
		    "Poverty::draw(update)");

      if (this->player == NULL)
	DEBUG_RETURNING(VOID,
			INFO_GTKMM_POVERTY && INFO_GTKMM_DRAW,
			"Poverty::draw(update)");

      if ((this->status == FINISHED)
      || (this->status == ACCEPTED))
	DEBUG_RETURNING(VOID,
			INFO_GTKMM_POVERTY && INFO_GTKMM_DRAW,
			"Poverty::draw(update)");

      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()->card(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

      DEBUG_RETURNING(VOID,
		      INFO_GTKMM_POVERTY && INFO_GTKMM_DRAW,
		      "Poverty::draw(update)");
    } // 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)
    {
      DEBUG_CALLING(INFO_GTKMM_POVERTY && INFO_GTKMM_EVENT,
		    "Poverty::button_press_event(button_event)");

      if (this->status == FINISHED)
	DEBUG_RETURNING(false,
			INFO_GTKMM_POVERTY && INFO_GTKMM_EVENT,
			"Poverty::button_press_event(button_event)");

      Player& player = const_cast<Player&>(*(this->player));

      if (player.type() != Player::HUMAN)
	DEBUG_RETURNING(false,
			INFO_GTKMM_POVERTY && INFO_GTKMM_EVENT,
			"Poverty::button_press_event(button_event)");

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

      if (this->shifting_valid()) {
	// test whether the arrow is clicked
	Gdk::Rectangle outline = this->arrow_outline();
	if ((button_event->x >= outline.get_x())
	    && (button_event->x <= outline.get_x() + outline.get_width())
	    && (button_event->y >= outline.get_y())
	    && (button_event->y <= outline.get_y() + outline.get_height())
	   ) {
	  this->shift_cards = true;
	  accepted = true;
	} // 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 ((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)

	if (cardno != UINT_MAX) {
	  switch(this->status) {
	  case SHIFTING:
	    // move a card in the hand
	    if (this->cards[cardno].istrump(player.game().type()))
	      break;
	  case SHIFTING_BACK:
	    if (this->cards[cardno] == Card())
	      break;

	    // move a card in the hand
	    if (button_event->button == 3) {
	      // right click -- put all cards in the hand
	      for (vector<Card>::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)
	    } else { // if !(button_event->button == 3)
	      player.sorted_hand().unplaycard(this->cards[cardno]);
	      this->cards[cardno] = Card();
	    } // if !(button_event->button == 3)

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

	    break;
	  case ASKING:
	    // accept the cards
	    this->accept_cards = true;
	    accepted = true;
	    break;
	  case GETTING_BACK:
	    // take the cards
	    this->accept_cards = true;
	    accepted = true;
	    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(static_cast<int>(button_event->x), static_cast<int>(button_event->y));
	    if (cardno != UINT_MAX)
	      this->add_card_to_shift(cardno);
	  } // if (middle has a free place)


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

      DEBUG_RETURNING(accepted,
		      INFO_GTKMM_POVERTY && INFO_GTKMM_EVENT,
		      "Poverty::button_press_event(button_event)");
    } // bool Poverty::button_press_event(GdkEventButton* button_event)

  /**
   **
   ** 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)
    {
      DEBUG_CALLING(INFO_GTKMM_POVERTY && INFO_GTKMM_EVENT,
		    "Poverty::add_card_to_shift(cardno)");

      Player& player = const_cast<Player&>(*(this->player));

      // search the first free card in the middle
      vector<Card>::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
	DEBUG_RETURNING(VOID,
			INFO_GTKMM_POVERTY && INFO_GTKMM_EVENT,
			"Poverty::add_card_to_shift(cardno)");

      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 (vector<Card>::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

      DEBUG_RETURNING(VOID,
		      INFO_GTKMM_POVERTY && INFO_GTKMM_EVENT,
		      "Poverty::add_card_to_shift(cardno)");
    } // void Poverty::add_card_to_shift(unsigned const cardno)
} // namespace UI_GTKMM_NS

#endif // #ifdef USE_UI_GTKMM
