/**********************************************************************
 *
 *   freedoko a Doppelkopf-Game
 *    
 *   Copyright (C) 2001-2005  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 "basistypes.h"


////////////////
// GAMESTATUS //
////////////////

// status of the current game
GameStatus game_status = GAMESTATUS::PROGRAMSTART;


/**
 ** -> result
 **
 ** @param	game_status	game status
 **
 ** @return	name of 'game_status'
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.8
 **
 **/
string
name(GameStatus const& game_status)
{
  using namespace GAMESTATUS;

  switch(game_status) {
  case PROGRAMSTART:
    return "program start";
  case QUIT:
    return "quit";
  case PARTY_NEW:
    return "party new";
  case PARTY_INIT:
    return "party init";
  case PARTY_PLAY:
    return "party play";
  case PARTY_FINISHED:
    return "party finished";
  case GAME_NEW:
    return "game new";
  case GAME_INIT:
    return "game init";
  case GAME_RESERVATION:
    return "game reservation";
  case GAME_REDISTRIBUTE:
    return "game redistribute";
  case GAME_POVERTY_SHIFT:
    return "game poverty shift";
  case GAME_PLAY:
    return "game play";
  case GAME_FULL_TRICK:
    return "game full trick";
  case GAME_FINISHED:
    return "game finished";
  } // switch(game_status)

  DEBUG_ASSERTION(false,
		  "::name(GameStatus):\n"
		  "  game status not found: " << static_cast<int>(game_status));

  return "";
} // string name(GameStatus const& game_status)


//////////
// Team //
//////////

/**
 ** converts a maybe team to a real team
 **
 ** @param	team	team to convert
 **
 ** @result	RE for 'team == RE' or 'team == MAYBE_RE',
 **		CONTRA for 'team == CONTRA' or 'team == MAYBE_CONTRA'
 **		UNKNOWN otherwise
 **
 ** @author	Borg Enders
 ** @author	Diether Knof
 **
 ** @version	0.6.8
 **
 **/
Team
maybe_to_team(Team const& team)
{
  using namespace TEAM;

  switch(team) {
  case RE:
  case MAYBE_RE:
    return RE;
  case CONTRA:
  case MAYBE_CONTRA:
    return CONTRA;
  default:
    return UNKNOWN;
  } // switch(team)
} // Team maybe_to_team(Team team)

/**
 ** converts a real team to a maybe team
 **
 ** @param	team	team to convert
 **
 ** @result	MAYBE_RE for 'team == RE' or 'team == MAYBE_RE',
 **		MAYBE_CONTRA for 'team == CONTRA' or 'team == MAYBE_CONTRA'
 **		UNKNOWN otherwise
 **
 ** @author	Borg Enders
 ** @author	Diether Knof
 **
 ** @version	0.6.8
 **
 **/
Team
team_to_maybe(Team const& team)
{
  using namespace TEAM;

  switch(team) {
  case RE:
  case MAYBE_RE:
    return MAYBE_RE;
  case CONTRA:
  case MAYBE_CONTRA:
    return MAYBE_CONTRA;
  default:
    return UNKNOWN;
  } // switch(team)
} // Team team_to_maybe(Team team)

/**
 ** -> result
 **
 ** @param	team	team to flip
 **
 ** @result	CONTRA for 'team == RE',
 **		MAYBE_CONTRA for 'team == MAYBE_RE',
 **		RE for 'team == CONTRA'
 **		MAYBE_RE for 'team == MAYBE_CONTRA'
 **		UNKNOWN otherwise
 **
 ** @author	Borg Enders
 ** @author	Diether Knof
 **
 ** @version	0.6.8
 **
 **/
Team
opposite(Team const& team)
{
  using namespace TEAM;

  switch(team) {
  case RE:
    return CONTRA;
  case MAYBE_RE:
    return MAYBE_CONTRA;
  case CONTRA:
    return RE;
  case MAYBE_CONTRA:
    return MAYBE_RE;
  default:
    return UNKNOWN;
  } // switch(team)
} // Team opposite(Team team)

/**
 **
 ** -> result
 **
 ** @param	team	team
 **
 ** @return	name of the team
 **
 ** @author	Borg Enders
 ** @author	Diether Knof
 **
 ** @version	0.6.8
 **
 **/
