/**********************************************************************
 *
 *   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 "party.h"

#include "../utils/string.h"

#include "rule.h"
#include "../game/gamepointstable.h"
#include "../player/player.h"
#include "../player/ai/ai.h"

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

#include "../ui/ui.h"
#include "../ui/ui.wrap.h"


/**
 **
 ** constructor:
 ** load the players from the private data directory
 **
 ** @param	-
 **
 ** @return	-
 **
 ** @author	Diether Knof
 **
 ** @version	0.5.2
 **
 **/
Party::Party() :
game_p(),
  rule_p(new Rule),
  gameno_p(0),
  player_p(0),
  gamepointstable_p(),
  seed_first_p(SEED_START),
  startplayer_first_p(STARTPLAYER),
  seed_p(this->seed_first_p),
startplayer_p(this->startplayer_first_p)
{
  DEBUG_CALLING(INFO_PARTY && INFO_INIT,
		"Party::Party()");

  // load the players from the private data directory
  // or take default ones
  for (unsigned n = 0;
       (this->playerno() < this->rule()(Rule::NUMBER_OF_PLAYERS));
       n++) {
    Player* player = Player::new_(::setting(Setting::PRIVATE_DATA_DIRECTORY)
				  + "/player."
				  + DK::Utils::String::to_string(n + 1));
    if (player)
      this->player_p.push_back(player);
    else
      this->player_p.push_back(Player::new_((((n == 0) && (!FAST_PLAY))
					     ? Player::HUMAN
					     : Player::AI)));

    this->player_p.back()->no_set(n);
  } // for (n; this->playerno() < this->rule()(Rule::NUMBER_OF_PLAYERS))

  DEBUG_RETURNING(VOID,
		  INFO_PARTY && INFO_INIT,
		  "Party::Party()");
} // Party::Party()

/**
 **
 ** destructor
 **
 ** @param	-
 **
 ** @return	-
 **
 ** @author	Diether Knof
 **
 ** @version	0.5.2
 **
 **/
Party::~Party()
{
  DEBUG_CALLING(INFO_PARTY && INFO_INIT,
		"Party::~Party()");

  delete this->game_p;
  delete this->rule_p;

  DEBUG_RETURNING(VOID,
		  INFO_PARTY && INFO_INIT,
		  "Party::~Party()");
} // Party::~Party()

/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	the current game
 **
 ** @author	Diether Knof
 **
 ** @version	0.5.2
 **
 **/
