// ################################
// ##   Tridy na hracske ucty    ##
// ##  obsahuji vedu a podobne   ##
// ################################

#pragma once
#ifndef PLAYERS_REALMS_H
#define PLAYERS_REALMS_H

#include "common.h"

#include <vector>

#include "independent_constants.h"

#include "cache_list.h"
#include "context.h"
#include "science_tree.h"
#include "space.h"

using namespace std;

// ################################
// ################################

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

// ################################

enum playerAddingResult
{
    PAR_OK,
    PAR_NAME_ALREADY_EXISTS,
    PAR_LOGIN_ALREADY_EXISTS,
    PAR_INTERNAL_ERROR
};

// ################################
// ################################

#define FORTRESSES_FOR_START                             2
#define BIONODES_FOR_ONE_FORTRESS                        RANGE_MAINFRAME_BIO_NODES_MIN / FORTRESSES_FOR_START
#define CONTAINERED_RESOURCES_COUNT                      5

#define NPR_SCIENCE_QUALITY_REQUIRED_FOR_SHIELDS (double)0.08
#define NPR_DRONE_MISSILES_MIN_COUNT                     25
#define NPR_DRONE_MISSILES_MAX_COUNT                     2500
#define NPR_SCIENCE_QUALITY_REQUIRED_FOR_MCP     (double)0.64
#define NPR_MCP_MIN_COUNT                                1
#define NPR_MCP_MAX_COUNT                                16
#define NPR_BASE_SUBMERSIBLE_FT_MIN_COUNT                16
#define NPR_BASE_SUBMERSIBLE_FT_MAX_COUNT                16000
#define NPR_SHIP_SUBMERSIBLE_FT_MIN_COUNT                4
#define NPR_SHIP_SUBMERSIBLE_FT_MAX_COUNT                400
#define NPR_BASE_SUBMARINE_MM_MIN_COUNT                  16
#define NPR_BASE_SUBMARINE_MM_MAX_COUNT                  16000
#define NPR_SHIP_SUBMARINE_MM_MIN_COUNT                  4
#define NPR_SHIP_SUBMARINE_MM_MAX_COUNT                  400
#define NPR_BASE_UNDERGROUND_DM_MIN_COUNT                16
#define NPR_BASE_UNDERGROUND_DM_MAX_COUNT                16000
#define NPR_SHIP_UNDERGROUND_DM_MIN_COUNT                4
#define NPR_SHIP_UNDERGROUND_DM_MAX_COUNT                400
#define NPR_BASE_ANDROIDS_MIN_COUNT                      262144
#define NPR_BASE_ANDROIDS_MAX_COUNT                      1073741824
#define NPR_SHIP_ANDROIDS_MIN_COUNT                      4096
#define NPR_SHIP_ANDROIDS_MAX_COUNT                      1048576
#define NPR_SCIENCE_QUALITY_REQUIRED_FOR_QGP     (double)0.16
#define NPR_BASE_MAGNETICAL_GRIDS_MIN_COUNT              256
#define NPR_BASE_MAGNETICAL_GRIDS_MAX_COUNT              32768
#define NPR_SHIP_MAGNETICAL_GRIDS_MIN_COUNT              10
#define NPR_SHIP_MAGNETICAL_GRIDS_MAX_COUNT              1024
#define NPR_BASE_TRANSPORT_CONTAINERS_MIN_COUNT          256
#define NPR_BASE_TRANSPORT_CONTAINRES_MAX_COUNT          32768
#define NPR_SHIP_TRANSPORT_CONTAINERS_MIN_COUNT          16
#define NPR_SHIP_TRANSPORT_CONTAINERS_MAX_COUNT          2048
#define NPR_BASE_ENERGETIC_CELLS_MIN_COUNT               256
#define NPR_BASE_ENERGETIC_CELLS_MAX_COUNT               32768
#define NPR_SHIP_ENERGETIC_CELLS_MIN_COUNT               10
#define NPR_SHIP_ENERGETIC_CELLS_MAX_COUNT               1024
#define NPR_MAGNETICAL_FILTERS_MIN_COUNT                 1
#define NPR_MAGNETICAL_FILTERS_MAX_COUNT                 4096
#define NPR_DEUTERIUM_DECOMPOSERS_MIN_COUNT              1
#define NPR_DEUTERIUM_DECOMPOSERS_MAX_COUNT              4096
#define NPR_ZIRCONIUM_REACTORS_MIN_COUNT                 4
#define NPR_ZIRCONIUM_REACTORS_MAX_COUNT                 16384
#define NPR_ILMENITE_FURNACES_MIN_COUNT                  4
#define NPR_ILMENITE_FURNACES_MAX_COUNT                  16384
#define NPR_RESOURCES_PART                       (double)0.75
#define NPR_MIN_ULREI                                    32768
#define NPR_MAX_ULREI                                    4194304