string
name(Team const& team)
{
  using namespace TEAM;

  switch(team) {
  case RE:
    return "re";
  case CONTRA:
    return "contra";
  case MAYBE_RE:
    return "maybe re";
  case MAYBE_CONTRA:
    return "maybe contra";
  case UNKNOWN:
    return "unknown team";
  case NOTEAM:
    return "no team";
  } // switch(team)

  DEBUG_ASSERTION(false,
		  "::name(Team):\n"
		  "  team not found: " << static_cast<int>(team));

  return "";
} // string name(Team team)

/**
 **
 ** -> result
 **
 ** @param	team	team
 **
 ** @return	name of the team
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.8
 **
 **/
string
short_name(Team const& team)
{
  using namespace TEAM;

  switch(team) {
  case RE:
    return "re";
  case CONTRA:
    return "contra";
  case MAYBE_RE:
    return "?re?";
  case MAYBE_CONTRA:
    return "?contra?";
  case UNKNOWN:
    return "?";
  case NOTEAM:
    return "-";
  } // switch(team)

  DEBUG_ASSERTION(false,
		  "::short_name(Team):\n"
		  "  team not found: " << static_cast<int>(team));

  return "";
} // string short_name(Team team)



//////////////
// GAMETYPE //
//////////////

/**
 **
 ** -> result
 **
 ** @param	game_type	game_type
 **
 ** @return	name of the game type
 **
 ** @author	Borg Enders
 ** @author	Diether Knof
 **
 ** @version	0.6.8
 **
 **/
string
name(GameType const& game_type)
{
  using namespace GAMETYPE;

  switch(game_type) {
  case NORMAL:
    return "normal";
  case FIVE_NINES:
    return "five nines";
  case SIX_KINGS:
    return "six kings";
  case FOX_HIGHEST_TRUMP:
    return "fox highest trump";
  case POVERTY:
    return "poverty";
  case GENSCHER:
    return "genscher";
  case MARRIAGE:
    return "marriage";
  case MARRIAGE_SOLO:
    return "marriage solo";
  case MARRIAGE_SILENT:
    return "marriage silent";
  case SOLO_JACK:
    return "solo jack";
  case SOLO_QUEEN:
    return "solo queen";
  case SOLO_KING:
    return "solo king";
  case SOLO_QUEEN_JACK:
    return "solo queen-jack";
  case SOLO_KING_JACK:
    return "solo king-jack";
  case SOLO_KING_QUEEN:
    return "solo king-queen";
  case SOLO_KOEHLER:
    return "solo koehler";
  case SOLO_CLUB:
    return "solo club";
  case SOLO_SPADE:
    return "solo spade";
  case SOLO_HEART:
    return "solo heart";
  case SOLO_DIAMOND:
    return "solo diamond";
  case SOLO_MEATLESS:
    return "solo meatless";
  } // switch(gametype)

  DEBUG_ASSERTION(false,
		  "::name(GameType):\n"
		  "  game type not found: " << static_cast<int>(game_type));

  return "";
} // string name(GameType game_type)

/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @result	whether the status is in a running game
 **
 ** @author	Borg Enders
 ** @author	Diether Knof
 **
 ** @version	0.6.4
 **
 **/
bool
in_running_game()
{
  return ((::game_status == GAMESTATUS::GAME_PLAY)
	  || (::game_status == GAMESTATUS::GAME_FULL_TRICK));
} // bool in_running_game()

/**
 **
 ** -> return
 **
 ** @param	game_type	the game type
 **
 ** @return	whether 'game_type' is a 'normal' game
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.6
 **
 **/
bool
GAMETYPE::is_normal(GameType const game_type)
{
  switch (game_type) {
  case GAMETYPE::NORMAL:
  case GAMETYPE::POVERTY:
  case GAMETYPE::MARRIAGE:
  case GAMETYPE::GENSCHER:
    return true;
  default:
    return false;
  } // switch(game_type)
} // bool GAMETYPE::is_normal(GameType const game_type)

/**
 **
 ** -> return
 **
 ** @param	game_type	the game type
 **
 ** @return	whether 'game_type' is a marriage
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.6
 **
 **/
