/**********************************************************************
 *
 *   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 "os.h"
#include "gameplay.h"
#include "party_points.h"
#include "seed.h"
#include "bug_report.h"

using namespace OS_TYPE;

// Nearly all functions of OS are virtual (all but OSType OS::type())

/**
 **
 ** Constructor
 ** (to be called from a child class)
 **
 ** @param	type	the OSType
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
OS::OS(OSType const type) :
type_p(type),
  party_(NULL),
  game_(NULL),
  trick_(NULL)
{ }

/**
 **
 ** Constructor
 **
 ** @param	-
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
OS::OS() :
type_p(OS_TYPE::NONE),
  party_(NULL),
  game_(NULL),
  trick_(NULL)
{ }

/**
 **
 ** Constructor
 **
 ** @param	os	the OS
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
OS::OS(OS const& os) :
type_p(os.type_p),
  party_(os.party_),
  game_(os.game_),
  trick_(os.trick_)
{ }

/**
 **
 ** copy operator
 **
 ** @param	os	the OS
 **
 ** @return	the os
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
OS&
OS::operator=(OS const& os)
{
  this->type_p = os.type_p;
  this->party_ = os.party_;
  this->game_ = os.game_;
  this->trick_ = os.trick_;
  return *this;
}

/**
 **
 ** Destructor
 **
 ** @param	-
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
OS::~OS()
{ }

/**
 **
 ** create a new os
 ** (it should just call the new-operator of the child class)
 **
 ** @param	type	type of the OS to create
 **
 ** @return	pointer of OS
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
OS*
new_OS(OSType const type)
{
  OS* os = NULL;

  switch (type) {
  case NONE:
    os = new OS(NONE);
    break;
  case GAMEPLAY:
    os = new OS_NS::Gameplay;
    break;
  case PARTY_POINTS:
    os = new OS_NS::PartyPoints;
    break;
  case SEED:
    os = new OS_NS::Seed;
    break;
  case OS_BUG_REPORT:
    os = new OS_NS::BugReport;
    break;
  case OS_BUG_REPORT_REPLAY:
    DEBUG_ASSERTION(false,
		    "OS* new_OS(type):\n"
		    "  call with 'type' == 'BUG_REPORT_REPLAY'.\n"
		    "  this os needs an argument (the bug report)");\
      break;
  case SOUND:
    DEBUG_ASSERTION(false,
		    "OS 'SOUND' not yet implemented");
    break;
  } // switch(type)

  return os;
} // OS* new_OS(OSType const type)

/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	type of the OS
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
OSType
OS::type() const
{ return this->type_p; }

/**
 **
 ** Function for the initialisation of the OS.
 **
 ** @param	argc	number of arguments
 ** @param	argv	arguments
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
void
OS::init(int& argc, char**& argv)
{ }


/**
 **
 ** updates the OS
 **
 ** @param	-
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
void
OS::update()
{ }

/**
 **
 ** sleeps the given time
 ** (in miliseconds, UINT_MAX for infinity)
 **
 ** @param	sleep_usec	time to sleep
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
void
OS::sleep(unsigned const sleep_usec)
{ }

/**
 **
 ** all language elements of the OS shall be updated
 **
 ** @param	-
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
void
OS::language_update()
{ }

/**
 **
 ** the party is opened
 **
 ** @param	the party that is opened
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
void
OS::party_open(Party const& party)
{
  DEBUG_ASSERTION(!this->party_,
		  "OS::party_open(party):\n"
		  "  party already set");
  this->party_ = &party;
  return ;
}

/**
 **
 ** gets and sets the settings of the party
 **
 ** @param	-
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
void
OS::party_get_settings()
{ }

/**
 **
 ** start of the party
 **
 ** @param	-
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
void
OS::party_start()
{ }

/**
 **
 ** a new round is started
 **
 ** @param	round	round that is started
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
void
OS::party_start_round(unsigned const round)
{ }

/**
 **
 ** end of the party
 ** (p.e. to show the points and the winner)
 **
 ** @param	-
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
void
OS::party_finish()
{ }

/**
 **
 ** the party will close
 **
 ** @param	-
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
void
OS::party_close()
{
  DEBUG_ASSERTION(this->party_,
		  "OS::party_close():\n"
		  "  party not set");
  this->party_ = NULL;
  return ;
}


/**
 **
 ** a game is opened
 **
 ** @param	game	the game that is opened
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
void
OS::game_open(Game const& game)
{
  DEBUG_ASSERTION(!this->game_,
		  "OS::game_open(game):\n"
		  "  game already set");
  this->game_ = &game;
  return ;
}

/**
 **
 ** the game is redistributed
 **
 ** @param	-
 **
 ** @return	-
 **
 ** @version	0.6.7b
 **
 ** @author	Diether Knof
 **
 **/
void
OS::game_redistribute()
{ }


