/*
   base/ship.h
   This file is part of the Osirion project and is distributed under
   the terms and conditions of the GNU General Public License version 2
*/

#ifndef __INCLUDED_BASE_SHIP_H__
#define __INCLUDED_BASE_SHIP_H__

#include "core/player.h"
#include "core/entity.h"
#include "base/shipmodel.h"
#include "base/jumppoint.h"
#include "math/vector3f.h"

namespace game
{

const float 		MIN_DELTA = 0.000001f;

// planet docking distance
const float 		PLANET_SAFE_DISTANCE = 50.0f;
const float 		COMBAT_DISTANCE = 100.0f;


/**
 * @brief A ship in the game, controled by a player
 * */
class Ship : public core::EntityControlable
{
public:
	enum AutoPilotFlags { AutoPilotDisabled = 0, AutoPilotEnabled = 1, AutoPilotDock = 2, AutoPilotFormation = 4, AutoPilotCombat = 8, AutoPilotRecall = 16 };
	
	Ship(core::Player *owner, const ShipModel *shipmodel);
	~Ship();

	/* -- inspectors ------------------------------------------- */
	
	/// shipmodel
	inline const ShipModel *shipmodel() const
	{
		return ship_shipmodel;
	}
	
	/// impulse drive force
	inline const float impulse_force() const
	{
		return ship_impulse_force;
	}
		
	/// thruster force
	inline const float thrust_force() const
	{
		return ship_thrust_force;
	}
	
	/// strafe force 
	inline const float strafe_force() const
	{
		return ship_strafe_force;
	}
	
	/// turn force
	inline const float turn_force() const
	{
		return ship_turn_force;
	}
	
	/// roll force
	inline const float roll_force() const
	{
		return ship_roll_force;
	}
	
	/// entity the ship is currently docked at
	inline core::Entity *dock()
	{
		return ship_dock;
	}
	
	/// (dockable) entity where the ship will respawn if destroyed
	inline core::Entity *spawn()
	{
		return ship_spawn;
	}

	inline JumpPoint *jumpdepart()
	{
		return ship_jumpdepart;
	}

	/// current autopilot target
	inline core::Entity *autopilot_target()
	{
		return ship_autopilot_target;
	}
	
	inline bool has_autopilot_flag(const AutoPilotFlags flag) const {
		return ( (ship_autopilot_flags & flag) == flag);
	}
	
	/// maximal armor strength
	inline const float maxarmor() const
	{
		return ship_maxarmor;
	}
	
	/// current armor strength
	inline const float armor() const
	{
		return ship_armor;
	}
	
	/// maximal armor strength
	inline const float maxshield() const
	{
		return ship_maxshield;
	}
	
	/// current armor strength
	inline const float shield() const
	{
		return ship_shield;
	}
	
	virtual void print() const;
	
	/* -- mutators --------------------------------------------- */
	
	/// physics frame
	virtual void action (btScalar seconds);

	/// game frame
	virtual void frame(const unsigned long elapsed);

	/// move the ship to a different zone
	virtual void set_zone(core::Zone *zone);

	/// true if the ship is equiped with a jumpdrive
	inline bool jumpdrive() const {
		return ship_jumpdrive;
	}
	
	/// set jumpdrive capability
	inline void set_jumpdrive(const bool jumpdrive) {
		ship_jumpdrive = jumpdrive;
	}
	
	/// set impulse drive force
	inline void set_impulse_force(const float impulse) {
		ship_impulse_force = impulse;
		
	}
		
	/// set thruster force
	inline void set_thrust_force(const float thrust) {
		ship_thrust_force = thrust;
	}
	
	/// set strafe force
	inline void set_strafe_force(const float strafe) {
		ship_strafe_force = strafe;
	}
	
	/// set turn force
	inline void set_turn_force(const float turn) {
		ship_turn_force = turn;
	}
	
	/// set roll force
	inline void set_roll_force(const float roll) {
		ship_roll_force = roll;
	}
	
	/// set maximal armor strength (100% health)
	inline void set_maxarmor(const float maxarmor)
	{
		ship_maxarmor = maxarmor;
	}
	
	/// set current armor strength (current health)
	void set_armor(const float armor);
	
	/// set maximal shield strength
	inline void set_maxshield(const float maxshield)
	{
		ship_maxshield = maxshield;
	}
	
	/// set current shield strength
	inline void set_shield(const float shield)
	{
		ship_shield = shield;
	}
	
	/// initiate jump sequence, departing from a jump point
	void initiate_jump(JumpPoint *depart);

	/// reset physics state and ship controls
	virtual void reset();
	
	/// collision callback
	virtual void collision(core::Entity *other);

	/// hit-by weapon callback
	virtual void hit(core::Entity *other);
	
	/// explode the ship
	void explode();

	/// toggle impulse drive activation
	void func_impulse();

	/// toggle jump drive activation
	void func_jump(std::string const & args);
	
	/**
	 * @brief dock the ship at a station, planet or another player's ship_dock
	 * This will set the ship's state to Entity::Docked and reset spawn if required
	 */
	void set_dock(core::Entity *dock);
	
	/**
	 * @brief set the autopilot target
	 * */
	void set_autopilot_target(core::Entity *target);
	
	inline void set_autopilot_flag(const AutoPilotFlags flag) {
		ship_autopilot_flags = ship_autopilot_flags | flag;
	}
	
	inline void unset_autopilot_flag(const AutoPilotFlags flag) {
		ship_autopilot_flags = ship_autopilot_flags & ~flag;
	}
	
	void launch();
	
	void set_spawn(core::Entity *spawn);
	
	/**
	 * @brief eject an item from inventory
	 * Ejecting an item while the ship is docked will destroy it,
	 * otherwise it will create a cargo pod
	 * */
	void eject(core::Item *item, const long eject_amount, const bool eject_message);

protected:
	/**
	 * @brief autopilot frame
	 * */	
	void frame_autopilot(const unsigned long elapsed);
	
	/**
	 * @brief autopilot goto target
	 * */
	void frame_autopilot_goto(const unsigned long elapsed, core::Entity *target);
	
	/**
	 * @brief autopilot combat
	 * */
	void frame_autopilot_combat(const unsigned long elapsed, core::Entity *target);
	
	/**
	 * @brief autopilo dock target
	 * */
	void frame_autopilot_dock(const unsigned long elapsed, core::Entity *target);

	/**
	 * @brief autopilot formation flying
	 * */
	void frame_autopilot_formation(const unsigned long elapsed, core::Entity *target);
		
private:
	JumpPoint *find_closest_jumppoint();

	const ShipModel		*ship_shipmodel;

	float 			current_target_direction;
	float 			current_target_pitch;
	float 			current_target_roll;
	float			current_target_strafe;
	float			current_target_vstrafe;
	float			current_target_afterburner;
	bool			current_impulse;

	bool			ship_jumpdrive;
	float			ship_jumpdrive_timer;
	float			ship_impulsedrive_timer;

	JumpPoint		*ship_jumpdepart;
	
	float			ship_impulse_force;
	float			ship_thrust_force;
	float			ship_strafe_force;
	float			ship_turn_force;
	float			ship_roll_force;
	
	float			ship_maxarmor;
	float			ship_armor;
	
	float			ship_maxshield;
	float			ship_shield;
	
	core::Entity 		*ship_dock;
	
	core::Entity		*ship_spawn;
	
	int			ship_autopilot_flags;
	core::Entity		*ship_autopilot_target;
};

}

#endif // __INCLUDED_BASE_SHIP_H__