bool
GAMETYPE::is_marriage(GameType const game_type)
{
  if (GAMETYPE::is_color_solo(game_type)
      || GAMETYPE::is_picture_solo(game_type))
    return true;

  switch (game_type) {
  case GAMETYPE::MARRIAGE:
  case GAMETYPE::MARRIAGE_SOLO:
  case GAMETYPE::MARRIAGE_SILENT:
    return true;
  default:
    return false;
  } // switch(game_type)
} // bool GAMETYPE::is_marriage(GameType const game_type)

/**
 **
 ** -> return
 **
 ** @param	game_type	the game type
 **
 ** @return	whether 'game_type' is a poverty
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.6
 **
 **/
bool
GAMETYPE::is_poverty(GameType const game_type)
{
  switch (game_type) {
  case FIVE_NINES:
  case SIX_KINGS:
  case FOX_HIGHEST_TRUMP:
  case POVERTY:
    return true;
  default:
    return false;
  } // switch(game_type)
} // bool GAMETYPE::is_poverty(GameType const game_type)

/**
 **
 ** -> return
 **
 ** @param	game_type	the game type
 **
 ** @return	whether 'game_type' is a solo
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.6
 **
 **/
bool
GAMETYPE::is_solo(GameType const game_type)
{
  if (GAMETYPE::is_color_solo(game_type)
      || GAMETYPE::is_picture_solo(game_type))
    return true;

  switch (game_type) {
  case GAMETYPE::SOLO_MEATLESS:
  case GAMETYPE::MARRIAGE_SOLO:
  case GAMETYPE::MARRIAGE_SILENT:
    return true;
  default:
    return false;
  } // switch(game_type)
} // bool GAMETYPE::is_solo(GameType const game_type)

/**
 **
 ** -> return
 **
 ** @param	game_type	the game type
 **
 ** @return	whether 'game_type' is a color solo
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.6
 **
 **/
bool
GAMETYPE::is_color_solo(GameType const game_type)
{
  switch (game_type) {
  case GAMETYPE::SOLO_CLUB:
  case GAMETYPE::SOLO_SPADE:
  case GAMETYPE::SOLO_HEART:
  case GAMETYPE::SOLO_DIAMOND:
    return true;
  default:
    return false;
  } // switch(game_type)
} // bool GAMETYPE::is_color_solo(GameType const game_type)

/**
 **
 ** -> return
 **
 ** @param	game_type	the game type
 **
 ** @return	whether 'game_type' is a picture solo
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.6
 **
 **/
bool
GAMETYPE::is_picture_solo(GameType const game_type)
{
  return ( GAMETYPE::is_single_picture_solo(game_type)
	   || GAMETYPE::is_double_picture_solo(game_type)
	   || (game_type == GAMETYPE::SOLO_KOEHLER));
} // bool GAMETYPE::is_picture_solo(GameType const game_type)

/**
 **
 ** -> return
 **
 ** @param	game_type	the game type
 **
 ** @return	whether 'game_type' is a single picture solo
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.6
 **
 **/
bool
GAMETYPE::is_single_picture_solo(GameType const game_type)
{
  switch (game_type) {
  case GAMETYPE::SOLO_JACK:
  case GAMETYPE::SOLO_QUEEN:
  case GAMETYPE::SOLO_KING:
    return true;
  default:
    return false;
  } // switch(game_type)
} // bool GAMETYPE::is_single_picture_solo(GameType const game_type)

/**
 **
 ** -> return
 **
 ** @param	game_type	the game type
 **
 ** @return	whether 'game_type' is a double picture solo
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.6
 **
 **/
bool
GAMETYPE::is_double_picture_solo(GameType const game_type)
{
  switch (game_type) {
  case GAMETYPE::SOLO_QUEEN_JACK:
  case GAMETYPE::SOLO_KING_JACK:
  case GAMETYPE::SOLO_KING_QUEEN:
    return true;
  default:
    return false;
  } // switch(game_type)
} // bool GAMETYPE::is_double_picture_solo(GameType const game_type)



//////////////////
// ANNOUNCEMENT //
//////////////////

/**
 **
 ** -> result
 **
 ** @param	announcement	announcement
 **
 ** @result	name of the announcement
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.4
 **
 **/
