#include "Common.h"
#include "LocutusUnit.h"
#include "InformationManager.h"
#include "Micro.h"
#include "MapTools.h"
#include "PathFinding.h"

const double pi = 3.14159265358979323846;

namespace { auto & bwemMap = BWEM::Map::Instance(); }

using namespace UAlbertaBot;

LocutusUnit::LocutusUnit()
	: the(The::Root())
	, targetPosition(BWAPI::Positions::Invalid)
	, currentlyMovingTowards(BWAPI::Positions::Invalid)
{
}


bool LocutusUnit::moveTo(BWAPI::Unit unit,BWAPI::Position position)
{
    // Fliers just move to the target
    if (unit->isFlying())
    {
		//Move(unit, position);
        //Micro::Instance().Move(unit, position);
		//unit->move(position);//ZTODO @zhang 2019年9月3日16:41:07 改为micro的move
		the.micro.Move(unit, position);
        return true;
    }

    // If the unit is already moving to this position, don't do anything
    BWAPI::UnitCommand currentCommand(unit->getLastCommand());
    //if (position == targetPosition ||
	if (position == targetPosition &&//@zhang 2019年9月5日12:44:29 防止设定的targetPosition与最后的position相同就直接return，导致单位移动到第一个路口就不动
        (currentCommand.getType() == BWAPI::UnitCommandTypes::Move && currentCommand.getTargetPosition() == position))
		//@zhang 2019年9月5日13:41:58 ZTODO 在路口上，计算是有多少个waypoint，会不会还是算在之前的区域，导致不动
        return true;

	//@zhang 2019年9月5日13:44:20 if（没到点&&要去的currentCommand.getTargetPosition()和currentlyMovingTowards一样）
	if (unit->getDistance(currentCommand.getTargetPosition()) >20&& (currentCommand.getTargetPosition()==currentlyMovingTowards))
	{
		return true;
	}
    // Clear any existing waypoints
    waypoints.clear();
    targetPosition = BWAPI::Positions::Invalid;
    currentlyMovingTowards = BWAPI::Positions::Invalid;

    // If the unit is already in the same area, or the target doesn't have an area, just move it directly
    auto targetArea = bwemMap.GetArea(BWAPI::WalkPosition(position));
    if (!targetArea || targetArea == bwemMap.GetArea(BWAPI::WalkPosition(unit->getPosition())))
    {
		//Move(unit, position);

        //Micro::Move(unit, position);
		//Micro::Instance().Move(unit, position);
		//unit->move(position);//ZTODO @zhang 2019年9月3日16:41:07 改为micro的move
		the.micro.Move(unit, position);


        return true;
    }

    // Get the BWEM path
    // TODO: Consider narrow chokes
    auto& path = PathFinding::GetChokePointPath(
        unit->getPosition(), 
        position, 
        unit->getType(),
        PathFinding::PathFindingOptions::UseNearestBWEMArea);
    if (path.empty()) return false;

    for (const BWEM::ChokePoint * chokepoint : path)
        waypoints.push_back(chokepoint);

    // Start moving
    targetPosition = position;
    moveToNextWaypoint(unit);
    return true;
}
void LocutusUnit::moveToNextWaypoint(BWAPI::Unit unit)
//void LocutusUnit::moveToNextWaypoint()
{
    // If there are no more waypoints, move to the target position
    // State will be reset after latency frames to avoid resetting the order later
    if (waypoints.empty())
    {
		//Move(unit, targetPosition);

        //Micro::Move(unit, targetPosition);
		//Micro::Instance().Move(unit, targetPosition);
		//unit->move(targetPosition);//ZTODO @zhang 2019年9月3日16:41:07 改为micro的move
		the.micro.Move(unit, targetPosition);


        //lastMoveFrame = BWAPI::Broodwar->getFrameCount();
        return;
    }

    const BWEM::ChokePoint * nextWaypoint = *waypoints.begin();

   
    // Determine the position on the choke to move towards

    // If it is a narrow ramp, move towards the point with highest elevation
    // We do this to make sure we explore the higher elevation part of the ramp before bugging out if it is blocked
	//@zhang 2019年9月4日13:38:31
    /*ChokeData & chokeData = *((ChokeData*)nextWaypoint->Ext());
    if (chokeData.width < 96 && chokeData.isRamp)
    {
        currentlyMovingTowards = BWAPI::Position(chokeData.highElevationTile) + BWAPI::Position(16, 16);
    }
    else
    {*/

    // Get the next position after this waypoint
    BWAPI::Position next = targetPosition;//@zhang 2019年9月5日11:27:19 next就是目标
    if (waypoints.size() > 1) next = BWAPI::Position(waypoints[1]->Center());//@zhang 2019年9月5日11:32:50 下一个路口的中间

    //// Move to the part of the choke closest to the next position
    //int bestDist = INT_MAX;
    //for (auto walkPosition : nextWaypoint->Geometry())
    //{
    //    BWAPI::Position pos(walkPosition);
    //    int dist = pos.getApproxDistance(next);
    //    if (dist < bestDist)
    //    {
    //        bestDist = dist;
    //        currentlyMovingTowards = pos;
    //    }
    //}
	//@zhang 2019年9月4日18:47:48 加入判定，如果现在单位现在离要去的这个地方太近，去下一个路口
	/*if (unit->getDistance(currentlyMovingTowards) < 10)
	{
		currentlyMovingTowards= BWAPI::Position(next);//@zhang 这里可能会直接让它去中间，意思是还没到point进行了判定
	}*/

    //}
	currentlyMovingTowards = BWAPI::Position(next);//@zhang 2019年9月4日18:35:27

	//Move(unit, currentlyMovingTowards);
    //Micro::Move(unit, currentlyMovingTowards);
	//Micro::Instance().Move(unit, currentlyMovingTowards);
	//unit->move(currentlyMovingTowards);//ZTODO @zhang 2019年9月3日16:41:07 改为micro的move
	the.micro.Move(unit, currentlyMovingTowards);

    //lastMoveFrame = BWAPI::Broodwar->getFrameCount();
}


LocutusUnit & LocutusUnit::Instance()//@zhang 2019年9月4日15:41:32
{
	static LocutusUnit instance;
	return instance;
}