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

#include "player.h"

#include "human/human.h"
#include "ai/ai.h"
#include "ai.dummy/ai.h"
#include "../card/hand.h"
#include "../party/party.h"
#include "../party/rule.h"
#include "../game/game_summary.h"
#include "../card/trick.h"
#include "../misc/setting.h"
#include "../ui/ui.h"
#include "playersDb.h"

/**
 **
 ** -> result
 **
 ** @param       type    playertype
 **
 ** @return      pointer to a new player of the given type
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 ** @version     0.4.4
 **
 **/
Player*
Player::new_(Type const& type)
{
  Player* player = NULL;

  switch(type) {
  case Player::UNSET:
    DEBUG_ASSERTION(false,
		    "Player::new_(type, player):\n"
		    "  type == UNSET");
    break;
  case Player::HUMAN:
    player = new Human();
    break;
  case Player::AI:
    player = new Ai();
    break;
  case Player::AI_DUMMY:
    player = new AiDummy();
    break;
  } // switch(type)

  return player;
} // Player* Player::new_(Type const& type)

/**
 **
 ** -> result
 **
 ** @param	type	playertype
 ** @param	p	the player to be copied
 **
 ** @return	pointer to a new player of the given type and with data
 **		from 'player'
 **
 ** @author	Diether Knof
 **
 ** @version	0.4.4
 **
 **/
Player*
Player::new_(Type const& type, Player const& p)
{
  Player* player = NULL;

  switch(type) {
  case Player::UNSET:
    DEBUG_ASSERTION(false,
		    "Player::new_(type, player):\n"
		    "  type == UNSET");
    break;
  case Player::HUMAN:
#ifdef WORKAROUND
    if (dynamic_cast<Ai const*>(&p) != NULL)
      player = new Human(dynamic_cast<Ai const&>(p));
    else if (dynamic_cast<Aiconfig const*>(&p) != NULL)
      player = new Human(p, dynamic_cast<Aiconfig const&>(p));
    else
      player = new Human(p);
#else
    // see 'AI'
    player = new Human(p);
#endif
    break;

  case Player::AI:
#ifdef WORKAROUND
    if (dynamic_cast<Ai const*>(&p) != NULL)
      player = new Ai(dynamic_cast<Ai const&>(p));
    else if (dynamic_cast<Aiconfig const*>(&p) != NULL)
      player = new Ai(p, dynamic_cast<Aiconfig const&>(p));
    else
      player = new Ai(p);
#else
    // if 'p' is of type 'Human', the GNU C++ compiler calls 'Ai(Player)' but
    // not 'Ai(Ai)' although 'Human' is a child of 'Ai'
    player = new Ai(p);
#endif
    break;
  case Player::AI_DUMMY:
    if (dynamic_cast<Aiconfig const*>(&p) != NULL)
      player = new AiDummy(p, dynamic_cast<Aiconfig const&>(p));
    else
      player = new AiDummy(p);
    break;
  } // switch(type)

  return player;
} // Player* Player::new_(Type const& type, Player const& player)

/**
 **
 ** returns a player, created by the infos of the file
 **
 ** @param	filename	file with the player info
 **
 ** @return	pointer to a new player of the given type
 **
 ** @author	Diether Knof
 **
 ** @version	0.5.2
 **
 **/
Player*
Player::new_(string const& filename)
{
  ifstream istr(filename.c_str());
  if (istr.fail())
    return NULL;

  return Player::new_(istr);
} // Player* Player::new_(string const& filename)

/**
 **
 ** returns a player, created by the infos of the stream
 **
 ** @param	istr	stream with the player info
 **
 ** @return	pointer to a new player of the given type
 **
 ** @author	Diether Knof
 **
 ** @version	0.5.2
 **
 **/
Player*
Player::new_(istream& istr)
{
  // word that has been read
  string line;

  // the first line has the name 'name':
  // Player n: name
  std::getline(istr, line);
  if ((string(line, 0, strlen("Player:")) != "Player:")
      || istr.fail())
    return NULL;

  // the name of the player
  string name;
  // the rest of the line is the name of the player
  if (line.length() > strlen("Player: "))
    name = string(line, strlen("Player: "), string::npos);
  else
    name = "";

  // the second line is the player type 'type'
  // Player type: 'type'
  std::getline(istr, line);
  if ((string(line, 0, strlen("Player type:")) != "Player type:")
      || istr.fail())
    return NULL;

  // the rest of the line is the type of the player
  string type = string(line, strlen("Player type: "), string::npos);
  // ignore DOS EOL
  if (*(type.rbegin()) == '\r')
    type.resize(type.size() - 1);

  // new player
  Player* player = NULL;

  if (type == ::name(HUMAN)) {
    player = new Human(istr);
  } else if (type == ::name(AI)) {
    player = new Ai(istr);
  } else if (type == ::name(AI_DUMMY)) {
    player = new AiDummy(istr);
  } else { // if (type == 'type')
    DEBUG_ASSERTION(false,
		    "Player::new_(istr):\n"
		    "  player type '" << type << "' not known");
  }

  if (player)
    player->name_set(name);

  return player;
} // Player* Player::new_(istream& istr)

/**
 **
 ** constructor
 **
 ** @param       type type of the player
 **
 ** @return      -
 **
 ** @version     0.4.4
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 **/
Player::Player(Type const& type)  :
  game_p(NULL),
  type_p(type),
  name_p(),
  no_p(UINT_MAX),
  hand_p(),
  sorted_hand_p(this->hand_p),
  trickpile_(),
  db_( NULL ),
  teaminfo_p(vector<Team>(::party.rule()(Rule::NUMBER_OF_PLAYERS_IN_GAME),
			  TEAM::UNKNOWN))
{
  this->db_ = new PlayersDb();

  return ;
} // Player::Player(Type const& type)  :

/**
 **
 ** copy constructor
 **
 ** @param       player  player to copy
 **
 ** @return      -
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 ** @version     0.6.4
 **
 **/
Player::Player(Player const& player) :
  game_p(player.game_p),
  type_p(Player::UNSET),
  name_p(player.name_p),
  no_p(player.no_p),
  hand_p(*this, player.hand_p),
  sorted_hand_p(player.sorted_hand_p, this->hand_p),
  trickpile_(player.trickpile_),
  db_( (player.db_ == NULL)
       ? NULL
       : new PlayersDb(*(player.db_)) ), // *** DK must use a copy!
  teaminfo_p(player.teaminfo_p)
{
  return ;
} // Player::Player(const Player& player)

/**
 **
 ** destructor
 **
 ** @param       -
 **
 ** @return      -
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 ** @version     0.5.3
 **
 **/
Player::~Player()
{
  DEBUG_CALLING(INFO_PLAYER && INFO_INIT,
		"Player::~Player()");

  delete this->db_;

  DEBUG_RETURNING(VOID,
		  INFO_PLAYER && INFO_INIT,
		  "Player::~Player()");
} // Player::~Player()

/**
 ** self check
 ** when an error is found, an ASSERTION is created
 **
 ** @param	-
 **
 ** @return	wether the self-check was successful (no error)
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.7
 **
 ** @todo	check the hand
 ** @todo	check the sorted hand
 **
 **/