string
name(Announcement const& announcement)
{
  using namespace ANNOUNCEMENT;

  switch (announcement) {
  case NOANNOUNCEMENT:
    return "no announcement";
  case NO120:
    return "no 120";
  case NO90:
    return "no 90";
  case NO60:
    return "no 60";
  case NO30:
    return "no 30";
  case NO0:
    return "no 0";
  case REPLY:
    return "announcement reply";
  case NO120_REPLY:
    return "no 120 reply";
  case NO90_REPLY:
    return "no 90 reply";
  case NO60_REPLY:
    return "no 60 reply";
  case NO30_REPLY:
    return "no 30 reply";
  case NO0_REPLY:
    return "no 0 reply";
  } // switch(announcement)

  DEBUG_ASSERTION(false,
		  "::name(Announcement):\n"
		  "  announcement not found: " << static_cast<int>(announcement)
		 );

  return "";
} // string name(Announcement const& announcement)

/**
 **
 ** -> result
 **
 ** @param	announcement	announcement
 **
 ** @return	whether the announcement is a real announcement (no reply)
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.4
 **
 **/
bool
ANNOUNCEMENT::is_real(Announcement const& announcement)
{
  using namespace ANNOUNCEMENT;

  switch(announcement) {
  case NOANNOUNCEMENT:
    return false;
  case NO120:
  case NO90:
  case NO60:
  case NO30:
  case NO0:
    return true;
  case REPLY:
  case NO120_REPLY:
  case NO90_REPLY:
  case NO60_REPLY:
  case NO30_REPLY:
  case NO0_REPLY:
    return false;
  } // switch(announcement)

  DEBUG_ASSERTION(false,
		  "ANNOUNCEMENT::is_real(Announcement):\n"
		  "  announcement not found: " << announcement);
  return false;
} // bool ANNOUNCEMENT::is_real(Announcement const& announcement)
/**
 **
 ** -> result
 **
 ** @param	announcement	announcement
 **
 ** @return	whether the announcement is a reply
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.4
 **
 **/
bool
ANNOUNCEMENT::is_reply(Announcement const& announcement)
{
  using namespace ANNOUNCEMENT;

  switch(announcement) {
  case NOANNOUNCEMENT:
    return false;
  case NO120:
  case NO90:
  case NO60:
  case NO30:
  case NO0:
    return false;
  case REPLY:
  case NO120_REPLY:
  case NO90_REPLY:
  case NO60_REPLY:
  case NO30_REPLY:
  case NO0_REPLY:
    return true;
  } // switch(announcement)

  DEBUG_ASSERTION(false,
		  "ANNOUNCEMENT::is_reply(Announcement):\n"
		  "  announcement not found: " << announcement);
  return false;
} // bool ANNOUNCEMENT::is_reply(Announcement const& announcement)

/**
 **
 ** -> result
 **
 ** @param	announcement	announcement
 **
 ** @return	reply version of 'announcement'
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.4
 **
 **/
Announcement
ANNOUNCEMENT::to_reply(Announcement const& announcement)
{
  using namespace ANNOUNCEMENT;

  switch(announcement) {
  case NOANNOUNCEMENT:
    DEBUG_ASSERTION(false,
		    "ANNOUNCEMENT::to_reply(announcement):\n"
		    "  announcement '" << ::name(announcement) << "' not valid.");
    return NOANNOUNCEMENT;
  case NO120:
    return NO120_REPLY;
  case NO90:
    return NO90_REPLY;
  case NO60:
    return NO60_REPLY;
  case NO30:
    return NO30_REPLY;
  case NO0:
    return NO0_REPLY;
  case REPLY:
  case NO120_REPLY:
  case NO90_REPLY:
  case NO60_REPLY:
  case NO30_REPLY:
  case NO0_REPLY:
    DEBUG_ASSERTION(false,
		    "ANNOUNCEMENT::to_reply(announcement):\n"
		    "  announcement '" << ::name(announcement) << "' not valid.");
    return NOANNOUNCEMENT;;
  } // switch(announcement)

  DEBUG_ASSERTION(false,
		  "ANNOUNCEMENT::to_reply(Announcement):\n"
		  "  announcement not found: " << announcement);
  return NOANNOUNCEMENT;
} // Announcement ANNOUNCEMENT::to_reply(Announcement announcement)