// ################################
// ################################

class fortressClass;
class baseClass;
class shipClass;
class fortressStateClass;
typedef vector<dtIdentifier                         > dtIdentifierVector;
typedef pair  <fortressClass *, fortressStateClass *> fortressPFortressStatePPair;
typedef pair  <baseClass     *, fortressStateClass *> basePFortressStatePPair;
typedef pair  <shipClass     *, fortressStateClass *> shipPFortressStatePPair;
typedef pair  <dtIdentifier   , fortressStateClass  > fortressIDFortressStatePair;
typedef vector<fortressIDFortressStatePair          > fortressIDFortressStatePairVector;

// ################################
// ################################

/*class fortressStateClass
{
private:
	bool mainframeIsInNetwork_;
public:
	fortressStateClass()      { mainframeIsInNetwork_ = 1;    };

	void mainframeFailure()   { mainframeIsInNetwork_ = 0;    };
	void mainframeConnected() { mainframeIsInNetwork_ = 1;    };
	bool canBeControlled()    { return mainframeIsInNetwork_; };
};*/

// ################################
// ################################

class banClass
{
private:
	int level_;
	int durationInDays_;
	std::string reason_;
	dv_time::datetime timePlaced_;
public:
	int getLevel() const;
	int getDurationInDays() const;
	std::string getReason() const;
	dv_time::datetime getTimePlaced() const;

    void setBanParameters(int level, int durationInDays, const std::string & reason, dv_time::datetime timePlaced);
	banClass(int level, int durationInDays, const std::string & reason, dv_time::datetime timePlaced);
};

// ################################
// ################################

class tradeBundleClass;

enum tradingRole
{
	TRADE_ROLE_HOST, TRADE_ROLE_PARTNER_TRADER, TRADE_ROLE_NONE, TRADE_ROLE_CANCELED, TRADE_ROLE_SELF_TRADER, TRADE_ROLE_LOOT_TRADER, TRADE_ROLE_SPACE_TRADER,
};

enum tradingCommitRole 
{
	TRADE_COMMIT_ROLE_HOST, TRADE_COMMIT_ROLE_INVITED, TRADE_COMMIT_ROLE_NONE,
};

class tradeStateClass 
{
private:	
	tradeBundleClass* tradeBundle_;
	tradeBundleClass* partnerTradeBundle_;

	void createTradeBundle();
	void createPartnerTradeBundle();
	void deleteTradeBundles();

	dtIdentifier enemyId_;
	dtIdentifier enemyFortressId_;
	dtIdentifier ownedFortressId_;
	
	tradingRole tradeRole_;	
	tradingCommitRole commitRole_;
public:
	tradeStateClass() { tradeBundle_ = NULL; partnerTradeBundle_ = NULL; };

	tradeBundleClass* getTradeBundle() const;	
	tradeBundleClass* getPartnerTradeBundle() const;
	
