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

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

/**********************************************************************
 *
 ** bool operator==(Card const& a, Card const& b)
 *
 ** Parameters:  two cards for comparing
 *
 ** Result: true if a equals b, else false
 *
 ** Version: Release
 *
 ** Description: 
 **   
 *
 **********************************************************************/
bool
operator==(Card const& a, Card const& b)
{
  DEBUG_CALLING(INFO_CARD && INFO_VALUE,
	       	"operator==(Card const& a, Card const& b)");

  DEBUG_RETURNING((a.value() == b.value()) && (a.color() == b.color()),
		  INFO_CARD && INFO_VALUE,
		  "operator==(Card const& a, Card const& b)");
} // bool operator==(Card const& a, Card const& b)

/**********************************************************************
 *
 ** bool operator!=(Card const& a, Card const& b)
 *
 ** Parameters:  two cards for comparing
 *
 ** Result: false if a equals b, else true
 *
 ** Version: Release
 *
 ** Description: 
 **   
 *
 **********************************************************************/

bool operator!=(Card const& a, Card const& b)
{
  DEBUG_CALLING(INFO_CARD && INFO_VALUE,
		"operator!=(Card const& a, Card const& b)");

  DEBUG_RETURNING(!(a == b),
		  INFO_CARD && INFO_VALUE,
		  "operator!=(Card const& a, Card const& b)");
} // bool operator!=(Card const& a, Card const& b)

/**
 **
 ** -> result
 **
 ** @note	if both cards are equal, the first (this) is not less than
 **		the second (card)
 **		(but the dollen -- see rules)
 **
 ** @param	b	the card to compare with
 ** @param	game	the game (with the ruleset and trickno)
 **
 ** @return	true, if the card is less than 'b', else false
 **
 ** @version	0.5
 **
 ** @author	Diether Knof
 **
 ** @todo	test rule 'DOLLE_CONTRARY_IN_LAST_TRICK'
 **
 **/