/**
 **
 ** -> result
 **
 ** @param	announcement	announcement
 **
 ** @return	reply version of 'announcement'
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.4
 **
 **/
Announcement
ANNOUNCEMENT::from_reply(Announcement const& announcement)
{
  using namespace ANNOUNCEMENT;

  switch(announcement) {
  case NOANNOUNCEMENT:
  case NO120:
  case NO90:
  case NO60:
  case NO30:
  case NO0:
  case REPLY:
    DEBUG_ASSERTION(false,
		    "ANNOUNCEMENT::from_reply(announcement):\n"
		    "  announcement '" << ::name(announcement) << "' not valid.");
    return NOANNOUNCEMENT;;
  case NO120_REPLY:
    return NO120;
  case NO90_REPLY:
    return NO90;
  case NO60_REPLY:
    return NO60;
  case NO30_REPLY:
    return NO30;
  case NO0_REPLY:
    return NO0;
  } // switch(announcement)

  DEBUG_ASSERTION(false,
		   "ANNOUNCEMENT::is_reply(Announcement):\n"
		   "  announcement not found: " << announcement);
  return NOANNOUNCEMENT;
} // Announcement ANNOUNCEMENT::from_reply(Announcement announcement)

/**
 **
 ** -> result
 **
 ** @param	name	name of the announcemnet
 **
 ** @return	announcement 'name'
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.8
 **
 **/
Announcement
ANNOUNCEMENT::from_name(string const& name)
{
  for (int a = ANNOUNCEMENT::NOANNOUNCEMENT;
       a <= ANNOUNCEMENT::NO0_REPLY;
       ++a)
    if (name == ::name(static_cast<Announcement>(a)))
      return static_cast<Announcement>(a);

  // ToDo: Error

  return ANNOUNCEMENT::NOANNOUNCEMENT;
} // Announcement ANNOUNCEMENT::from_name(string const& name)





///////////////////////
// MARRIAGE_SELECTOR //
///////////////////////


/**
 ** -> result
 **
 ** @param	marriage_selector	marriage selector
 **
 ** @return	name of 'marriage_selector'
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.8
 **
 **/
string
name(MarriageSelector const& marriage_selector)
{
  using namespace MARRIAGE_SELECTOR;

  switch(marriage_selector) {
  case TEAM_SET:
    return "team set";
  case FIRST_FOREIGN:
    return "first foreign";
  case FIRST_TRUMP:
    return "first trump";
  case FIRST_COLOR:
    return "first color";
  case FIRST_CLUB:
    return "first club";
  case FIRST_SPADE:
    return "first spade";
  case FIRST_HEART:
    return "first heart";
  } // switch(marriage_selector)

  DEBUG_ASSERTION(false,
		  "::name(MarriageSelector):\n"
		  "  no name found for " << static_cast<int>(marriage_selector)
		 );

  return "";
} // string name(MarriageSelector const& marriage_selector)

/**
 **
 ** -> result
 **
 ** @param	rotation	rotation
 **
 ** @return	'rotation' clockwise rotated
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.7
 **
 **/
Rotation
ROTATION::clockwise(Rotation const rotation)
{
  switch (rotation) {
  case UP:
    return LEFT;
  case DOWN:
    return RIGHT;
  case RIGHT:
    return UP;
  case LEFT:
    return DOWN;
  } // switch(rotation)

  DEBUG_ASSERTION(false,
		  "ROTATION::conterclockwise(rotation):\n"
		  "  behind 'switch(rotation)'");

  return UP;
} // Rotation ROTATION::clockwise(Rotation const rotation)

/**
 **
 ** -> result
 **
 ** @param	rotation	rotation
 **
 ** @return	'rotation' counterclockwise rotated
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.7
 **
 **/
Rotation
ROTATION::counterclockwise(Rotation const rotation)
{
  switch (rotation) {
  case UP:
    return RIGHT;
  case DOWN:
    return LEFT;
  case RIGHT:
    return DOWN;
  case LEFT:
    return UP;
  } // switch(rotation)

  DEBUG_ASSERTION(false,
		  "ROTATION::conterclockwise(rotation):\n"
		  "  behind 'switch(rotation)'");

  return UP;
} // Rotation ROTATION::counterclockwise(Rotation const rotation)