	bool isHost() const { return tradeRole_ == TRADE_ROLE_HOST; }
	bool isPartnerTrader() const { return tradeRole_ == TRADE_ROLE_PARTNER_TRADER; }
	bool isSelfTrader() const { return tradeRole_ == TRADE_ROLE_SELF_TRADER; }
	bool isLootTrader() const { return tradeRole_ == TRADE_ROLE_LOOT_TRADER; }
	bool isSpaceTrader() const { return tradeRole_ == TRADE_ROLE_SPACE_TRADER; }
	bool isAnyTrader() const { return isPartnerTrader() || isSelfTrader() || isLootTrader() || isSpaceTrader(); }	
	bool isParticipant() const { return isHost() || isAnyTrader(); }
	bool isCanceled() const { return tradeRole_ == TRADE_ROLE_CANCELED; }
	bool isCommiterHost() const { return commitRole_ == TRADE_COMMIT_ROLE_HOST; }
	bool isCommiterInvited() const { return commitRole_ == TRADE_COMMIT_ROLE_INVITED; }

	void becomeHost(dtIdentifier partnerId, dtIdentifier partnerFortressId, dtIdentifier ownedFortressId);
	
	void becomePartnerTrader(dtIdentifier partnerId, dtIdentifier partnerFortressId, dtIdentifier ownedFortressId);	
	void becomeSelfTrader(dtIdentifier partnerId, dtIdentifier partnerFortressId, dtIdentifier ownedFortressId);	
	void becomeLootTrader(dtIdentifier partnerId, dtIdentifier partnerFortressId, dtIdentifier ownedFortressId);	
	void becomeSpaceTrader(dtIdentifier ownedFortressId);
	void becomeCommiterHost();
	void becomeCommiterInvited();
	void becomeCommiterAcknowledged();
	void becomeCanceled();

	void cancelTrade();	
	void commitTrade();
	void cancelCommit();

	dtIdentifier getEnemyID() const { return enemyId_; }
	dtIdentifier getOwnedFortressID() const { return ownedFortressId_; }
	dtIdentifier getEnemyFortressID() const { return enemyFortressId_; }
	tradingRole getTradeRole() const { return tradeRole_; }
};

// ################################
// ################################

class realmClass : public dataListObjectClass
{
#define REALM_MAX_NAME_LENGTH    32
#define LOGIN_MAX_NAME_LENGTH    32
#define PASSWORD_MAX_NAME_LENGTH 32
private:
//	fortressIDFortressStatePairVector   bases_;
//	fortressIDFortressStatePairVector   ships_;
	dtIdentifierVector                  bases_;
	dtIdentifierVector                  ships_;
	dtIdentifierVector                  uncontrollableFortresses_;
	scientificTree                      science_;
	dtIdentifierVector                  discoveredSolarSystems_;

    std :: string                       playerName_;
    std :: string                       login_;
    std :: string                       password_;

	banClass*							ban_;

	void                      addNewFortressWithoutAnyControll(fortressClass * newFortress, bool controllable);
public:
	realmClass() { bases_.clear(); ships_.clear(); uncontrollableFortresses_.clear(); discoveredSolarSystems_.clear(); 
	               playerName_ = string(""); login_ = string(""); password_ = string("");
				   ban_ = NULL; };

	static playerAddingResult createNewPlayer(string name, string login, string password,
		                                      unsigned long basesCount, double basesQualityRating,
											  unsigned long shipsCount, double shipsQualityRating,
											  double scienceQualityRating); // rating je od 0 do 1, 0 je nejhorsi, 1 nejlepsi

//	basePFortressStatePPair   bases(unsigned long position)                 { if (position < bases_.size()) return make_pair((baseClass *)(actx->cacheFortressesList[bases_[position].first]), (fortressStateClass *)(&(bases_[position].second))); else return make_pair((baseClass *)NULL, (fortressStateClass *)NULL); };
//	baseClass               * basesOnly(unsigned long position)             { return bases(position).first;                                                                                                                                                                                                               };
//	baseClass               * basesControllableOnly(unsigned long position) { basePFortressStatePPair bsp = bases(position); if (bsp.second->canBeControlled()) return bsp.first; else return NULL;                                                                                                                       };
//	shipPFortressStatePPair   ships(unsigned long position)                 { if (position < ships_.size()) return make_pair((shipClass *)(actx->cacheFortressesList[ships_[position].first]), (fortressStateClass *)(&(ships_[position].second))); else return make_pair((shipClass *)NULL, (fortressStateClass *)NULL); };
//	shipClass               * shipsOnly(unsigned long position)             { return ships(position).first;                                                                                                                                                                                                               };
//	shipClass               * shipsControllableOnly(unsigned long position) { shipPFortressStatePPair ssp = ships(position); if (ssp.second->canBeControlled()) return ssp.first; else return NULL;};    
	baseClass               * controllableBases       (unsigned long position);
	shipClass               * controllableShips       (unsigned long position);
	fortressClass           * uncontrollableFortresses(unsigned long position);

