/**********************************************************************
 *
 *   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_GTK

#include "poverty.h"
#include "gtk_gui.h"
#include "card.h"
#include "table.h"

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

namespace GTK_DOKO {
#include <gtk/gtkmain.h>
#include <gtk/gtkgc.h>

  /**
   **
   ** Constructor
   **
   ** @param	table	the table, this poverty belongs to
   **
   ** @return	-
   ** 
   ** @version	0.5
   **
   ** @author	Diether Knof
   **
   **/
  Poverty::Poverty(Table* table) :
    table_p(table),
  cards(),
  shift_cards(false),
  accept_cards(false),
  finished(false),
  gc(gdk_gc_new(this->gui().ref_window))
  {
    DEBUG_CALLING(INFO_GTK_POVERTY && INFO_GTK_INIT,
		  "Poverty::Poverty()");

    this->arrow_color_set();

    DEBUG_RETURNING(VOID,
		    INFO_GTK_POVERTY && INFO_GTK_INIT,
		    "Poverty::Poverty()");
  } // Poverty::Poverty(Table* table)

  /**
   **
   ** inits the poverty
   **
   ** @param	-
   **
   ** @return	-
   ** 
   ** @version	0.5
   **
   ** @author	Diether Knof
   **
   **/
  void
    Poverty::init()
    {
      DEBUG_CALLING(INFO_GTK_POVERTY && INFO_GTK_INIT,
		    "Poverty::init()");

      DEBUG_RETURNING(VOID,
		      INFO_GTK_POVERTY && INFO_GTK_INIT,
		      "Poverty::init()");
    } // void Poverty::init()

  /**
   **
   ** -> result
   **
   ** @param	-
   **
   ** @return	the gui
   **
   ** @version	0.5
   **
   ** @author	Diether Knof
   **
   **/
  GTK_GUI&
    Poverty::gui()
    {
      DEBUG_CALLING(INFO_GTK_POVERTY && INFO_GTK_VALUE,
		    "Poverty::gui()");

      DEBUG_RETURNING(this->table().gui(),
		      INFO_GTK_POVERTY && INFO_GTK_VALUE,
		      "Poverty::gui()");
    } // GTK_GUI& Poverty::gui()

  /**
   **
   ** -> result
   **
   ** @param	player	the player
   **
   ** @return	whether 'player' can shift
   ** 
   ** @version	0.5
   **
   ** @author	Diether Knof
   **
   **/
  bool
    Poverty::shifting_valid(Player const& player)
    {
      DEBUG_CALLING(INFO_GTK_POVERTY && INFO_GTK_VALUE,
		    "Poverty::shifting_valid()");

      if (!(player.type() & Player::HUMAN))
	DEBUG_RETURNING(false,
			INFO_GTK_POVERTY && INFO_GTK_VALUE,
			"Poverty::shifting_valid()"
			" = false");

      // the soloplayer has got cards back
      if ((player == ::party.game().soloplayer())
	  && (this->accept_cards == false))
	DEBUG_RETURNING(false,
			INFO_GTK_POVERTY && INFO_GTK_VALUE,
			"Poverty::shifting_valid()"
			" = false");

      // the player is asked to shift
      if ((player != ::party.game().soloplayer())
	  && (this->accept_cards == false))
	DEBUG_RETURNING(true,
			INFO_GTK_POVERTY && INFO_GTK_VALUE,
			"Poverty::shifting_valid()"
			" = true");

      // all cards have to be filled
      for (vector<Card>::const_iterator card = this->cards.begin();
	   card != this->cards.end();
	   card++)
	if (*card == Card())
	  DEBUG_RETURNING(false,
			  INFO_GTK_POVERTY && INFO_GTK_VALUE,
			  "Poverty::shifting_valid()"
			  " = false");

      DEBUG_RETURNING(true,
		      INFO_GTK_POVERTY && INFO_GTK_VALUE,
		      "Poverty::shifting_valid()"
		      " = true");
    } // bool Poverty::shifting_valid(Player const& player)

  /**
   **
   ** -> result
   **
   ** @param	-
   **
   ** @return	the table, this poverty belongs to
   ** 
   ** @version	0.5
   **
   ** @author	Diether Knof
   **
   **/
  Table&
    Poverty::table()
    {
      DEBUG_CALLING(INFO_GTK_POVERTY && INFO_GTK_VALUE,
		    "Poverty::table()");

      DEBUG_ASSERTION((this->table_p != NULL),
		      "Poverty::table()\n"
		      "  `table_p` == NULL");

      DEBUG_RETURNING(*(this->table_p),
		      INFO_GTK_POVERTY && INFO_GTK_VALUE,
		      "Poverty::table()");
    } // Table& Poverty::table()

  /**
   **
   ** 'player' shifts 'cardno' cards
   **
   ** @param	player	the player who shifts the cards
   ** @param	cardno	the number of cards that are shifted
   **
   ** @return	-
   **
   ** @version	0.5
   **
   ** @author	Diether Knof
   **
   **/
  void
    Poverty::shift(Player const& player, unsigned const cardno)
    { 
      DEBUG_CALLING(INFO_GTK_POVERTY && INFO_GTK_GAMEPLAY,
		    "Poverty::shift(player, cardno)");

      // reset the values
      if (::setting(Setting::SHOW_ALL_HANDS))
	this->cards = player.game().poverty_cards()->cards();
      else
	this->cards = vector<Card>(cardno, Card());

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

      DEBUG_RETURNING(VOID,
		      INFO_GTK_POVERTY && INFO_GTK_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.5
   **
   ** @author	Diether Knof
   **
   **/
  void
    Poverty::take_denied(Player const& player)
    { 
      DEBUG_CALLING(INFO_GTK_POVERTY && INFO_GTK_GAMEPLAY,
		    "Poverty::take_denied(player)");

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

  /**
   **
   ** all players have denied to take the cards
   **
   ** @param	-
   **
   ** @return	-
   **
   ** @version	0.5
   **
   ** @author	Diether Knof
   **
   **/
  void
    Poverty::take_denied_by_all()
    { 
      DEBUG_CALLING(INFO_GTK_POVERTY && INFO_GTK_GAMEPLAY,
		    "Poverty::take_denied_by_all()");

      DEBUG_RETURNING(VOID,
		      INFO_GTK_POVERTY && INFO_GTK_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.5
   **
   ** @author	Diether Knof
   **
   **/
  void
    Poverty::take_accepted(Player const& player,
			   unsigned const cardno, unsigned const trumpno)
    { 
      DEBUG_CALLING(INFO_GTK_POVERTY && INFO_GTK_GAMEPLAY,
		    "Poverty::take_accepted(player, cardno, trumpno)");

      DEBUG_RETURNING(VOID,
		      INFO_GTK_POVERTY && INFO_GTK_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
   **
   ** @return	the cards that are to be shifted
   **
   ** @version	0.5
   **
   ** @author	Diether Knof
   **
   **/
  Hand
    Poverty::shift(Player& player)
    { 
      DEBUG_CALLING(INFO_GTK_POVERTY && INFO_GTK_GAMEPLAY,
		    "Poverty::shift(player)");

      // reset the values
      this->cards = vector<Card>(::party.game().poverty_cardno(), Card());

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

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

      this->table().draw_all();

      // wait until the player shifts the cards
      while ((::game_status == GAMESTATUS::GAME_POVERTY_SHIFT)
	     && (this->shift_cards == false))
	gtk_main();

      if (::game_status == GAMESTATUS::GAME_POVERTY_SHIFT) {
	// mark all cards as not played
	for (vector<Card>::const_iterator card = this->cards.begin();
	     card != this->cards.end();
	     card++)
	  player.hand().unplaycard(*card);
	// remove the cards from the hand of the player
	player.hand().remove(this->cards);
      } // if (::game_status == GAMESTATUS::GAME_POVERTY_SHIFT)

      DEBUG_RETURNING(::Hand(this->cards),
		      INFO_GTK_POVERTY && INFO_GTK_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.5
   **
   ** @author	Diether Knof
   **
   **/
  void
    Poverty::ask(Player const& player, unsigned const cardno)
    { 
      DEBUG_CALLING(INFO_GTK_POVERTY && INFO_GTK_GAMEPLAY,
		    "Poverty::ask(player, cardno)");

      this->table().draw_all();

      DEBUG_RETURNING(VOID,
		      INFO_GTK_POVERTY && INFO_GTK_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.5
   **
   ** @author	Diether Knof
   **
   **/
  bool
    Poverty::take_accept(Player& player, unsigned const cardno)
    { 
      DEBUG_CALLING(INFO_GTK_POVERTY && INFO_GTK_GAMEPLAY,
		    "Poverty::take_accept(player, cardno)");

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

      // wait until the player has accepted or not
      while ((::game_status == GAMESTATUS::GAME_POVERTY_SHIFT)
	     && (this->shift_cards == false)
	     && (this->accept_cards == false))
	gtk_main();

      DEBUG_RETURNING(this->accept_cards,
		      INFO_GTK_POVERTY && INFO_GTK_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.5
   **
   ** @author	Diether Knof
   **
   **/
  Hand
    Poverty::cards_change(Player& player, Hand const& cards_shifted)
    { 
      DEBUG_CALLING(INFO_GTK_POVERTY && INFO_GTK_GAMEPLAY,
		    "Poverty::cards_change(player, cards_shifted)");

      // first make all cards in the middle empty,
      // so than an early mouse click does not lead to indeterminable behaviour
      this->cards = vector<Card>(cards_shifted.cardsnumber(), Card());

      if (this->cards.size() == 0)
	// nothing to do
	DEBUG_RETURNING(this->cards,
			INFO_GTK_POVERTY && INFO_GTK_GAMEPLAY,
			"Poverty::cards_change(player, cards_shifted)");

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

#ifdef WORKAROUND
      // just testing
      DEBUG_ASSERTION((player.hand().cardsnumber() + this->cards.size()
		       == player.hand().cardsnumber_all()),
		      "Poverty::cards_change(player, cards_shifted):\n"
		      "  'player.hand().cardsnumber() + this->cards.size()' "
		      " = " << player.hand().cardsnumber() + this->cards.size()
		      << " != " << player.hand().cardsnumber_all()
		      << " = player.hand().cardsnumber_all()\n"
		      << "  shifted cards: " << this->cards << '\n'
		      << "  Hand: " << player.hand());
#endif // #ifdef WORKAROUND

      this->table().draw_all();

      this->shift_cards = false;
      // wait until the player shifts the cards
      while ((::game_status == GAMESTATUS::GAME_POVERTY_SHIFT)
	     && (this->shift_cards == false))
	gtk_main();

      if (::game_status == GAMESTATUS::GAME_POVERTY_SHIFT) {
#ifdef WORKAROUND
	// just testing
	DEBUG_ASSERTION((player.hand().cardsnumber() + this->cards.size()
			 == player.hand().cardsnumber_all()),
			"Poverty::cards_change(player, cards_shifted):\n"
			"  'player.hand().cardsnumber() + this->cards.size()' "
			" = " << player.hand().cardsnumber() + this->cards.size()
			<< " != " << player.hand().cardsnumber_all()
			<< " = player.hand().cardsnumber_all()\n"
			<< "  shifted cards: " << this->cards << '\n'
			<< "  Hand: " << player.hand());
#endif // #ifdef WORKAROUND

#ifdef OUTDATED
	// mark all cards as not played
	for (vector<Card>::const_iterator card = this->cards.begin();
	     card != this->cards.end();
	     card++)
	  player.hand().unplaycard(*card);
#endif
	// remove the cards from the hand of the player
	player.hand().remove(this->cards);

#ifdef WORKAROUND
	// testing, that all cards are unplayed
	DEBUG_ASSERTION((player.hand().cardsnumber()
			 == player.hand().cardsnumber_all()),
			"Poverty::cards_change(player, cards_shifted):\n"
			"  There are 'played' cards:\n"
			<< "  shifted cards: " << this->cards << '\n'
			<< "  Hand: " << player.hand());
#endif // #ifdef WORKAROUND
      } // if (::game_status == GAMESTATUS::GAME_POVERTY_SHIFT)

      DEBUG_RETURNING(this->cards,
		      INFO_GTK_POVERTY && INFO_GTK_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.5
   **
   ** @author	Diether Knof
   **
   **/
  void
    Poverty::cards_get_back(Player& player, Hand const& cards_returned)
    { 
      DEBUG_CALLING(INFO_GTK_POVERTY && INFO_GTK_GAMEPLAY,
		    "Poverty::cards_get_back(player, cards_returned)");

      this->cards = cards_returned.cards();

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

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

      this->table().draw_all();

      // wait until the player accepts the cards
      while ((::game_status == GAMESTATUS::GAME_POVERTY_SHIFT)
	     && (this->accept_cards == false))
	gtk_main();
      this->finished = true;

      if (::game_status == GAMESTATUS::GAME_POVERTY_SHIFT) {
	// mark all cards as not played
	for (vector<Card>::const_iterator card = this->cards.begin();
	     card != this->cards.end();
	     card++)
	  player.hand().unplaycard(*card);
      } // if (::game_status == GAMESTATUS::GAME_POVERTY_SHIFT)

      DEBUG_RETURNING(VOID,
		      INFO_GTK_POVERTY && INFO_GTK_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.5
   **
   ** @author	Diether Knof
   **
   **/
  GdkPoint
    Poverty::card_pos(Player const& player, unsigned const cardno)
    {
      DEBUG_CALLING(INFO_GTK_POVERTY && INFO_GTK_VALUE,
		    "Poverty::card_pos(player, cardno)");

      DEBUG_ASSERTION((cardno <= Rule::MAX_NUMBER_OF_POVERTY_TRUMPS),
		      "Poverty::card_pos(player, cardno):\n"
		      "  `cardno` not valid");

      GdkPoint pos;
      GdkRectangle const arrow_outline = this->arrow_outline(player);

      switch (player.no()) {
      case 0: // player.no()
	switch(::party.game().poverty_cardno()) {
	case 0: // ::party.game().poverty_cardno()
	  pos.x = (this->table().hand(player).start_x()
		   + this->table().hand(player).width() / 2
		   - this->gui().cards().height() / 2);
	  pos.y = (arrow_outline.y - arrow_outline.height / 2
		   - this->gui().cards().width());
	  break;
	case 1: // ::party.game().poverty_cardno()
	  switch(cardno) {
	  case 0:
	    pos.x = (this->table().hand(player).start_x()
		     + this->table().hand(player).width() / 2
		     - this->gui().cards().width() / 2);
	    pos.y = (arrow_outline.y - arrow_outline.height / 2
		     - this->gui().cards().height());
	    break;
	  default:
	    break;
	  } // switch(cardno)
	  break;
	case 2: // ::party.game().poverty_cardno()
	  switch(cardno) {
	  case 0:
	    pos.x = (this->table().hand(player).start_x()
		     + this->table().hand(player).width() / 4);
	    pos.y = (arrow_outline.y - arrow_outline.height / 2
		     - this->gui().cards().height());
	    break;
	  case 1:
	    pos.x = (this->table().hand(player).start_x()
		     + this->table().hand(player).width()
		     - this->table().hand(player).width() / 4
		     - this->gui().cards().width());
	    pos.y = (arrow_outline.y - arrow_outline.height / 2
		     - this->gui().cards().height());
	    break;
	  default:
	    break;
	  } // switch(cardno)
	  break;
	case 3: // ::party.game().poverty_cardno()
	  switch(cardno) {
	  case 0:
	    pos.x = (this->table().hand(player).start_x()
		     + this->table().hand(player).width() / 8);
	    pos.y = (arrow_outline.y - arrow_outline.height / 2
		     - this->gui().cards().height());
	    break;
	  case 1:
	    pos.x = (this->table().hand(player).start_x()
		     + this->table().hand(player).width() / 2
		     - this->gui().cards().width() / 2);
	    pos.y = (arrow_outline.y - arrow_outline.height / 2
		     - this->gui().cards().height() / 2
		     - this->gui().cards().height());
	    break;
	  case 2:
	    pos.x = (this->table().hand(player).start_x()
		     + this->table().hand(player).width()
		     - this->table().hand(player).width() / 8
		     - this->gui().cards().width());
	    pos.y = (arrow_outline.y - arrow_outline.height / 2
		     - this->gui().cards().height());
	    break;
	  default:
	    break;
	  } // switch(cardno)
	  break;
	default: // ::party.game().poverty_cardno()
	  break;
	} // switch(::party.game().poverty_cardno())
	break;
      case 1: // player.no()
	switch(::party.game().poverty_cardno()) {
	case 0: // ::party.game().poverty_cardno()
	  pos.x = (arrow_outline.x + arrow_outline.width * 3 / 2);
	  pos.y = (this->table().hand(player).start_y()
		   + this->table().hand(player).height() / 2
		   - this->gui().cards().height() / 2);
	  break;
	case 1: // ::party.game().poverty_cardno()
	  switch(cardno) {
	  case 0:
	    pos.x = (arrow_outline.x + arrow_outline.width * 3 / 2);
	    pos.y = (this->table().hand(player).start_y()
		     + this->table().hand(player).height() / 2
		     - this->gui().cards().width() / 2);
	    break;
	  default:
	    break;
	  } // switch(cardno)
	  break;
	case 2: // ::party.game().poverty_cardno()
	  switch(cardno) {
	  case 0:
	    pos.x = (arrow_outline.x + arrow_outline.width * 3 / 2);
	    pos.y = (this->table().hand(player).start_y()
		     + this->table().hand(player).height()
		     - this->table().hand(player).height() / 4
		     - this->gui().cards().width());
	    break;
	  case 1:
	    pos.x = (arrow_outline.x + arrow_outline.width * 3 / 2);
	    pos.y = (this->table().hand(player).start_y()
		     + this->table().hand(player).height() / 4);
	    break;
	  default:
	    break;
	  } // switch(cardno)
	  break;
	case 3: // ::party.game().poverty_cardno()
	  switch(cardno) {
	  case 0:
	    pos.x = (arrow_outline.x + arrow_outline.width * 3 / 2);
	    pos.y = (this->table().hand(player).start_y()
		     + this->table().hand(player).height()
		     - this->table().hand(player).height() / 8
		     - this->gui().cards().width());
	    break;
	  case 1:
	    pos.x = (arrow_outline.x + arrow_outline.width * 3 / 2
		     + this->gui().cards().height() / 2);
	    pos.y = (this->table().hand(player).start_y()
		     + this->table().hand(player).height() / 2
		     - this->gui().cards().width() / 2);
	    break;
	  case 2:
	    pos.x = (arrow_outline.x + arrow_outline.width * 3 / 2);
	    pos.y = (this->table().hand(player).start_y()
		     + this->table().hand(player).height() / 8);
	    break;
	  default:
	    break;
	  } // switch(cardno)
	  break;
	default: // ::party.game().poverty_cardno()
	  break;
	} // switch(::party.game().poverty_cardno())
	break;
      case 2: // player.no()
	switch(::party.game().poverty_cardno()) {
	case 0: // ::party.game().poverty_cardno()
	  pos.x = (this->table().hand(player).start_x()
		   + this->table().hand(player).width() / 2
		   - this->gui().cards().height() / 2);
	  pos.y = (arrow_outline.y + arrow_outline.height * 3 / 2);
	  break;
	case 1: // ::party.game().poverty_cardno()
	  switch(cardno) {
	  case 0:
	    pos.x = (this->table().hand(player).start_x()
		     + this->table().hand(player).width() / 2
		     - this->gui().cards().width() / 2);
	    pos.y = (arrow_outline.y + arrow_outline.height * 3 / 2);
	    break;
	  default:
	    break;
	  } // switch(cardno)
	  break;
	case 2: // ::party.game().poverty_cardno()
	  switch(cardno) {
	  case 0:
	    pos.x = (this->table().hand(player).start_x()
		     + this->table().hand(player).width()
		     - this->table().hand(player).width() / 4
		     - this->gui().cards().width());
	    pos.y = (arrow_outline.y + arrow_outline.height * 3 / 2);
	    break;
	  case 1:
	    pos.x = (this->table().hand(player).start_x()
		     + this->table().hand(player).width() / 4);
	    pos.y = (arrow_outline.y + arrow_outline.height * 3 / 2);
	    break;
	  default:
	    break;
	  } // switch(cardno)
	  break;
	case 3: // ::party.game().poverty_cardno()
	  switch(cardno) {
	  case 0:
	    pos.x = (this->table().hand(player).start_x()
		     + this->table().hand(player).width()
		     - this->table().hand(player).width() / 8
		     - this->gui().cards().width());
	    pos.y = (arrow_outline.y + arrow_outline.height * 3 / 2);
	    break;
	  case 1:
	    pos.x = (this->table().hand(player).start_x()
		     + this->table().hand(player).width() / 2
		     - this->gui().cards().width() / 2);
	    pos.y = (arrow_outline.y + arrow_outline.height * 3 / 2
		     + this->gui().cards().height() / 2);
	    break;
	  case 2:
	    pos.x = (this->table().hand(player).start_x()
		     + this->table().hand(player).width() / 8);
	    pos.y = (arrow_outline.y + arrow_outline.height * 3 / 2);
	    break;
	  default:
	    break;
	  } // switch(cardno)
	  break;
	default: // ::party.game().poverty_cardno()
	  break;
	} // switch(::party.game().poverty_cardno())
	break;
      case 3: // player.no()
	switch(::party.game().poverty_cardno()) {
	case 0: // ::party.game().poverty_cardno()
	  pos.x = (arrow_outline.x - arrow_outline.width / 2
		   - this->gui().cards().width());
	  pos.y = (this->table().hand(player).start_y()
		   + this->table().hand(player).height() / 2
		   - this->gui().cards().height() / 2);
	  break;
	case 1: // ::party.game().poverty_cardno()
	  switch(cardno) {
	  case 0:
	    pos.x = (arrow_outline.x - arrow_outline.width / 2
		     - this->gui().cards().height());
	    pos.y = (this->table().hand(player).start_y()
		     + this->table().hand(player).height() / 2
		     - this->gui().cards().width() / 2);
	    break;
	  default:
	    break;
	  } // switch(cardno)
	  break;
	case 2: // ::party.game().poverty_cardno()
	  switch(cardno) {
	  case 0:
	    pos.x = (arrow_outline.x - arrow_outline.width / 2
		     - this->gui().cards().height());
	    pos.y = (this->table().hand(player).start_y()
		     + this->table().hand(player).height()
		     - this->table().hand(player).height() / 4
		     - this->gui().cards().width());
	    break;
	  case 1:
	    pos.x = (arrow_outline.x - arrow_outline.width / 2
		     - this->gui().cards().height());
	    pos.y = (this->table().hand(player).start_y()
		     + this->table().hand(player).height() / 4);
	    break;
	  default:
	    break;
	  } // switch(cardno)
	  break;
	case 3: // ::party.game().poverty_cardno()
	  switch(cardno) {
	  case 0:
	    pos.x = (arrow_outline.x - arrow_outline.width / 2
		     - this->gui().cards().height());
	    pos.y = (this->table().hand(player).start_y()
		     + this->table().hand(player).height() / 8);
	    break;
	  case 1:
	    pos.x = (arrow_outline.x - arrow_outline.width / 2
		     - this->gui().cards().height() * 3 / 2);
	    pos.y = (this->table().hand(player).start_y()
		     + this->table().hand(player).height() / 2
		     - this->gui().cards().width() / 2);
	    break;
	  case 2:
	    pos.x = (arrow_outline.x - arrow_outline.width / 2
		     - this->gui().cards().height());
	    pos.y = (this->table().hand(player).start_y()
		     + this->table().hand(player).height()
		     - this->table().hand(player).height() / 8
		     - this->gui().cards().width());
	    break;
	  default:
	    break;
	  } // switch(cardno)
	  break;
	default: // ::party.game().poverty_cardno()
	  break;
	} // switch(::party.game().poverty_cardno())
	break;
      default:
	DEBUG_ASSERTION(false,
			"Poverty::card_pos(player, cardno):\n"
			"  `player.no()` not valid (not 0, 1, 2, 3)");
	break;
      } // switch (player->no())

      DEBUG_RETURNING(pos,
		      INFO_GTK_POVERTY && INFO_GTK_VALUE,
		      "Poverty::card_pos(player, cardno)");
    } // GdkPos Poverty::card_pos(Player const& player, unsigned const cardno)

  /**
   **
   ** -> result
   **
   ** @param	player	the player, whose arrow is requested
   **
   ** @return	outline rectangle of the arrow
   ** 
   ** @version	0.5
   **
   ** @author	Diether Knof
   **
   **/
  GdkRectangle
    Poverty::arrow_outline(Player const& player)
    {
      DEBUG_CALLING(INFO_GTK_POVERTY && INFO_GTK_VALUE,
		    "Poverty::arrow_outline()");

      GdkRectangle rectangle;

      switch (player.no()) {
      case 0:
	rectangle.width = this->table().hand(player).width() / 2;
	rectangle.height = this->gui().cards().height() / 5;
	rectangle.x = (this->table().hand(player).start_x()
		       + this->table().hand(player).width() / 4);
	rectangle.y = (this->table().icongroup(player).border_y()
		       - this->table().icongroup(player).height()
		       - rectangle.height
		       - rectangle.height / 2);
	break;
      case 1:
	rectangle.width = this->gui().cards().height() / 5;
	rectangle.height = this->table().hand(player).height() / 2;
	rectangle.x = (this->table().icongroup(player).border_x()
		       + this->table().icongroup(player).width()
		       + rectangle.width / 2);
	rectangle.y = (this->table().hand(player).start_y()
		       + this->table().hand(player).height() / 4);
	break;
      case 2:
	rectangle.width = this->table().hand(player).width() / 2;
	rectangle.height = this->gui().cards().height() / 5;
	rectangle.x = (this->table().hand(player).start_x()
		       + this->table().hand(player).width() / 4);
	rectangle.y = (this->table().icongroup(player).border_y()
		       + this->table().icongroup(player).height()
		       + rectangle.height / 2);
	break;
      case 3:
	rectangle.width = this->gui().cards().height() / 5;
	rectangle.height = this->table().hand(player).height() / 2;
	rectangle.x = (this->table().icongroup(player).border_x()
		       - this->table().icongroup(player).width()
		       - rectangle.width
		       - rectangle.width / 2);
	rectangle.y = (this->table().hand(player).start_y()
		       + this->table().hand(player).height() / 4);
	break;
      default:
	DEBUG_ASSERTION(false,
			"Poverty::arrow_outline():\n"
			"  `player.no()` not valid (not 0, 1, 2, 3)");
	break;
      } // switch (player->no())

      DEBUG_RETURNING(rectangle,
		      INFO_GTK_POVERTY && INFO_GTK_VALUE,
		      "Poverty::arrow_outline()");
    } // GdkRectangle Poverty::arrow_outline(Player const& player)

  /**
   **
   ** 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.5
   **
   ** @author	Diether Knof
   **
   **/
  void
    Poverty::draw(Player const& player, bool const update)
    {
      DEBUG_CALLING(INFO_GTK_POVERTY && INFO_GTK_DRAW,
		    "Poverty::draw(poverty, update)");

      DEBUG_ASSERTION((table().pixmap() != NULL),
		      "Poverty::draw:\n"
		      "'table().pixmap()' == NULL");

      if (this->finished)
	DEBUG_RETURNING(VOID,
			INFO_GTK_POVERTY && INFO_GTK_EVENT,
			"Poverty::draw(player, update)");

      vector<Card> const cards_to_draw
	= ((this->accept_cards
	    || ::setting(Setting::SHOW_ALL_HANDS))
	   ? this->cards
	   : vector<Card>(player.game().poverty_cardno(), Card())
	  );


      {
	// draw the arrow
	GdkRectangle outline = this->arrow_outline(player);

	// redraw the background
	this->table().background_draw(outline.x, outline.y,
				      outline.width + 1, outline.height + 1);

	if (this->shifting_valid(player)) {

	  int x, y, width, height;
	  GdkPoint points[3];
	  bool const mirror = (this->accept_cards
			       && (player != player.game().soloplayer()));

	  switch(player.no()) {
	  case 0:
	    x = outline.x + (mirror ? 0 : outline.width / 6);
	    y = outline.y + outline.height / 4;
	    width = outline.width * 5 / 6;
	    height = outline.height / 2;
	    points[0].x = x + (mirror ? width : 0);
	    points[0].y = outline.y;
	    points[1].x = points[0].x;
	    points[1].y = outline.y + outline.height;
	    points[2].x = outline.x + (mirror ? outline.width : 0);
	    points[2].y = outline.y + outline.height / 2;
	    break;
	  case 1:
	    x = outline.x + outline.width / 4;
	    y = outline.y + (mirror ? 0 : outline.height / 6);
	    width = outline.width / 2;
	    height = outline.height * 5 / 6;
	    points[0].x = outline.x;
	    points[0].y = y + (mirror ? height : 0);
	    points[1].x = outline.x + outline.width;
	    points[1].y = points[0].y;
	    points[2].x = outline.x + outline.width / 2;
	    points[2].y = outline.y + (mirror ? outline.height : 0);
	    break;
	  case 2:
	    x = outline.x + (mirror ? outline.width / 6 : 0);
	    y = outline.y + outline.height / 4;
	    width = outline.width * 5 / 6;
	    height = outline.height / 2;
	    points[0].x = x + (mirror ? 0 : width);
	    points[0].y = outline.y;
	    points[1].x = points[0].x;
	    points[1].y = outline.y + outline.height;
	    points[2].x = outline.x + (mirror ? 0 : outline.width);
	    points[2].y = outline.y + outline.height / 2;
	    break;
	  case 3:
	    x = outline.x + outline.width / 4;
	    y = outline.y + (mirror ? outline.height / 6 : 0);
	    width = outline.width / 2;
	    height = outline.height * 5 / 6;
	    points[0].x = outline.x;
	    points[0].y = y + (mirror ? 0 : height);
	    points[1].x = outline.x + outline.width;
	    points[1].y = points[0].y;
	    points[2].x = outline.x + outline.width / 2;
	    points[2].y = outline.y + (mirror ? 0 : outline.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
	  gdk_draw_rectangle(this->table().pixmap(),
			     this->gc,
			     TRUE,
			     x, y, width, height);
	  gdk_draw_polygon(this->table().pixmap(),
			   this->gc, TRUE,
			   points, 3);
	  gdk_draw_polygon(this->table().pixmap(),
			   this->gc, FALSE,
			   points, 3);
	}

	// update the DrawingArea
	if (update) {
	  this->table().update(outline.x, outline.y,
			       outline.width, outline.height);
	}
      } // draw the arrow

      // draw the cards
      for (unsigned i = 0; i < ::party.game().poverty_cardno(); i++) {
	GdkPoint pos;
	pos = this->card_pos(player, i);
	this->gui().cards().card(cards_to_draw[i],
				 player).draw(this->table().pixmap(),
					      pos.x, pos.y);
      }
      if (::party.game().poverty_cardno() == 0) {
	GdkPoint const pos = this->card_pos(player, 0);
	this->gui().cards().back(player).rotated().draw(this->table().pixmap(),
							pos.x, pos.y);
      }

      // update the DrawingArea
      if (update) {
	for (unsigned i = 0; i < ::party.game().poverty_cardno(); i++) {
	  GdkPoint pos;
	  pos = this->card_pos(player, i);
	  this->table().update(pos.x, pos.y,
			       this->gui().cards().card(cards_to_draw[i],
							player).width(),
			       this->gui().cards().card(cards_to_draw[i],
							player).height());
	} // for(i)
	if (::party.game().poverty_cardno() == 0) {
	  GdkPoint const pos = this->card_pos(player, 0);
	  this->table().update(pos.x, pos.y,
			       this->gui().cards().back(player).height(),
			       this->gui().cards().back(player).width());
	}
      } // if (update)

      DEBUG_RETURNING(VOID,
		      INFO_GTK_POVERTY && INFO_GTK_DRAW,
		      "Poverty::draw(poverty, update)");
    } // void Poverty::draw(Player const& player, 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.5
   **
   ** @author	Diether Knof
   **
   **/
  bool
    Poverty::mouse_click(GdkEventButton* button_event)
    {
      DEBUG_CALLING(INFO_GTK_POVERTY && INFO_GTK_EVENT,
		    "Poverty::mouse_click()");

      DEBUG_ASSERTION((::game_status == GAMESTATUS::GAME_POVERTY_SHIFT),
		      "Poverty::mouse_click():\n"
		      "  game_status != GAME_POVERTY_SHIFT: "
		      << game_status);

      if (this->finished)
	DEBUG_RETURNING(false,
			INFO_GTK_POVERTY && INFO_GTK_EVENT,
			"Poverty::mouse_click()");

      Player& player = ::party.game().player_current();

      vector<Card> const cards_drawn
	= ((this->accept_cards
	    || ::setting(Setting::SHOW_ALL_HANDS))
	   ? this->cards
	   : vector<Card>(player.game().poverty_cardno(), Card())
	  );

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

      if (this->shifting_valid(player)) {
	// test whether the arrow is clicked
	GdkRectangle outline = this->arrow_outline(player);
	if ((button_event->x >= outline.x)
	    && (button_event->x <= outline.x + outline.width)
	    && (button_event->y >= outline.y)
	    && (button_event->y <= outline.y + outline.height)) {
	  this->shift_cards = true;
	  this->gui().main_quit();
	  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 < ::party.game().poverty_cardno(); i++) {
	  GdkPoint pos;
	  pos = this->card_pos(player, i);
	  if ((button_event->x >= pos.x)
	      && (button_event->x <
		  pos.x + this->gui().cards().card(cards_drawn[i], player).width())
	      && (button_event->y >= pos.y)
	      && (button_event->y <
		  pos.y
		  + this->gui().cards().card(cards_drawn[i], player).height())
	      && !(this->gui().cards().card(cards_drawn[i], player)
		   .is_transparent(unsigned(button_event->x - pos.x),
				   unsigned(button_event->y - pos.y)))
	     ) {
	    if (this->accept_cards == false) {
	      // accept the cards
	      this->accept_cards = true;
	      this->gui().main_quit();
	      break;
	    } else if (cards_drawn[i]) {
	      cardno = i;
	      break;
	    } // if ()
	  } // if card clicked
	} // for (i)

	if ((::party.game().poverty_cardno() == 0)
	    && (this->accept_cards == false)) {
	  // the cards are accepted
	  this->accept_cards = true;
	  this->gui().main_quit();
	} else { // if !((::party.game().poverty_cardno() == 0) && (this->accept_card == false))

	  if ((cardno != UINT_MAX)
	      && ((player != ::party.game().soloplayer())
		  || (!cards_drawn[cardno].istrump()))) {
	    // test, whether a card is to be taken in the middle

	    if (button_event->button == 3) {
	      // right click -- put all cards in the hand
	      for (unsigned c = 0; c < this->cards.size(); c++)
		if (cards_drawn[c]) {
		  if ((player != ::party.game().soloplayer())
		      || (!cards_drawn[c].istrump())) {
		    player.hand().unplaycard(this->cards[c]);
		    this->cards[c] = Card();
		  } // if (card not trump when soloplayer)
		} // if (cards_drawn[c])
	    } else { // if !(button_event->button == 3)
	      player.hand().unplaycard(this->cards[cardno]);
	      this->cards[cardno] = Card();
	    } // if !(button_event->button == 3)

	    this->draw(player, true);
	    this->table().hand(player).draw(true);
	  } // if (cardno != UINT_MAX)

	} // if !((::party.game().poverty_cardno() == 0) && (this->accept_card == false))
      } // test whether a card in the middle is clicked

      DEBUG_RETURNING(accepted,
		      INFO_GTK_POVERTY && INFO_GTK_EVENT,
		      "Poverty::mouse_click()");
    } // bool Poverty::mouse_click(GdkEventButton* button_event)

  /**
   **
   ** moves the card at 'pos' in the middle
   **
   ** @param	pos	position of the card
   **
   ** @return	-
   ** 
   ** @version	0.5
   **
   ** @author	Diether Knof
   **
   **/
  void
    Poverty::add_card_to_shift(unsigned const pos)
    {
      DEBUG_CALLING(INFO_GTK_POVERTY && INFO_GTK_EVENT,
		    "Poverty::add_card_to_shift(pos)");

      Player& player = ::party.game().player_current();

      // search the first free card in the middle
      unsigned j = 0;
      for (j = 0; j < this->cards.size(); j++)
	if (this->cards[j] == Card())
	  break;

      if (j == this->cards.size()) {
	// no free card found - ignore the taking of the card

	DEBUG_RETURNING(VOID,
			INFO_GTK_POVERTY && INFO_GTK_EVENT,
			"Poverty::add_card_to_shift(pos)");
      } // if (j == this->cards().size())

      // move the card in the middle
      this->cards[j] = player.hand().card(pos);
      player.hand().playcard(pos);

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

#ifdef WORKAROUND
      { // just testing
	unsigned selected_cards = 0;
	for (j = 0; j < this->cards.size(); j++)
	  if (this->cards[j])
	    selected_cards += 1;
	DEBUG_ASSERTION((player.hand().cardsnumber() + selected_cards
			 == player.hand().cardsnumber_all()),
			"Poverty::add_card_to_shift(pos = " << pos << ")\n"
			"  'player.hand().cardsnumber() + this->cards.size()' "
			" = " << player.hand().cardsnumber() + this->cards.size()
			<< " != " << player.hand().cardsnumber_all()
			<< " = player.hand().cardsnumber_all()\n"
			<< "  shifted cards: " << this->cards << '\n'
			<< " Hand: " << player.hand());
      }
#endif // #ifdef WORKAROUND

      DEBUG_RETURNING(VOID,
		      INFO_GTK_POVERTY && INFO_GTK_EVENT,
		      "Poverty::add_card_to_shift(pos)");
    } // void Poverty::add_card_to_shift(unsigned const pos)


  /**
   **
   ** sets the color for the poverty arrow
   ** (from ::setting)
   **
   ** @param	-
   **
   ** @return	-
   ** 
   ** @version	0.5.1
   **
   ** @author	Diether Knof
   **
   **/
  void
    Poverty::arrow_color_set()
    {
      DEBUG_CALLING(INFO_GTK_POVERTY && INFO_GTK_UPDATE,
		    "Poverty::arrow_color_set()");

      GdkColor color;
      // translate the color from the name to a GdkColor
      if (gdk_color_parse(::setting(Setting::POVERTY_SHIFT_ARROW_COLOR).c_str(),
			  &color)) {
	if (gdk_colormap_alloc_color(gdk_colormap_get_system(),
				     &color, FALSE, TRUE)) {

	  // set the color
	  gdk_gc_set_foreground(this->gc, &color);

	} // if (!gdk_colormap_alloc_color)
      } // if (!gdk_color_parse)

      DEBUG_RETURNING(VOID,
		      INFO_GTK_POVERTY && INFO_GTK_UPDATE,
		      "Poverty::arrow_color_set()");
    } // int Poverty::arrow_color_set()

} // namespace GTK_DOKO
#endif // #ifdef USE_UI_GTK
