#ifndef STRUCTS_H
#define STRUCTS_H

#include <vector>
#include <algorithm>

#include "protocol.h"
#include "softProj\commonTypes.h"
#include "softProj\clientServer\datetime.h"

struct ShipJourneyDetailsFAIL {
	id_t shipId;
	std::string reason;
};

enum DockingResult
{
	DR_OK = 1,
	DR_BAD_SOURCE_FORTRESS_TYPE = 2,
	DR_BAD_TARGET_FORTRESS_TYPE = 3,
	DR_UNCONTROLLABLE_TARGET = 4,
	DR_NOT_YOUR_DOCK = 5,
	DR_OUT_OF_RANGE = 6,
	DR_IMPULS_DRIVE_FAIL = 7,
	DR_NOT_ENOUGH_DEUTERIUM = 8,
	DR_NO_FREE_HANGAR = 9,
	DR_NOT_DOCKING_SHIP = 10,
	DR_UNKNOWN_FAIL = 11
};

struct ShipJourneyDetailsSTANDARD {
	id_t shipId;
	position_t positionX;
	position_t positionY;
	std::string state;
	std::string target;
	unsigned long long speedInMetersPerSecond;
	unsigned long long accelerationInMetersPerSquaredSecond;
	bool isDockedInBase;
	DockingResult docking;
};

struct ShipJourneyDetailsPURSUIT {
	id_t shipId;
	std::string state;
	std::string target;
	id_t targetShip;
	dt_distance_t estimationDistanceInKilometers;
	unsigned long long estimationTimeInSeconds;
	position_t positionX;
	position_t positionY;
	unsigned long long speedInMetersPerSecond;
	unsigned long long accelerationInMetersPerSquaredSecond;
	DockingResult docking;
};

struct ShipJourneyDetailsMOVE_TO {
	id_t shipId;
	std::string state;
	std::string target;
	position_t targetY;
	position_t targetX;
	dt_distance_t estimationDistanceInKilometers;
	unsigned long long estimationTimeInSeconds;
	position_t positionX;
	position_t positionY;
	unsigned long long speedInMetersPerSecond;
	unsigned long long accelerationInMetersPerSquaredSecond;
	DockingResult docking;
};

struct ShipJourneyDetailsMOVE_TO_SPACE_OBJECT {
	id_t shipId;
	std::string state;
	std::string target;
	id_t targetSpaceObjectId;
	std::string targetSpaceObjectName;
	dt_distance_t estimationDistanceInKilometers;
	unsigned long long estimationTimeInSeconds;
	position_t positionX;
	position_t positionY;
	unsigned long long speedInMetersPerSecond;
	unsigned long long accelerationInMetersPerSquaredSecond;
	DockingResult docking;
};

struct LongRangeDetails {
	id_t shipId;
	position_t positionX;
	position_t positionY;
};

struct NavigationLongRangeDetails {
	id_t shipId;
	position_t positionX;
	position_t positionY;
	double distance;
};

struct HighResolutionDetails {
	position_t positionX;
	position_t positionY;
	id_t shipId;
	std::string fortressName;
	speed_t currentSpeed;
	speed_t currentAcceleration;
	course_t courseX;
	course_t courseY;
	id_t fortressClassId;
	std::string fortressRealm;
	double targetDistance;
	
	bool inWarp;
	bool inBase;
	bool isOrbiting;
	
	///if ship is in warp, then hlpPosX,Y says where is the ship now ( positionX, positionY is invalid at this moment)
	///if ship is in base, then hlpPosX,Y says the position of the planet, where is the ship  ( positionX, positionY is invalid at this moment)
	///if ship is on orbit, then hlpPosX,Y says the pivot of the orbit
	double hlpPosX; 
	double hlpPosY;
	
	bool isMining;
	double orbitingSpeed;

	
	//pair<targetId, targetIsShipFlag>
	 std::pair<id_t,bool> enemyTargetId; 

