#pragma once
#include "physics.h"
#include "ship.h"
#include "ai.h"
#include "outfit.h"
#include "faction.h"
#include "sound.h"
#include "economy.h"

#define PLAYER_ID 1                     /**< Player pilot ID. */

#define HYPERSPACE_ENGINE_DELAY   3000  /**< Warm up the engines. */
#define HYPERSPACE_FLY_DELAY      5000  /**< Time taken to hyperspace. */
#define HYPERSPACE_STARS_BLUR     2000  /**< Time stars blur. */
#define HYPERSPACE_STARS_LENGTH   1000  /**< Length the stars blur to at max. */
#define HYPERSPACE_FADEOUT        1000  /**< Time fadeout. */
#define HYPERSPACE_FUEL           100   /**< Amount of fuel taken. */

/* Aproximation for pilot size. */
#define PILOT_SIZE_APROX          0.8   /**< Approximation for pilot size. */
#define PILOT_DISABLED_ARMOUR     0.3   /**< Armour % that makes it disabled. */

/* Hooks. */
#define PILOT_HOOK_NONE           0     /**< No hook. */
#define PILOT_HOOK_DEATH          1     /**< Pilot died. */
#define PILOT_HOOK_BOARD          2     /**< Pilot got boarded. */
#define PILOT_HOOK_DISABLE        3     /**< Pilot got disabled. */

/* Flags. */
#define pilot_isFlag(p,f)   (p->flags & (f))  /**< Check if flag f is set on pilot p. */
#define pilot_setFlag(p,f)  (p->flags |= (f)) /**< Set flag f on pilot p. */
#define pilot_rmFlag(p,f)   (p->flags ^= (f)) /**< Remove flag f on pilot p. */
/* Creation. */
#define PILOT_PLAYER        (1<<0)  /**< Pilot is a player. */
#define PILOT_HASTURRET     (1<<20) /**< Pilot has turrets. */
#define PILOT_HASBEAMS      (1<<23) /**< Pilot has beam weapons. */
#define PILOT_NO_OUTFITS    (1<<21) /**< Do not create the pilot with outfits. */
#define PILOT_EMPTY         (1<<22) /**< Do not add pilot to stack. */
/* Dynamic. */
#define PILOT_HOSTILE       (1<<1)  /**< Pilot is hostile to the player. */
#define PILOT_COMBAT        (1<<2)  /**< Pilot is engaged in combat. */
#define PILOT_AFTERBURNER   (1<<3)  /**< Pilot has her afterburner activated. */
#define PILOT_HYP_PREP      (1<<5)  /**< Pilot is getting ready for hyperspace. */
#define PILOT_HYP_BEGIN     (1<<6)  /**< Pilot is starting engines. */
#define PILOT_HYPERSPACE    (1<<7)  /**< Pilot is in hyperspace. */
#define PILOT_BOARDED       (1<<8)  /**< Pilot has been boarded already! */
#define PILOT_DISABLED      (1<<9)  /**< Pilot is disabled. */
#define PILOT_DEAD          (1<<10) /**< Pilot is on it's death bed. */
#define PILOT_DEATH_SOUND   (1<<11) /**< Pilot just did death explosion. */
#define PILOT_EXPLODED      (1<<12) /**< Pilot did final death explosion. */
#define PILOT_DELETE        (1<<15) /**< Pilot will get delete asap. */

/* Just makes life simpler. */
#define pilot_isPlayer(p)   ((p)->flags & PILOT_PLAYER)   /**< Check if pilot is a player. */
#define pilot_isDisabled(p) ((p)->flags & PILOT_DISABLED) /**< Check if pilot is disabled. */

/**
 * @enum PilotOutfitState
 *
 * @brief Contains the state of the outfit.
 *
 * Currently only applicable to beam weapons.
 */
typedef enum PilotOutfitState_ {
  PILOT_OUTFIT_OFF,     /**< Normal state. */
  PILOT_OUTFIT_WARMUP,  /**< Outfit is starting to warm up. */
  PILOT_OUTFIT_ON       /**< Outfit is activated and running. */
} PilotOutfitState;

