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

#define MIN_HYPERSPACE_DIST 1500
#define MAX_HYPERSPACE_VEL  25

#define PLANET_TECH_MAX   8

/* Planet types. I didn't take them from Star Trek, I promise. */
typedef enum PlanetClass_ {
  PLANET_CLASS_NULL = 0,
  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)
#define PLANET_SERVICE_OUTFITS    (1<<3)
#define PLANET_SERVICE_SHIPYARD   (1<<4)
#define planet_hasService(p,s)    ((p)->services & s)

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

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

  glTexture* gfx_space;     /* Graphics in space. */
  glTexture* gfx_exterior;  /* Graphics in the exterior. */
} Planet;

/* Star system flags. */
#define SYSTEM_KNOWN      (1<<0)
#define SYSTEM_MARKED     (1<<1)
#define sys_isFlag(s,f)   ((s)->flags & (f))
#define sys_setFlag(s,f)  if(!sys_isFlag(s,f)) (s)->flags |= (f)
#define sys_rmFlag(s,f)   if(sys_isFlag(s,f))  (s)->flags ^= (f)
#define sys_isKnown(s)    sys_isFlag(s, SYSTEM_KNOWN)
#define sys_isMarked(s)   sys_isFlag(s, SYSTEM_MARKED)

/* Star systems. */
typedef struct SystemFleet_ {
  Fleet* fleet;           /* Fleet to appear. */
  int chance;             /* Chance of fleet appearing in the system. */
} SystemFleet;

typedef struct StarSystem_ {
  char* name;             /* Star system identifier. */
  Vec2 pos;               /* Position. */
  int stars, asteroids;   /* Un numero! */
  double interference;    /* Un uh.. Percentage. */

  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. */
  double nebu_volatility; /* Nebulae volatility - Not used yet. */

  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);

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