	fortressAddingResult      canNewFortressBeAdded    (fortressClass * newFortress, bool controllable);
	fortressAddingResult      addNewFortress           (fortressClass * newFortress);
	fortressAddingResult      addUncontrollableFortress(fortressClass * newFortress);
	void                      removeFortress           (fortressClass * oldFortress);
	void                      mainframeFailure         (fortressClass * oldFortress);

	void                      scientificUpdate();
	void                      medicalUpdate();

	dtIdentifier              discoveredStarID(unsigned long position)      { if (position < discoveredSolarSystems_.size()) return discoveredSolarSystems_[position]; else return 0;                                                                                                                                     };
	unsigned long             discoveredStarsCount()                        { return (unsigned long)discoveredSolarSystems_.size();                                                                                                                                                                                       };
	void                      discoverNewStar(dtIdentifier starID)          { discoveredSolarSystems_.push_back(starID);                                                                                                                                                                                                  };

    dtIdentifierVector :: const_iterator discoveredStarsBegin(void)         { return discoveredSolarSystems_.begin();                                                                                                                                                                                                     };
    dtIdentifierVector :: const_iterator discoveredStarsEnd(void)           { return discoveredSolarSystems_.end();                                                                                                                                                                                                       };

    const std :: string&      getPlayerName(void) const                     { return playerName_;                                                                                                     };
    const std :: string&      getLogin(void) const                          { return login_;                                                                                                          };
    const std :: string&      getPassword(void) const                       { return password_;                                                                                                       };
	void                      setPlayersNewName(string & newName    )       { newName.resize    (min((size_t)newName.length()    , (size_t)REALM_MAX_NAME_LENGTH   )); playerName_.swap(newName    ); };
	void                      setNewLogin      (string & newLogin   )       { newLogin.resize   (min((size_t)newLogin.length()   , (size_t)LOGIN_MAX_NAME_LENGTH   )); login_.swap     (newLogin   ); };
	void                      setNewPassword   (string & newPassword)       { newPassword.resize(min((size_t)newPassword.length(), (size_t)PASSWORD_MAX_NAME_LENGTH)); password_.swap  (newPassword); };

	scientificTree          * getScientificTree() { return &science_; };

	const dtIdentifierVector& getBaseList(void)                             { return bases_;            };
	const dtIdentifierVector& getShipList(void)                             { return ships_;            };

	virtual void          DB_Load       (  unsigned long ID                ) sealed;
	virtual void          DB_Save       (  unsigned long ID                ) sealed;
	virtual void          DB_Insert     (  unsigned long ID                ) sealed;

    virtual void          DB_InitBase   (  unsigned long ID                ) sealed { bases_.push_back(ID); };
    virtual void          DB_InitShip   (  unsigned long ID                ) sealed { ships_.push_back(ID); };
    virtual void          DB_InitUnct   (  unsigned long ID                ) sealed { uncontrollableFortresses_.push_back(ID); };

	bool hasBan();
	const banClass* getBan();
	void makeBan(int level, int days, std::string reason);
	void cancelBan();	

    virtual ~realmClass() { if (ban_) delete ban_; ban_ = NULL; }
	tradeStateClass tradeState;
};

// ################################
// ################################

#endif