bool
Player::self_check() const
{
  DEBUG_ASSERTION(this->db_,
		  "Player::self_check()\n"
		  "  no database");
  if (this->game_p) {
    DEBUG_ASSERTION((this == &this->game_p->player(this->no_p)),
		    "Player::self_check()\n"
		    "  number not valid: " << this->no_p);


    // ToDo
    // check the hand
    // check the sorted hand

    for (TrickPile::const_iterator t = this->trickpile_.begin();
	 t != this->trickpile_.end();
	 ++t) {
      if (this->game_p != &(*t)->game()) {
	COUT << "  " << this->game_p << " != " << &(*t)->game() << endl;
	COUT << "  trickpile anz: " << this->trickpile_.size() << endl;
	COUT << "  Player: " << this->no() << endl;
	COUT << "  Trick: " << *t << endl;
	COUT << "  Trick: " << **t << endl;
	DEBUG_ASSERTION((this->game_p == &(*t)->game()),
			"Player::self_check()\n"
			"  Trick " << (*t)->no() << " has not the same game");
      }
    } // for (t \in this->trickpile_)
  } // if (this->game_p)

  return true;
} // virtual bool Player::self_check() const

/**
 **
 ** -> result
 **
 ** @param	player	player to compare with
 **
 ** @return	whether the players are the same
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.6
 **
 **/
bool
Player::is_same(Player const& player) const
{
  return (this == &player);
} // bool Player::is_same(Player const& player) const

/**
 **
 ** -> result
 **
 ** @param	player	player to compare with
 **
 ** @return	whether the players are the equal (value)
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.6
 **
 ** @todo	compare values
 ** @todo	comparing sorted hands
 ** @todo	comparing database
 **
 **/
bool
Player::is_equal(Player const& player) const
{
  if (this->type() != player.type())
    return false;
  if (this->name_p != player.name_p)
    return false;
  if (this->no_p != player.no_p)
    return false;

  if (this->game_p != player.game_p)
    return false;

  if (this->hand_p != player.hand_p)
    return false;
#ifdef POSTPHONED
  if (this->sorted_hand_p != player.sorted_hand_p)
    return false;
#endif
  if (this->trickpile_ != player.trickpile_)
    return false;
#ifdef POSTPHONED
  if (*(this->db_) != *(player.db_))
    return false;
#endif

  if (this->teaminfo_p != player.teaminfo_p)
    return false;

  switch(this->type()) {
  case UNSET:
    return true;
  case HUMAN:
  case AI:
  case AI_DUMMY:
    // ToDo: compare with values
    return this->is_same(player);
  } // switch (this->type())

  DEBUG_ASSERTION(false,
		  "Player::is_equal(player):\n"
		  "  behind the 'case' block");

  return true;
} // bool Player::is_equal(Player const& player) const

/**
 **
 ** clone the player
 **
 ** @param       -
 **
 ** @return      pointer of a clone
 **
 ** @author      Diether Knof
 **
 ** @version     0.5.3
 **
 **/
Player*
Player::clone() const
{  
  DEBUG_CALLING(INFO_PLAYER && INFO_INIT,
		"Player::clone()");

  DEBUG_RETURNING(new Player(*this),
		  INFO_PLAYER && INFO_INIT,
		  "Player::clone()");
} // virtual Player* Player::clone() const

/**
 **
 ** copy operator
 **
 ** @param       player  player to be copied
 **
 ** @return      copy of player
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 ** @version     0.4.4
 **
 **/
Player&
Player::operator=(const Player& player)
{  
  DEBUG_CALLING(INFO_PLAYER && INFO_INIT,
		"Player::operator=(player)");

  // copy the values
  this->game_p = player.game_p;
  this->type_p = player.type_p;
  this->name_p = player.name_p;
  this->no_p = player.no_p;
  this->hand_p = player.hand_p;
  this->hand_p.set_player(*this);
  this->sorted_hand_p = SortedHand(player.sorted_hand_p, this->hand_p);
  this->trickpile_ = player.trickpile_;
  this->teaminfo_p = player.teaminfo_p;
  this->db_        = ((player.db_ == NULL)
		      ? NULL
		      : new PlayersDb(*(player.db_))); // *** DK must use a copy!

  DEBUG_RETURNING(*this,
		  INFO_PLAYER && INFO_INIT,
		  "Player::operator=(player)");
} // Player& Player::operator=(const Player& player)

/**
 **
 ** -> result
 **
 ** @param	player1		player 1 to compare
 ** @param	player2	 player 2 to compare
 **
 ** @return	whether the players are equal (they lie in the same memory)
 **
 ** @author	Diether Knof
 **
 ** @version	0.4.4
 **
 ** @todo	compare with values
 **
 **/
bool
operator==(Player const& player1, Player const& player2)
{
  return player1.is_equal(player2);
} // bool operator==(Player const& player1, Player const& player2)

/**
 **
 ** -> result
 **
 ** @param       player1 player 1 to compare
 ** @param       player2 player 2 to compare
 **
 ** @return      whether the players are not equal
 **              (they don't lie in the same memory)
 **
 ** @author      Diether Knof
 **
 ** @version     0.4.4
 **
 **/
bool
operator!=(Player const& player1, Player const& player2)
{
  return !(player1 == player2);
} // bool operator!=(Player const& player1, Player const& player2)

/**
 **
 ** save the player in the file 'filename'
 **
 ** @param	filename    file the player shall be saved
 **
 ** @return	whether the saving was sucessful
 **
 ** @author	Diether Knof
 **
 ** @version	0.5.2
 **
 **/
bool
Player::save(string const& filename) const
{
  DEBUG_CALLING(INFO_PLAYER && INFO_IO,
		"Player::save(filename)");

  ofstream ostr(filename.c_str());
  if (ostr.fail())
    DEBUG_RETURNING(false,
		    INFO_PLAYER && INFO_IO,
		    "Player::save(filename)");    

  this->out(ostr);

  DEBUG_RETURNING(ostr.good(),
		  INFO_PLAYER && INFO_IO,
		  "Player::save(filename)");    
} // virtual bool Player::save(string const& filename) const

/**
 **
 ** ouput of the player in the stream
 **
 ** @param       ostr    output stream
 **
 ** @return      output stream
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 ** @version     0.4.4
 **
 **/
ostream&
Player::out(ostream& ostr) const
{
  DEBUG_CALLING(INFO_PLAYER && INFO_IO,
		"Player::out(ostr)");

  ostr << "Player: " << this->name() << "\n"
    << "Player type: " << this->type() << "\n"
    << '\n'
    << "Database\n"
    << "{\n"
    << this->db()
    << "}\n";

#if 0
  if (::game_status & GAMESTATUS::GAME) {
    ostr << "Team" << ": " << this->team() << "\n"
      << "Announcement" << ": " << this->announcement()
      << "\n"
      << this->hand()
      << "Teaminfo" << ": \n";
    for(vector<Player*>::const_iterator player = this->game().player_begin();
	player != this->game().player_end();
	player++)
      ostr << (*player)->no() << ": " << this->teaminfo(**player) << "\n";

  } // if (::gamestatus & GAMESTATUS::GAME)
#endif

  DEBUG_RETURNING(ostr,
		  INFO_PLAYER && INFO_IO,
		  "Player::out(ostr)");    
} // virtual ostream& Player::out(ostream& ostr) const

