// ################################
// ##  Tridy , ktere tvori vedu  ##
// ##   ne konkretni instance    ##
// ################################

#pragma once
#ifndef SCIENCE_TREE_H
#define SCIENCE_TREE_H

#include "common.h"

#include <vector>

#include "common_routines.h"
#include "independent_constants.h"

using namespace std;

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

enum entitiesSupportedByScience
{
	SCIENCE_ENTITY_SHIPS,
	SCIENCE_ENTITY_BASES,
	SCIENCE_ENTITY_ENERGETIC_ACCUMULATOR,
	SCIENCE_ENTITY_NAVIGATION_COMPUTER,
	SCIENCE_ENTITY_QUARK_GLUON_CORE,
	SCIENCE_ENTITY_SUBSPACE_BEACON,
	SCIENCE_ENTITY_INERTIAL_DAMPERS,
	SCIENCE_ENTITY_IMPULS_JET_ENGINE,
	SCIENCE_ENTITY_MECHANICAL_DAMPERS,
	SCIENCE_ENTITY_DEFLECTOR_SHIELDS,
	SCIENCE_ENTITY_WEAPON_ENERGY_CIRCUIT,
	SCIENCE_ENTITY_DRONE_MISSILE_LAUNCHER,
	SCIENCE_ENTITY_DRONE_MISSILES,
	SCIENCE_ENTITY_LASER_GUN,
	SCIENCE_ENTITY_TRANSPORT_BEAM_GENERATOR,
	SCIENCE_ENTITY_MAGNETICAL_COLLECTORS_OF_PLASMA,
	SCIENCE_ENTITY_SUBMERSIBLE_FILTRATION_TANK,
	SCIENCE_ENTITY_SUBMARINE_MINING_MACHINE,
	SCIENCE_ENTITY_UNDERGROUND_DRILLING_MACHINE,
	SCIENCE_ENTITY_PROBE,
	SCIENCE_ENTITY_HIGH_RESOLUTION_SENSORS,
	SCIENCE_ENTITY_LONG_RANGE_SENSORS,
	SCIENCE_ENTITY_CLOAKING_DEVICE,
	SCIENCE_ENTITY_ANDROIDS,
	SCIENCE_ENTITY_SCIENTIFIC_LAB,
	SCIENCE_ENTITY_LIFE_SUPPORT,
	SCIENCE_ENTITY_MAINFRAME,
	SCIENCE_ENTITY_HANGAR,
	SCIENCE_ENTITY_MAGNETICAL_FILTER,
	SCIENCE_ENTITY_DEUTERIUM_DECOMPOSER,
	SCIENCE_ENTITY_ZIRCONIUM_REACTOR,
	SCIENCE_ENTITY_ILMENITE_FURNACE
};

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

enum supremeEntitiesSupportedByScience
{
	SCIENCE_SUPREME_ENTITY_SCIENCE,

	SCIENCE_SUPREME_ENTITY_DRIVE,
	SCIENCE_SUPREME_ENTITY_PLATFORM,
	SCIENCE_SUPREME_ENTITY_MODULES,
	SCIENCE_SUPREME_ENTITY_PRODUCTION,

	SCIENCE_SUPREME_ENTITY_SUBSPACE_DRIVE,
	SCIENCE_SUPREME_ENTITY_IMPULS_DRIVE,
	SCIENCE_SUPREME_ENTITY_CONSTRUCTION,
	SCIENCE_SUPREME_ENTITY_EQUIPMENT,
	SCIENCE_SUPREME_ENTITY_ENERGETIC_RING,
	SCIENCE_SUPREME_ENTITY_RECOGNITION_DEVICES,
	SCIENCE_SUPREME_ENTITY_FACTORIES,
	SCIENCE_SUPREME_ENTITY_QUARRYING_MACHINES
};

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

#define SCIENTIFIC_UPDATES_IN_ONE_REAL_DAY                  4
#define AVERAGE_SECONDS_BETWEEN_SCIENTIFIC_UPDATES          HOURS_TO_DAY / SCIENTIFIC_UPDATES_IN_ONE_REAL_DAY * SECONDS_TO_HOUR * GAME_TIME_TO_WALL_TIME_SPEED_RATIO

#define MAX_TOTAL_SCIENCE_LEVEL                             128
#define LEVEL_TO_SCIENTIFIC_POINTS_EXPONENT                 (double)4.4

