#pragma once

// README!
// You can override the default configuration by creating a new file Config\User\ConfigImpl.h
// This new file should not be committed to the SVN repository (since every user may have a different local configuration).
// Changing this local configuration file should only trigger the recompilation of Config.cpp, not the whole solution.
//
// Example (Config\User\ConfigImpl.h):
//
//#include "../Default/ConfigImpl.h"
//#include "../Config.h"
//
//#define ConfigImpl UserConfig
//
//class UserConfig : public DefaultConfig
//{
//public:
//  static void initialize(Config* config)
//  {
//    DefaultConfig::initialize(config);
//
//    config->m_displayOwnUnitsActions = false;
//  }
//
//  static bool displayProcessesUnitsInGUI()
//  {
//    return true;
//  }
//};

class DefaultConfig;
class UserConfig;

class Config
{
public:
  //////////////////
  // Spar options //
  //////////////////

  static Config& getInstance() { return s_instance; }

  /**
   * @brief Maximum number of players involved in the game; 3 is an optimization for two-player games 
   *        (+ the neutral player). It would obviously crash for games of three players and more.
   */
  static const unsigned int MAX_NB_PLAYERS = 3;
  /**
   * @brief Returns the types of events that need to be logged, by default everything except ON_FRAME.
   *        This function is static to allow initializing the logger with this value.
   * @return The type of events to log.
   */
  unsigned int getDefaultLoggerEvents() const;
  /**
   * @brief Returns the speed for single-player games, by default 0 (speed up the game as much as possible).
   * @return The default speed for single-player games.
   */
  int getDefaultSpeed() const;
  /**
   * @brief Returns the server on which the log server listens for incoming connections.
   * @return The listening port of the log server.
   */
  unsigned short getLogServerPort() const;
  /**
   * @brief Returns the amount of worker threads to start. Defaults to the amount of physical cores on the machine - 1.
   * @return The amount of worker threads to start for the scheduler.
   * @remarks This value is ignored if USE_MULTITHREADED_SCHEDULER is not defined.
   */
  unsigned int getWorkerThreadCount() const;

  bool startLogServerThread() const;

  bool startStatsThread() const;

  /**
   * @brief Returns the maximum number of milliseconds available per frame to execute tasks, regardless of the game speed.
   *        Use MS_NO_LIMIT if there shouldn't be any maximum; all tasks are executed during the original frame they were specified to
   *        but the game may lag.
   *        Use MS_SCHEDULER to let the scheduler automatically calculate the number of milliseconds available to avoid lag.
   *        The default value is MS_SCHEDULER.
   * @return The maximum number of milliseconds available per frame to execute tasks, regardless of game speed.
   */
  unsigned int getAvailableMillisecondsPerFrame() const { return m_availableMsPerFrame; }
  void setAvailableMillisecondsPerFrame(unsigned int availableMsPerFrame);
  static const unsigned int MS_NO_LIMIT;
  static const unsigned int MS_SCHEDULER;

  bool displayMap() const { return m_displayMap;}
  void setDisplayMap(bool displayMap) { m_displayMap = displayMap; }
  bool displayUnitsInFogOfWar() const { return m_displayUnitsInFogOfWar;}
  void setDisplayUnitsInFogOfWar(bool displayUnitsInFogOfWar) { m_displayUnitsInFogOfWar = displayUnitsInFogOfWar; }
  bool displayEnemyInfluenceMap() const { return m_displayEnemyInfluenceMap; }
  void setDisplayEnemyInfluenceMap(bool displayEnemyInfluenceMap) { m_displayEnemyInfluenceMap = displayEnemyInfluenceMap; }
  bool displaySelfInfluenceMap() const { return m_displaySelfInfluenceMap; }
  void setDisplaySelfInfluenceMap(bool displaySelfInfluenceMap) { m_displaySelfInfluenceMap = displaySelfInfluenceMap; }
  bool displayVisibilityInfluenceMap() const { return m_displayVisibilityInfluenceMap; }
  void setDisplayVisibilityInfluenceMap(bool displayVisibilityInfluenceMap) { m_displayVisibilityInfluenceMap = displayVisibilityInfluenceMap; }
  bool displayStructureInfluenceMap() const { return m_displayStructureInfluenceMap; }
  void setDisplayStructureInfluenceMap(bool displayStructureInfluenceMap) { m_displayStructureInfluenceMap = displayStructureInfluenceMap; }
  bool displayDetectionInfluenceMap() const { return m_displayDetectionInfluenceMap; }
  void setDisplayDetectionInfluenceMap(bool displayDetectionInfluenceMap) { m_displayDetectionInfluenceMap = displayDetectionInfluenceMap; }
  bool displayOwnUnitsActions() const { return m_displayOwnUnitsActions; }
  void setDisplayOwnUnitsActions(bool displayOwnUnitsActions) { m_displayOwnUnitsActions = displayOwnUnitsActions; }
  bool displayVulnerabilityInfluenceMap() const {return m_displayVulnerabilityInfluenceMap;}
  void setDisplayVulnerabilityInfluenceMap(bool displayVulnerabilityInfluenceMap) { m_displayVulnerabilityInfluenceMap = displayVulnerabilityInfluenceMap;}


  //////////////////////
  // Spar GUI options //
  //////////////////////
  bool displayActionsOnlyInGUI() const;
  bool displayProcessesUnitsInGUI() const;

protected:
  friend class DefaultConfig;
  friend class UserConfig;

  Config();
  static Config s_instance;

  bool m_displayMap;
  bool m_displayUnitsInFogOfWar;
  bool m_displayEnemyInfluenceMap;
  bool m_displaySelfInfluenceMap;
  bool m_displayVisibilityInfluenceMap;
  bool m_displayStructureInfluenceMap;
  bool m_displayDetectionInfluenceMap;
  bool m_displayOwnUnitsActions;
  bool m_displayVulnerabilityInfluenceMap;
  unsigned int m_availableMsPerFrame;
};

