/**********************************************************************
 *
 *   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 "constants.h"
#include "hand_cards.h"

#include "../player/player.h"
#include "../game/game.h"
#include "../party/rule.h"
#ifdef DKNOF
#include "../party/party.h"
#include "trick.h"
#include "card.h"
#endif

/**
 **
 ** constructor
 **
 ** @param	cards	cards of the hand
 **
 ** @return	-
 **
 ** @version	0.6.8
 **
 ** @author	Diether Knof
 **
 **/
HandCards::HandCards(vector<HandCard> const& cards) :
  vector<HandCard>(cards)
{
#ifndef DEBUG_NO_ASSERTS
  // test whether all cards are from the same player
  Player const* const player = &cards[0].player();
  for (HandCards::const_iterator c = this->begin();
       c != this->end();
       ++c)
    DEBUG_ASSERTION((player == &c->player()),
		    "HandCards::HandCards(cards):\n"
		    "  the cards belong to different players: "
		    << player->no() << " and " << c->player().no());
#endif
  return ;
} // HandCards::HandCards(vector<HandCard> const& cards)

/**
 ** constructor
 **
 ** @param	cards	cards of the hand
 **
 ** @return	-
 **
 ** @author	Diether Knof
 **
 ** @version	0.7.3
 **/
HandCards::HandCards(vector<Card> const& cards) :
  vector<HandCard>()
{
  for (vector<Card>::const_iterator c = cards.begin();
       c != cards.end();
       ++c)
    this->push_back(HandCard(*c));
  return ;
} // HandCards::HandCards(vector<Card> cards)

/**
 ** constructor
 **
 ** @param     cards   cards of the hand
 ** @param     hand    corresponding hand
 **
 ** @return    -
 **
 ** @author    Diether Knof
 **
 ** @version   0.7,3
 **/
HandCards::HandCards(Hand const& hand,
		     vector<Card> const& cards) :
  vector<HandCard>(cards.size())
{
  for (unsigned i = 0; i < cards.size(); ++i)
    (*this)[i] = HandCard(hand, cards[i]);

  return ;
} // HandCards::HandCards(vector<HandCard> const& cards)

/**
 **
 ** constructor
 **
 ** @param	n	number of cards
 **
 ** @return	-
 **
 ** @version	0.6.8
 **
 ** @author	Diether Knof
 **
 **/
HandCards::HandCards(unsigned const n) :
  vector<HandCard>(n)
{ }

/**
 **
 ** reads the cards from the input stream
 **
 ** @param	istr	input stream
 **
 ** @return	-
 **
 ** @version	0.6.8
 **
 ** @author	Diether Knof
 **
 **/
HandCards::HandCards(istream& istr) :
  vector<HandCard>()
{
  while (istr.good()) {
#ifndef OUTDATED
    // DK: 0.6.8
    while (std::isdigit(istr.peek()))
      istr.get();
#endif
    string line;
    std::getline(istr, line);
    if (!line.empty() && (*line.rbegin() == '\r'))
      line.erase(line.end() - 1);
    if (line.empty())
      break;

    this->push_back(HandCard(Card(line)));
  } // while (this->istr->good())
} // HandCards::HandCards(istream& istr)

/**
 **
 ** constructor
 **
 ** @param	-
 **
 ** @return	-
 **
 ** @version	0.6.8
 **
 ** @author	Diether Knof
 **
 **/
HandCards::HandCards() :
  vector<HandCard>()
{ }

/**
 **
 ** copy constructor
 **
 ** @param	cards	cards to copy
 **
 ** @return	-
 **
 ** @version	0.6.8
 **
 ** @author	Diether Knof
 **
 **/
HandCards::HandCards(HandCards const& cards) :
  vector<HandCard>(cards)
{ }

/**
 **
 ** copy operator
 **
 ** @param	cards	cards to copy
 **
 ** @return	this cards
 **
 ** @version	0.6.8
 **
 ** @author	Diether Knof
 **
 **/
HandCards&
HandCards::operator=(HandCards const& cards)
{
  static_cast<vector<HandCard>&>(*this) = cards;

  return *this;
} // HandCards::HandCards(HandCards const& cards) :

/**
 **
 ** destructor
 **
 ** @param	-
 **
 ** @return	-
 **
 ** @version	0.6.8
 **
 ** @author	Diether Knof
 **
 **/
HandCards::~HandCards()
{
} // HandCards::~Hand()

/**
 **
 ** converts the vector in a vector of simple cards
 **
 ** @param	-
 **
 ** @return	this cards
 **
 ** @version	0.6.8
 **
 ** @author	Diether Knof
 **
 **/
HandCards::operator vector<Card>() const
{
  vector<Card> cards;

  for (HandCards::const_iterator c = this->begin();
       c != this->end();
       ++c)
    cards.push_back(*c);

  return cards;
} // HandCards::vector<Card>() const

/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	number of cards
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.8
 **
 **/