/**
 **
 ** gets the reservations of the player 'player'
 ** Here is the first time, the hands can be shown (and should)
 **
 ** @param	player	the player that makes the reservation
 **
 ** @return	Reservation of the player 'player'
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
void
OS::reservation_get(Player const& player)
{ }

/**
 **
 ** the game is started
 ** (p.e. show the announcements of the other players)
 **
 ** @param	-
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
void
OS::game_start()
{ }

/**
 **
 ** the game is finished
 ** (p.e. show the winner and the points of the game)
 **
 ** @param	-
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
void
OS::game_finish()
{ }

/**
 **
 ** the game will close
 **
 ** @param	-
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
void
OS::game_close()
{
  DEBUG_ASSERTION(this->game_,
		  "OS::game_close():\n"
		  "  game not set");
  this->game_ = NULL;
  return ;
}


/**
 **
 ** a new trick is opened
 **
 ** @param	trick	trick that is opened
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
void
OS::trick_open(Trick const& trick)
{
  DEBUG_ASSERTION(!this->trick_,
		  "OS::trick_open(trick):\n"
		  "  trick already set");
  this->trick_ = &trick;
  return ;
}

/**
 **
 ** the trick 'trick' is full
 **
 ** @param	-
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
void
OS::trick_full()
{ }

/**
 **
 ** moves the trick in the pile of the winnerplayer
 **
 ** @param	-
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
void
OS::trick_move_in_pile()
{ }

/**
 **
 ** the trick is closed
 **
 ** @param	-
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
void
OS::trick_close()
{
  DEBUG_ASSERTION(this->trick_,
		  "OS::trick_close():\n"
		  "  trick not set");
  this->trick_ = NULL;
  return ;
}

/**
 **
 ** gets the card, the player wishes to play
 ** (don't remove it from the hand!)
 **
 ** @param	player	the player who shall play a card
 **
 ** @return	Card to be played
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
void
OS::card_get(Player const& player)
{ }

/**
 **
 ** the player 'player' plays the card 'card'
 **
 ** @param	card  	the played card
 ** @param	player	the player, who has played a card
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
void
OS::card_played(Card const& card, Player const& player)
{ }

/**
 **
 ** the announcement 'announcement' has been made by player 'player'
 **
 ** @param	announcement	the announcement
 ** @param	player		the player, who has made the announcement
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
void
OS::announcement_made(Announcement const& announcement, Player const& player)
{ }

/**
 **
 ** the player has swines
 **
 ** @param	player		the player with the swines
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
void
OS::swines_announced(Player const& player)
{ }

/**
 **
 ** the player has hyperswines
 **
 ** @param	player		the player with the hyperswines
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
void
OS::hyperswines_announced(Player const& player)
{ }

/**
 **
 ** 'player' has a poverty and shifts cards
 **
 ** @param	player	the player who has the poverty
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
void
OS::poverty_shifting(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	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
void
OS::poverty_shift(Player const& player, unsigned const cardno)
{ }

/**
 **
 ** ask 'player' whether to accept the poverty
 **
 ** @param	player	the player who has denied to take the cards
 ** @param	cardno	number of cards that are given back
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
void
OS::poverty_ask(Player const& player, unsigned const cardno)
{ }

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

/**
 **
 ** all players have denied to take the cards
 **
 ** @param	-
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
void
OS::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 denied to take the cards
 ** @param	cardno	number of cards that are given back
 ** @param	trumpno	number of trumps of the cards
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
void
OS::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	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
void
OS::poverty_shift(Player const& player)
{ }

/**
 **
 ** returns whether 'player' accepts the shifted cards
 **
 ** @param	player	the player who shifts the cards
 ** @param	cardno	the number of shifted cards
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
void
OS::poverty_take_accept(Player const& player, unsigned const cardno)
{ }

/**
 **
 ** changes the cards from the poverty-player
 **
 ** @param	player	the player who has accepted the cards
 ** @param	cards	the cards that are given to the player
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
void
OS::poverty_cards_change(Player const& player, Hand const& cards)
{ }

/**
 **
 ** the poverty player 'player' gets 'cards'
 **
 ** @param	player	the player gets the cards
 ** @param	cards	the cards that are given to the player
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
void
OS::poverty_cards_get_back(Player const& player, Hand const& cards)
{ }

/**
 **
 ** marriage: Information of the new team
 **
 ** @param	bridegroom	the player with the marriage
 ** @param	bride		the bride
 **
 ** @return	-
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.7
 **
 **/
void
OS::marriage(Player const& bridegroom,
	     Player const& bride)
{ }

/**
 **
 ** genscher: -> result
 **
 ** @param	-
 **
 ** @return	-
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.7
 **
 **/
void
OS::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.6.7
 **
 **/
void
OS::genscher(Player const& player,
	     Player const& partner)
{ }

