#pragma once

#include "Common.h"
#include "Squad.h"
#include "SquadData.h"
#include "InformationManager.h"
#include "StrategyManager.h"
#include "The.h"

namespace UAlbertaBot
{
class CombatCommander
{
	The &			the;
	SquadData       _squadData;
    BWAPI::Unitset  _combatUnits;
    bool            _initialized;

	bool			_goAggressive;

	BWAPI::Position	_scourgeTarget;

	BWAPI::Position	_reconTarget;
	int				_lastReconTargetChange;         // frame number

	void            updateIdleSquad();
	void            updateOverlordSquad();
	void			updateScourgeSquad();
	void			updateReconSquad();
	void			updateWatchSquads();
	void            updateBaseDefenseSquads();
	void            updateScoutDefenseSquad();
	void            updateDropSquads();
	///////////////////////////++
	int             spiderStep;          //记录蜘蛛雷的放置步长
	BWAPI::Position	defenseLine;         //防守阵线的位置
	BWAPI::Position _lastDefenseLine;
	int             _lastScanMinute;      //记录上次使用雷达探查敌方主基地的时间
	bool            _barracksIsWorking;
	BWAPI::Unit     _clostestUnit;       //阵线上离对方最近的我方单位
	BWAPI::Position _aimEnemyBase;
	///////////////////////////__

	bool            wantSquadDetectors() const;
	void			maybeAssignDetector(Squad & squad, bool wantDetector);

	void			loadOrUnloadBunkers();
	void			doComsatScan();

	int				weighReconUnit(const BWAPI::Unit unit) const;
	int				weighReconUnit(const BWAPI::UnitType type) const;

	bool			isFlyingSquadUnit(const BWAPI::UnitType type) const;
	bool			isOptionalFlyingSquadUnit(const BWAPI::UnitType type) const;
	bool			isGroundSquadUnit(const BWAPI::UnitType type) const;

	bool			unitIsGoodToDrop(const BWAPI::Unit unit) const;

	void			cancelDyingItems();

	int             getNumType(BWAPI::Unitset & units, BWAPI::UnitType type);

	BWAPI::Unit     findClosestDefender(const Squad & defenseSquad, BWAPI::Position pos, bool flyingDefender, bool pullWoekers, bool enemyHasAntiAir);
    BWAPI::Unit     findClosestWorkerToTarget(BWAPI::Unitset & unitsToAssign, BWAPI::Unit target);

	void			chooseScourgeTarget(const Squad & squad);
	BWAPI::Position getDefendLocation();
	void			chooseReconTarget();
	BWAPI::Position getReconLocation() const;
	SquadOrder		getAttackOrder(const Squad * squad);
	BWAPI::Position getAttackLocation(const Squad * squad);
	BWAPI::Position getDropLocation(const Squad & squad);
	BWAPI::Position	getDefenseLocation();

    void            initializeSquads();
    void            assignFlyingDefender(Squad & squad);
    void            emptySquad(Squad & squad, BWAPI::Unitset & unitsToAssign);
    int             getNumGroundDefendersInSquad(Squad & squad);
    int             getNumAirDefendersInSquad(Squad & squad);

	void            updateDefenseSquadUnits(Squad & defenseSquad, const size_t & flyingDefendersNeeded, const size_t & groundDefendersNeeded, bool pullWorkers, bool enemyHasAntiAir);

    int             numZerglingsInOurBase() const;
    bool            buildingRush() const;


public:

	CombatCommander();

	void update(const BWAPI::Unitset & combatUnits);

	void setAggression(bool aggressive) { _goAggressive = aggressive; };
	bool getAggression() const { return _goAggressive; };
	
	void pullWorkers(int n);
	void releaseWorkers();
	
	void drawSquadInformation(int x, int y);
	void drawCombatSimInformation();

	//////////////////////////////////////////++