/**
 * @struct PilotOutfit
 *
 * @brief Store an outfit the pilot has.
 */
typedef struct PilotOutfit_ {
  Outfit* outfit;         /**< Associated outfit. */
  int quantity;           /**< Number of outfits of this type that the pilot has. */
  PilotOutfitState state; /**< State of the outfit. */
  int beamid;             /**< ID of the beam used in this outfit, only for beams. */
  unsigned int timer;     /**< Used to store last used weapon time. */
} PilotOutfit;

/**
 * @struct PilotCommodity
 *
 * @brief Store a pilot commodity.
 */
typedef struct PilotCommodity_ {
  Commodity* commodity; /**< Assotiated commodity. */
  int quantity;         /**< Amount player has. */
  unsigned int id;      /**< Special mission id for cargo, 0 means none. */
} PilotCommodity;

/**
 * @struct Pilot
 *
 * @brief The representation of an ingame pilot.
 */
typedef struct Pilot_ {
  unsigned int id;  /**< Pilots id. */
  char* name;       /**< Pilot's name (if unique). */
  char* title;      /**< Title - Usuall indicating special properties - @todo. */

  int faction;      /**< Pilot faction. */

  /* Object characteristics. */
  Ship* ship;     /**< Pilots ship. */
  Solid* solid;   /**< Associated solid (physics). */
  int tsx;        /**< Current sprite x position, calculated on update. */
  int tsy;        /**< Current sprite y position, calculated on update. */

  double thrust;  /**< Pilots thrust. */
  double turn;    /**< Pilots turn. */
  double speed;   /**< Pilots speed. */

  /* Current health. */
  double armour;        /**< Current armour. */
  double shield;        /**< Current shield. */
  double energy;        /**< Current energy. */
  double fuel;          /**< Current fuel. */
  double armour_max;    /**< Max armour. */
  double shield_max;    /**< Max shield. */
  double energy_max;    /**< Max energy. */
  double fuel_max;      /**< Max fuel. */
  double armour_regen;  /**< Armour regeneration rate (per second). */
  double shield_regen;  /**< Shield regeneration rate (per second). */
  double energy_regen;  /**< Energy regeneration rate (per second). */

  void (*think)(struct Pilot_*);                /**< AI thinking for the pilot. */
  void (*update)(struct Pilot_*, const double); /**< Update the pilot. */
  void (*render)(struct Pilot_*);               /**< Rendering the pilot. */

  /* Outfit management. */
  PilotOutfit* outfits;     /**< Pilot outfit stack. */
  int noutfits;             /**< Pilot number of outfits. */
  PilotOutfit* secondary;   /**< Secondary weapon. */
  PilotOutfit* ammo;        /**< Secondary ammo (if needed). */
  PilotOutfit* afterburner; /**< The afterburner. */

  /* Jamming. */
  double jam_range;         /**< Range at wich pilot starts jamming. */
  double jam_chance;        /**< Jam chance. */

  /* Cargo. */
  int credits;                  /**< Moniez the pilot has. */
  PilotCommodity* commodities;  /**< Commodity and quantity. */
  int ncommodities;             /**< Number of commodies. */
  int cargo_free;               /**< Free commodity space. */

  /* Weapon Properties. */
  double weap_range; /**< Average range of primary weapons. */
  double weap_speed; /**< Average speed of primary weapons. */

  /* Misc. */
  uint32_t flags;       /**< Used for AI etc. */
  unsigned int ptimer;  /**< Generic timer for internal pilot use. */
  int lockons;          /**< Stores how many seeking weapons are targetting pilot. */

  /* Hook attached to the pilot. */
  int hook_type;  /**< Type of the hook atached to the pilot. */
  int hook;       /**< Hook id. */

  /* AI. */
  AI_Profile* ai;                     /**< Ai personality profile. */
  unsigned int tcontrol;              /**< Timer for control tick. */
  unsigned int timer[MAX_AI_TIMERS];  /**< Timers for AI. */
  Task* task;                         /**< Current action. */
} Pilot;