/**
 **
 ** redraw all
 **
 ** @param	-
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
void
OS::redraw_all()
{ }

/**
 **
 ** the player 'player' has to be updated
 **
 ** @param	player	the player, who has changed
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
void
OS::player_update(Player const& player)
{ }

/**
 **
 ** the name of the player 'player' has to be updated
 **
 ** @param	player	the player, whose name is changed
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
void
OS::name_update(Player const& player)
{ }

/**
 **
 ** the hand of the player 'player' has to be updated
 **
 ** @param	player	the player, whose hand is to be updated
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
void
OS::hand_update(Player const& player)
{ }

/**
 **
 ** the teaminfo of the player 'player' has to be updated
 **
 ** @param	player	the player whose team should be updated
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
void
OS::teaminfo_update(Player const& player)
{ }

/**
 **
 ** the gametype has to be updated
 ** (take the player from 'game.soloplayer()'
 **
 **
 ** @param	-
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
void
OS::gametype_update()
{ }

/**
 **
 ** the rule 'type' has changed
 **
 ** @param	type		the type that has changed
 ** @param	old_value	old value
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
void
OS::rule_update(int const type, void const* const old_value)
{ }

/**
 **
 ** the setting 'type' has changed
 **
 ** @param	type		the type that has changed
 ** @param	old_value	old value
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
void
OS::setting_update(int const type, void const* const old_value)
{ }

/**
 **
 ** load the page with the help
 ** use the settings
 **
 ** @param	page	the page to be loaded
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
void
OS::help_load(string const& page)
{ }

/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	the latest status message
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
Translator::Translation
OS::status_message() const
{
  if (this->status_message_.empty())
    return ::translator("");

  return this->status_message_.back();
} // Translator::Translation OS::status_message() const

/**
 **
 ** adds the status message
 **
 ** @param	status_message	the new status message
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
void
OS::add_status_message(Translator::Translation const& status_message)
{
  this->status_message_.push_back(status_message);
  this->status_message_changed(status_message);

  return ;
} // void OS::add_status_message(Translator::Translation const& status_message)

/**
 **
 ** remove the status message
 **
 ** @param	status_message	the status message that is to be removed
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
void
OS::remove_status_message(Translator::Translation const& status_message)
{
  vector<Translator::Translation>::iterator pos = std::find(this->status_message_.begin(),
							    this->status_message_.end(),
							    status_message);

  DEBUG_ASSERTION((pos != this->status_message_.end()),
		  "OS::remove_status_message(status_message):\n"
		  "  message '" << status_message << "' "
		  "not found in the list");

  if (pos != this->status_message_.end())
    pos = this->status_message_.erase(pos);

  if (pos == this->status_message_.end())
    this->status_message_changed(this->status_message());

  return ;
} // void OS::remove_status_message(Translator::Translation const& status_message)

/**
 **
 ** the status message has changed
 **
 ** @param	status_message	the status message
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
void
OS::status_message_changed(Translator::Translation const& status_message)
{ }

/**
 **
 ** the program is busy
 **
 ** @param	-
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
void
OS::set_busy()
{
  this->busy_ = true;
  return ;
}

/**
 **
 ** the program is not busy any more
 **
 ** @param	-
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
void
OS::set_not_busy()
{
  this->busy_ = false;
  return ;
}

/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	the progress
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
double
OS::progress() const
{
  if (this->progress_max_ == 0)
    return 1;

  return (this->progress_ / this->progress_max_);
} // double OS::progress() const

/**
 **
 ** sets the maximal progress
 **
 ** @param	progress_max	the maximal progress
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
void
OS::set_max_progress(double const progress_max)
{
  DEBUG_ASSERTION((this->progress_max_ == 0),
		  "OS::set_max_progress(progress_max):\n"
		  "  'this->progress_max_' is already set: "
		  << this->progress_max_ << ".");

  this->progress_max_ = progress_max;
  this->progress_changed(this->progress());

  return ;
} // void OS::set_max_progress(double const progress_max)

/**
 **
 ** adds 'progress' to the progress
 **
 ** @param	progress	the progress
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
void
OS::add_progress(double const progress)
{
  this->progress_ += progress;
  DEBUG_ASSERTION((this->progress() <= 1),
		  "OS::add_progress(progress):\n"
		  "  'progress' is greater than 1");

  this->progress_changed(this->progress());

  return ;
} // void OS::add_progress(double const progress)

/**
 **
 ** the progress is finished
 **
 ** @param	-
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
void
OS::finish_progress()
{
  DEBUG_ASSERTION((this->progress() != 1),
		  "OS::finish_progress():\n"
		  "  'progress' is not equal to 1");

  this->progress_finished();

  return ;
} // void OS::finish_progress()

/**
 **
 ** the progress has changed
 **
 ** @param	progress	the progress
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
void
OS::progress_changed(double const progress)
{ }

/**
 **
 ** the progress is finished
 **
 ** @param	-
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
void
OS::progress_finished()
{ }

/**
 **
 ** information for the user
 **
 ** @param	message		message
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
void
OS::information(Translator::Translation const& message)
{ }

/**
 **
 ** an error has occured
 **
 ** @param	message		error message
 **
 ** @return	-
 **
 ** @version	0.6.7
 **
 ** @author	Diether Knof
 **
 **/
void
OS::error(string const& error)
{ }