	HighResolutionDetails(void)
	{
		//default constructor to init some 'valid' data
		this->positionX = 0;
		this->positionY = 0;
		this->shipId = 0;
		this->fortressName = "";
		this->currentSpeed = 0;
		this->currentAcceleration = 0;
		this->courseX = 0;
		this->courseY = 0;
		this->fortressClassId = 0;
		this->fortressRealm = "";
		this->targetDistance = 10000000000000; //id destination position not known then move along the course to infinity ( in our case some huge value )
		
		this->isOrbiting = false;
		this->inWarp = false;
		this->inBase = false;

		this->hlpPosX = 0;
		this->hlpPosY = 0;

		this->isMining = false;
		this->orbitingSpeed = 0;

		this->enemyTargetId.first = false;
		this->enemyTargetId.second = false;
	}		 
};

struct PlayerShipDetails: public HighResolutionDetails
{
	int lifeStatus;
	int shieldStatus;

	PlayerShipDetails(void)
	{
		this->lifeStatus = 100;
		this->shieldStatus = 100;
	}
};

struct NavigationHighResolutionDetails {
	position_t positionX;
	position_t positionY;
	id_t shipId;
	std::string fortressName;
	speed_t currentSpeed;
	speed_t currentAcceleration;
	course_t courseX;
	course_t courseY;
	std::string fortressRealm;
	double distance;
};

struct NavigationObject {
	std::string name;
	id_t id;
	double distance;
};

struct NavigationBaseObject : public NavigationObject {
	DockingResult canShipDockDown;
};

struct NavigationStatus {
	std::vector<NavigationObject> myShips;
	std::vector<NavigationBaseObject> myBases;
	std::vector<NavigationLongRangeDetails> shipsInLongRange;
	std::vector<NavigationHighResolutionDetails> shipsInHighResolution;
	std::vector<NavigationObject> discoveredStars;
};

struct PlanetDetails {
	id_t id;
	dt_distance_t pivotX;
	dt_distance_t pivotY; 
	speed_t speed; 
	dt_distance_t radius;
	dt_distance_t size;
	dt_distance_t angle; 
	weight_t weight;
	unsigned long long yearPeriod;
	unsigned long long dayPeriod;
	unsigned long type;
	long dayTemperature;
	long nightTemperature;
	long sea;

	long heavyWaterSource;
	long crystalsSource;
	long ilmeniteSource;

	std::string name;

	//pair<targetId, targetIsShipFlag>
	std::vector< std::pair<id_t,bool> > enemyTargetIds; 
	 
	PlanetDetails(void)
	{
		this->id = 0;
		this->pivotX = 0;
		this->pivotY = 0; 
		this->speed = 0; 
		this->radius = 0;
		this->size = 0;
		this->angle = 0; 
		this->weight = 0;
		this->yearPeriod = 0;
		this->dayPeriod = 0;
		this->type = 0;
		this->dayTemperature = 0;
		this->nightTemperature = 0;
		this->sea = 0;
		this->heavyWaterSource = 0;
		this->crystalsSource = 0;
		this->ilmeniteSource = 0;
		this->name = "";
		this->enemyTargetIds.clear();
	}
};

struct PlanetsInStarAreaDetails {
	id_t areaId;
	double sunObjectRadius;
	double sunAreaRadius;
	std::string sunName;
	weight_t sunWeight;
	unsigned long sunType;
	dv_time::datetime gameTime; 

	std::vector<PlanetDetails> planets;
};

struct ScienceTreeRawUpdateData : public sciencetree_raw_data {
    double realPtsQUARK_GLUON_CORE_SPEED;
    double realPtsQUARK_GLUON_CORE_CONSUMPTION;

    double realPtsNAVIGATION_COMPUTER_SPEED;

    double realPtsSUBSPACE_BEACON_SPEED;

    double realPtsINERTIAL_DAMPERS_SPEED;

    double realPtsIMPULS_ENGINE_FORCE;
    double realPtsIMPULS_ENGINE_CONSUMPTION;