Game&
Party::game()
{
  DEBUG_CALLING(INFO_PARTY && INFO_VALUE,
		"Party::game()");

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

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

/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	the gamenumber
 **
 ** @author	Diether Knof
 **
 ** @version	0.5.2
 **
 **/
unsigned
Party::gameno() const
{
  DEBUG_CALLING(INFO_PARTY && INFO_VALUE,
		"Party::gameno()");

  DEBUG_RETURNING(this->gameno_p,
		  INFO_PARTY && INFO_VALUE,
		  "Party::gameno()");
} // unsigned Party::gameno() const

/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	the rule
 **
 ** @author	Diether Knof
 **
 ** @version	0.5.2
 **
 **/
Rule&
Party::rule()
{
  DEBUG_CALLING(INFO_PARTY && INFO_VALUE,
		"Party::rule()");

  DEBUG_ASSERTION(this->rule_p != NULL,
		  "Party::rule():\n"
		  "'rule_p' is a NULL-pointer");

  DEBUG_RETURNING(*(this->rule_p),
		  INFO_PARTY && INFO_VALUE,
		  "Party::rule()");
} // Rule Party::rule()

/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	the rule
 **
 ** @author	Diether Knof
 **
 ** @version	0.5.2
 **
 **/
Rule const&
Party::rule() const
{
  DEBUG_CALLING(INFO_PARTY && INFO_VALUE,
		"Party::rule()");

  DEBUG_ASSERTION(this->rule_p != NULL,
		  "Party::rule():\n"
		  "'rule_p' is a NULL-pointer");

  DEBUG_RETURNING(*(this->rule_p),
		  INFO_PARTY && INFO_VALUE,
		  "Party::rule()");
} // Rule Party::rule()

/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	the number of players
 **
 ** @author	Diether Knof
 **
 ** @version	0.5.1
 **
 **/
unsigned
Party::playerno() const
{
  DEBUG_CALLING(INFO_PARTY && INFO_VALUE,
		"Party::playerno()");

  DEBUG_RETURNING(this->player_p.size(),
		  INFO_PARTY && INFO_VALUE,
		  "Party::playerno()");
} // unsigned Party::playerno() const

/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	number of humans in the party
 **
 ** @version	0.5.1
 **
 ** @author	Diether Knof
 **
 **/
unsigned
Party::humanno() const
{
  DEBUG_CALLING(INFO_PARTY && INFO_VALUE,
		"Party::humanno()");

  // count the number of human players
  unsigned human_no = 0;
  for (vector<Player*>::const_iterator player = this->player_p.begin();
       player != this->player_p.end();
       player++)
    if ((*player)->type() == Player::HUMAN)
      human_no += 1;

  DEBUG_RETURNING(human_no,
		  INFO_PARTY && INFO_VALUE,
		  "Party::humanno()");
} // unsigned Party::humanno() const

/**
 **
 ** -> result
 **
 ** @param	p	number of the player
 **
 ** @return	the player with the number 'p'
 **
 ** @author	Diether Knof
 **
 ** @version	0.5.1
 **
 **/
Player&
Party::player(unsigned const p)
{
  DEBUG_CALLING(INFO_PARTY && INFO_VALUE,
		"Party::player(p)");

  DEBUG_ASSERTION((p < this->playerno()),
		  "Party::player(p):\n"
		  "'p' is not valid (");

  DEBUG_RETURNING(*(this->player_p[p]),
		  INFO_PARTY && INFO_VALUE,
		  "Party::player(p)");
} // Player& Party::player(unsigned const p)

/**
 **
 ** -> result
 **
 ** @param	p	number of the player
 **
 ** @return	the player with the number 'p'
 **
 ** @author	Diether Knof
 **
 ** @version	0.5.1
 **
 **/
Player const&
Party::player(unsigned const p) const
{
  DEBUG_CALLING(INFO_PARTY && INFO_VALUE,
		"Party::player(p)");

  DEBUG_ASSERTION((p < this->playerno()),
		  "Party::player(p):\n"
		  "'p' is not valid (");

  DEBUG_RETURNING(*(this->player_p[p]),
		  INFO_PARTY && INFO_VALUE,
		  "Party::player(p)");
} // Player const& Party::player(unsigned const p) const

/**
 **
 ** Sets the player in the party
 ** (the playernumber is taken from 'player').
 ** The player is taken directly, 'party' deletes it afterwards.
 **
 ** @param	player	the player to be set
 ** @param	n	the number of the player
 **
 ** @return	the new player
 **
 ** @author	Diether Knof
 **
 ** @version	0.5.2
 **
 **/
Player const&
Party::player_set(Player* player, unsigned const n)
{
  DEBUG_CALLING(INFO_PARTY && INFO_VALUE,
		"Party::player_set(player, n)");

  DEBUG_ASSERTION((n < this->playerno()),
		  "Party::player_set(player, n):\n"
		  "'n' is not valid");

  DEBUG_ASSERTION(!((::game_status & GAMESTATUS::GAME)
		    && !this->game().trick_current().isfull()),
		  "Party::player_set(player, n):\n"
		  "  game_status is in the game.");

  delete this->player_p[n];
  this->player_p[n] = player;
  this->player_p[n]->no_set(n);

  if (::ui != NULL)
    ::ui->player_update(this->player(n));

  DEBUG_RETURNING(*(this->player_p[n]),
		  INFO_PARTY && INFO_VALUE,
		  "Party::player_set(player)");
} // Player Party::player_set(Player* player, unsigned const n)


/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	the gamepointstable
 **
 ** @author	Borg Enders
 **
 ** @version	0.5.2
 **
 **/
GamePointsTable const&
Party::gamepointstable() const
{
  DEBUG_CALLING(INFO_PARTY && INFO_VALUE,"Party::gamepointstable()");

  DEBUG_ASSERTION(this->gamepointstable_p != NULL,
		  "Party::gamepointstable_p is not valid");

  DEBUG_RETURNING(*(this->gamepointstable_p),
		  INFO_PARTY && INFO_VALUE,
		  "Party::table()");
} // GamePointsTable const& Party::gamepointstable() const

/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	the gamepointstable
 **
 ** @author	Borg Enders
 **
 ** @version	0.5.2
 **
 **/
GamePointsTable&
Party::gamepointstable()
{
  DEBUG_CALLING(INFO_PARTY && INFO_VALUE,
		"Party::gamepointstable()");

  DEBUG_ASSERTION(this->gamepointstable_p != NULL,
		  "Party::gamepointstable_p is not valid");

  DEBUG_RETURNING(*(this->gamepointstable_p),
		  INFO_PARTY && INFO_VALUE,
		  "Party::gamepointstable()");
} // GamePointsTable& Party::gamepointstable()

/**
 **
 ** set the name of the player 'player_no' to 'new_name'
 **
 ** @param	player_no	the number of the player
 ** @param	new_name	the new name
 **
 ** @return	the (new) name of the player
 **
 ** @author	Borg Enders
 **
 ** @version	0.5.2
 **
 **/
string const
Party::playername_set(unsigned const player_no,
		      string const& new_name)
{
  DEBUG_CALLING(INFO_PARTY && INFO_VALUE,"Party::playername_set()");

  DEBUG_ASSERTION((player_no < this->playerno()),
		  "Party::playername_set():  Illegal Value for player number: "
		  << player_no);

  this->player_p[player_no]->name_set(new_name);
  if (::ui != NULL)
    ::ui->name_update(this->player(player_no));

  DEBUG_RETURNING(this->player(player_no).name(),
		  INFO_PARTY && INFO_VALUE,"Party::playername_set()");  
} // string const Party::playername_set(player_no, new_name)


/**
 **
 ** sets the type of the player 'player_no' to 'new_type'
 **
 ** @param	player_no	the number of the player
 ** @param	new_type	the new type
 **
 ** @return	the (new) type of the player
 **
 ** @author	Borg Enders
 ** @author	Diether Knof
 **
 ** @version	0.5.2
 **
 ** @todo	keep the aiconfig
 **
 **/
Player::Type
Party::playertype_set(unsigned const player_no,
		      Player::Type const new_type)
{
  DEBUG_CALLING(INFO_PARTY && INFO_VALUE,
		"Party::playertype_set()");

  DEBUG_ASSERTION((player_no < this->playerno()),
		  "Party::playertype_set(): "
		  << "  Illegal Value for player number: "
		  << player_no); 

  DEBUG_ASSERTION((this->player_p[player_no] != NULL),
		  "Party::playertype_set(): "
		  << "  player " << player_no << " does not exists");

  if (this->player(player_no).type() == new_type)
    DEBUG_RETURNING(this->player(player_no).type(),
		    INFO_PARTY && INFO_VALUE,
		    "Party::playertype_set()");

  // create the new player
  this->player_set(Player::new_(new_type, this->player(player_no)),
		   player_no);

  DEBUG_RETURNING(this->player(player_no).type(),
		  INFO_PARTY && INFO_VALUE,
		  "Party::playertype_set()");
} // Player::Type Party::playertype_set(unsigned const player_no, Player::Type const new_type)


/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	seed of the party
 **
 ** @author	Diether Knof
 **
 ** @version	0.5.2
 **
 **/
unsigned
Party::seed_first() const
{
  DEBUG_CALLING(INFO_PARTY && INFO_VALUE,
		"Party::seed_first()");

  DEBUG_RETURNING(this->seed_first_p,
		  INFO_PARTY && INFO_VALUE,
		  "Party::seed_first()");
} // unsigned Party::seed_first() const

/**
 **
 ** sets the first seed
 **
 ** @param	seed_first_new	new first seed
 **
 ** @return	new first seed
 **
 ** @author	Diether Knof
 **
 ** @version	0.5.2
 **
 **/
unsigned
Party::seed_first_set(unsigned const seed_first_new)
{
  DEBUG_CALLING(INFO_PARTY && INFO_VALUE,
		"Party::seed_first_set(seed_first_new)");

  this->seed_first_p = seed_first_new;

  DEBUG_RETURNING(seed(),INFO_PARTY && INFO_VALUE,
		  "Party::seed_first_set(seed_first_new)");
} // unsigned Party::seed_first_set(unsigned const seed_first_new)

/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	seed of the party
 **
 ** @author	Diether Knof
 **
 ** @version	0.5.2
 **
 **/
unsigned
Party::seed() const
{
  DEBUG_CALLING(INFO_PARTY && INFO_VALUE,
		"Party::seed()");

  DEBUG_RETURNING(this->seed_p,
		  INFO_PARTY && INFO_VALUE,
		  "Party::seed()");
} // unsigned Party::seed() const

/**
 **
 ** sets the seed
 **
 ** @param	seed_new	new seed
 **
 ** @return	new seed
 **
 ** @author	Diether Knof
 **
 ** @version	0.5.2
 **
 **/
unsigned
Party::seed_set(unsigned const seed_new)
{
  DEBUG_CALLING(INFO_PARTY && INFO_VALUE,
		"Party::seed_set(seed_new)");

  if (seed_new == UINT_MAX)
    this->seed_set_random();
  else
    this->seed_p = seed_new % PSEUDO_RAND_MAX;

  DEBUG_RETURNING(this->seed(),
		  INFO_PARTY && INFO_VALUE,
		  "Party::seed_set(seed_new)");
} // unsigned Party::seed_set(unsigned const seed_new)

/**
 **
 ** sets the seed of the party to a random value
 ** (uses the system clock)
 **
 ** @param	-
 **
 ** @return	seed of the party
 **
 ** @author	Diether Knof
 **
 ** @version	0.5.2
 **
 ** @todo	'better' random value
 **
 **/
unsigned
Party::seed_set_random()
{
  DEBUG_CALLING(INFO_PARTY && INFO_VALUE,
		"Party::seed_set_random()");

  // *** not so elegant
  //this->seed_p = static_cast<unsigned>(clock()) % PSEUDO_RAND_MAX;

  this->seed_p = static_cast<unsigned>(time(NULL) % PSEUDO_RAND_MAX);
  this->seed_next();

  DEBUG_RETURNING(this->seed(),
		  INFO_PARTY && INFO_VALUE,
		  "Party::seed_set_random()");
} // unsigned Party::seed_set_random()

/**
 **
 ** calculates the next seed with the old one
 **
 ** @param	-
 **
 ** @return	the next seed
 **
 ** @author	Diether Knof
 **
 ** @version	0.5.2
 **
 **/
unsigned
Party::seed_next()
{
  DEBUG_CALLING(INFO_PARTY && INFO_VALUE, " Party::seed_next()"); 

  ::pseudo_rand_set(this->seed());

  // don't take the next random value but skip 48 values
  // (because 48 values are used for the distribution of the cards
  //  and we do want totally new hands)
  for (unsigned i = 0; i < 49; i++)
    this->seed_p = ::pseudo_rand_next();

  if (SEED_OUT) {
    // count the seeds
    static int seed_count = 0;
    seed_count += 1;

    // when a random number has already been tested, stop
    static vector<bool> tested(PSEUDO_RAND_MAX, false);
    if (tested[this->seed()] || (seed_count == PSEUDO_RAND_MAX)) {
      cout << "\nNumber of seeds: " << seed_count
	<< " (" << PSEUDO_RAND_MAX << ")" << endl;
      ::game_status = GAMESTATUS::QUIT;
      ::exit(0);
    }

    tested[this->seed()] = true;
  } // if (SEED_OUT)

  DEBUG_RETURNING(this->seed(),
		  INFO_PARTY && INFO_VALUE,
		  " Party::seed_next()"); 
} // unsigned Party::seed_next()

/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	the first startplayer
 **
 ** @author	Diether Knof
 **
 ** @version	0.5.2
 **
 **/
unsigned
Party::startplayer_first() const
{
  DEBUG_CALLING(INFO_PARTY && INFO_VALUE,
		"Party::startplayer_first()");

  DEBUG_RETURNING(this->startplayer_first_p,
		  INFO_PARTY && INFO_VALUE,
		  "Party::startplayer_first()");   
} // unsigned Party::startplayer_first() const

/**
 **
 ** sets the first startplayer
 **
 ** @param	startplayer_first_new	the new first startplayer
 **
 ** @return	-
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.2
 **
 **/
void
Party::startplayer_first_set(unsigned const startplayer_first_new)
{
  DEBUG_CALLING(INFO_PARTY && INFO_VALUE,
		"Party::startplayer_first_set(startplayer_first_new)");

  DEBUG_ASSERTION((startplayer_first_new < this->playerno()),
		  "Party::startplayer_first_set"
		  "(" << startplayer_first_new << "):\n"
		  "  Illegal Value for startplayer number");

  this->startplayer_first_p = startplayer_first_new;

  DEBUG_RETURNING(VOID,
		  INFO_PARTY && INFO_VALUE,
		  "Party::startplayer_first_set(startplayer_first_new)");
} // void Party::startplayer_first_set(unsigned const startplayer_first_new)

/**
 **
 ** sets the first startplayer to random
 **
 ** @param	-
 **
 ** @return	-
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.2
 **
 **/
void
Party::startplayer_first_set_random()
{
  DEBUG_CALLING(INFO_PARTY && INFO_VALUE,
		"Party::startplayer_first_set_random()");

  this->startplayer_first_p = UINT_MAX;

  DEBUG_RETURNING(VOID,
		  INFO_PARTY && INFO_VALUE,
		  "Party::startplayer_first_set_random()");
} // void Party::startplayer_first_set_random()

/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	the startplayer
 **
 ** @author	Diether Knof
 **
 ** @version	0.5.2
 **
 **/
unsigned
Party::startplayer() const
{
  DEBUG_CALLING(INFO_PARTY && INFO_VALUE,
		"Party::startplayer()");

  DEBUG_RETURNING(this->startplayer_p,
		  INFO_PARTY && INFO_VALUE,
		  "Party::startplayer()");   
} // unsigned Party::startplayer() const

/**
 **
 ** write the party into the output stream
 **
 ** @param	ostr	output stream
 **
 ** @return	output stream
 **
 ** @author	Diether Knof
 **
 ** @version	0.5.2
 **
 ** @todo	output of the game?
 **
 **/
ostream&
Party::out(ostream& ostr) const
{
  DEBUG_CALLING(INFO_PARTY && INFO_IO,
		"Party::out(ostr)");

  ostr << "Party:\n";

  ostr << "first seed: " << this->seed_first() << "\n"
    << "first startplayer: " << this->startplayer_first() << "\n"
    << "seed: " << this->seed() << "\n"
    << "startplayer: " << this->startplayer() << "\n"
    << "gameno: " << this->gameno() << "\n"
    << "\n";
  ostr << "Rules: \n"
    << "{\n"
    << this->rule()
    << "}\n";

  ostr << "Players: \n"
    << "{";
  for (vector<Player*>::const_iterator player
       = ::party.player_p.begin();
       player != this->player_p.end();
       player++)
    ostr << "Player " << (*player)->no()
      << " (" << (*player)->name()
      << "):\n"
      << **player
      << "\n";
  ostr << "}\n";
  ostr << "\n";

#ifdef POSTPHONED
  // *** is this necessary?
  if (this->game_p != NULL)
    ostr << "Game:\n"
      << this->game();
#endif

  DEBUG_RETURNING(ostr,
		  INFO_PARTY && INFO_IO,
		  "Party::out(ostr)");
} // ostream& Party::out(ostream& ostr) const

/**
 **
 ** inits the party:
 ** get the info of the first startplayer, the first seed,
 ** the ruleset and the players
 **
 ** @param	-
 **
 ** @return	-
 **
 ** @author	Diether Knof
 **
 ** @version	0.5.2
 **
 **/
void
Party::init()
{
  DEBUG_CALLING(INFO_PARTY && INFO_INIT, "Party::init()");

  this->gameno_p = 0;

  // create new pointstable;
  if (this->gamepointstable_p != NULL)
    delete this->gamepointstable_p;
  this->gamepointstable_p = new GamePointsTable(vector<string>(), -1);

  for (vector<Player*>::const_iterator player = this->player_p.begin();
       player != this->player_p.end();
       player++)
    ::ui->name_update(**player);

  if (::game_status != GAMESTATUS::PARTY_INIT)
    DEBUG_RETURNING(VOID,
		    INFO_PARTY && INFO_INIT,
		    "Party::init()");

  // get the settings
  ::ui->party_get_settings();
  if (dynamic_cast<UI_Wrap*>(::ui)
      && (dynamic_cast<UI_Wrap*>(::ui)->ui->type() == UI_TYPE::NONE)) {
    for (unsigned p = 0; p < this->playerno(); p++)
      this->playertype_set(p, Player::AI);
  } // if (::ui->type() == UI_TYPE::NONE)


  if (::game_status != GAMESTATUS::PARTY_INIT)
    DEBUG_RETURNING(VOID,
		    INFO_PARTY && INFO_INIT,
		    "Party::init()");

  // set the seed
  this->seed_set(this->seed_first());
  // set the startplayer
  if (this->startplayer_first() == UINT_MAX) {
    this->startplayer_p = (static_cast<unsigned>(::time(NULL))
			   % this->playerno());
  } else {
    this->startplayer_p = this->startplayer_first();
  }

  if (::setting(Setting::SAVE_PARTY_CHANGES)) {
    // save the rules in the private data directory
    this->rule().save(::setting(Setting::PRIVATE_DATA_DIRECTORY)
		      + "/"
		      + ::setting(Setting::RULES_DIRECTORY)
		      + "/"
		      + "last");

    { // save the players in the private data directory
      unsigned n = 0;
      for (vector<Player*>::const_iterator player = this->player_p.begin();
	   player != this->player_p.end();
	   n++, player++)
	(*player)->save(::setting(Setting::PRIVATE_DATA_DIRECTORY)
			+ "/player." + DK::Utils::String::to_string(n + 1));
    } // save the players in the private data directory
  } // if (::setting(Setting::SAVE_PARTY_CHANGES))

  DEBUG_RETURNING(VOID,
		  INFO_PARTY && INFO_INIT,
		  "Party::init()");
} // void Party::init()


/**
 **
 ** play the party:
 ** play games until the user ends the party
 ** or the party is ended according to the rules
 **
 ** @param	-
 **
 ** @return	-
 **
 ** @author	Diether Knof
 **
 ** @version	0.5.2
 **
 **/
void
Party::play()
{
  DEBUG_CALLING(INFO_PARTY &&  INFO_GAMEPLAY, "Party::play()");


  using namespace GAMESTATUS;

  // init the party
  ::game_status = PARTY_INIT;
  this->init();

  if (::game_status != PARTY_INIT)
    DEBUG_RETURNING(VOID,
		    INFO_PARTY && INFO_GAMEPLAY,
		    "Party::play()");

  ::game_status = PARTY_PLAY;


  ::ui->party_start();
  for (this->gameno_p = 0; ::game_status == PARTY_PLAY; ++(this->gameno_p)) {

#ifdef POSTPHONED
    if (this->gameno_p == this->rule()(Rule::NUMBER_OF_GAMES))
      break;
#endif

    if (SEED_OUT)
      this->startplayer_p = 0;

    // create a new game
    ::game_status = GAME_NEW;
    this->game_p = new Game(*this, *(this->player_p[this->startplayer()]));

    this->game().play();
    if (::game_status != GAME_FINISHED) {
      ::ui->game_close();
      DEBUG_RETURNING(VOID,
		      INFO_PARTY &&  INFO_GAMEPLAY,
		      "Party::play()");
    }

    ::game_status = GAME_CLOSE;
    ::ui->game_close();
    if (::game_status != GAME_CLOSE)
      DEBUG_RETURNING(VOID,
		      INFO_PARTY && INFO_GAMEPLAY,
		      "Party::play()");

    ::game_status = PARTY_PLAY;
    if ((this->game().type() == GAMETYPE::NORMAL)
	|| ((this->game().type() == GAMETYPE::POVERTY)
	    && (this->rule()(Rule::POVERTY_SHIFT))
	   )
	|| (this->game().type() == GAMETYPE::MARRIAGE)) {
      (this->startplayer_p += 1) %= this->playerno();
    }

    delete this->game_p;
    this->game_p = NULL;

    // next seed
    this->seed_next();

  } // for (gameno)
  ::game_status = PARTY_FINISHED;

  if (::game_status != PARTY_FINISHED)
    DEBUG_RETURNING(VOID,
		    INFO_PARTY &&  INFO_GAMEPLAY,
		    "Party::play()");
  ::ui->party_finish();

  DEBUG_RETURNING(VOID,
		  INFO_PARTY &&  INFO_GAMEPLAY,
		  "Party::play()");
} // void Party::play()

/**
 **
 ** write the party into the output stream
 **
 ** @param	ostr	output stream
 ** @param	party	party
 **
 ** @return	output stream
 **
 ** @author	Diether Knof
 **
 ** @version	0.5.2
 **
 **/
ostream&
operator<<(ostream& ostr, Party const& party)
{
  DEBUG_CALLING(INFO_PARTY && INFO_IO,
		"operator<<(ostr, party)");

  party.out(ostr);

  DEBUG_RETURNING(ostr,
		  INFO_PARTY && INFO_IO,
		  "operator<<(ostr, party)");
} // ostream& operator<<(ostream& ostr, Party const& party)
