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

/* Hyperspace parameters. */
#define HYPERSPACE_ENGINE_DELAY   3.    /**< Warm up the engines. */
#define HYPERSPACE_FLY_DELAY      5.    /**< Time taken to hyperspace. */
#define HYPERSPACE_STARS_BLUR     2.    /**< Time stars blur. */
#define HYPERSPACE_STARS_LENGTH   1000  /**< Length the stars blur to at max. */
#define HYPERSPACE_FADEOUT        1.    /**< Time fadeout. */
#define HYPERSPACE_FUEL           100   /**< Amount of fuel taken. */
#define HYPERSPACE_THRUST         2000. /**< How much thrust you use in hyperspace. */
#define HYPERSPACE_VEL            HYPERSPACE_THRUST*HYPERSPACE_FLY_DELAY /**< Vel at hyp.*/
#define HYPERSPACE_ENTER_MIN      HYPERSPACE_VEL*0.5  /**< Min entering distance. */
#define HYPERSPACE_ENTER_MAX      HYPERSPACE_VEL*0.6  /**< Max entering distance. */
#define HYPERSPACE_EXIT_MIN       1500. /**< Min distance to begin jumping. */

/* 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_HOOKS               4     /**< Max number of hooks a pilot can have. */
#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. */
#define PILOT_HOOK_JUMP           4     /**< Pilot jumped. */

/* 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_ESCORT        (1<<1)    /**< Pilot is an escort. */
#define PILOT_CARRIED       (1<<2)    /**< Pilot usually resides in a fighter bay. */
#define PILOT_EMPTY         (1<<5)    /**< Do not add pilot to stack. */
#define PILOT_NO_OUTFITS    (1<<6)    /**< Do not create the pilot with outfits. */
#define PILOT_HASTURRET     (1<<9)    /**< Pilot has turrets. */
#define PILOT_HASBEAMS      (1<<10)   /**< Pilot has beam weapons. */
/* Dynamic. */
#define PILOT_HOSTILE       (1<<11)   /**< Pilot is hostile to the player. */
#define PILOT_COMBAT        (1<<12)   /**< Pilot is engaged in combat. */
#define PILOT_AFTERBURNER   (1<<13)   /**< Pilot has her afterburner activated. */
#define PILOT_HYP_PREP      (1<<15)   /**< Pilot is getting ready for hyperspace. */
#define PILOT_HYP_BEGIN     (1<<16)   /**< Pilot is starting engines. */
#define PILOT_HYPERSPACE    (1<<17)   /**< Pilot is in hyperspace. */
#define PILOT_HYP_END       (1<<18)   /**< Pilot is exiting hyperspace. */
#define PILOT_BOARDED       (1<<20)   /**< Pilot has been boarded already! */
#define PILOT_BRIBED        (1<<21)   /**< Pilot has been bribed already. */
#define PILOT_DISABLED      (1<<26)   /**< Pilot is disabled. */
#define PILOT_DEAD          (1<<27)   /**< Pilot is on it's death bed. */
#define PILOT_DEATH_SOUND   (1<<28)   /**< Pilot just did death explosion. */
#define PILOT_EXPLODED      (1<<29)   /**< Pilot did final death explosion. */
#define PILOT_DELETE        (1<<30)   /**< Pilot will get delete asap. */

/* Just makes life simpler. */
#define pilot_isPlayer(p)   pilot_isFlag(p, PILOT_PLAYER)   /**< Check if pilot is a player. */
#define pilot_isDisabled(p) pilot_isFlag(p, 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. */
  double 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. */
  unsigned 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. */
  double 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[PILOT_HOOKS];  /**< Type of the hook atached to the pilot. */
  int hook[PILOT_HOOKS];       /**< Hook id. */

  /* Escort stuff. */
  unsigned int  parent;        /**< Pilots parent. */
  unsigned int* escorts;       /**< Pilots escorts. */
  int           nescorts;      /**< Number of pilot escorts. */

  /* AI. */
  unsigned int target;         /**< AI target. */
  AI_Profile* ai;              /**< Ai personality profile. */
  double tcontrol;             /**< Timer for control tick. */
  double 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. */
  char* ai;       /**< Ai difference of fleet's 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. */

  char* 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_getPrevID(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 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);
double pilot_face(Pilot* p, const double dir);
void pilot_hyperspaceAbort(Pilot* p);
/* Special outfit stuff. */
void pilot_switchSecondary(Pilot* p, int i);
void pilot_setSecondary(Pilot* p, const char* secondary);
void pilot_setAmmo(Pilot* p);
int pilot_getAmmo(Pilot* p, Outfit* o);
void pilot_setAfterburner(Pilot* p);
/* Escort stuff. */
int pilot_dock(Pilot* p, Pilot* target);
/* Explosion. */
void pilot_explode(double x, double y, double radius,
    DamageType dtype, double damage, unsigned int parent);
/* 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);
int pilot_oquantity(Pilot* p, PilotOutfit* w);
/* 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);
int pilot_moveCargo(Pilot* dest, Pilot* src);
/* 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, int jettison);


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

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

Pilot* pilot_createEmpty(Ship* ship, char* name,
                         int faction, char* ai, const unsigned 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);
void pilot_runHook(Pilot* p, int hook_type);