    double realPtsMECHANICAL_DAMPERS_ACCELERATION;

    double realPtsDRONE_MISSILES_DAMAGE;
    double realPtsDRONE_MISSILES_PRECISION;
    double realPtsDRONE_MISSILES_RANGE;

    double realPtsDRONE_MISSILE_LAUNCHER_ACCUMULATOR;
    double realPtsDRONE_MISSILE_LAUNCHER_CHARGING;

    double realPtsSHIPS_LEVEL;

    double realPtsBASES_LEVEL;

    double realPtsHANGARS_LEVEL;

    double realPtsANDROIDS_LEVEL;
    double realPtsANDROIDS_CONSUMPTION;

    double realPtsENERGETIC_ACCUMULATOR_ACCUMULATOR;
    double realPtsENERGETIC_ACCUMULATOR_CHARGING;

    double realPtsMAINFRAME_BIO_NODES;
    double realPtsMAINFRAME_PREDICTION;
    double realPtsMAINFRAME_TIME_REUSABILITY;
    double realPtsMAINFRAME_CONSUMPTION;

    double realPtsSCIENTIFIC_LABS_LEVEL;

    double realPtsLIFE_SUPPORT_CAPACITY;
    double realPtsLIFE_SUPPORT_CONSUMPTION;

    double realPtsWEAPON_ENERGY_CIRCUIT_CHARGING;

    double realPtsTRANSPORT_BEAM_GENERATOR_ACCUMULATOR;
    double realPtsTRANSPORT_BEAM_GENERATOR_CHARGING;
    double realPtsTRANSPORT_BEAM_GENERATOR_FORCIBILITY;
    double realPtsTRANSPORT_BEAM_GENERATOR_PRECISION;
    double realPtsTRANSPORT_BEAM_GENERATOR_RANGE;

    double realPtsLASER_GUN_ACCUMULATOR;
    double realPtsLASER_GUN_CHARGING;
    double realPtsLASER_GUN_FORCIBILITY;
    double realPtsLASER_GUN_PRECISION;
    double realPtsLASER_GUN_RANGE;

    double realPtsDEFLECTOR_SHIELDS_GENERATOR_SOLIDITY;
    double realPtsDEFLECTOR_SHIELDS_GENERATOR_ACCUMULATOR;
    double realPtsDEFLECTOR_SHIELDS_GENERATOR_CHARGING;

    double realPtsHIGH_RESOLUTION_SENSORS_LEVEL;
    double realPtsHIGH_RESOLUTION_SENSORS_RANGE;
    double realPtsHIGH_RESOLUTION_SENSORS_CONSUMPTION;

    double realPtsLONG_RANGE_SENSORS_LEVEL;
    double realPtsLONG_RANGE_SENSORS_RANGE;
    double realPtsLONG_RANGE_SENSORS_CONSUMPTION;

    double realPtsCLOAKING_DEVICE_LEVEL;
    double realPtsCLOAKING_DEVICE_CONSUMPTION;

    double realPtsPROBE_DEVICE_LEVEL;

    double realPtsMAGNETICAL_FILTER_PRODUCTION;

    double realPtsDEUTERIUM_DECOMPOSER_PRODUCTION;
    double realPtsDEUTERIUM_DECOMPOSER_METAMORPHOSIS;

    double realPtsZIRCONIUM_REACTOR_PRODUCTION;
    double realPtsZIRCONIUM_REACTOR_METAMORPHOSIS;

    double realPtsILMENITE_FURNACE_PRODUCTION;
    double realPtsILMENITE_FURNACE_METAMORPHOSIS;

    double realPtsMAGNETICAL_COLLECTORS_OF_PLASMA_WINDING_SPEED;

    double realPtsSUBMERSIBLE_FILTRATION_TANK_WINDING_SPEED;
    double realPtsSUBMERSIBLE_FILTRATION_TANK_RANGE;