/**
 **
 ** output of the player
 **
 ** @param       ostr    output stream
 ** @param       player  player to be put in the stream
 **
 ** @return      output stream
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 ** @version     0.4.4
 **
 **/
ostream&
operator<<(ostream& ostr, const Player& player)
{
  DEBUG_CALLING(INFO_PLAYER && INFO_IO,
		"operator<<(ostr, player)");

  player.out(ostr);

  DEBUG_RETURNING(ostr,
		  INFO_PLAYER && INFO_IO,
		  "operator<<(ostr, player)");    
} // ostream& operator<<(ostream& ostr, const Player& player)


/**
 **
 ** -> result
 **
 ** @param       -
 **
 ** @return      game the player is playing
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 ** @version     0.4.4
 **
 **/
Game&
Player::game()
{
  DEBUG_CALLING(INFO_PLAYER && INFO_VALUE,
		"Player::game()");

  DEBUG_ASSERTION(this->game_p,
		  "Player::game(): 'game_p' is a NULL-pointer\n"
		  "  this = " << this);

  DEBUG_RETURNING(*(this->game_p),
		  INFO_PLAYER && INFO_VALUE,
		  "Player::game()");
} // Game& Player::game()

/**
 **
 ** -> result
 **
 ** @param       -
 **
 ** @return      game the player is playing
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 ** @version     0.4.4
 **
 **/
Game const&
Player::game() const
{
  DEBUG_CALLING(INFO_PLAYER && INFO_VALUE,
		"Player::game()");

  DEBUG_ASSERTION(this->game_p != NULL,
		  "Player::game(): 'game_p' is a NULL-pointer\n"
		  "  this = " << this);

  DEBUG_RETURNING(*(this->game_p),
		  INFO_PLAYER && INFO_VALUE,
		  "Player::game()");
} // Game const& Player::game() const

/**
 **
 ** set the game
 **
 ** @param       game    new game
 **
 ** @return      -
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 ** @version     0.6.7
 **
 **/
void
Player::game_set(Game& game)
{
  this->game_p = &game;

  for (TrickPile::iterator t = this->trickpile_.begin();
       t != this->trickpile_.end();
       ++t)
    *t = &game.trick((*t)->no());

  return ;
} // void Player::game_set(Game& game)

/**
 **
 ** -> result
 **
 ** @param       -
 **
 ** @return      type
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 ** @version     0.4.4
 **
 **/
Player::Type const&
Player::type() const
{
  DEBUG_CALLING(INFO_PLAYER && INFO_VALUE,
		"Player::type()");

  DEBUG_RETURNING(this->type_p,
		  INFO_PLAYER && INFO_VALUE,
		  "Player::type()");
} // Player::Type const& Player::type() const

/**
 **
 ** sets the type
 **
 ** @param       type - new player type
 **
 ** @return      new type
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 ** @version     0.4.4
 **
 **/
Player::Type const&
Player::type_set(Type const& type)
{
  DEBUG_CALLING(INFO_PLAYER && INFO_VALUE,
		"Player::type_set()");

  this->type_p = type;

  DEBUG_RETURNING(this->type(),
		  INFO_PLAYER && INFO_VALUE,
		  "Player::type_set()");
} // Player::Type const& Player::type_set(Type const& type)

/**
 **
 ** -> result
 **
 ** @param       -
 **
 ** @return      name of the player
 **              if it is empty, take a default
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 ** @version     0.4.4
 **
 **/
string const
Player::name() const
{
  DEBUG_CALLING(INFO_PLAYER && INFO_VALUE,
		"Player::name()");

  if (this->name_p.empty())
    DEBUG_RETURNING(Player::default_name(this->type()),
		    INFO_PLAYER && INFO_VALUE,
		    "Player::name()");


  DEBUG_RETURNING(this->name_p,
		  INFO_PLAYER && INFO_VALUE,
		  "Player::name()");
} // string const Player::name() const

/**
 **
 ** sets the name
 **
 ** @param       name    new name
 **
 ** @return      name
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 ** @version     0.4.4
 **
 **/
string const
Player::name_set(string const& name)
{
  DEBUG_CALLING(INFO_PLAYER && INFO_VALUE,
		"Player::name_set(name)");

  if (Player::default_name(this->type()) == name)
    this->name_p = "";
  else
    this->name_p = name;

  DEBUG_RETURNING(this->name(),
		  INFO_PLAYER && INFO_VALUE,
		  "Player::name_set(name)");
} // string const Player::name_set(string const& name)

/**
 **
 ** -> result
 **
 ** @param       -
 **
 ** @return      value of the name of the player
 **
 ** @author      Diether Knof
 **
 ** @version     0.5.3
 **
 **/
string const&
Player::name_value() const
{
  DEBUG_CALLING(INFO_PLAYER && INFO_VALUE,
		"Player::name_value()");

  DEBUG_RETURNING(this->name_p,
		  INFO_PLAYER && INFO_VALUE,
		  "Player::name_value()");
} // string const& Player::name_value() const

/**
 **
 ** -> result
 **
 ** @param       type    the type
 **
 ** @return      default name of the type
 **
 ** @author      Diether Knof
 **
 ** @version     0.5.3
 **
 **/
string
Player::default_name(Type const& type)
{
  DEBUG_CALLING(INFO_PLAYER && INFO_BASISTYPES && INFO_NAME,
		"Player::default_name(type)");

  switch(type) {
  case HUMAN:
    DEBUG_RETURNING(::setting(Setting::NAME),
		    INFO_PLAYER && INFO_VALUE,
		    "Player::default_name(type)");
    break;
  default:
    DEBUG_RETURNING(::name(type),
		    INFO_PLAYER && INFO_VALUE,
		    "Player::default_name(type)");
    break;
  } // switch(this->type())
} // string Player::default_name(const Player::Type& type)

/**
 **
 ** -> result
 **
 ** @param       -
 **
 ** @return      the number of the player in the game
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 ** @version     0.4.4
 **
 **/
unsigned
Player::no() const
{
  DEBUG_CALLING(INFO_PLAYER && INFO_VALUE,
		"Player::no()");

#ifdef POSTPHONED
  DEBUG_ASSERTION((::game_status & GAMESTATUS::GAME),
		  "Player::no():\n"
		  "  game_status is not GAME");
#endif

#ifdef POSTPHONED
  DEBUG_RETURNING(this->game().no_of_player(*this),
		  INFO_PLAYER && INFO_VALUE,
		  "Player::no()");
#else
  DEBUG_ASSERTION((this->no_p != UINT_MAX),
		  "Player::no():\n"
		  "  no not set (use Player::no_set(unsigned))");

  DEBUG_RETURNING(this->no_p,
		  INFO_PLAYER && INFO_VALUE,
		  "Player::no()");
#endif
} // unsigned Player::no() const

/**
 **
 ** sets the playernumber
 **
 ** @param       no      new playernumber
 **
 ** @return      the playernumber
 **
 ** @author      Diether Knof
 **
 ** @version     0.4.4
 **
 **/
