/**********************************************************************
 *
 *   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_AICONFIG_HEADER
#define CLASS_AICONFIG_HEADER

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

#include <map>

namespace AITYPE {
  enum AiType {
    AITYPE_FIRST = 0,

    NO_CHOOSEBESTCARD = AITYPE_FIRST,
    RANDOM,
    VIRTUAL_GAMES,
    GAMETREE,
    GAMETREE_WITH_HEURISTICS,
    MONTE_CARLO,

    AITYPE_LAST = MONTE_CARLO
  }; // enum AiType
  extern unsigned const NUMBER;
} // namespace AITYPE
using AITYPE::AiType;
extern AiType aitype;

string name(const AiType& aitype);
WRITE_NAME2(AITYPE, AiType)


class Aiconfig {
  public:
    enum Difficulty {
      DIFFICULTY_FIRST = 0,

      CUSTOM = DIFFICULTY_FIRST,
      NOVICE,
      STANDARD_DEFENSIVE,
      STANDARD_OFFENSIVE,
      PROFI,
      PROFI_UNFAIR,

      DIFFICULTY_LAST = PROFI_UNFAIR
    }; // enum Difficulty

    enum Heuristic {
      HEURISTIC_FIRST,

      NO_HEURISTIC = HEURISTIC_FIRST,
      BUG_REPORT,
      ONLY_VALID_CARD,
      PLAY_TO_MARRY,           // Heuristics::play_to_marry
      CHOOSE_ACE,              // Heuristics::choose_ace
      CHOOSE_FOR_COLOR_TRICK,  // Heuristics::choose_for_color_trick
      RETRY_COLOR,
      SERVE_COLOR_TRICK,
      SERVE_TRUMP_TRICK,
      CHOOSE_PFUND,            // Heuristics::choose_pfund 
      CHOOSE_PFUND_POVERTY,    // Heuristics::choose_pfund_poverty
      JAB_FOR_ACE,             // Heuristics::jab_for-ace
      CREATE_FEHL,             // Heuristics::create_fehl
      BEST_WINNING,            // Heuristics::best_winning_card
      LOW_HIGH,                // Heuristics::play_low_high    
      PLAY_FOR_TEAM,           // Heuristics::play_for_team
      JAB_FOX,                 // Heuristics::jab_fox
      TRY_FOR_DOPPELKOPF,                 // Heuristics::try_for_doppelkopf
      DRAW_TRUMP,             
      GET_TRICK_FOR_ANNOUNCEMENT,

      POVERTY_PLAYER_PLAY_PFUND,
	  
      MEATLESS_PLAYHIGHESTCOLOR,        // Meatless: Heuristics::play_highest_color
      PICTURE_SECONDBESTTRUMP,

      COLOR_CHOOSE_ACE,
      COLOR_BEST_WINNING,
      COLOR_JAB_FOR_ACE,
      COLOR_LOW_HIGH,

      CHOOSE_BEST_CARD, // for the database

      HEURISTIC_LAST = CHOOSE_BEST_CARD
    }; // enum Heuristic
    static unsigned const HEURISTIC_NUMBER;
    static bool is_general(Heuristic const h);
    static bool is_poverty(Heuristic const h);
    static bool is_solo(Heuristic const h);
    static bool is_solo_color(Heuristic const h);
    static bool is_solo_picture(Heuristic const h);
    static bool is_solo_meatless(Heuristic const h);

    enum TypeBool {
      BOOL_FIRST = HEURISTIC_LAST + 1,

      TRUSTING = BOOL_FIRST, // whether the ai is trusting

      FAIRPLAYHANDS, // whether the ai takes the current hands of the players
      FAIRPLAYTEAMS, // whether the ai knows the team of the other players

      FEHLCREATIONONFIRSTCARD,

      BOOL_LAST = FEHLCREATIONONFIRSTCARD
    }; // enum TypeBool
    static unsigned const BOOL_NUMBER;

    enum TypeUnsigned {
      UNSIGNED_FIRST = BOOL_LAST + 1,

      REMEMBERTRICKS = UNSIGNED_FIRST, // how many tricks are remembered

      LIMIT_THROW_FEHL, // maximum points for playing a fehl
      LIMITQUEEN, // mininum points per trick for jabbing with a queen
      LIMITDOLLE, // minimum points per trick for jabbing with dollen or higher

      LASTFEHLCREATION, // last trick to create a fehl color
      LASTHEURISTICTRICK,
      FIRST_TRICK_FOR_TRUMP_POINTS_OPTIMIZATION,

      ANNOUNCELIMIT, // points of hand for first announcement 
      ANNOUNCELIMITDEC, // points of hand you can lose between two announcements
      ANNOUNCECONFIG, // Parameter for Playerconfiguration of announcements
      ANNOUNCELIMITREPLY, // points of hand for first Reply
      ANNOUNCECONFIGREPLY, // Decrement for each announcment made, when replying 

      TAKEPOVERTY,

      SINGLESOLO, // minimum cardvalue for a solo with only one picture trump
      DOUBLESOLO, // minimum cardvalue for a solo with two pictures trump
      TRIPLESOLO, // minimum cardvalue for a solo with three pictures trump
      COLORSOLO, // minimun cardvalue for playing a colorsolo
      MEATLESS, // minimun cardvalue for playing a fleischlosen

      FUTURE_LIMIT, // number of tricks calculated into the future

      UNSIGNED_LAST = FUTURE_LIMIT
    }; // enum TypeUnsigned
    static unsigned const UNSIGNED_NUMBER;

    enum TypeCard {
      CARD_FIRST = UNSIGNED_LAST + 1,

      LIMITTHROWING = CARD_FIRST, // minimum team mate card for not over jabbing

      TRUMPLIMIT_SOLOCOLOR,
      TRUMPLIMIT_SOLOJACK,
      TRUMPLIMIT_SOLOQUEEN,
      TRUMPLIMIT_SOLOKING,
      TRUMPLIMIT_SOLOJACKKING,
      TRUMPLIMIT_SOLOJACKQUEEN,
      TRUMPLIMIT_SOLOQUEENKING,
      TRUMPLIMIT_SOLOKOEHLER,
      TRUMPLIMIT_MEATLESS,
      TRUMPLIMIT_NORMAL,

      LOWEST_TRUMPLIMIT_SOLOCOLOR,
      LOWEST_TRUMPLIMIT_SOLOJACK,
      LOWEST_TRUMPLIMIT_SOLOQUEEN,
      LOWEST_TRUMPLIMIT_SOLOKING,
      LOWEST_TRUMPLIMIT_SOLOJACKKING,
      LOWEST_TRUMPLIMIT_SOLOJACKQUEEN,
      LOWEST_TRUMPLIMIT_SOLOQUEENKING,
      LOWEST_TRUMPLIMIT_SOLOKOEHLER,
      LOWEST_TRUMPLIMIT_MEATLESS,
      LOWEST_TRUMPLIMIT_NORMAL,

      LIMITHIGH, // minimum team mate card for throwing a ten or ace into this trick

      CARD_LAST = LIMITHIGH
    }; // enum TypeCard
    static unsigned const CARD_NUMBER;

  public:
    // returns a preset ai
    static Aiconfig const& preset(Difficulty const difficulty);

  public:
    friend class Ai;

  public:
    Aiconfig();
    Aiconfig(istream& istr);
    Aiconfig(Aiconfig const& aiconfig);
    Aiconfig& operator=(Aiconfig const& aiconfig);
    ~Aiconfig();

#ifndef OUTDATED
    // 0.7.2
    void reset_to_hardcoded();
#endif

    // (re)sets the aiconfig to the given difficulty
    void set_to_difficulty(Difficulty const difficulty);

    // whether the aiconfig is equal
    bool equal(Aiconfig const& aiconfig) const;

    Difficulty difficulty() const;
    AiType const& aitype(unsigned const trickno) const;
    void set_aitype(unsigned const trickno, AiType const& aitype);
    void set_aitype_for_all_tricks(AiType const& aitype);
    unsigned const future_limit(unsigned const trickno) const;
    void set_future_limit(unsigned const trickno, unsigned const future_limit);
    void set_future_limit_for_all_tricks(unsigned const future_limit);

    // returns the value
    bool value(Heuristic const type) const;
    bool value(TypeBool const type) const;
    unsigned value(TypeUnsigned const type) const;
    Card value(TypeCard const type) const;

    // the minimum and maximum value
    unsigned min(TypeUnsigned const& type) const;
    unsigned max(TypeUnsigned const& type) const;

    // the valid cards for the type
    list<Card> const& valid_cards(TypeCard const type) const;

    // sets the value
    bool set(string const& type, string const& value);

    void set(Heuristic const type, string const& value);
    void set(TypeBool const type, string const& value);
    void set(TypeUnsigned const type, string const& value);
    void set(TypeCard const type, string const& value);

    void set(Heuristic const type, bool const value);
    void set(TypeBool const type, bool const value);
    void set(TypeUnsigned const type, unsigned const value);
    void set(TypeCard const type, Card const value);

    bool load(string const& filename);
    bool load(istream& istr);
    bool save(string const& filename) const;

    // output of the settings
    ostream& write(ostream& ostr) const;
  private:
    vector<AiType> aitype_p;
    vector<unsigned> future_limit_p;

    vector<bool> heuristic_p;
    vector<bool> bool_p;
    vector<unsigned> unsigned_p;
    vector<Card> card_p;
}; // class Aiconfig

namespace HeuristicsMap {
  typedef std::map<Key, vector<Aiconfig::Heuristic> > Map;
}; // namespace HeuristicsMap

// whether the two aiconfigs are equal
bool operator==(Aiconfig const& aiconfig_a, Aiconfig const& aiconfig_b);
// whether the two aiconfigs are different
bool operator!=(Aiconfig const& aiconfig_a, Aiconfig const& aiconfig_b);

string name(Aiconfig::Difficulty const difficulty);
WRITE_NAME2(Aiconfig, Difficulty)

// conversion in a string
string name(Aiconfig::Heuristic const type);

string name(Aiconfig::TypeBool const type);
string name(Aiconfig::TypeUnsigned const type);
string name(Aiconfig::TypeCard const type);

// output of the name
WRITE_NAME2(Aiconfig, Heuristic)
WRITE_NAME2(Aiconfig, TypeBool)
WRITE_NAME2(Aiconfig, TypeUnsigned)
WRITE_NAME2(Aiconfig, TypeCard)

// output of the Aiconfig
ostream& operator<<(ostream& ostr, Aiconfig const& aiconfig);

#endif // #ifndef CLASS_AICONFIG_HEADER