#define TOKENS_TOTAL_COUNT                                  10000
#define DEFAULT_SPEC_PTS_FOR_FULL_USAGE                     100


#define ROOT_TO_CATEGORIES_MULTIPLIER                       (double)0.3
#define CATEGORIES_TO_GROUPS_MULTIPLIER                     (double)0.55
#define GROUPS_TO_ITEMS_MULTIPLIER                          (double)0.3
#define NORMALIZED_LEAF_TOTAL_TOKENS                        (double)TOKENS_TOTAL_COUNT * ROOT_TO_CATEGORIES_MULTIPLIER * CATEGORIES_TO_GROUPS_MULTIPLIER * GROUPS_TO_ITEMS_MULTIPLIER


#define INDEX_QUARK_GLUON_CORE_SPEED                        0
#define INDEX_QUARK_GLUON_CORE_CONSUMPTION                  1
#define INDEX_QUARK_GLUON_CORE_END                          2

#define INDEX_NAVIGATION_COMPUTER_SPEED                     0
#define INDEX_NAVIGATION_COMPUTER_END                       1

#define INDEX_SUBSPACE_BEACON_SPEED                         0
#define INDEX_SUBSPACE_BEACON_END                           1

#define INDEX_INERTIAL_DAMPERS_SPEED                        0
#define INDEX_INERTIAL_DAMPERS_END                          1

#define INDEX_IMPULS_ENGINE_FORCE                           0
#define INDEX_IMPULS_ENGINE_CONSUMPTION                     1
#define INDEX_IMPULS_ENGINE_END                             2

#define INDEX_MECHANICAL_DAMPERS_ACCELERATION               0
#define INDEX_MECHANICAL_DAMPERS_END                        1

#define INDEX_DRONE_MISSILES_DAMAGE                         0
#define INDEX_DRONE_MISSILES_PRECISION                      1
#define INDEX_DRONE_MISSILES_RANGE                          2
#define INDEX_DRONE_MISSILES_END                            3

#define INDEX_DRONE_MISSILE_LAUNCHER_ACCUMULATOR            0
#define INDEX_DRONE_MISSILE_LAUNCHER_CHARGING               1
#define INDEX_DRONE_MISSILE_LAUNCHER_END                    2

#define INDEX_SHIPS_LEVEL                                   0
#define INDEX_SHIPS_END                                     1

#define INDEX_BASES_LEVEL                                   0
#define INDEX_BASES_END                                     1

#define INDEX_HANGARS_LEVEL                                 0
#define INDEX_HANGARS_END                                   1

#define INDEX_ANDROIDS_LEVEL                                0
#define INDEX_ANDROIDS_CONSUMPTION                          1
#define INDEX_ANDROIDS_END                                  2

#define INDEX_ENERGETIC_ACCUMULATOR_ACCUMULATOR             0
#define INDEX_ENERGETIC_ACCUMULATOR_CHARGING                1
#define INDEX_ENERGETIC_ACCUMULATOR_END                     2

#define INDEX_MAINFRAME_BIO_NODES                           0
#define INDEX_MAINFRAME_PREDICTION                          1
#define INDEX_MAINFRAME_TIME_REUSABILITY                    2
#define INDEX_MAINFRAME_CONSUMPTION                         3
#define INDEX_MAINFRAME_END                                 4

#define INDEX_SCIENTIFIC_LABS_LEVEL                         0
#define INDEX_SCIENTIFIC_LABS_END                           1

#define INDEX_LIFE_SUPPORT_CAPACITY                         0
#define INDEX_LIFE_SUPPORT_CONSUMPTION                      1
#define INDEX_LIFE_SUPPORT_END                              2

#define INDEX_WEAPON_ENERGY_CIRCUIT_CHARGING                0
#define INDEX_WEAPON_ENERGY_CIRCUIT_END                     1

#define INDEX_TRANSPORT_BEAM_GENERATOR_ACCUMULATOR          0
#define INDEX_TRANSPORT_BEAM_GENERATOR_CHARGING             1
#define INDEX_TRANSPORT_BEAM_GENERATOR_FORCIBILITY          2
#define INDEX_TRANSPORT_BEAM_GENERATOR_PRECISION            3
#define INDEX_TRANSPORT_BEAM_GENERATOR_RANGE                4
#define INDEX_TRANSPORT_BEAM_GENERATOR_END                  5