unsigned
Player::no_set(unsigned const no)
{
  DEBUG_CALLING(INFO_PLAYER && INFO_VALUE,
		"Player::no_set()");

#ifdef POSTPHONED
  DEBUG_ASSERTION((::game_status & GAMESTATUS::GAME),
		  "Player::no_set():\n"
		  "  game_status is not GAME");

  DEBUG_ASSERTION((no < this->game().playerno()),
		  "Player::no_set():\n"
		  "  no is too great");
#else
  DEBUG_ASSERTION((no < ::party.playerno()),
		  "Player::no_set():\n"
		  "  no is too great");
#endif

  this->no_p = no;

  DEBUG_RETURNING(this->no(),
		  INFO_PLAYER && INFO_VALUE,
		  "Player::playerno()");
} // unsigned Player::no() const

/**
 **
 ** -> result
 **
 ** @param       -
 **
 ** @return      the database
 **
 ** @author      Borg Enders
 **
 ** @version     0.6.2
 **
 **/
PlayersDb const&
Player::db() const
{
  DEBUG_CALLING(INFO_PLAYER && INFO_VALUE,
		"Player::db()");

  DEBUG_ASSERTION(this->db_,
		  "Playe::db():\n"
		  "  'this->db_' == NULL");

  DEBUG_RETURNING(*(this->db_),
		  INFO_PLAYER && INFO_VALUE,
		  "Player::db()");
} // PlayersDb const& Player::db() const

/**
 **
 ** -> result
 **
 ** @param       -
 **
 ** @return      the database
 **
 ** @author      Diether Knof
 **
 ** @version     0.6.6
 **
 **/
PlayersDb&
Player::db()
{
  DEBUG_CALLING(INFO_PLAYER && INFO_VALUE,
		"Player::db()");

  DEBUG_ASSERTION(this->db_,
		  "Playe::db():\n"
		  "  'this->db_' == NULL");

  DEBUG_RETURNING(*(this->db_),
		  INFO_PLAYER && INFO_VALUE,
		  "Player::db()");
} // PlayersDb& Player::db()

/**
 **
 ** -> result
 **
 ** @param       -
 **
 ** @return      hand
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 ** @version     0.4.4
 **
 **/
Hand const&
Player::hand() const
{
  DEBUG_CALLING(INFO_PLAYER && INFO_VALUE,
		"Player::hand() const");

  DEBUG_RETURNING(this->hand_p,
		  INFO_PLAYER && INFO_VALUE,
		  "Player::hand() ");
} // Hand const& Player::hand() const

/**
 **
 ** -> result
 **
 ** @param       -
 **
 ** @return      hand
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 ** @version     0.4.4
 **
 **/
Hand&
Player::hand()
{
  DEBUG_CALLING(INFO_PLAYER && INFO_VALUE,
		"Player::hand()");

  DEBUG_RETURNING(this->hand_p,
		  INFO_PLAYER && INFO_VALUE,
		  "Player::hand() ");
} // Hand& Player::hand()


/**
 **
 ** -> result
 **
 ** @param       -
 **
 ** @return      sorted hand
 **
 ** @author      Diether Knof
 **
 ** @version     0.6.4
 **
 **/
SortedHand const&
Player::sorted_hand() const
{
  DEBUG_CALLING(INFO_PLAYER && INFO_VALUE,
		"Player::sorted_hand() const");

  DEBUG_RETURNING(this->sorted_hand_p,
		  INFO_PLAYER && INFO_VALUE,
		  "Player::sorted_hand() ");
} // SortedHand const& Player::sorted_hand() const

/**
 **
 ** -> result
 **
 ** @param       -
 **
 ** @return      hand
 **
 ** @author      Diether Knof
 **
 ** @version     0.6.4
 **
 **/
SortedHand&
Player::sorted_hand()
{
  DEBUG_CALLING(INFO_PLAYER && INFO_VALUE,
		"Player::sorted_hand()");

  DEBUG_RETURNING(this->sorted_hand_p,
		  INFO_PLAYER && INFO_VALUE,
		  "Player::sorted_hand() ");
} // SortedHand& Player::hand()


/**
 **
 ** sort the hand
 **
 ** @param       -
 **
 ** @return      sorted hand
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 ** @version     0.5.4
 **
 **/
Hand const&
Player::hand_sort()
{
  DEBUG_CALLING(INFO_PLAYER && INFO_VALUE,
		"Player::hand_sort()");

  if (::setting(Setting::CARDS_ORDER).sorted()
      && (this->game_p != NULL)
      && !(this->game().isvirtual())) {
    bool const changed = this->sorted_hand().sort();
    if (changed)
      ::ui->hand_update(*this);
  } // if (::setting(Setting::CARDS_ORDER).sorted())

  DEBUG_RETURNING(this->hand(),
		  INFO_PLAYER && INFO_VALUE,
		  "Player::hand_sort()");
} // Hand const& Player::hand_sort()

/**
 **
 ** mixes the hand
 **
 ** @param       -
 **
 ** @return      mixed hand
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 ** @version     0.5.4
 **
 **/
Hand const&
Player::hand_mix()
{
  DEBUG_CALLING(INFO_PLAYER && INFO_VALUE,
		"Player::hand_mix()");

  if (!::setting(Setting::CARDS_ORDER).sorted()) {
    this->sorted_hand().mix();
    if ((this->game_p != NULL)
	&& (!this->game().isvirtual()))
      ::ui->hand_update(*this);
  } // if (!::setting(Setting::CARDS_ORDER).sorted())

  DEBUG_RETURNING(this->hand(),
		  INFO_PLAYER && INFO_VALUE,
		  "Player::hand_mix()");
} // Hand const& Player::hand_mix()


/**
 **
 ** set the hand
 **
 ** @param       hand    new hand
 **
 ** @return      player with hand h
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 ** @version     0.6.7
 **
 **/
Hand const&
Player::hand_set(Hand const& hand)
{
  this->hand_p = hand;
  this->hand_p.set_player(*this);

  if (!this->game().isvirtual()
      && (*this == this->game().player(this->no())) )
    // In virtual games the hand is not shown, so it does not have to be sorted.
    if (::setting(Setting::CARDS_ORDER).sorted())
      this->hand_sort();
    else
      this->hand_mix();

  return this->hand();
} // Hand const& Player::hand_set(Hand const& hand)


/**
 **
 ** -> result
 **
 ** @param       -
 **
 ** @return      whether the player is re
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 ** @version     0.4.4
 **
 **/
bool
Player::isre() const
{
  DEBUG_CALLING(INFO_PLAYER && INFO_VALUE,
		"Player::isre()");

  DEBUG_RETURNING((this->teaminfo(*this) == TEAM::RE),
		  INFO_PLAYER && INFO_VALUE,
		  "Player::isre()");
} // bool Player::isre() const

/**
 **
 ** -> result
 **
 ** @param       -
 **
 ** @return      whether the player has swines
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 ** @version     0.4.5
 **
 **/