    double realPtsSUBMARINE_MINING_MACHINE_WINDING_SPEED;
    double realPtsSUBMARINE_MINING_MACHINE_RANGE;

    double realPtsUNDERGROUND_QUARRYING_WINDING_SPEED;
    double realPtsUNDERGROUND_QUARRYING_RANGE;

	unsigned long long totalTokens;
};

struct CentralInfoDetails {
	id_t shipId;
	unsigned long long structuralIntegrityActual;
	unsigned long long structuralIntegrityTotal;
	double structuralIntegrityGradient;
	unsigned long manoeuvrability;
	double width;
	double length;
	double height;	

	unsigned long long quarkGluonPlasmaActual;
	unsigned long long quarkGluonPlasmaFreeCapacity;
	double quarkGluonPlasmaGradient;

	unsigned long long ulreaActual;
	double ulreaGradient;

	unsigned long long heavyWaterActual;
	unsigned long long heavyWaterSize;
	unsigned long long heavyWaterFreeCapacity;
	double heavyWaterGradient;

	unsigned long long deuteriumActual;
	unsigned long long deuteriumSize;
	unsigned long long deuteriumFreeCapacity;
	double deuteriumGradient;

	unsigned long long zirconiumCrystalsActual;
	unsigned long long zirconiumCrystalsSize;
	unsigned long long zirconiumCrystalsFreeCapacity;
	double zirconiumCrystalGradient;

	unsigned long long energyActual;
	unsigned long long energyFreeCapacity;
	double energyGradient;

	unsigned long long ilmeniteActual;
	unsigned long long ilmeniteSize;
	unsigned long long ilmeniteFreeCapacity;
	double ilmeniteGradient;

	unsigned long long titaniumActual;
	unsigned long long titaniumSize;
	unsigned long long titaniumFreeCapacity;
	double titaniumGradient;

	unsigned long long weight;
	unsigned long long weightWithCargo;
	unsigned long long loadingWeightLimit;
	unsigned long long loadingCapacityLimit;
	unsigned long long actualTotalCargoWeight;
	unsigned long long freeWeight;
	unsigned long long actualSizeOfCargoInWarehouse;
	unsigned long long freeCapacity;

	unsigned long long freeResWeight;
	unsigned long long commonRawMaterialCapacityLimit;
	unsigned long heavyWaterDensity;
	unsigned long deuteriumDensity;
	unsigned long zirconiumCrystalDensity;
	unsigned long ilmeniteDensity;
	unsigned long titaniumDensity;
};

struct ShieldsDetails {
	id_t shipId;

	double damageStatus;
	unsigned long solidityActual;	
	unsigned long chargingSpeedActual;	
	unsigned long long energyActual;	
	/** Size of accumulator, that also means maximum of energy */ 
	unsigned long long accumulatorActual;
	double energyLeakActual;
	/**  Amount to which this device should be charged at maximum */
	unsigned long long chargingLimit;
	/** How many energy are shields actually consuming */
	double energyConsumptionActual;
	bool avalDeflectorShields;
	double gradient;
};

struct LoginDetails {
	std::string name;
	std::string password;
	std::string server;
	unsigned long port;
};

struct MainframeDetails {
	// TODO Types and fields not final - just preview and depends on Jakub!

	unsigned long long prediction;
	unsigned long long consumption;
	unsigned long long bionodes;
	unsigned long long timeReusability;
};

struct WeaponsChangeDetails {
	std::list<idx_and_energy_lvl> laserGuns;
	std::list<idx_and_energy_lvl> droneGuns;
};

