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

#include"../../game/game.h"
#include"../../party/rule.h"

/**
 **
 ** Constructor
 **
 ** @param	-
 **
 ** @return	-
 **
 ** @version	0.5.4
 **
 ** @author	Diether Knof
 **
 **/
AiDummy::AiDummy() :
Player(Player::AI_DUMMY),
Aiconfig()
{
  DEBUG_CALLING(INFO_AI_DUMMY && INFO_INIT,
		"AiDummy::AiDummy()");

  //  this->name_set(::generate_name(RAND(4) + 5));

  DEBUG_RETURNING(VOID,
		  INFO_AI_DUMMY && INFO_INIT,
		  "AiDummy::AiDummy()");
} // AiDummy::AiDummy()

/**
 **
 ** Construktor
 **
 ** @param	istr	stream with the infos
 **
 ** @return	-
 **
 ** @author	Diether Knof
 **
 ** @version	0.5.2
 **
 ** @todo	all
 **
 **/
AiDummy::AiDummy(istream& istr) :
Player(AI_DUMMY),
Aiconfig()
{
  DEBUG_CALLING(INFO_AI_DUMMY && INFO_INIT,
		"AiDummy::AiDummy(istr)");

  (void)istr;
  DEBUG_ASSERTION(false,
		  "AiDummy::AiDummy(istr):\n"
		  "  Contructor not implemented");

  DEBUG_RETURNING(VOID,
		  INFO_AI_DUMMY && INFO_INIT,
		  "AiDummy::AiDummy(istr)");
} // AiDummy::AiDummy(istream& istr)

/**
 **
 ** copy constructor
 **
 ** @param	player	player to copy
 **
 ** @return	-
 **
 ** @version	0.5.3
 **
 ** @author	Diether Knof
 **      
 **
 **/
AiDummy::AiDummy(Player const& player) :
Player(player),
Aiconfig()
{
  DEBUG_CALLING(INFO_AI_DUMMY && INFO_INIT,
		"AiDummy::AiDummy(player)");

  this->type_set(AI_DUMMY);

  DEBUG_RETURNING(VOID,
		  INFO_AI_DUMMY && INFO_INIT,
		  "AiDummy::AiDummy(player)");
} // AiDummy::AiDummy(Player const& player)

/**
 **
 ** copy constructor
 **
 ** @param	ai_dummy	ai to copy
 **
 ** @return	-
 **
 ** @version	0.5.3
 **
 ** @author	Diether Knof
 **      
 **
 **/
AiDummy::AiDummy(AiDummy const& ai_dummy) :
Player(ai_dummy),
Aiconfig(ai_dummy)
{
  DEBUG_CALLING(INFO_AI_DUMMY && INFO_INIT,
		"AiDummy::AiDummy(ai_dummy)");

  this->type_set(AI_DUMMY);

  DEBUG_RETURNING(VOID,
		  INFO_AI_DUMMY && INFO_INIT,
		  "AiDummy::AiDummy(ai_dummy)");
} // AiDummy::AiDummy(AiDummy const& ai_dummy)

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

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

/**
 **
 ** copy operator
 **
 ** @param	ai_dummy	ai to copy
 **
 ** @return	copied ai
 **
 ** @version	0.5.4
 **
 ** @author	Diether Knof
 **      
 **
 **/
AiDummy&
AiDummy::operator=(AiDummy const& ai_dummy)
{
  DEBUG_CALLING(INFO_AI_DUMMY && INFO_INIT,
		"AiDummy& operator=(AiDummy const& ai_dummy)");

  static_cast<Player&>(*this) = static_cast<Player const&>(ai_dummy);
  static_cast<Aiconfig&>(*this) = static_cast<Aiconfig const&>(ai_dummy);

  DEBUG_RETURNING(*this,
		  INFO_AI_DUMMY && INFO_INIT,
		  "AiDummy& operator=(AiDummy const& ai_dummy)");
} // AiDummy& AiDummy::operator=(AiDummy const& ai_dummy)

/**
 **
 ** Destructor
 **
 ** @param	-
 **
 ** @return	-
 **
 ** @version	0.5.4
 **
 ** @author	Diether Knof
 **      
 **
 **/
AiDummy::~AiDummy()
{
  DEBUG_CALLING(INFO_AI_DUMMY && INFO_INIT,
		"AiDummy::~AiDummy()");

  DEBUG_RETURNING(VOID,
		  INFO_AI_DUMMY && INFO_INIT,
		  "AiDummy::~AiDummy()");
} // AiDummy::~AiDummy()

/**
 ** -> result
 ** (test of poverty, marriage, swines, hyperswines)
 **
 ** @param	duty_solo	whether the player has to play a solo
 ** 				(default: false)
 **
 ** @return	simple Reservation
 **
 ** @author	Diether Knof
 **
 ** @version	0.5.3
 **
 **/