bool
Card::less(Card const& b, Game const& game) const
{
  DEBUG_CALLING(INFO_CARD && INFO_VALUE,
		"operator<(Card const& a, Card const& b)");

  Card const& a = *this;

  // both cards are not trump
  if (!a.istrump() && !b.istrump()) {
    if (a.color() == b.color()) // same color
      DEBUG_RETURNING((a.value() < b.value()),
		      INFO_CARD && INFO_VALUE,
		      "Card::less(card, game)"
		      << ((a.value() < b.value()) ? "true" : "false") );
    else // different color
      DEBUG_RETURNING(false,
		      INFO_CARD && INFO_VALUE,
		      "Card::less(card, game) = false");
  }

  // a is trump but b not
  if (a.istrump() && !b.istrump())
    DEBUG_RETURNING(false,
		    INFO_CARD && INFO_VALUE,
		    "Card::less(card, game) = false");

  // a is not trump but b is
  if (!a.istrump() && b.istrump())
    DEBUG_RETURNING(true,
		    INFO_CARD && INFO_VALUE,
		    "Card::less(card, game) = true");


  // The difficult case: both cards are trump

  switch(party.game().type()) {
    using namespace GAMETYPE;
  case NORMAL:
  case POVERTY:
  case FOX_HIGHEST_TRUMP:
  case GENSCHER:
  case MARRIAGE:
  case MARRIAGE_SOLO:
  case MARRIAGE_SILENT:
  case SOLO_DIAMOND:
  case SOLO_CLUB:
  case SOLO_HEART:
  case SOLO_SPADE:

    // Hyperswines
    if (party.rule()(Rule::HYPERSWINES)) {
      if (a.ishyperswine())
	DEBUG_RETURNING(false,
			INFO_CARD && INFO_VALUE,
			"Card::less(card, game) = false");

      if (b.ishyperswine())
	DEBUG_RETURNING(true,
			INFO_CARD && INFO_VALUE,
			"Card::less(card, game) = true");
    }

    // Swines
    if (party.rule()(Rule::SWINES)) {
      if (a.isswine())
	DEBUG_RETURNING(false,
			INFO_CARD && INFO_VALUE,
			"Card::less(card, game) = false");

      if (b.isswine())
	DEBUG_RETURNING(true,
			INFO_CARD && INFO_VALUE,
			"Card::less(card, game) = true");
    }

    // Dollen
    if (party.rule()(Rule::DOLLEN)) {
      if (a == Card::DOLLE) {
	if (b == Card::DOLLE) { // both cards are dollen
	  if (game.rule()(Rule::DOLLEN_CONTRARY_IN_LAST_TRICK)
	      && (game.tricks_remaining_no() == 1)) {
	    // we are in the last trick
	    // and the rule 'DOLLEN_CONTRARY_IN_LAST_TRICK' is valid
	    if (party.rule()(Rule::DOLLEN_SECOND_OVER_FIRST)) {
	      DEBUG_RETURNING(false,
			      INFO_CARD && INFO_VALUE,
			      "Card::less(card, game) = false");
	    } else { // if !(party.rule()(Rule::DOLLEN_SECOND_OVER_FIRST)
	      DEBUG_RETURNING(true,
			      INFO_CARD && INFO_VALUE,
			      "Card::less(card, game) = true");
	    } // if !(party.rule()(Rule::DOLLEN_SECOND_OVER_FIRST)
	  } else { // if !(game.tricks_remaining_no() == 1)
	    if (party.rule()(Rule::DOLLEN_SECOND_OVER_FIRST)) {
	      DEBUG_RETURNING(true,
			      INFO_CARD && INFO_VALUE,
			      "Card::less(card, game) = true");
	    } else { // if !(party.rule()(Rule::DOLLEN_SECOND_OVER_FIRST)
	      DEBUG_RETURNING(false,
			      INFO_CARD && INFO_VALUE,
			      "Card::less(card, game) = false");
	    } // if !(party.rule()(Rule::DOLLEN_SECOND_OVER_FIRST)
	  } // if !(game.tricks_remaining_no() == 1)
	} else { // if !(b == Card::DOLLE)
	  DEBUG_RETURNING(false,
			  INFO_CARD && INFO_VALUE,
			  "Card::less(card, game) = false");
	} // if !(b == Card::DOLLE)
      } else { // if !(a == Card::DOLLE)
	if (b == Card::DOLLE)
	  DEBUG_RETURNING(true,
			  INFO_CARD && INFO_VALUE,
			  "Card::less(card, game) = true");
      } // if !(a == Card::DOLLE)
    } // if (rule.dollen)

    if (a.value() == Card::QUEEN) { // 'a' is a QUEEN
      if (b.value() == Card::QUEEN) // both cards are QUEENs
	DEBUG_RETURNING((a.color() < b.color()),
			INFO_CARD && INFO_VALUE,
			"Card::less(card, game)");
      else // 'b' is lesser than a QUEEN (JACK or DIAMOND)
	DEBUG_RETURNING(false,
			INFO_CARD && INFO_VALUE,
			"Card::less(card, game) = false");
    }

    if (a.value() == Card::JACK) { // 'a' is a JACK
      if (b.value() == Card::QUEEN) // 'b' is a QUEEN
	DEBUG_RETURNING(true,
			INFO_CARD && INFO_VALUE,
			"Card::less(card, game) = true");
      else if (b.value() == Card::JACK) // 'a' and 'b' are JACKs
	DEBUG_RETURNING((a.color() < b.color()),
			INFO_CARD && INFO_VALUE,
			"Card::less(card, game)");
      else // 'b' is a DIAMOND/CLUB/SPADE/HEART
	DEBUG_RETURNING(false,
			INFO_CARD && INFO_VALUE,
			"Card::less(card, game) = false");
    }

    // 'a' is a simple ace/ten/king/nine
    if ( (b.value() == Card::QUEEN) ||
	 (b.value() == Card::JACK) ) // 'b' is higher than an ace/ten/king/nine
      DEBUG_RETURNING(true,
		      INFO_CARD && INFO_VALUE,
		      "Card::less(card, game) = true");

    // both cards are simple ace/ten/king/nine
    DEBUG_RETURNING((a.value() < b.value()),
		    INFO_CARD && INFO_VALUE,
		    "Card::less(card, game)");
    break;
  case SOLO_JACK:
  case SOLO_QUEEN:
  case SOLO_KING:
    DEBUG_RETURNING((a.color() < b.color()),
		    INFO_CARD && INFO_VALUE,
		    "Card::less(card, game)");
    break;
  case SOLO_QUEEN_JACK:
    if (a.value() != b.value()) // one card is queen, one is jack
      DEBUG_RETURNING((a.value() == Card::JACK),
		      INFO_CARD && INFO_VALUE,
		      "Card::less(card, game)");
    // both card are JACK/QUEEN
    DEBUG_RETURNING((a.color() < b.color()),
		    INFO_CARD && INFO_VALUE,
		    "Card::less(card, game)");
    break;
  case SOLO_KING_JACK:
    if (a.value() != b.value()) // one card is king, one is jack
      DEBUG_RETURNING((a.value() == Card::JACK),
		      INFO_CARD && INFO_VALUE,
		      "Card::less(card, game)");
    // both card are JACK/KING
    DEBUG_RETURNING((a.color() < b.color()),
		    INFO_CARD && INFO_VALUE,
		    "Card::less(card, game)");
    break;
  case SOLO_KING_QUEEN:
    if (a.value() != b.value()) // one card is king, one is queen
      DEBUG_RETURNING((a.value() == Card::QUEEN),
		      INFO_CARD && INFO_VALUE,
		      "Card::less(card, game)");
    // both card are QUEEN/KING
    DEBUG_RETURNING((a.color() < b.color()),
		    INFO_CARD && INFO_VALUE,
		    "Card::less(card, game)");
    break;
  case SOLO_KOEHLER:
    if (a.value() == b.value()) // both cards are the same value
      DEBUG_RETURNING((a.color() < b.color()),
		      INFO_CARD && INFO_VALUE,
		      "Card::less(card, game)");
    // both cards have different values
    if (a.value() == Card::JACK)
      DEBUG_RETURNING(true,
		      INFO_CARD && INFO_VALUE,
		      "Card::less(card, game) = true");
    if (b.value() == Card::JACK)
      DEBUG_RETURNING(false,
		      INFO_CARD && INFO_VALUE,
		      "Card::less(card, game) = true");
    // one card is queen, one is king
    // -- hey, that is like in 'SOLO_KING_QUEEN', take that code
    DEBUG_RETURNING((a.value() == Card::QUEEN),
		    INFO_CARD && INFO_VALUE,
		    "Card::less(card, game) = true");
    break;
  case SOLO_MEATLESS:
    // cannot be, because no card is trump
    DEBUG_ASSERTION(false,
		    "  SOLO_MEATLESS with trump ");

    break;
  case FIVE_NINES:
    DEBUG_RETURNING((a.color() < b.color()),
		    INFO_CARD && INFO_VALUE,
		    "Card::less(card, game)");
    break;
  case SIX_KINGS:
    DEBUG_RETURNING((a.color() < b.color()),
		    INFO_CARD && INFO_VALUE,
		    "Card::less(card, game)");
    break;
  } // switch(game.type())

  DEBUG_ASSERTION(false,
		  "Card::less(card, game):\n"
		  "  after 'switch(game.type())");

  DEBUG_RETURNING(false,
		  INFO_CARD && INFO_VALUE,
		  "operator<(Card const& a, Card const& b)");
} // bool Card::less(Card const& b, Game const& game) const

/**********************************************************************
 *
 ** static int Card_relative_position(Card const& a, Card const& b)
 *
 ** Parameters:	a, b - the two cards to compare
 *
 ** Result:	whether the card 'a' is left (-1) or right (1) from card 'b'
 *
 ** Version:	0.4.2
 *
 ** Description:	-> result
 *
 **********************************************************************/
int
Card::relative_position(Card const& a, Card const& b)
{
  DEBUG_CALLING(INFO_HAND && INFO_VALUE,
		"Card::relative_position(Card const& a, Card const& b)");

  DEBUG_RETURNING(::setting(Setting::CARDS_ORDER).relative_position(a, b),
		  INFO_HAND && INFO_VALUE,
		  "Card_relative_position(Card const& a, Card const& b)");
} // int Card::relative_position(Card const&, Card const&)
