/**********************************************************************
 *
 *   FreeDoko a Doppelkopf-Game
 *    
 *   Copyright (C) 2001-2006  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 "trickweighting.h"

#include "VirtualGamesInterface.h"
#include "ai.h"
#include "info.h"
#include "../../party/party.h"
#include "../../game/game.h"
#include "../../game/exception.h"
#include "../../card/trick.h"
#include "../../misc/setting.h"
#include "../../ui/ui.h"

/**
 **
 ** -> result
 **
 ** @param      vgi	the virtual games interface
 ** @param      trick   the trick to be examined
 ** @param      t	the team which should make points
 ** @param      card    the card played by the player
 **
 ** @return     the weighting of the trick for the team 'team'
 **
 ** @version    0.4.4
 **
 ** @author     Borg Enders
 **
 ** @todo       perhaps points for getting the fox home
 ** @todo       perhaps when playing the highest card, subtract in modi
 **		the distance to the next lower card
 **/
 
int
TrickWeighting::modi(VirtualGamesInterface const& vgi,
		     Trick const& trick,
		     Team const t,
		     HandCard const& card)
{
  DEBUG_CALLING(INFO_W_VIRTUAL_GAMES && INFO_VALUE,
		"WVirtualGames::modi()");

  DEBUG_ASSERTION(trick.isfull(),
		  "TrickWeighting::modi()\n"
		  "  trick is not full");
  Game const& game_virt = trick.game();
  Ai const& ai = (dynamic_cast<Ai const*>(&game_virt.player(vgi.no()))
		  ? static_cast<Ai const&>(game_virt.player( vgi.no() ))
		  : static_cast<Ai const&>(vgi.game().player(vgi.no()))
					   );
  //Team const winnerteam = ai.teamofplayer(trick.winnerplayer());
  Team winnerteam
    = ::maybe_to_team(vgi.teamofplayer(trick.winnerplayer()));
  if (winnerteam == TEAM::UNKNOWN)
    winnerteam = ::opposite(t);

  if ((game_virt.type() == GAMETYPE::MARRIAGE)
      && (game_virt.marriage_selector() != MARRIAGE_SELECTOR::TEAM_SET)) {
    // in an undetermined marriage all players shall play for themselves
    if (t == TEAM::RE)
      winnerteam = ::maybe_to_team(ai.teaminfo(trick.winnerplayer()));
    else if (trick.winnerplayer().no() == vgi.no())
      winnerteam = ::maybe_to_team(t);
    else
      winnerteam = ::opposite(::maybe_to_team(t));
  }


  Team const team = ((game_virt.type() == GAMETYPE::MARRIAGE) 
		     ? maybe_to_team(t)
		     : t);

  int modi = 0;


  if (winnerteam == team)
    modi += trick.points();
  else
    modi -= trick.points();
#ifdef BENDERS
  // Playernumber for which to produce output
  unsigned playerCheck = 4;
#endif

#ifdef BENDERS
  if (!vgi.game().isvirtual())
    if (vgi.no() == playerCheck) {
      //COUT << trick.game().player(0).hand();
      cout << '\n';
      COUT << trick << endl;  
      COUT << team << "\t" << trick.winnerplayer().no() << " " << winnerteam << std::endl;
      for( unsigned i = 0; i < ai.game().playerno(); i++ )
	COUT << game_virt.player( i ).team() << "\t";
      COUT << std::endl;
      COUT << card << "\t" << modi << "\t";
    }
#endif

  if (    vgi.game().type() == GAMETYPE::SOLO_MEATLESS 
      && ai.no() != vgi.game().soloplayer().no() 
      && ai.hand().numberof(card.color(), vgi.game()) > 0
      && ai.hand().numberof(card.color(), vgi.game()) < 3
      && (   ai.hand().numberof(Card(card.color(),Card::ACE)) > 0 
	  || ai.hand().numberof(Card(card.color(),Card::TEN)) > 0 
	  || card.value() == Card::ACE || card.value() == Card::TEN )
     )
  { // prevent non soloplayer from blank playing of cards
    modi -= 12;
  }

  // high cards in meatless 
  if (    vgi.game().type() == GAMETYPE::SOLO_MEATLESS 
  	   && (    card.value() == Card::ACE 
  	        || card.value() == Card::TEN )
  	  )
  	 modi -= card.value() - 3; 
  
  

  // have played a very high card
  if (card.isswine()
      || card.ishyperswine()
      || card.isdolle())
    // 2005-08-06: swines in the last three tricks
    // modi -= 29; // previous values: 23,14,21,24, 29, 33, 35
    modi -= (29 - ai.game().played_cards_no());
  if (card.isswine() || card.ishyperswine() ) // so that a dolle is prefered to a swine
    modi -= 9;  //previous values: 2, 7, 3

  if ( card.istrump() && ( card.value() == Card::QUEEN 
			  || card.isswine()
			  || card.ishyperswine()
			  || card.isdolle())
      && trick.points() - card.value() < ai.value(Aiconfig::LIMITQUEEN))
    modi-= 4;  

  if( card.istrump()
     && (   card != trick.winnercard()
	 || trick.winnercardno() != 3)
     && trick.cardno_of_player(card.player()) == 3 )
  {
    modi -= 2;
    if(  vgi.game().type()!=GAMETYPE::SOLO_KING  &&
       vgi.game().type()!=GAMETYPE::SOLO_QUEEN_JACK &&
       vgi.game().type()!=GAMETYPE::SOLO_KING_JACK &&       
       vgi.game().type()!=GAMETYPE::SOLO_KING_QUEEN &&
       vgi.game().type()!=GAMETYPE::SOLO_KOEHLER  &&
       (card.value() == Card::JACK  || card.value() == Card::QUEEN)  ) // a king is better, but has two points more
      modi -= 3;
  }

  if(  card.istrump() 
     && (     vgi.game().type()==GAMETYPE::SOLO_KING
	 ||  vgi.game().type()==GAMETYPE::SOLO_QUEEN
	 ||  vgi.game().type()==GAMETYPE::SOLO_JACK   
	)
    )
    modi -= 4;


  if (!card.istrump()) {
    // prefer color cards a little bit
    if( card.value() == Card::NINE )
      modi += 1;
    if( card.value() == Card::KING )
      modi += 2;
  } // if (!card.istrump())

#ifdef BENDERS	
  if (!vgi.game().isvirtual())
    if (vgi.no() == playerCheck)
    {
      COUT << modi << "\t";
    }
#endif
  // have played a high card
  if ((ai.value(Aiconfig::LIMITHIGH).less(card)
       || ai.value(Aiconfig::LIMITHIGH) == card)
      && trick.points() - card.value() < ai.value(Aiconfig::LIMITQUEEN) )
  {
    modi -= 3; 
    if ((2 * ai.hand().numberof_ge(ai.value(Aiconfig::LIMITHIGH))
	 < ai.hand().numberoftrumps())
	&& (ai.hand().numberof_ge(ai.value(Aiconfig::LIMITHIGH))
	    < 3))
      modi -= 18;
  }

  if( card.isfox() ) // to play a fox it must be worth it
  {
    modi -= 16; // previous 7 
  }

  bool allmyteam=true;

  for( unsigned i = trick.cardno_of_player( ai );
      i < ai.game().playerno();
      i++ )
    allmyteam=allmyteam && ( ai.team() == ::maybe_to_team( vgi.teamofplayer( trick.player_of_card(i) ) ) );

  if ( !card.istrump()  && card.value() == Card::ACE )
  {
    modi -= 2 - vgi.color_runs( card.color() );
  } else
    if(   card.istrump()
       && card.less( ai.value(Aiconfig::LIMITHIGH) )
       && !trick.startcard().istrump() 
       && (trick.cardno_of_player(trick.winnerplayer())
	   >= trick.cardno_of_player(card.player()))
       && (    !trick.islastcard()  
	   || allmyteam )
      )
    {
      modi -= card.value() * vgi.color_runs( trick.startcard().color() );
    }
  // force enemy to play high card
  if (   card != trick.winnercard()
      && (trick.cardno_of_player(trick.winnerplayer())
	  > trick.cardno_of_player(card.player()))
      && ai.value(Aiconfig::LIMITHIGH).less(trick.winnercard())
      && ai.team() != winnerteam
      && !card.isdolle() && !card.isswine() && !card.isfox())
  {
    modi += 7;
    if( trick.winnercard().isdolle() || trick.winnercard().isswine() || 
       trick.winnercard().ishyperswine() )
      modi += 3;
  }

  // create the teams-vector
  vector<Team> teams;
  for (vector<Player*>::const_iterator
       player = game_virt.players_begin();
       player != game_virt.players_end();
       player++) 
  {
    // determine team of player from ai out of virtual game
    Team const t = ai.teamofplayer( **player );
    if ( t != TEAM::UNKNOWN)
    {
      teams.push_back( maybe_to_team( t ) );
    } else
    {
      teams.push_back( opposite( maybe_to_team(ai.team()) ) );
    }

  } // for (player)

#ifdef BENDERS	
  if (!vgi.game().isvirtual())
    if (vgi.no() == playerCheck)
    {
      COUT << modi << "\t";

    }
#endif

  if((  card.isswine()
      || card.ishyperswine()
      || card.isdolle()
     )
     && maybe_to_team(winnerteam) != team)
    modi -= 26;

  if (maybe_to_team(winnerteam) == team)
  {
    Specialpointsvector spv=trick.specialpoints(teams);
    modi += (30
	     * Sum_of_Specialpoints(spv,
				    winnerteam,
				    trick.startplayer().game()));
	if (   card.isfox() 
	    && winnerteam == team
	    && ai.value(Aiconfig::LIMITHIGH).less(trick.winnercard()) 
	    ) 
	  modi += 30; // fox maybe home

  }
  else
  {
    Specialpointsvector spv=trick.specialpoints(teams);
    modi -= (30
	     * Sum_of_Specialpoints(spv,
				    winnerteam,
				    trick.startplayer().game()));
  }

  // bad style to play fox as first card
  if(    card.isfox() 
     && trick.startplayer().no() == vgi.no() )
  {
    modi -= 90; // previous	
  }

  if ( (   card.isswine()
	|| card.ishyperswine()
	|| card.isdolle() ) 
      && trick.startplayer().no() == vgi.no() )
  {
    modi -= 12;
  }


#ifdef BENDERS	
  if (!vgi.game().isvirtual())
    if (vgi.no() == playerCheck)
    {
      COUT << modi << "\t";
    }
#endif

  for (unsigned c = 0; c < trick.actcardno(); c++) {
    // test, whether the fox has been brought home

    if (trick.card(c).isfox() )
    {

      if( vgi.game().type() != GAMETYPE::POVERTY || //only for not poverty-player
	 vgi.no() == vgi.game().povertyPartner().no() )
      {
	unsigned fact = 25;
	if(   !ai.value(Aiconfig::FAIRPLAYHANDS)  
	   || ai.value(Aiconfig::TRUSTING) )
	{
	  fact += 10;
	  if( card.isfox() )
	    fact += 5;
	}
	if( !card.isfox() )
	  fact += 5;

	modi += fact * ((team == winnerteam)
			? +1
			: -1);                    

        } else // fox from above neutralized.
      	{ 
		  modi += 30 * ((team != winnerteam)
		         ? +1
		         : 0);
      	}
     }
  } // for (c < trick.actcardno())



#ifdef BENDERS

  if (!vgi.game().isvirtual())
    if (vgi.no() == playerCheck)
    {
      COUT << modi << endl;
    }
#endif

  DEBUG_RETURNING(modi,
		  INFO_W_VIRTUAL_GAMES && INFO_VALUE,
		  "WVirtualGames::modi()");

  DEBUG_ASSERTION(false,
		  "WVirtualGames::modi():\n"
		  "  after 'RETURNING'");
  return 0;
} // int WVirtualGames::modi(Trick const& trick, Team const& team, Card const& card)


/**
 **
 ** -> result
 **
 ** @param      card    the card played by the player
 ** @param      game_virt actual virtual game
 **
 ** @return     weighting modifier for getting own team in backhand
 **
 ** @version    0.6.3
 **
 ** @author     Borg Enders
 **
 **
 **/
int
TrickWeighting::backhand(VirtualGamesInterface const& vgi,
			 HandCard const& c,
			 Game const& game_virt )                         
{


  // add some points, if the own team is in the back,
  if (game_virt.trick_current_no() < game_virt.trickno() - 1) {
    if (game_virt.player_previous( game_virt.trick_current().winnerplayer() ).team()
	== vgi.team() && !c.isfox() &&
	vgi.game().type() != GAMETYPE::SOLO_MEATLESS )
      return 5;
    else
      return -5;
  } // if (game_virt.trick_current_no() < game_virt.trickno() - 1)

  return 0;
}