Reservation
AiDummy::reservation_get(bool duty_solo) const
{
  DEBUG_CALLING(INFO_AI_DUMMY && INFO_GAMEPLAY,
		"Reservation AiDummy::get_reservation(duty_solo)");

  (void)duty_solo;

  Reservation reservation;

  if (this->game().rule()(Rule::HYPERSWINES)
      && (this->hand().numberoftrumpnines() == 2))
    reservation.hyperswines = true;
  if (this->game().rule()(Rule::SWINES)
      && (this->hand().numberoftrumpaces() == 2))
    reservation.swines = true;

  if (this->hand().numberofclubqueens() == 2) {
    reservation.game_type = GAMETYPE::MARRIAGE;
    reservation.marriage_selector = MARRIAGE_SELECTOR::FIRST_FOREIGN;
  } // if (marriage)

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

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

  DEBUG_RETURNING(reservation,
		  INFO_AI_DUMMY && INFO_GAMEPLAY,
		  "Reservation AiDummy::reservation_get(duty_solo)");
} // Reservation AiDummy::reservation_get(bool duty_solo) const

/**
 ** -> result:
 ** if the dummy ai can get the trick, it takes its best card
 ** (also, if its the first card in the trick)
 ** else (if the dummy ai has no better than the winning card of the trick)
 ** the worst card is taken
 **
 **
 ** @param	-
 **
 ** @return	valid card
 **
 ** @author	Diether Knof
 **
 ** @version	0.5.2
 **
 **/
Card
AiDummy::card_get()
{
  DEBUG_CALLING(INFO_AI_DUMMY && INFO_GAMEPLAY,
		"AiDummy::card_get()");

  // the first card -- play the highest
  // if the ai cannot get the trick: play the lowest
  // if the ai can get the trick: play the highest

  Card card;
  bool can_win = false;

  for (vector<Card>::const_iterator c = this->hand().cards().begin();
       c != this->hand().cards().end();
       c++) {
    if (this->game().trick_current().isvalid(*c, this->hand())) {
      if (!card) {
	card = *c;
      } else { // if !(!card)
	bool const is_winnercard
	  = (this->game().trick_current().isempty()
	     ? true
	     : this->game().trick_current().winnercard().less(*c, this->game())
	    );
	can_win |= is_winnercard;

	if (this->game().trick_current().isempty()) {
	  // take the smallest card
	  if (card.less(*c, this->game()))
	    card = *c;
	} else if (this->game().trick_current().islastcard()) {
	  // if the player can win the trick take the smallest winnercard,
	  // else take the smallest card.

	  if (can_win
	      && is_winnercard
	      && c->less(card, this->game()))
	    card = *c;
	  if (!can_win
	      && !is_winnercard
	      && c->less(card, this->game()))
	    card = *c;
	} else { // if !(is first or last card in trick)
	  // if the player can win the trick take the greatest winnercard,
	  // else take the smallest card.

	  if (can_win
	      && is_winnercard
	      && card.less(*c, this->game()))
	    card = *c;
	  if (!can_win
	      && !is_winnercard
	      && c->less(card, this->game()))
	    card = *c;
	} // if !(is first or last card in trick)
      } // if !(!card)
    } // if (this->game().trick_current().isvalid(*c, this->hand()))
  } // for (c \in this->hand().cardsnumber())

  // valid_cards.card(RAND(valid_cards.cardsnumber()))
  DEBUG_RETURNING(card,
		  INFO_AI_DUMMY && INFO_GAMEPLAY,
		  "Card AiDummy::card_get()");
} // Card AiDummy::card_get()

/**
 ** -> result
 **
 ** @param	-
 **
 ** @return	announcement of the player
 **
 ** @author	Diether Knof
 **
 ** @version	0.5.4
 **
 **/
Announcement
AiDummy::announcement_request() const
{
  DEBUG_CALLING(INFO_AI_DUMMY && INFO_GAMEPLAY,
		"AiDummy::announcement_request()");

  // points of the own team
  unsigned points = 0;

  // count the points, the own team has made 
  for(vector<Player*>::const_iterator player = this->game().player_begin();
      player != this->game().player_end();
      player++)
    if (this->teaminfo(**player) == this->team())
      points += this->game().points_of_player(**player);

  if (points == 240)
    DEBUG_RETURNING(ANNOUNCEMENT::NO0,
		    INFO_AI_DUMMY && INFO_GAMEPLAY,
		    "AiDummy::announcement_request()");
  if (points > 240 - 30)
    DEBUG_RETURNING(ANNOUNCEMENT::NO30,
		    INFO_AI_DUMMY && INFO_GAMEPLAY,
		    "AiDummy::announcement_request()");
  if (points > 240 - 60)
    DEBUG_RETURNING(ANNOUNCEMENT::NO60,
		    INFO_AI_DUMMY && INFO_GAMEPLAY,
		    "AiDummy::announcement_request()");
  if (points > 240 - 90)
    DEBUG_RETURNING(ANNOUNCEMENT::NO90,
		    INFO_AI_DUMMY && INFO_GAMEPLAY,
		    "AiDummy::announcement_request()");
  if (points > 240 - 120)
    DEBUG_RETURNING(ANNOUNCEMENT::NO120,
		    INFO_AI_DUMMY && INFO_GAMEPLAY,
		    "AiDummy::announcement_request()");

  DEBUG_RETURNING(ANNOUNCEMENT::NOANNOUNCEMENT,
		  INFO_AI_DUMMY && INFO_GAMEPLAY,
		  "AiDummy::announcement_request()");
} // Announcement AiDummy::announcement_request() const
