#pragma once

enum class EnemyOpening
{
	Unknown,
	
	// Zerg
	Z_4_5Pool,
	Z_9Pool,
	Z_9PoolSpeed,
	Z_OverPool,
	Z_12Pool,
	Z_10Hatch,
	Z_12Hatch,
	Z_12HatchMain,
	
	// Terran
	T_BBS,
	T_2Rax,
	T_1Fac,
	T_2Fac,
	T_FastExpand,
	T_WallIn,
	
	// Protoss
	P_1GateCore,
	P_4GateGoon,
	P_2Gate,
	P_2GateFast,
	P_ProxyGate,
	P_FastExpand,
	P_ForgeFastExpand,
	P_CannonRush,
	P_CannonTurtle
};

class OpponentModel : public Singleton<OpponentModel>
{
public:
	void init();
	void update();
	EnemyOpening enemy_opening() const { return enemy_opening_; }
	std::string enemy_opening_info() const;
	bool emp_seen() const { return emp_seen_; }
	Race initial_enemy_race() const { return initial_enemy_race_; }
	bool enemy_race_known() const { return race_known(enemy_race_); }
	Race enemy_race() const { return enemy_race_; }
	int enemy_latest_expansion_frame();
	bool air_to_ground_present() const { return air_to_ground_present_; }
	bool cloaked_present() const { return cloaked_present_; }
	bool cloaked_or_mine_present() const;
	bool blocked_expansion_seen() { return blocked_expansion_seen_; }
	bool non_basic_combat_unit_seen() const { return non_basic_combat_unit_seen_; }
	
	bool enemy_base_sufficiently_scouted() const { return enemy_base_sufficiently_scouted_; }
	bool enemy_natural_sufficiently_scouted() const { return enemy_natural_sufficiently_scouted_; }
	
private:
	static int constexpr k5PoolSpawningPoolFrame = 1071;
	static int constexpr k9PoolSpawningPoolFrame = 1619;
	static int constexpr kOverPoolSpawningPoolFrame = 1803;
	static int constexpr k12PoolSpawningPoolFrame = 2184;
	static int constexpr k10HatchSpawningPoolFrame = 2500;
	static int constexpr k12HatchSpawningPoolFrame = 2826;
	
	static int constexpr k10HatchHatcheryFrame = 2143;
	static int constexpr k12HatchHatcheryFrame = 2380;
	static int constexpr kOverPoolHatcheryFrame = 2976;
	static int constexpr k9PoolHatcheryFrame = 3333;
	
	static int constexpr k5PoolZerglingFrame = 2682;
	static int constexpr k9PoolZerglingFrame = 3167;
	static int constexpr kOverPoolZerglingFrame = 3453;
	static int constexpr k12PoolZerglingFrame = 4007;
	
	static int constexpr k9PoolSpeedExtractorFrame = 1905;
	static int constexpr k9PoolSpeedMetabolicBoostFrame = 3333;
	
	static int constexpr kBBSFirstBarracksFrame = 1905;
	static int constexpr k2RaxSecondBarracksFrame = 2619;
	static int constexpr k2FacSecondFactoryFrame = 4881;
	static int constexpr k14CCCommandCenterFrame = 3048;
	
	static int constexpr kCannonRushForgeFrame = 2024;
	static int constexpr k99GateSecondGatewayFrame = 2262;
	static int constexpr k1012GateFirstGatewayFrame = 1905;
	static int constexpr k1012GateSecondGatewayFrame = 2500;
	static int constexpr k12NexusNexusFrame = 2619;
	
	static int constexpr k4GateGoonBuildingsFrame = 8571;
	static int constexpr k4GateGoon7Frame = 8571;
	static int constexpr k4GateGoon11Frame = 9286;
	static int constexpr k4GateGoon15Frame = 10357;
	
	static int constexpr kTerranWallInDetectUntilFrame = 5714;
	
	Race initial_enemy_race_ = Races::Unknown;
	Race enemy_race_ = Races::Unknown;
	bool air_to_ground_present_ = false;
	bool cloaked_present_ = false;
	bool blocked_expansion_seen_ = false;
	EnemyOpening enemy_opening_ = EnemyOpening::Unknown;
	bool emp_seen_ = false;
	bool enemy_base_sufficiently_scouted_ = false;
	bool enemy_natural_sufficiently_scouted_ = false;
	int enemy_natural_sufficiently_scouted_start_frame_ = -1;
	bool non_basic_combat_unit_seen_ = false;
	
	bool position_not_in_main(Position enemy_position);
	bool position_in_enemy_main(Position enemy_position);
	bool position_in_main_near_choke(Position enemy_position,int max_distance=128);
	bool position_in_or_near_potential_natural(Position enemy_position,int max_distance=128);
	bool is_non_start_hatchery(Unit unit);
	void update_state_for_unit(Unit unit);
	bool is_air_to_ground(Unit unit);
	bool is_cloaked(Unit unit);
	void update_state_for_spawning_pool(Unit unit);
	void update_state_for_hatchery(Unit unit);
	void update_state_for_zergling(Unit unit);
	void update_state_for_dragoon(Unit unit);
	bool is_cannon_rush(Unit unit);
	bool is_proxy_gate(Unit unit);
	void update_state_for_unit(const InformationUnit& unit);
	void update_state_for_resource_depot(const InformationUnit& unit);
	bool is_cannon_turtle(const InformationUnit& unit);
	bool is_forge_fast_expand(const InformationUnit& unit);
	void update_emp_seen();
	void update_blocked_expansion_seen();
	void update_enemy_base_sufficiently_scouted();
	
	static bool race_known(Race race) { return race == Races::Zerg || race == Races::Terran || race == Races::Protoss; }
};