#define INDEX_LASER_GUN_ACCUMULATOR                         0
#define INDEX_LASER_GUN_CHARGING                            1
#define INDEX_LASER_GUN_FORCIBILITY                         2
#define INDEX_LASER_GUN_PRECISION                           3
#define INDEX_LASER_GUN_RANGE                               4
#define INDEX_LASER_GUN_END                                 5

#define INDEX_DEFLECTOR_SHIELDS_GENERATOR_SOLIDITY          0
#define INDEX_DEFLECTOR_SHIELDS_GENERATOR_ACCUMULATOR       1
#define INDEX_DEFLECTOR_SHIELDS_GENERATOR_CHARGING          2
#define INDEX_DEFLECTOR_SHIELDS_GENERATOR_END               3

#define INDEX_HIGH_RESOLUTION_SENSORS_LEVEL                 0
#define INDEX_HIGH_RESOLUTION_SENSORS_RANGE                 1
#define INDEX_HIGH_RESOLUTION_SENSORS_CONSUMPTION           2
#define INDEX_HIGH_RESOLUTION_SENSORS_END                   3

#define INDEX_LONG_RANGE_SENSORS_LEVEL                      0
#define INDEX_LONG_RANGE_SENSORS_RANGE                      1
#define INDEX_LONG_RANGE_SENSORS_CONSUMPTION                2
#define INDEX_LONG_RANGE_SENSORS_END                        3

#define INDEX_CLOAKING_DEVICE_LEVEL                         0
#define INDEX_CLOAKING_DEVICE_CONSUMPTION                   1
#define INDEX_CLOAKING_DEVICE_END                           2

#define INDEX_PROBE_DEVICE_LEVEL                            0
#define INDEX_PROBE_DEVICE_END                              1

#define INDEX_MAGNETICAL_FILTER_PRODUCTION                  0
#define INDEX_MAGNETICAL_FILTER_END                         1

#define INDEX_DEUTERIUM_DECOMPOSER_PRODUCTION               0
#define INDEX_DEUTERIUM_DECOMPOSER_METAMORPHOSIS            1
#define INDEX_DEUTERIUM_DECOMPOSER_END                      2

#define INDEX_ZIRCONIUM_REACTOR_PRODUCTION                  0
#define INDEX_ZIRCONIUM_REACTOR_METAMORPHOSIS               1
#define INDEX_ZIRCONIUM_REACTOR_END                         2

#define INDEX_ILMENITE_FURNACE_PRODUCTION                   0
#define INDEX_ILMENITE_FURNACE_METAMORPHOSIS                1
#define INDEX_ILMENITE_FURNACE_END                          2

#define INDEX_MAGNETICAL_COLLECTORS_OF_PLASMA_WINDING_SPEED 0
#define INDEX_MAGNETICAL_COLLECTORS_OF_PLASMA_END           1

#define INDEX_SUBMERSIBLE_FILTRATION_TANK_WINDING_SPEED     0
#define INDEX_SUBMERSIBLE_FILTRATION_TANK_RANGE             1
#define INDEX_SUBMERSIBLE_FILTRATION_TANK_END               2

#define INDEX_SUBMARINE_MINING_MACHINE_WINDING_SPEED        0
#define INDEX_SUBMARINE_MINING_MACHINE_RANGE                1
#define INDEX_SUBMARINE_MINING_MACHINE_END                  2

#define INDEX_UNDERGROUND_DRILLING_MACHINE_WINDING_SPEED    0
#define INDEX_UNDERGROUND_DRILLING_MACHINE_RANGE            1
#define INDEX_UNDERGROUND_DRILLING_MACHINE_END              2

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

class treeNode;
typedef vector<treeNode               *> treeNodePVector;
typedef pair  <unsigned short, double  > unsignedShortDoublePair;
typedef vector<unsignedShortDoublePair > unsignedShortDoublePairVector;

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