unsigned
HandCards::cardsnumber() const
{
  return this->size();
} // unsigned HandCards::cardsnumber() const

/**
 **
 ** -> result
 **
 ** @param	i	number of card
 **
 ** @return	card i of the hand (with remaining cards)
 **
 ** @author	Borg Enders
 ** @author	Diether Knof
 **
 ** @version	0.6.8
 **
 **/
HandCard const&
HandCards::card(unsigned const i) const
{
  DEBUG_ASSERTION((i < this->size()),
		  "HandCards::card(i):\n"
		  "  invalid value 'i' = " << i
		  << " (max = " << this->size() << ")\n"
		  "HandCards: "
		  << *this);

  return (*this)[i];
} // HandCard HandCards::card(unsigned i) const

/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	the player this hand belongs to
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.8
 **
 **/
Player const&
HandCards::player() const
{
  return (*this)[0].player();
} // Player HandCards::player() const

/**
 **
 ** -> result
 **
 ** @param	i	number of card
 **
 ** @return	in which trick the card has been played
 **		(UINT_MAX, if not played, yet)
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.8
 **
 **/
HandCard const&
HandCards::highest_card() const
{
  DEBUG_ASSERTION((this->size() > 0),
		  "HandCards::highest_card():\n"
		  "  Hand is empty");

  HandCards::const_iterator highest_card = this->begin();

  for (HandCards::const_iterator c = this->begin() + 1;
       c != this->end();
       ++c) {
    if (highest_card->less(*c))
      highest_card = c;
  } // for (c)

  return *highest_card;
} // HandCard const& HandCards::highest_card() const

/**
 **
 ** removes 'cards' from the vector
 **
 ** @param	cards	cards to remove
 **
 ** @return	-
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.8
 **
 **/
void
HandCards::remove(HandCards const& cards)
{
  for (HandCards::const_iterator c = cards.begin();
       c != cards.end();
       ++c) {
    HandCards::iterator d;
    for (d = this->begin();
	 *c != *d;
	 ++d) {
      DEBUG_ASSERTION((d != this->end()),
		      "HandCards::remove(cards):\n"
		      "  card '" << *c << "' not found in the cards.\n"
		      << *this);
    }
    this->erase(d);
  } // for (c \in cards)
} // void HandCards::remove(HandCards cards)

/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	whether there is a trump still on the hand
 **
 ** @author	Borg Enders
 ** @author	Diether Knof
 **
 ** @version	0.6.8
 **
 **/
bool
HandCards::hastrump() const
{
  for (HandCards::const_iterator c = this->begin();
       c != this->end();
       ++c)
    if (c->istrump())
      return true;

  return false;
} // bool HandCards::hastrump()

/**
 **
 ** -> result
 **
 ** @param	tcolor	trump-color to search for
 **
 ** @return	whether there is a card with trump-color 'tcolor' on the hand
 **
 ** @author	Borg Enders
 ** @author	Diether Knof
 **
 ** @version	0.6.8
 **
 **/
bool
HandCards::existstcolor(Card::TColor const& tcolor) const
{
  for (HandCards::const_iterator c = this->begin();
       c != this->end();
       ++c)
    if (c->tcolor() == tcolor)
      return true;

  return false;
} // bool HandCards::existstcolor(Card::TColor const& tcolor)

/**
 **
 ** -> result
 **
 ** @param	value	value to count
 **
 ** @return	number of cards with the value 'value'
 **
 ** @author	Borg Enders
 ** @author	Diether Knof
 **
 ** @version	0.6.8
 **
 **/
unsigned
HandCards::numberof(Card::Value const& value) const
{
  unsigned number = 0;

  for (HandCards::const_iterator c = this->begin();
       c != this->end();
       ++c)
    if (c->value() == value)
      number += 1;

  return number;
} // unsigned HandCards::numberof(Card::Value const& value)

/**
 **
 ** -> result
 **
 ** @param	tcolor	trump-color to count
 **
 ** @return	number of cards with the trump-color 'tcolor'
 **
 ** @author	Borg Enders
 ** @author	Diether Knof
 **
 ** @version	0.6.8
 **
 **/
unsigned
HandCards::numberof(Card::TColor const& tcolor) const
{
  unsigned number = 0;

  for (HandCards::const_iterator c = this->begin();
       c != this->end();
       ++c)
    if (c->tcolor() == tcolor)
      number += 1;

  return number;
} // unsigned HandCards::numberof(Card::TColor const& tcolor)

/**
 **
 ** -> result
 **
 ** @param	card	card to count
 **
 ** @return	number of cards 'card'
 **
 ** @author	Borg Enders
 ** @author	Diether Knof
 **
 ** @version	0.6.8
 **
 **/
unsigned
HandCards::numberof(Card const& card) const
{
  unsigned number = 0;

  for (HandCards::const_iterator c = this->begin();
       c != this->end();
       ++c)
    if (*c == card)
      number += 1;

  return number;
} // unsigned HandCards::numberof(Card const& card) const