bool
Player::swines_has() const
{
  DEBUG_CALLING(INFO_PLAYER && INFO_VALUE,
		"Player::swines_has()");

  if (this->game().swines_announced()
      && (this == this->game().swines_owner())) {
    if ((::game_status == GAMESTATUS::GAME_POVERTY_SHIFT)
	&& (*this == this->game().soloplayer()))
      DEBUG_RETURNING(true,
		      INFO_PLAYER && INFO_VALUE,
		      "Player::swines_has() = true");
    // search a swine in all cards of the hand
    for (unsigned c = 0; c < hand().cardsnumber_all(); c++)
      if (hand().card_all(c).isswine())
	DEBUG_RETURNING(true,
			INFO_PLAYER && INFO_VALUE,
			"Player::swines_has() = true");
  } // if (this->game().swines_announced())

  DEBUG_RETURNING(false,
		  INFO_PLAYER && INFO_VALUE,
		  "Player::swines_has() = false");
} // bool Player::swines_has() const

/**
 **
 ** -> result
 **
 ** @param       -
 **
 ** @return      whether the player has hyperswines
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 ** @version     0.4.5
 **
 **/
bool
Player::hyperswines_has() const
{
  DEBUG_CALLING(INFO_PLAYER && INFO_VALUE,
		"Player::hyperswines_has()");

  if (this->game().hyperswines_announced()
      && (this == this->game().hyperswines_owner())) {
    // search a hyperswine in all cards of the hand
    for (unsigned c = 0; c < hand().cardsnumber_all(); c++)
      if (hand().card_all(c).ishyperswine())
	DEBUG_RETURNING(true,
			INFO_PLAYER && INFO_VALUE,
			"Player::hyperswines_has()");
  } // if (this->game().hyperswines_announced())

  DEBUG_RETURNING(false,
		  INFO_PLAYER && INFO_VALUE,
		  "Player::hyperswines_has()");
} // bool Player::hyperswines_has() const


/**
 **
 ** -> result
 **
 ** @param       -
 **
 ** @return      the trickpile of the player
 **
 ** @author      Diether Knof
 **
 ** @version     0.6.4
 **
 **/
TrickPile const&
Player::trickpile() const
{
  return this->trickpile_;
} // TrickPile const& Player::trickpile() const

/**
 **
 ** -> result
 **
 ** @param       -
 **
 ** @return      team of the player
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 ** @version     0.4.4
 **
 **/
Team
Player::team() const
{
  DEBUG_CALLING(INFO_PLAYER && INFO_VALUE,
		"Player::team()");

  DEBUG_RETURNING(this->teaminfo(*this),
		  INFO_PLAYER && INFO_VALUE,
		  "Player::team()");
} // Team Player::team() const

/**
 **
 ** -> result
 **
 ** @param       player whose teaminfo is returned
 **
 ** @return      the team of the given player, as far as this player knows it
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 ** @version     0.4.4
 **
 **/
Team const&
Player::teaminfo(Player const& player) const
{
  DEBUG_CALLING(INFO_PLAYER && INFO_VALUE,
		"Player::teaminfo(player)");

  DEBUG_ASSERTION((player.no() < this->teaminfo_p.size()),
		  "Player::teaminfo(player):\n"
		  "  player.no() too great");

  DEBUG_RETURNING(this->teaminfo_p[player.no()],
		  INFO_PLAYER && INFO_VALUE,
		  "Player::teaminfo(player)");    
} // Team const& Player::teaminfo(Player const& player) const


/**
 **
 ** updates the information of the teams (uses the current trick)
 **
 ** @param       -
 **
 ** @return      the known teams
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 ** @version     0.4.4
 **
 ** @todo	two contra + 1 re without trump
 **
 **/
void
Player::teaminfo_update()
{
  DEBUG_CALLING(INFO_PLAYER && INFO_VALUE,
		"Player::teaminfo_update()");

  using namespace TEAM;

  // update with the teaminfo of 'game'
  for(vector<Player*>::const_iterator player = this->game().player_begin();
      player != this->game().player_end();
      player++) {
    if ((this->game().teaminfo(**player) == RE)
	|| (this->game().teaminfo(**player) == CONTRA))
      this->teaminfo_p[(*player)->no()] = this->game().teaminfo(**player);
  }

  // set the team of himself
  if ((this->game().type() == GAMETYPE::NORMAL)
      && (this->teaminfo(*this) == UNKNOWN))
    // look, whether there is a club queen in the hand
    this->teaminfo_p[this->no()]
      = ((this->hand().getpos_all(Card::CLUB_QUEEN) != UINT_MAX) ? RE : CONTRA);

  { // count the re and contra
    unsigned re_no = 0; // number of re
    unsigned contra_no = 0; // number of re

    for(vector<Player*>::const_iterator player = this->game().player_begin();
	player != this->game().player_end();
	player++) {
      if (this->teaminfo(**player) == RE)
	re_no += 1;
      else if (this->teaminfo(**player) == CONTRA)
	contra_no += 1;
    } // for (player)

    if (re_no + contra_no
	< this->game().rule()(Rule::NUMBER_OF_PLAYERS_IN_GAME)) {
      // there are no more the two players in the re team
      if (re_no == this->game().rule()(Rule::NUMBER_OF_PLAYERS_PER_TEAM))
	for(vector<Player*>::const_iterator player = this->game().player_begin();
	    player != this->game().player_end();
	    player++)
	  if (this->teaminfo(**player) != RE) {
	    teaminfo_p[(*player)->no()] = CONTRA;
	    if (&(this->game()) == &(::party.game()))
	      ::ui->teaminfo_update(**player);
	  }

      // one player must be re
      if ((contra_no == this->game().rule()(Rule::NUMBER_OF_PLAYERS_IN_GAME) - 1)
	  || ((contra_no
	       == this->game().rule()(Rule::NUMBER_OF_PLAYERS_IN_GAME) - 2)
	      && (this->team() == RE))) {
	// if there are 3 contra, the remaining player must be re
	// if I am re and there are two contra, the remaining player must be re
	for(vector<Player*>::const_iterator player = this->game().player_begin();
	    player != this->game().player_end();
	    player++)
	  if (this->teaminfo(**player) != CONTRA) {
	    teaminfo_p[(*player)->no()] = RE;
	    if (&(this->game()) == &(::party.game()))
	      ::ui->teaminfo_update(**player);
	  }
      } // if (contra max)
    } // if (not all teams known)
  } // count the re and contra

  DEBUG_RETURNING(VOID,
		  INFO_PLAYER && INFO_VALUE,
		  "Player::teaminfo_update()");
} // void Player::teaminfo_update()

/**
 **
 ** -> result
 **
 ** @param       -
 **
 ** @return      announcment of this player (taken from 'game')
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 ** @version     0.4.4
 **
 **/
Announcement const&
Player::announcement() const
{
  DEBUG_CALLING(INFO_PLAYER && INFO_VALUE,
		"Player::announcement()");

  DEBUG_RETURNING(this->game().announcement_of_player(*this).announcement,
		  INFO_PLAYER && INFO_VALUE,
		  "Player::announcement()");
} // Announcement const& Player::announcement() const

/**
 **
 ** -> result
 **
 ** @param       -
 **
 ** @return      the number of tricks the player has (taken from 'game')
 **
 ** @author      Diether Knof
 **
 ** @version     0.6.0
 **
 **/
