#pragma once
#include <fstream> // ifstream & ofstream !! FOR DEBUG
#include <BWAPI.h>
#include "unordered_map_serialization.h"

// Hit Points
#define CRITICAL 0
#define LOW 1
#define NORMAL 2
#define HIGH 3

// Number of units
#define NONE -1
#define SMALL 0
#define MEDIUM 1
#define LARGE 2

// Distance (MEDIUM 1 is already definend in Number of enemies) 
#define CLOSE 0
#define FARTHER 2

// Top Speed (MEDIUM 1 is already definend in Number of enemies) 
#define SLOW 0
#define FAST 2

#define FEATURES 15

class State
{
private:
	int hp; // hit points of our unit
	int hpEnemies; // hit points of the enemies
	int allies; // number of allied units
	int enemies; // number of enemy units
	int distance; // averaged distance to enemies
	int dps; // damage per second
	int dpsEnemies; // enemies damage per second
	int coolDown;  // it's the weapon's lapse to be ready to shoot (in frames)
	int attacked; // whether the unit is under attack or not
	int speed; // Top speed of our unit
	friend std::ostream& operator<<(std::ostream&, const State&);
	friend class boost::serialization::access;
	friend class StateHash;

	template<class Archive>
	void serialize(Archive & ar, const unsigned int version){
		ar & hp;
		ar & hpEnemies;
		ar & allies;
		ar & enemies;
		ar & distance;
		ar & dps;
		ar & dpsEnemies;
		ar & coolDown;
		ar & attacked;
		ar & speed;
		// WARNING: do not serialize bool attributes
	}

public:
	State();
	State(int hp, int hpEnemies, int allies, int enemies, int distance, int dps, int dpsEnemies, int coolDown, int attacked, int speed);
	bool operator==(const State &state) const;
	// Getters
	int getHP();
	int getHPEnemies();
	int getAllies();
	int getEnemies();
	int getDistance();
	int getDPS();
	int getDPSEnemies();
	int getCoolDown();
	int getAttacked();
	int getSpeed();
	// Utilities
	static int getEnemiesThreshold(int friends, int foes);
	static int getAlliesThreshold(int friends, int foes);
	static int getHPThreshold(int hp);
	static int getHPEnemies(BWAPI::Unitset foes);
	static int getHPEnemiesThreshold(BWAPI::Unitset foes, int ownUnits);
	static int getEnemyDistanceThreshold(int dist, BWAPI::Unit u);
	static int getClosestEnemyDistance(BWAPI::Unitset foes, BWAPI::Unit u);
	static int calculateDPS(BWAPI::Unit unit);
	static int calculateDPS(BWAPI::Unitset units);
	static int getDPSThreshold(int dps);
	static int getSpeedThreshold(BWAPI::Unit unit);
};

class StateHash
{
public:
	size_t operator()(const State &state) const;
};