/**********************************************************************
 *
 *   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
 *
 *********************************************************************/

#ifndef CLASS_CARDS_INFORMATION_HEADER
#define CLASS_CARDS_INFORMATION_HEADER

#include "../../card/card.h"

#include "../../basistypes.h"
#include "../../card/hand.h"
#include "../../card/card_counter.h"

#include "../../game/exception.h"

class Player;
class Ai;
class Game;

#ifndef RELEASE
// card of interest, for debugging
#define COI Card(Card::CLUB, Card::ACE)
#endif

/**
 ** Contains and analyses the information, who has played which card
 ** and gives the information which cards a player can have.
 **
 ** @author	Diether Knof
 **/
class CardsInformation {
  friend bool operator==(CardsInformation const&, CardsInformation const&);
  public:
  /**
   ** Information of the cards a specific player can have
   **
   ** @author	Diether Knof
   **/
  class OfPlayer {
    friend bool operator==(OfPlayer const&, OfPlayer const&);
    friend class CardsInformation;

    public:
    OfPlayer(CardsInformation& cards_information,
	     unsigned const playerno);
    // copy constructor
    OfPlayer(OfPlayer const& of_player);
    // copy operator
    OfPlayer& operator=(OfPlayer const& of_player);
    // destructor
    ~OfPlayer();


    // reset all informations
    void reset();


    // writes the information in 'ostr'
    void write(ostream& ostr) const;


    // the corresponding game
    Game const& game() const;
    // the corresponding player
    Player const& player() const;

    // changes the corresponding cards information
    void set_cards_information(CardsInformation& cards_information);


    // how many cards 'card' the player has played
    unsigned played(Card const& card) const;
    // how many cards of the tcolor 'tcolor' the player has played
    unsigned played(Card::TColor const& tcolor) const;
    // how many cards the player must still have on the hand
    unsigned must_have(Card const& card) const;
    // how many cards the player can still have on the hand
    unsigned can_have(Card const& card) const;
    // whether the player cannot have the card
    bool cannot_have(Card const& card) const;
    // whether the player has not the color
    bool does_not_have(Card::TColor const& tcolor) const;


    // the possible hand of the player
    Hand possible_hand() const;


    // the player has played 'card'
    void card_played(HandCard const& card);

    // adds the information that the player must have the card 'no' times
    void add_must_have(Card const& card, unsigned const no = 1);
    // adds the information that the player must have the cards
    void add_must_have(vector<Card> const& cards);

    // adds the information that the player can have the card at max 'no' times
    void add_can_have(Card const& card, unsigned const no);
    // adds the information that the player can only have the cards
    void add_can_only_have(vector<Card> const& cards);

    // adds the information that the player cannot have the card
    void add_cannot_have(Card const& card);
    // adds the information that the player cannot have the cards
    void add_cannot_have(vector<Card> const& cards);
    // whether the player has not the color
    void add_does_not_have(Card::TColor const tcolor);

    // updates the information of the card
    void update_information(Card const& card);
    // updates 'can have' according to 'remaining cards'
    void update_remaining_cards();

    private:
    // check whether the cards the player can have are the ones
    // he has to have
    void check_can_is_must();
    // check whether the cards the player has to have are the only ones
    // he can have
    void check_must_is_can();
    // checks the data for error
    bool self_check() const;

    private:
    // the cards information
    PRIV_VAR_P_RW(CardsInformation, cards_information);
    // the playerno
    PRIV_VAR_R(unsigned, playerno);

    // number of played cards of the player
    CardCounter played_;
    // number of cards, the player must have
    CardCounter must_have_;
    // number of cards, the player can have
    CardCounter can_have_;

    // whether the player does not have the color anymore
    mutable map<Card::TColor, bool> does_not_have_tcolor_;
  }; // class OfPlayer

  public:
  // constructor
  CardsInformation(Ai const& player);
  // copy constructor
  CardsInformation(CardsInformation const& cards_information);
  // copy operator
  CardsInformation& operator=(CardsInformation const& cards_information);
  // destructor
  ~CardsInformation();


  // writes the information in 'ostr'
  void write(ostream& ostr) const;

  // reset all informations
  void reset();
  // recalcs all information
  void recalc();


  // the information of singe players
  OfPlayer const& of_player(Player const& player) const;
  OfPlayer const& of_player(unsigned const playerno) const;

  // the hand the player can have
  Hand possible_hand(Player const& player) const;

  // the corresponding game
  Game const& game() const;


  // some settings

  // set the player
  void set_player(Ai const& player);
  // set the hand of the player
  void set_hand(Player const& player, Hand const& hand);


  // intern methods

  // updates the information of the card
  void update_information(Card const& card);
  // updates the information of all cards
  void update_information_all();
  // updates 'can have' according to 'remaining cards'
  void update_remaining_cards();


  // the number of forgotten tricks
  unsigned forgotten_tricks_no() const;
  // the number of forgotten cards
  unsigned forgotten_cards_no() const;
  // how many cards have been played in total in the game
  unsigned played_cards_no() const;
  // how many of 'card' have been played
  unsigned played(Card const& card) const;


  // the information from the game

  // the game starts
  void game_start();
  // the trick is opened
  void trick_open(Trick const& trick);
  // the card is played
  void card_played(HandCard const& card);
  // an announcement is made
  void announcement_made(Announcement const& announcement,
			 Player const& player);
  // the player has swines
  void swines_announced(Player const& player);
  // the player has hyperswines
  void hyperswines_announced(Player const& player);
  // a player has announced a genscher
  void genscher(Player const& genscher, Player const& partner);

  private:
#ifdef DKNOF
  public:
#endif
  // checks the data for error
  bool self_check() const;

  private:
  // the corresponding player
  PRIV_VAR_CP_R(Ai, player);
  // the information for a specific player
  vector<OfPlayer> of_player_;
  // how many cards have been played
  CardCounter played_;
  // whether we are in a recalcing
  PRIV_VAR_R(bool, in_recalcing);

  private: // unused
  CardsInformation();
}; // class CardsInformation

// writes the cards information into the output stream
ostream& operator<<(ostream& ostr,
		    CardsInformation const& cards_information);
// compares two cards informations
bool operator==(CardsInformation const& cards_information_a,
		CardsInformation const& cards_information_b);
// compares two cards informations
bool operator!=(CardsInformation const& cards_information_a,
		CardsInformation const& cards_information_b);

// writes the cards information about a player into the output stream
ostream& operator<<(ostream& ostr,
		    CardsInformation::OfPlayer const& of_player);
// compares two cards informations about a player
bool operator==(CardsInformation::OfPlayer const& of_player_a,
		CardsInformation::OfPlayer const& of_player_b);
// compares two cards informations about a player
bool operator!=(CardsInformation::OfPlayer const& of_player_a,
		CardsInformation::OfPlayer const& of_player_b);

#endif // #ifndef CLASS_CARDS_INFORMATION_HEADER