unsigned
Player::number_of_tricks() const
{
  DEBUG_CALLING(INFO_PLAYER && INFO_VALUE,
		"Player::number_of_tricks()");

  DEBUG_ASSERTION((this->game_p != NULL),
		  "Player::number_of_tricks():\n"
		  "  'this->game' == NULL");

  DEBUG_RETURNING(this->game().numberoftricks_of_player(*this),
		  INFO_PLAYER && INFO_VALUE,
		  "Player::number_of_tricks()");
} // unsigned Player::number_of_tricks() const

/**
 **
 ** -> result
 **
 ** @param       -
 **
 ** @return      the points of the tricks the player has (taken from 'game')
 **
 ** @author      Diether Knof
 **
 ** @version     0.6.0
 **
 **/
unsigned
Player::points_in_trickpile() const
{
  DEBUG_ASSERTION((this->game_p != NULL),
		  "Player::points_in_trickpile():\n"
		  "  'this->game' == NULL");

  return this->game().points_of_player(*this);
} // unsigned Player::points_in_trickpile() const

/**
 **
 ** the game 'game' is opened
 **
 ** @param       game    opened game
 **
 ** @return      -
 **
 ** @author      Diether Knof
 **
 ** @version     0.6.7
 **
 **/
void
Player::game_open(Game& game)
{
  this->game_p = &game;
  this->hand_p = Hand();

  this->teaminfo_p = vector<Team>(this->game().playerno(), TEAM::UNKNOWN);

  return ;
} // void Player::game_open(Game& game)

/**
 **
 ** the game 'game' is closed
 **
 ** @param       game    closed game
 **
 ** @return      -
 **
 ** @author      Diether Knof
 **
 ** @version     0.6.7
 **
 **/
void
Player::game_close(Game& game)
{
  DEBUG_ASSERTION((this->game_p == &game),
		  "Player::game_close(game):\n"
		  "  wrong game is closed");

  this->trickpile_.clear();
  this->game_p = NULL;

  return ;
} // void Player::game_close(Game& game)

/**
 **
 ** the player can make an announcement
 **
 ** @param       -
 **
 ** @return      announcement of the player
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 ** @version     0.4.4
 **
 **/
Announcement
Player::announcement_request() const
{
  DEBUG_CALLING(INFO_PLAYER && INFO_OTHER_FUNCTION,
		"Player::announcement_request()");

  DEBUG_RETURNING(ANNOUNCEMENT::NOANNOUNCEMENT,
		  INFO_PLAYER && INFO_OTHER_FUNCTION,
		  "Player::announcement_request()");
} // Announcement Player::announcement_request() const

/**
 **
 ** the given player has made the given announcement
 **
 ** @param       announcement    the announcement
 ** @param       player          the player, who has made the announcement
 **
 ** @return      -
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 ** @version     0.4.4
 **
 **/
void
Player::announcement_made(Announcement const& announcement,
			  Player const& player)
{
  DEBUG_CALLING(INFO_PLAYER && INFO_OTHER_FUNCTION,
		"Player::announcement_made(announcement, player)");

  DEBUG_RETURNING(VOID,
		  INFO_PLAYER && INFO_OTHER_FUNCTION,
		  "Player::announcement_made(announcement, player)");
} // void Player::announcement_made(Announcement const& announcement, Player const& player)

/**
 **
 ** 'player' shifts 'cardno' cards
 **
 ** @param      player  the player who shifts the cards
 ** @param      cardno  the number of cards that are shifted
 **
 ** @return     -
 **
 ** @author     Diether Knof
 **
 ** @version    0.4.5
 **
 **/
void
Player::poverty_shift(Player const& player, unsigned const cardno)
{ 
  DEBUG_CALLING(INFO_PLAYER && INFO_GAMEPLAY,
		"Player::poverty_shift(player, cardno)");

  DEBUG_RETURNING(VOID,
		  INFO_PLAYER && INFO_GAMEPLAY,
		  "Player::poverty_shift(player, cardno)");
} // void Player::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     -
 **
 ** @author     Diether Knof
 **
 ** @version    0.4.5
 **
 **/
void
Player::poverty_take_denied(Player const& player)
{ 
  DEBUG_CALLING(INFO_PLAYER && INFO_GAMEPLAY,
		"Player::poverty_take_denied(player)");

  DEBUG_RETURNING(VOID,
		  INFO_PLAYER && INFO_GAMEPLAY,
		  "Player::poverty_take_denied(player)");
} // void Player::poverty_take_denied(Player const& player)

/**
 **
 ** all players have denied to take the cards
 **
 ** @param      -
 **
 ** @return     -
 **
 ** @author     Diether Knof
 **
 ** @version    0.4.5
 **
 **/
void
Player::poverty_take_denied_by_all()
{ 
  DEBUG_CALLING(INFO_PLAYER && INFO_GAMEPLAY,
		"Player::poverty_take_denied_by_all()");

  DEBUG_RETURNING(VOID,
		  INFO_PLAYER && INFO_GAMEPLAY,
		  "Player::poverty_take_denied_by_all()");
} // void Player::poverty_take_denied_by_all()

/**
 **
 ** 'player' accepts to take the shifted cards
 ** and returns 'cardno' cards with 'trumpno' trumps
 **
 ** @param      player  the player who has accepted to take the cards
 ** @param      cardno  number of cards that are given back
 ** @param      trumpno number of trumps of the cards
 **
 ** @return     -
 **
 ** @author     Diether Knof
 **
 ** @version    0.4.5
 **
 **/
void
Player::poverty_take_accepted(Player const& player,
			      unsigned const cardno, unsigned const trumpno)
{ 
  DEBUG_CALLING(INFO_PLAYER && INFO_GAMEPLAY,
		"Player::poverty_take_accepted(player, cardno, trumpno)");

  DEBUG_RETURNING(VOID,
		  INFO_PLAYER && INFO_GAMEPLAY,
		  "Player::poverty_take_accepted(player, cardno, trumpno)");
} // void Player::poverty_take_accepted(Player const& player, unsigned const cardno, unsigned const trumpno)

/**
 **
 ** returns which cards the player shifts
 **
 ** @param      -
 **
 ** @return     the cards that are to be shifted
 **
 ** @author     Diether Knof
 **
 ** @version    0.4.5
 **
 **/
Hand
Player::poverty_shift()
{ 
  DEBUG_CALLING(INFO_PLAYER && INFO_GAMEPLAY,
		"Player::poverty_shift()");

  cerr << "call of Player::poverty shift()"
    << endl;

  DEBUG_RETURNING(Hand(),
		  INFO_PLAYER && INFO_GAMEPLAY,
		  "Player::poverty_shift()");
} // void Player::poverty_shift(Player const& player)

/**
 **
 ** returns whether 'player' accepts the shifted cards
 **
 ** @param      cardno  the number of shifted cards
 **
 ** @return     whether to accept the cards
 **
 ** @author     Diether Knof
 **
 ** @version    0.4.5
 **
 **/
bool
Player::poverty_take_accept(unsigned const cardno)
{ 
  DEBUG_CALLING(INFO_PLAYER && INFO_GAMEPLAY,
		"Player::poverty_take_accept(cardno)");

  cerr << "call of Player::poverty_take_accept(cardno)"
    << endl;

  DEBUG_RETURNING(false,
		  INFO_PLAYER && INFO_GAMEPLAY,
		  "Player::poverty_take_accept(cardno)");
} // void Player::poverty_take_accept(unsigned const cardno)