/**
 **
 ** -> result
 ** Note: 'HandCards::numberof(Card)' does not cover the case (TRUMP, ACE)
 **
 ** @param	tcolor	trump-color of the card
 ** @param	value	value of the card
 **
 ** @return	number of cards with trump-color 'tcolor' and value 'value'
 **
 ** @author	Borg Enders
 ** @author	Diether Knof
 **
 ** @version	0.6.8
 **
 **/
unsigned
HandCards::numberof(Card::TColor const& tcolor, Card::Value const& value) const
{
  unsigned number = 0;

  for (HandCards::const_iterator c = this->begin();
       c != this->end();
       ++c) {
    if ( (c->tcolor() == tcolor)
	 && (c->value() == value) )
      number += 1;
  }

  return number;
} // unsigned HandCards::numberof(Card::TColor, Card::Value)

/**
 **
 ** -> result
 ** Note: 'HandCards::numberof(Card)' does not cover the case (TRUMP, ACE)
 **
 ** @param	color	color to count
 ** @param	game	game
 **
 ** @return	number of cards with color 'color' given the gametype 'gt'
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.8
 **
 **/
unsigned
HandCards::numberof(Card::Color const& color, Game const& game) const
{
  return this->numberof(color, game.type(), game.rule()(Rule::DOLLEN));
} // unsigned HandCards::numberof(Card::Color color, Game game) const

/**
 **
 ** -> result
 ** Note: 'HandCards::numberof(Card)' does not cover the case (TRUMP, ACE)
 **
 ** @param	color		color to count
 ** @param	gametype	the gametype
 ** @param	dollen		whether dollen are allowed
 **
 ** @return	number of cards with color 'color' given the gametype and the dollen rule
 **
 ** @author	Borg Enders
 ** @author	Diether Knof
 **
 ** @version	0.6.8
 **
 **/
unsigned
HandCards::numberof(Card::Color const& color,
		    GameType const gametype, bool const dollen) const
{
  unsigned number = 0;

  for (HandCards::const_iterator c = this->begin();
       c != this->end();
       ++c)
    if ((c->color() == color)
	&& !c->Card::istrump(gametype, dollen))
      number += 1;

  return number;
} // unsigned HandCards::numberof(Card::Color color, GameType gametype, bool dollen) const

/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	number of trumps on the hand
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.8
 **
 **/
unsigned
HandCards::numberoftrumps() const
{
  return this->numberof(Card::TRUMP);
} // unsigned HandCards::numberoftrumps() const

/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	number of trump kings on the hand
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.8
 **
 **/
unsigned
HandCards::numberoftrumpkings() const
{
  return this->numberof(Card::TRUMP, Card::KING);
} // unsigned HandCards::numberoftrumpkings() const

/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	number of nines on the hand
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.8
 **
 **/
unsigned
HandCards::numberofnines() const
{
  return this->numberof(Card::NINE);
} // unsigned HandCards::numbernines()

/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	number of kings on the hand
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.8
 **
 **/
unsigned
HandCards::numberofkings() const
{
  return this->numberof(Card::KING);
} // unsigned HandCards::numberkings()

/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	number of club queens on the hand
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.8
 **
 **/
unsigned
HandCards::numberofclubqueens() const
{
  return this->numberof(Card::CLUB_QUEEN);
} // unsigned HandCards::numberofclubqueens()

/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	number of trump aces on the hand
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.8
 **
 **/
unsigned
HandCards::numberoftrumpaces() const
{
  return this->numberof(Card::TRUMP, Card::ACE);
} // unsigned HandCards::numberoftrumpaces() const

/**
 **
 ** -> result
 **
 ** @param	-
 **
 ** @return	number of trump nines on the hand
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.8
 **
 **/
unsigned
HandCards::numberoftrumpnines() const
{
  return this->numberof(Card::TRUMP, Card::NINE);
} // unsigned HandCards::numberoftrumpnines() const

/**
 ** -> result
 **
 ** @param	cards	cards to compare with
 ** 
 ** @return	whether 'cards' is equal to 'this' (without order)
 **
 ** @author	Diether Knof
 **
 ** @version	0.7.3
 **/
bool
HandCards::equal(HandCards const& cards) const
{
  for (HandCards::const_iterator c = cards.begin();
       c != cards.end();
       ++c)
    if (this->numberof(*c) != cards.numberof(*c))
      return false;

  return true;
} // bool HandCards::equal(HandCards cards) const

/**
 **
 ** write the hand on 'ostr'
 **
 ** @param	ostr	stream to write the hand to
 ** @param	cards	cards to write
 **
 ** @return	output stream
 **
 ** @author	Diether Knof
 **
 ** @version	0.6.8
 **
 **/
ostream&
operator<<(ostream& ostr, HandCards const& cards)
{
  for (HandCards::const_iterator c = cards.begin();
       c != cards.end();
       ++c)
    ostr << *c << '\n';

  return ostr;
} // ostream& operator<<(ostream&, HandCards)
