/**********************************************************************
 *
 *   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 "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      trick   the trick to be examined
 ** @param      team    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
 **
 **/
int
TrickWeighting::modi(VirtualGamesInterface const& vgi,
		     Trick const& trick,
		     Team const t,
		     Card 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 = static_cast<const Ai&>(game_virt.player( vgi.no() ));
  Team const winnerteam = vgi.teamofplayer(trick.winnerplayer());

  Team team = t;
  if( game_virt.type()==GAMETYPE::MARRIAGE ) 
  { 
    team = maybe_to_team( t );
  } 

  int modi = 0;

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

#ifdef BENDERS
  if (!vgi.game().isvirtual())
    if (vgi.no() == playerCheck) {
      //COUT << trick.game().player(0).hand();
      COUT << trick << 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(),GAMETYPE::SOLO_MEATLESS) > 0
	  && ai.hand().numberof(card.color(),GAMETYPE::SOLO_MEATLESS) < 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;
  }


  // have played a very high card
  if (card.isswine()
      || card.ishyperswine()
      || card.isdolle())
    modi -= 29; // previous values: 23,14,21,24, 29, 33, 35
  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() < ai.value(Aiconfig::LIMITQUEEN))
    modi-= 4; 

  if( card.istrump() && (card != trick.winnercard() || trick.winnercardno() != 3) && trick.card(3) == card )
  {
    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;
  }

#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, game_virt)
       || ai.value(Aiconfig::LIMITHIGH) == card)
      && trick.points() < ai.value(Aiconfig::LIMITQUEEN) )
  {

    modi -= 3; 
  }

  if( card.isfox() ) // to play a fox it must be worth it
  {
    modi -= 7; 
  }
  if ( !card.istrump()  && card.value() == Card::ACE )
  {
    modi -= 2 - vgi.color_runs( card.color() );
  }
  // force enemy to play high card
  if ( card != trick.winnercard() && trick.card(3) != card &&
       ai.value(Aiconfig::LIMITHIGH).less(trick.winnercard(), game_virt) &&
       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.player_begin();
       player != game_virt.player_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 (maybe_to_team(winnerteam) == team)
  {
    Specialpointsvector spv=trick.specialpoints(game_virt.type(),
						teams,
						(game_virt.tricks_remaining_no()
						 == 0));
    modi += (30
	     * Sum_of_Specialpoints(spv,
				    winnerteam,
				    trick.startplayer().game()));

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

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

#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())


#if POSTPHONED
  // don't play two times the same card
  for (unsigned c = 0; c < trick.actcardno(); c++) {
    if(    trick.card(c) == card 
	   && (trick.cardno_of_player(trick.player_of_card(c))
	       < trick.cardno_of_player( ai ) ))
    {
      modi+= card.value() * ((team == trick.player_of_card(c).team())
			     ? -1
			     : 0);   
    }           
  }
#endif  

#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,
			 Card 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;
}