/**
 *  @struct FleetPilot
 *
 *  @brief Represents a pilot in a fleet.
 *
 *  @sa Fleet
 *  @sa Pilot
 */
typedef struct FleetPilot_ {
  Ship* ship;     /**< Ship that the pilot is flying. */
  char* name;     /**< For special 'unique' names. */
  int chance;     /**< Chance of this pilot appearing in the fleet. */
  AI_Profile* ai; /**< AI different of fleets global ai. */
} FleetPilot;

/**
 * @struct Fleet
 *
 * @brief Represents a fleet.
 *
 * Fleets are used to create pilots, both from being in a system and from
 * mission triggers.
 *
 * @sa FleetPilot
 */
typedef struct Fleet_ {
  char* name;   /**< Fleet name, used as an identifier. */
  int faction;  /**< Faction of the fleet. */

  AI_Profile* ai; /**< AI profile to use. */

  FleetPilot* pilots; /**< The pilots in the fleet. */
  int npilots;        /**< Total number of pilots. */
} Fleet;

/* Grabing pilot crap. */
extern Pilot* player; /* The player. */
Pilot* pilot_get(unsigned int id);
unsigned int pilot_getNextID(const unsigned int id);
unsigned int pilot_getNearestEnemy(const Pilot* p);
unsigned int pilot_getNearestHostile(void); /* Only for the player. */
unsigned int pilot_getNearestPilot(const Pilot* p);
Fleet* fleet_get(const char* name);
int pilot_getJumps(const Pilot* p);

/* Misc. */
void pilot_shoot(Pilot* p, const unsigned int target, const int secondary);
void pilot_shootStop(Pilot* p, const int secondary);
void pilot_hit(Pilot* p, const Solid* w, const unsigned int shooter,
    const DamageType dtype, const double damage);
void pilot_switchSecondary(Pilot* p, int i);
void pilot_setSecondary(Pilot* p, const char* secondary);
void pilot_setAmmo(Pilot* p);
void pilot_setAfterburner(Pilot* p);
double pilot_face(Pilot* p, const double dir);
void pilot_hyperspaceAbort(Pilot* p);
/* Outfits. */
int pilot_freeSpace(Pilot* p); /* Pilot space. */
int pilot_addOutfit(Pilot* pilot, Outfit* outfit, int quantity);
int pilot_rmOutfit(Pilot* pilot, Outfit* outfit, int quantity);
char* pilot_getOutfits(Pilot* pilot);
void pilot_calcStats(Pilot* pilot);
/* Normal cargo. */
int pilot_cargoUsed(Pilot* pilot);   /* Get amount of cargo onboard. */
int pilot_cargoFree(Pilot* p);      /* Cargo space. */
int pilot_addCargo(Pilot* pilot, Commodity* cargo, int quantity);
int pilot_rmCargo(Pilot* pilot, Commodity* cargo, int quantity);
/* Mission cargo - Not to be confused with normal cargo. */
unsigned int pilot_addMissionCargo(Pilot* pilot, Commodity* cargo, int quantity);
int pilot_rmMissionCargo(Pilot* pilot, unsigned int cargo_id);


/* Creation. */
void pilot_init(Pilot* dest, Ship* ship, char* name, int faction,
                AI_Profile* ai, const double dir, const Vec2* pos,
                const Vec2* vel, const int flags);

unsigned int pilot_create(Ship* ship, char* name, int faction,
                          AI_Profile* ai, const double dir, const Vec2* pos,
                          const Vec2* vel, const int flags);

Pilot* pilot_createEmpty(Ship* ship, char* name,
                         int faction, AI_Profile* ai, const int flags);

Pilot* pilot_copy(Pilot* src);

/* Init/Cleanup. */
void pilot_destroy(Pilot* p);
void pilots_free(void);
void pilots_clean(void);
void pilots_cleanAll(void);
void pilot_free(Pilot* p);
int fleet_load(void);
void fleet_free(void);

/* Update. */
void pilots_update(double dt);
void pilots_render(void);

void pilot_addHook(Pilot* pilot, int type, int hook);