	void            updateDefenseLine();             //实时更新防守阵线的位置
	BWAPI::Position getDefenseLine();     //获取防守阵线
	void            updateAttackEnemyBase(); //8.16.2019//更新目前需要进攻的敌方分基地，没有则为空
	void            updateAggression();
	bool            isTimeToPush();//8.30.2019//根据敌我双方单位的数量和位置，判断我方是否应该推进

	BWAPI::Position getNearPosition(BWAPI::Position frontPos, BWAPI::Position backPos, bool isFront, int distance);//获取坐标点前方或者后方指定距离的一个坐标
	BWAPI::Position getRowPosition(BWAPI::Position frontPos, BWAPI::Position backPos, int interval, int length);
	void            updateChokeSquads();
	void            updateSpiderSquads();//放置蜘蛛雷的部队单独创建一个队列，放完之后再脱离该队列，同时起到前锋的作用//8.12.2019已经弃用
	void            updateFrontSquads();//防守阵线的两翼队列，混编
	void            updateGoliathSquad();//8.18.2019
	void            updateBaseAttackSquad();//8.18.2019
	void            updateTankSquads();//防守阵线的坦克队列，位于阵线中间偏后的位置
	void            updatePioneerSquad();//将雷车作为先锋，为坦克抵挡敌方的冲击
	void            updateBunkerSquad();//每一个squad由4个机枪兵组成，驻守在地堡内，自动跟随阵线推进而改变驻守的地堡
	void            updateStartingBaseDefenseSquad();//主基地非常重要，需要更多单位来应对敌方的进攻
	void            updateB3Squad();
	BWAPI::Position getSquadPosition(std::string squadID);//以当前的防守点为中心，确定各个队列的位置，以组成阵线
	void            updateAttackSquads();//7.18
	void            clearSquad(std::string squadName);
	void            updateMineAsRowFrontSquad(BWAPI::Position aimPosition, BWAPI::Position backPos, int interval, int length, bool doubleLine);//在前线埋雷的雷车队 
	void            updateMineAsRowBackSquad(BWAPI::Position aimPosition, BWAPI::Position backPos, int interval, int length);//在后方埋雷的雷车队 
	bool            canUseMinePosition(BWAPI::Position targetPos);
	void            updateScvSquad();
	void            updateResidentBaseSquad();//8.9.2019//除了主基地和二基地
	void            updateScoutSquad();//8.14.2019//2个雷车的侦察小队，布雷在分基地
	void            updateScvScoutSquad();//8.14.2019//前期防守不足，使用SCV侦察
	void            updateHarassSquad();//9.2.2019//雷车和坦克等前期骚扰对方
	void            updateFindingEnemyBaseSquad();//9.8.2019/寻找敌方基地
	////////////
	void 	        updateBarracks();             //控制路口处的建筑升起或者降落//7.31.2019//兵营作为前锋提供视野
	void            updateBarracksIsWorking();
	void            updateClostestUnit();
	////////////
	BWAPI::Position frontBarracksPosition();//假如兵营不存在，返回None
	BWAPI::Unit     getFrontBarracks();
	//////////////////////////////////////////__
	//8.4.2019 @liang
	BWAPI::Position getPointBetweenCC_Mineral();
	void            updateMineCC_MineralSquad();

	void            liftAndMoveEbay(); //8.7.2019//升起工程湾,并移动到主基地上方
	void            updateSecondBase();//8.29.2019//在主基地内修的二基地建筑，需要飞到对应位置

	static CombatCommander & Instance();

	static int		workerPullScore(BWAPI::Unit worker);//@zhang 2019年8月30日21:25:17 改为public，为了PullWorkerCompare使用

};

struct PullWorkerCompare //重写仿函数//@zhang 2019年8月30日21:25:17 修改lambda函数为struct
{
	bool operator() (BWAPI::Unit left, BWAPI::Unit right)
	{
		return CombatCommander::workerPullScore(left) < CombatCommander::workerPullScore(right); //大顶堆
	}
};
}