enum ETradingResult
{
	TR_DONE,
	TR_FIRST_FORTRESS_WEIGHT_LIMIT,
	TR_SECOND_FORTRESS_WEIGHT_LIMIT,
	TR_FIRST_FORTRESS_CAPACITY_LIMIT,
	TR_SECOND_FORTRESS_CAPACITY_LIMIT,
	TR_FIRST_FORTRESS_NOT_STORING_ITEMS,
	TR_SECOND_FORTRESS_NOT_STORING_ITEMS,
	TR_FIRST_FORTRESS_MAGNETICAL_GRIDS_LACK,
	TR_SECOND_FORTRESS_MAGNETICAL_GRIDS_LACK,
	TR_FIRST_FORTRESS_TRANSPORT_CONTAINERS_LACK,
	TR_SECOND_FORTRESS_TRANSPORT_CONTAINERS_LACK,
	TR_FIRST_FORTRESS_ENERGETIC_CELLS_LACK,
	TR_SECOND_FORTRESS_ENERGETIC_CELLS_LACK,
	TR_NOT_IN_RANGE,
	TR_UNKNOWN_FAIL,

	TR_UNKNOWN_MAPPING,
};

enum ETradingCommitRole 
{
	TRADE_COMMIT_ROLE_HOST,
	TRADE_COMMIT_ROLE_INVITED,
	TRADE_COMMIT_ROLE_NONE,

	TRADE_COMMIT_ROLE_UNKNOWN_MAPPING,
};

struct FortressInRangeData 
{
	id_t id;	
	std::string name;	
	std::string realmName;
	bool isInTradeRange;
	bool isInConquerRange;
	bool isShell;
};

enum BaseBuildingResult
{
	BBR_SHELL_BUILT = 1,
	BBR_NO_PLANET_IN_RANGE = 2,
	BBR_NOT_ENOUGH_TITANIUM = 3,
	BBR_INVALID_PARAMS = 4,
	BBR_UNKNOWN_FAIL = 5
};

enum EFortressType {
	FORTRESS_TYPE_BASE = 1,
	FORTRESS_TYPE_SHIP = 2, 
};

enum FortressAddingResult
{
	FAR_DONE = 1,
	FAR_NOT_ENOUGH_BIONODES = 2,
	FAR_MAINFRAME_NOT_MOUNTED = 3,
	FAR_MAINFRAME_ENERGY_LACK = 4,
	FAR_FORTRESS_ALREADY_OWNED = 5,
	FAR_OUT_OF_RANGE = 6,
	FAR_NULL_FORTRESS = 7
};

struct ConquerResultData {
	bool isConquered;
	bool isDetailsAvailable;
	bool isMainframeFailure;
	bool isEnergeticAccumulatorFailure;
	unsigned long long energyInTarget;
	FortressAddingResult addingResult;
	id_t selfFortressId;
	id_t enemyFortressId;
};

struct RegistrationData {
	std::string username;
	std::string password;
	std::string realname;
	std::string server;
	unsigned long port;
};

enum PlayerAddingResult
{
    PAR_OK = 1,
    PAR_NAME_ALREADY_EXISTS = 2,
    PAR_LOGIN_ALREADY_EXISTS = 3,
    PAR_INTERNAL_ERROR = 4
};

struct RegistrationResult {
	PlayerAddingResult addingResult;
	std::string username;
	std::string password;
};

enum AttackResult
{
	AR_NOT_FIRED = 1,
	AR_MISS = 2,
	AR_FUTILE_HIT = 3,
	AR_HIT = 4,
	AR_CRITICAL_HIT = 5,
	AR_TARGET_ANNIHILATED = 6,
};

enum SpaceObjectPlanetType
{
    TERESTRIAL = 1,
    GAS_TITAN = 2
};

struct NavigationPlanetDetails : public PlanetDetails {
	double shipDistance;

	double ilmeniteModifier;
	double heavyWaterModifier;
	double crystalsModifier;

	// Same as type, but casted for safety, because Martin's planet type is different than server one
	SpaceObjectPlanetType planetType;
};

struct NavigationPlanetsInStarAreaDetails {
	id_t areaId;
	id_t shipId;
	double sunObjectRadius;
	double sunAreaRadius;
	std::string sunName;
	weight_t sunWeight;
	unsigned long sunType;
	dv_time::datetime gameTime; 

	std::vector<NavigationPlanetDetails> planets;
};

#endif