/**
 **
 ** changes the cards from the poverty-player
 **
 ** @param      cards   the cards that are given to the player
 **
 ** @return     the cards that are returned to the poverty-player
 **
 ** @author     Diether Knof
 **
 ** @version    0.4.5
 **
 **/
Hand
Player::poverty_cards_change(Hand const& cards)
{ 
  DEBUG_CALLING(INFO_PLAYER && INFO_GAMEPLAY,
		"Player::poverty_cards_change(cards)");

  cerr << "call of Player::poverty_cards_change(cards)"
    << endl;

  DEBUG_RETURNING(Hand(),
		  INFO_PLAYER && INFO_GAMEPLAY,
		  "Player::poverty_cards_change(cards)");
} // void Player::poverty_cards_change(Hand const& cards)

/**
 **
 ** gets the cards from the partner and add them to the hand
 **
 ** @param	cards	the cards that are given to the player
 **
 ** @return	-
 **
 ** @author	Diether Knof
 **
 ** @version	0.5
 **
 **/
void
Player::poverty_cards_get_back(Hand const& cards)
{ 
  DEBUG_CALLING(INFO_PLAYER && INFO_GAMEPLAY,
		"Player::poverty_cards_get_back(cards)");

  this->hand().add(cards);
  this->hand_sort();

  DEBUG_RETURNING(VOID,
		  INFO_PLAYER && INFO_GAMEPLAY,
		  "Player::poverty_cards_get_back(cards)");
} // void Player::poverty_cards_get_back(Hand const& cards)

/**
 **
 ** genscher: -> result
 **
 ** @param	-
 **
 ** @return	pointer to the new teammate,
 **		NULL if the genscher is not to be announced
 **
 ** @author	Diether Knof
 **
 ** @version	0.5.4
 **
 **/
Player const*
Player::genscher_partner()
{ 
  DEBUG_CALLING(INFO_PLAYER && INFO_GAMEPLAY,
		"Player::genscher_partner()");

  DEBUG_RETURNING(NULL,
		  INFO_PLAYER && INFO_GAMEPLAY,
		  "Player::genscher_partner()");
} // Player const* Player::genscher_partner()

/**
 **
 ** genscher: Information of the new team
 **
 ** @param	player	genscher player
 ** @param	partner	partner of the gensher player
 **
 ** @return	-
 **
 ** @author	Diether Knof
 **
 ** @version	0.5.4
 **
 **/
void
Player::genscher(Player const& player,
		 Player const& partner)
{ 
  DEBUG_CALLING(INFO_PLAYER && INFO_GAMEPLAY,
		"Player::genscher(player, partner)");

  DEBUG_RETURNING(VOID,
		  INFO_PLAYER && INFO_GAMEPLAY,
		  "Player::genscher(player, partner)");
} // void Player::genscher(Player const& player, Player const& partner)

/**
 **
 ** a new game has started - init the player:
 ** empty the hand,
 ** set the teaminfo to the teaminfo of the game
 **
 ** @param       game    the game
 **
 ** @return      -
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 ** @version     0.4.4
 **
 **/
void
Player::new_game(Game& game)
{ 
  DEBUG_CALLING(INFO_PLAYER && INFO_VALUE,
		"Player::new_game()");

  this->game_p = &game;
  this->hand_p = Hand();

  this->teaminfo_p = vector<Team>(this->game().playerno(), TEAM::UNKNOWN);

  DEBUG_RETURNING(VOID,
		  INFO_PLAYER && INFO_VALUE,
		  "Player::new_game()");
} // void Player::new_game()

/**
 **
 ** the player makes his reservation
 **
 ** @param       isDuty ?
 **
 ** @return      reservation of the player
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 ** @version     0.4.4
 **
 ** @todo	isDuty documentation
 **
 **/
Reservation
Player::reservation_get( bool isDuty ) 
{ 
  DEBUG_CALLING(INFO_PLAYER && INFO_VALUE,
		"Player::reservation_get()");

  DEBUG_ASSERTION(false,
		  "Player::reservation_get():\n"
		  "  call of this function");

  DEBUG_RETURNING(this->reservation_get_default(),
		  INFO_PLAYER && INFO_VALUE,
		  "Player::reservation_get()");
} // Reservation Player::reservation_get() const

/**
 **
 ** -> result
 ** that is swines and hyperswines, if the player has them,
 ** poverty (nines, kings, trump), marriage
 **
 ** @param	-
 **
 ** @return	default reservation of the player
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.0
 **
 **/
Reservation
Player::reservation_get_default() const
{ 
  DEBUG_CALLING(INFO_PLAYER && INFO_VALUE,
		"Player::reservation_get_default()");

  Reservation reservation;

  if (this->hand().numberofclubqueens()
      == this->game().rule()(Rule::NUMBER_OF_SAME_CARDS)) {
    reservation.game_type = GAMETYPE::MARRIAGE;
    if (this->game().rule()(MARRIAGE_SELECTOR::FIRST_FOREIGN))
      reservation.marriage_selector = MARRIAGE_SELECTOR::FIRST_FOREIGN;
    else if (this->game().rule()(MARRIAGE_SELECTOR::FIRST_COLOR))
      reservation.marriage_selector = MARRIAGE_SELECTOR::FIRST_COLOR;
    else if (this->game().rule()(MARRIAGE_SELECTOR::FIRST_TRUMP))
      reservation.marriage_selector = MARRIAGE_SELECTOR::FIRST_TRUMP;
    else if (this->game().rule()(MARRIAGE_SELECTOR::FIRST_CLUB))
      reservation.marriage_selector = MARRIAGE_SELECTOR::FIRST_CLUB;
    else if (this->game().rule()(MARRIAGE_SELECTOR::FIRST_SPADE))
      reservation.marriage_selector = MARRIAGE_SELECTOR::FIRST_SPADE;
    else if (this->game().rule()(MARRIAGE_SELECTOR::FIRST_HEART))
      reservation.marriage_selector = MARRIAGE_SELECTOR::FIRST_HEART;
    else
      DEBUG_ASSERTION(false,
		      "Player::reservation_get_default():\n"
		      "  no marriage selector valid.\n"
		      "  Ruleset:"
		      << this->game().rule());
  }

  reservation.swines
    = (this->game().rule()(Rule::SWINES)
       && this->game().rule()(Rule::SWINES_ANNOUNCEMENT_BEGIN)
       && (this->hand().numberoftrumpaces()
	   == this->game().rule()(Rule::NUMBER_OF_SAME_CARDS)));

  reservation.hyperswines
    = (this->game().rule()(Rule::HYPERSWINES)
       && this->game().rule()(Rule::HYPERSWINES_ANNOUNCEMENT_BEGIN)
       && (this->hand().numberoftrumpnines()
	   == this->game().rule()(Rule::NUMBER_OF_SAME_CARDS)));


  if (this->game().rule()(Rule::POVERTY)
      && (this->hand().numberoftrumps()
	  <= Rule::MAX_NUMBER_OF_POVERTY_TRUMPS))
    reservation.game_type = GAMETYPE::POVERTY;

  if (this->game().rule()(Rule::THROW_WHEN_FOX_HIGHEST_TRUMP)) {
    unsigned c;
    for (c = 0; c < this->hand().cardsnumber(); ++c)
      if (Card(Card::DIAMOND, Card::ACE).less(this->hand().card(c),
					      this->game()))
	break;

    if (c == this->hand().cardsnumber())
      reservation.game_type = GAMETYPE::FOX_HIGHEST_TRUMP;
  } // test fox highest trump

  if (this->game().rule()(Rule::THROW_WITH_FIVE_NINES)
      && (this->hand().numberofnines()
	  >= Rule::MIN_NUMBER_OF_THROWING_NINES))
    reservation.game_type = GAMETYPE::FIVE_NINES;

  if (this->game().rule()(Rule::THROW_WITH_SIX_KINGS)
      && (this->hand().numberofkings()
	  >= Rule::MIN_NUMBER_OF_THROWING_KINGS))
    reservation.game_type = GAMETYPE::SIX_KINGS;

  DEBUG_RETURNING(reservation,
		  INFO_PLAYER && INFO_VALUE,
		  "Player::reservation_get_default()");
} // Reservation Player::reservation_get_default() const