class treeNode
// pts jsou tokeny, realne body jsou getRealScientificLevel
{
protected:
	friend class scientificTree;
	friend class treeInnerNode;
	friend class treeLeaf;

	treeNode       * ascendant_;
	unsigned short   assignedPts_;
	unsigned short   nodeIndex_;

	virtual          bool    isInner() = 0;
	virtual          bool    isLeaf()  = 0;
	        unsigned short   setPts(unsigned short newPts )         { assignedPts_  = newPts ; return newPts;  };
			unsigned short   addPts(unsigned short morePts)         { assignedPts_ += morePts; return morePts; };
			unsigned short   subPts(unsigned short lessPts)         { assignedPts_ -= lessPts; return lessPts; };
	                 bool    isRoot()                               { return (NULL == ascendant_);             };	        	        
			treeNode       * getAscendant ()                        { return ascendant_;                       };
			void             setAscendant (treeNode * newAscendant) { ascendant_ = newAscendant;               };
	        unsigned short   getPts()                               { return assignedPts_;                     };
    virtual          void    markNodeIndex(unsigned short& currentIndex) { nodeIndex_ = ++currentIndex;        };
    virtual          void    DBInsert(dtIdentifier userId) = 0;
	virtual          void    DBLoad(dtIdentifier userId) = 0;
	virtual          void    DBSave(dtIdentifier userId) = 0;
};

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

class treeLeaf : public treeNode
// specialisationPts jsou ty body v listech u jednotlivych parametru komponenty
{
private:
	friend class scientificTree;

	entitiesSupportedByScience    entity_;
	unsignedShortDoublePairVector itemComponents_;
	unsigned short                freePtsInNode_;

	treeLeaf(entitiesSupportedByScience leafEntity, size_t entityIndexesEnd);
	bool isInner()                                                   { return 0;                    };
	bool isLeaf()                                                    { return 1;                    };
	entitiesSupportedByScience getEntity()                           { return entity_;              };
	bool isEntityMatchingPattern(entitiesSupportedByScience pattern) { return (pattern == entity_); };	
	unsigned short getSpecialisationPts(size_t specialisationIndex                        );
	unsigned short setSpecialisationPts(size_t specialisationIndex, unsigned short newPts );
	unsigned short addSpecialisationPts(size_t specialisationIndex, unsigned short morePts);
	unsigned short subSpecialisationPts(size_t specialisationIndex, unsigned short lessPts);
	unsigned short collectAllPtsUptoRoot();
	double         getRealScientificLevel(size_t specialisationIndex);
	void           increaseScientificLevelsByScientificPoints(unsigned long long producedScientificPoints);
	void           DBInsert(dtIdentifier userId);
	void           DBLoad(dtIdentifier userId);
	void           DBSave(dtIdentifier userId);

	virtual       ~treeLeaf() {};
};

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

class treeInnerNode : public treeNode
// pts jsou tokeny, realne body jsou getRealScientificLevel
{
private:
	friend class scientificTree;
	friend class treeLeaf;
	
	supremeEntitiesSupportedByScience supremeEntity_;
	treeNodePVector                   descendants_;

	treeInnerNode(supremeEntitiesSupportedByScience innerNodeEntity);
	bool isInner()                                                                 { return 1;                                                           };
	bool isLeaf()                                                                  { return 0;                                                           };
	supremeEntitiesSupportedByScience getSupremeEntity()                           { return supremeEntity_;                                              };
	bool isSupremeEntityMatchingPattern(supremeEntitiesSupportedByScience pattern) { return (pattern == supremeEntity_);                                 };	
	void addDescendant(treeNode * descendant)                                      { descendants_.push_back(descendant); descendant->setAscendant(this); };
	void markNodeIndex(unsigned short& currentIndex);
	void DBInsert(dtIdentifier userId);
	void DBLoad(dtIdentifier userId);
	void DBSave(dtIdentifier userId);

	virtual ~treeInnerNode() {};
};

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

class scientificTree
{
private:
	treeInnerNode * scienceTotal_;


	treeInnerNode * drive_;
	treeInnerNode * platform_;
	treeInnerNode * modules_;
	treeInnerNode * production_;


	treeInnerNode * subspaceDrive_;
	treeInnerNode * impulsDrive_;
	treeInnerNode * construction_;
	treeInnerNode * equipment_;
	treeInnerNode * energeticRig_;
	treeInnerNode * recognitionDevices_;
	treeInnerNode * factories_;
	treeInnerNode * quarryingMachines_;


