#pragma once
#include "AbstractOrder.h"
#include "Common.h"


class GameState
{
public:
	struct combatStats_t {
		double airDPF; // DPF = Damage Per Frame
		double groundDPF;
		double airHP;
		double groundHP;
	};
	struct unitState_t {
		uint8_t unitTypeId;
		uint8_t numUnits;
		uint8_t regionId;
		uint8_t orderId;
		uint8_t targetRegionId;
		int endFrame; // expected frame where the order is done
	};

    enum BuildingOption
	{
		NoneBuilding,
		ResourceDepot,
        AllBuildings
	};

	GameState();
    void initFileVariables();
    int _buildingTypes;

	std::vector<unitState_t> friendlyUnits;
	std::vector<unitState_t> enemyUnits;
	std::set<int> regionsInCombat;
	// pair 1 = friend, pair 2 = enemy, map<int> = region id
	typedef std::map<int, std::pair<std::set<unitState_t*>, std::set<unitState_t*> > > combatList_t;
	combatList_t combatList; 

	void updateGameState();
    void addAllEnemyUnits();
    void addSelfBuildings();
    unsigned int addFriendlyUnit(BWAPI::Unit *unit);
    void addGroup(int unitId, int numUnits, int regionId, int listID);
    void expectedEndFrame();
	int getAbstractOrderID(int orderId, int currentRegion, int targetRegion);
	const std::string getAbstractOrderName(BWAPI::Order order, int currentRegion, int targetRegion);
	const std::string getAbstractOrderName(int abstractId);
	std::string toString();

	int _time;
	void execute(playerActions_t playerActions, bool player);
	bool canExecuteAnyAction(bool player);
    void moveForward(int forwardTime = 0);
	int winner();
    bool gameover();
    bool hasOnlyBuildings(std::vector<unitState_t> unitsVector);
	GameState cloneIssue(playerActions_t playerActions, bool player);
    void mergeGroups();

    void resetFriendlyActions();
    BWAPI::Position getCenterRegionId(int regionId);
    int getRegionDistance(int regId1, int regId2);

private:
	unsigned int addUnit(unitState_t unit, std::vector<unitState_t>& vectorState);
	int getMoveTime(int unitTypeId, int regionId, int targetRegionId);
    void calculateCombatTimes();
	void getCombatTime();
	void getCombatStats(combatStats_t & combatStats, BWAPI::UnitType unitType, uint8_t numUnits );
	int removeAirUnits(std::vector<unitState_t> *unitsList, int regionId, int totalDamage);
	int removeGroundUnits(std::vector<unitState_t> *unitsList, int regionId, int totalDamage);
};