/**
 **
 ** the game is started
 **
 ** @param       -
 **
 ** @return      -
 **
 ** @author      Diether Knof
 **
 ** @version     0.6.6
 **
 **/
void
Player::game_start() 
{ 
  DEBUG_CALLING(INFO_PLAYER && INFO_GAMEPLAY,
		"Player::game_start()");

  // last time for swines announcements

  DEBUG_RETURNING(VOID,
		  INFO_PLAYER && INFO_GAMEPLAY,
		  "Player::game_start()");
} // void Player::game_start()

/**
 **
 ** the player plays a card
 **
 ** @param       -
 **
 ** @return      card of the player
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 ** @version     0.4.4
 **
 **/
Card
Player::card_get()
{ 
  DEBUG_CALLING(INFO_PLAYER && INFO_VALUE,
		"Player::card_get()");

  DEBUG_ASSERTION(false,
		  "Player::card_get():\n"
		  "  call of this function");

  DEBUG_RETURNING(this->hand().card(0),
		  INFO_PLAYER && INFO_VALUE,
		  "Player::card_get()");
} // Card Player::card_get()

/**
 **
 ** 'player' has played the card 'card'
 **
 ** @param       card    played card
 ** @param       player  player who has played the card
 **
 ** @return      -
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 ** @version     0.4.4
 **
 **/
void
Player::card_played(Card const& card, Player const& player)
{ 
  DEBUG_CALLING(INFO_PLAYER && INFO_VALUE,
		"Player::card_played(card, player)");

  DEBUG_RETURNING(VOID,
		  INFO_PLAYER && INFO_VALUE,
		  "Player::card_played(card, player)");
} // void Player::card_played(Card const& card, Player const& player)

/**
 **
 ** the trick is full
 **
 ** @param      trick   full trick
 **
 ** @return     -
 **
 ** @author     Diether Knof
 **
 ** @version    0.4.5
 **
 **/
void
Player::trick_full(Trick const& trick)
{ 
  DEBUG_CALLING(INFO_PLAYER && INFO_GAMEPLAY,
		"Player::trick_full(trick)");

  DEBUG_RETURNING(VOID,
		  INFO_PLAYER && INFO_GAMEPLAY,
		  "Player::trick_full(trick)");
} // void Player::trick_full(Trick const& trick)

/**
 **
 ** move the trick in the trickpile
 **
 ** @param      trick   trick
 **
 ** @return     -
 **
 ** @author     Diether Knof
 **
 ** @version    0.6.7
 **
 **/
void
Player::move_in_trickpile(Trick const& trick)
{ 
  DEBUG_ASSERTION((&trick.game() == this->game_p),
		  "Player::move_in_trickpile(trick)"
		  "  trick.game != this->game");

  this->trickpile_.push_back(&trick);

  return ;
} // void Player::move_in_trickpile(Trick const& trick)

/**
 **
 ** 'player' has announce hyperswines
 **
 ** @param      player	player that has announced the hyperswines
 **
 ** @return     -
 **
 ** @author     Diether Knof
 **
 ** @version    0.6.6
 **
 **/
void
Player::hyperswines_announced(Player const& player)
{ 
  DEBUG_CALLING(INFO_PLAYER && INFO_GAMEPLAY,
		"Player::hyperswines_announced(player)");

  DEBUG_RETURNING(VOID,
		  INFO_PLAYER && INFO_GAMEPLAY,
		  "Player::hyperswines_announced(player)");
} // void Player::hyperswines_announced(Player const& player)

/**
 **
 ** 'player' has announce swines
 **
 ** @param      player	player that has announced the swines
 **
 ** @return     -
 **
 ** @author     Diether Knof
 **
 ** @version    0.6.6
 **
 **/
void
Player::swines_announced(Player const& player)
{ 
  DEBUG_CALLING(INFO_PLAYER && INFO_GAMEPLAY,
		"Player::swines_announced(player)");

  DEBUG_RETURNING(VOID,
		  INFO_PLAYER && INFO_GAMEPLAY,
		  "Player::swines_announced(player)");
} // void Player::swines_announced(Player const& player)

/**
 **
 ** evaluation of game for playersDb
 **
 ** @param      game_summary	game summary
 **
 ** @return     -
 **
 ** @author     Borg Enders
 ** @author     Diether Knof
 **
 ** @version    0.6.7
 **
 **/
void
Player::evaluate(GameSummary const& game_summary)
{
  this->db_->evaluate( *this, game_summary );
  return ;
}

/**
 **
 ** -> result
 **
 ** @param       type    the type
 **
 ** @return      name of the type
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 ** @version     0.4.4
 **
 **/
string
name(const Player::Type& type)
{
  DEBUG_CALLING(INFO_PLAYER && INFO_BASISTYPES && INFO_NAME,
		"string name(Player::Type)");

  string name;

  switch(type) {
  case Player::UNSET:
    name = "player type unset";
    break;
  case Player::HUMAN:
    name = "human";
    break;
  case Player::AI:
    name = "ai";
    break;
  case Player::AI_DUMMY:
    name = "dummy ai";
    break;
  } // switch(type)

  DEBUG_RETURNING(name,
		  INFO_PLAYER && INFO_BASISTYPES && INFO_NAME,
		  "string name(Player::Type)");
} // string name(const Player::Type& type)

/**
 **
 ** output of the name of 'type'
 **
 ** @param       ostr    output stream
 ** @param       type    player type
 **
 ** @return      output stream
 **
 ** @author      Borg Enders
 ** @author      Diether Knof
 **
 ** @version     0.4.4
 **
 **/
ostream&
operator<<(ostream& ostr, const Player::Type& type)
{
  DEBUG_CALLING(INFO_PLAYER && INFO_BASISTYPES && INFO_IO,
		"ostream& operator<<(ostr, Player::Type)");

  ostr << name(type);

  DEBUG_RETURNING(ostr,
		  INFO_PLAYER && INFO_BASISTYPES && INFO_IO,
		  "ostream& operator<<(ostr, Player::Type)");
} // ostream operator<<(ostream, type);