	treeLeaf * quarkGluonCore_;
	treeLeaf * navigationComputer_;
	treeLeaf * subspaceBeacon_;
	treeLeaf * inertialDampers_;

	treeLeaf * impulsJetEngine_;
	treeLeaf * mechanicalDampers_;
	treeLeaf * droneMissiles_;
	treeLeaf * droneMissileLauncher_;

	treeLeaf * shipsConstruction_;
	treeLeaf * basesConstruction_;
	treeLeaf * hangar_;
	treeLeaf * androids_;

	treeLeaf * energeticAccumulator_;
	treeLeaf * mainframe_;
	treeLeaf * scientificLab_;
	treeLeaf * lifeSupport_;

	treeLeaf * weaponEnergyCircuit_;
	treeLeaf * transportBeam_;
	treeLeaf * laserGun_;
	treeLeaf * deflectorShieldsGenerator_;

	treeLeaf * highResolutionSensors_;
	treeLeaf * longRangeSensors_;
	treeLeaf * cloakingDevice_;
	treeLeaf * probe_;

	treeLeaf * magneticalFilter_;
	treeLeaf * deuteriumDecomposer_;
	treeLeaf * zirconiumReactor_;
	treeLeaf * ilmeniteFurnace_;

	treeLeaf * magneticalCollectorsOfPlasma_;
	treeLeaf * submersibleFiltrationTank_;
	treeLeaf * submarineMiningMachine_;
	treeLeaf * undergroundDrillingMachine_;


	unsigned short freeTokens_;	


	treeLeaf      * getTreeLeafPtr     (entitiesSupportedByScience        leafEntity );
	treeInnerNode * getTreeInnerNodePtr(supremeEntitiesSupportedByScience innerEntity);

    void            nullifyNode(treeNode* node);
public:	
	scientificTree();
	~scientificTree();

	unsigned short getAllsLeafTokens (entitiesSupportedByScience        leafEntity                                          );
	// posbirani vsech tokenu az k listu (podeleno multiplikatorem)
	unsigned short getPureLeafTokens (entitiesSupportedByScience        leafEntity                                          );
	unsigned short setPureLeafTokens (entitiesSupportedByScience        leafEntity ,               unsigned short newTokens );
	unsigned short addPureLeafTokens (entitiesSupportedByScience        leafEntity ,               unsigned short moreTokens);
	unsigned short subPureLeafTokens (entitiesSupportedByScience        leafEntity ,               unsigned short lessTokens);	
	// tokeny polozene jen v listu
	unsigned short getSpecLeafTokens (entitiesSupportedByScience        leafEntity , size_t index                           );
	unsigned short setSpecLeafTokens (entitiesSupportedByScience        leafEntity , size_t index, unsigned short newTokens );
	unsigned short addSpecLeafTokens (entitiesSupportedByScience        leafEntity , size_t index, unsigned short moreTokens);
	unsigned short subSpecLeafTokens (entitiesSupportedByScience        leafEntity , size_t index, unsigned short lessTokens);
	// tokeny parametru listovych komponent
	unsigned short getPureInnerTokens(supremeEntitiesSupportedByScience innerEntity                                         );
	unsigned short setPureInnerTokens(supremeEntitiesSupportedByScience innerEntity,               unsigned short newTokens );
	unsigned short addPureInnerTokens(supremeEntitiesSupportedByScience innerEntity,               unsigned short moreTokens);
	unsigned short subPureInnerTokens(supremeEntitiesSupportedByScience innerEntity,               unsigned short lessTokens);
	// tokeny polozene ve vnitrnim uzlu
    unsigned short totalTokens       (void                                                                                  );
	// ne pridelenych, ale vsech na svete ve vede
    unsigned short nullifyTreeTokens (void                                                                                  );
	// vynulovani uplne totalne vseho

	double         getRealScienceLevel(entitiesSupportedByScience       leafEntity , size_t index                           );
	// skutecny level vedy
	void           distributeScientificPointsToLeafs(unsigned long long moreScientificPoints                                );
	// tohle se predpoklada cca 4x denne realneho casu

	void           setWholeTreeLevelForNewPlayer(double newScientificLevel);

	void DBInsert(dtIdentifier userId);
	void DBLoad(dtIdentifier userId);
	void DBSave(dtIdentifier userId);
	void DBDelete(dtIdentifier userId);
};

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

#endif