#pragma once
#include "faction.h"
#include "opengl.h"
#include "economy.h"
#include "pilot.h"

#define MIN_HYPERSPACE_DIST 1500  /**< Minimum distance to initiate hyperspace. */
#define MAX_HYPERSPACE_VEL  25    /**< Speed to brake to before jumping. */

#define PLANET_TECH_MAX   8       /**< Amount of special techs a planet can have. */

/**
 * @enum PlanetClass
 *
 * @brief Different planet classes.
 */
typedef enum PlanetClass_ {
  PLANET_CLASS_NULL = 0,  /**< Null/Not defined. */
  PLANET_CLASS_A,         /**< Geothermal. */
  PLANET_CLASS_B,         /**< Geomorteus. */
  PLANET_CLASS_C,         /**< Geoinactive. */
  PLANET_CLASS_D,         /**< Asteroid/Moon. */
  PLANET_CLASS_E,         /**< Geoplastic. */
  PLANET_CLASS_F,         /**< Geometallic. */
  PLANET_CLASS_G,         /**< GroCrystaline. */
  PLANET_CLASS_H,         /**< Desert. */
  PLANET_CLASS_I,         /**< Gas Supergiant. */
  PLANET_CLASS_J,         /**< Gas Giant. */
  PLANET_CLASS_K,         /**< Adaptable. */
  PLANET_CLASS_L,         /**< Marginal. */
  PLANET_CLASS_M,         /**< Terrestrial. */
  PLANET_CLASS_N,         /**< Reducing. */
  PLANET_CLASS_O,         /**< Pelagic. */
  PLANET_CLASS_P,         /**< Glaciated. */
  PLANET_CLASS_Q,         /**< Variable. */
  PLANET_CLASS_R,         /**< Rogue. */
  PLANET_CLASS_S,         /**< Ultragiant. */
  PLANET_CLASS_T,         /**< Ultragiant. */
  PLANET_CLASS_X,         /**< Demon. */
  PLANET_CLASS_Y,         /**< Demon. */
  PLANET_CLASS_Z,         /**< Demon. */
  STATION_CLASS_A,        /**< Civilian station. */
  STATION_CLASS_B,        /**< Military station. */
  STATION_CLASS_C,        /**< Interfactional station. */
  STATION_CLASS_D,        /**< Robotoc station. */
} PlanetClass;

/* Planet services. */
#define PLANET_SERVICE_LAND       (1<<0) /**< Can we land? */
#define PLANET_SERVICE_BASIC      (1<<1) /**< Refueling, spaceport bar, new. */
#define PLANET_SERVICE_COMMODITY  (1<<2) /**< Can trade commodities. */
#define PLANET_SERVICE_OUTFITS    (1<<3) /**< Can trade outfits. */
#define PLANET_SERVICE_SHIPYARD   (1<<4) /**< Can trade ships. */
#define planet_hasService(p,s)    ((p)->services & s) /**< Check if planet has service. */

/**
 * @struct Planet
 *
 * @brief Represents a planet.
 */
typedef struct Planet_ {
  char* name;               /**< Planet name */
  Vec2 pos;                 /**< Position in star system. */

  PlanetClass class;        /**< Planet type. */
  int faction;              /**< Planet faction. */

  char* description;        /**< Planet description. */
  char* bar_description;    /**< Spaceport bar description. */
  unsigned int services;    /**< Offered services. */
  Commodity** commodities;  /**< Commodities sold. */
  int ncommodities;         /**< Amount in stock. */

  int tech[PLANET_TECH_MAX];  /**< tech[0] stores the global tech level
                                   (everything that and below) while
                                   tech[1-PLANET_TECH_MAX] store the
                                   "unique" tech levels (only matches) */

  glTexture* gfx_space;     /**< Graphics in space. */
  char* gfx_exterior;       /**< Don't actually load the texture. */
} Planet;

/* Star system flags. */
#define SYSTEM_KNOWN      (1<<0)    /**< System is known. */
#define SYSTEM_MARKED     (1<<1)    /**< System is marked by a mission. */
#define sys_isFlag(s,f)   ((s)->flags & (f))  /**< Check system flag. */
#define sys_setFlag(s,f)  if(!sys_isFlag(s,f)) (s)->flags |= (f)  /**< Set a system flag. */
#define sys_rmFlag(s,f)   if(sys_isFlag(s,f))  (s)->flags ^= (f)  /**< Remove a system flag. */
#define sys_isKnown(s)    sys_isFlag(s, SYSTEM_KNOWN)   /**< Check if system is known. */
#define sys_isMarked(s)   sys_isFlag(s, SYSTEM_MARKED)  /**< Check if system is marked. */

/**
 * @struct SystemFleet
 *
 * @brief Represents a fleet that can appear in the system.
 */
typedef struct SystemFleet_ {
  Fleet* fleet;           /**< Fleet to appear. */
  int chance;             /**< Chance of fleet appearing in the system. */
} SystemFleet;

/**
 * @struct StarSystem
 *
 * @brief Represents a star system.
 *
 * The star system is the basic setting in Lephisto.
 */
typedef struct StarSystem_ {
  char* name;             /**< Star system identifier. */
  Vec2 pos;               /**< Position. */
  int stars;              /**< Ammount of "stars" it has. */
  int asteroids;          /**< @todo Implement asteroids. */
  double interference;    /**< in % @todo Implement interference. */

  int faction;            /**< Overall faction. */

  Planet* planets;        /**< Planets. */
  int nplanets;           /**< Total number of planets. */

  SystemFleet* fleets;    /**< Fleets that can appear in the current system. */
  int nfleets;            /**< Total number of fleets. */

  int* jumps;             /**< Adjacent star system index number. */
  int njumps;             /**< Number of adjacent jumps. */

  double nebu_density;    /**< Nebulae density (0. - 1000.).*/
  double nebu_volatility; /**< Nebulae volatility (0. - 1000.). */

  unsigned int flags;     /**< Flags for system properties. */
} StarSystem;

extern StarSystem* cur_system; /**< Current star system. */

/* Load/Exit. */
void space_init(const char* sysname);
int space_load(void);
void space_exit(void);

/* Planet stuff. */
char* planet_getSystem(char* planetname);
Planet* planet_get(char* planetname);
char planet_getClass(Planet* p);

/* Render. */
void space_render(const double dt);
void space_renderOverlay(const double dt);
void planets_render(void);

/* Update. */
void space_update(const double dt);

/* Misc. */
StarSystem* system_get(const char* sysname);
int space_canHyperspace(Pilot* p);
int space_hyperspace(Pilot* p);
int space_sysReachable(StarSystem* sys);
char** space_getFactionPlanet(int* nplanets, int* factions, int nfactions);
char* space_getRndPlanet(void);
void  space_clearKnown(void);
void  space_clearMarkers(void);
extern char* stardate;

