#pragma once
#include "../../../../Utils/Process/FSM/Condition.h"
#include "../../../../PerceptualState/Locations/Location.h"

template <class UnitGroup>
class GroupReachedPosition : public Condition
{
public:
	GroupReachedPosition(const UnitGroup& group, BWAPI::Position destination, double maxDistance)
    : m_group(group)
    , m_destination(destination)
    , m_maxDistance(maxDistance)
  {
  }

  bool evaluate() const
  {
    for(UnitGroup::const_iterator it = m_group.begin();
        it != m_group.end();
        ++it)
    {
      if((*it)->getPosition().getApproxDistance(m_destination) > m_maxDistance)
      {
        return false;
	    }
    }
    return true;
  }

protected:
  const UnitGroup& m_group;
  const BWAPI::Position m_destination;
  const double m_maxDistance;

  GroupReachedPosition& operator=(const GroupReachedPosition &);
};

class UnitReachedPosition : public Condition
{
public:
  UnitReachedPosition(BWAPI::Unit* unit, BWAPI::Position destination, double maxDistance)
    : m_unit(unit)
    , m_destination(destination)
    , m_maxDistance(maxDistance)
  {
  }

  bool evaluate() const
  {
	  return m_unit->getPosition().getApproxDistance(m_destination) <= m_maxDistance;
  }

protected:
  const BWAPI::Unit* const  m_unit;
  const BWAPI::Position m_destination;
  const double m_maxDistance;

private:
  UnitReachedPosition& operator=(const UnitReachedPosition&);
};

class UnitReachedLocation : public Condition
{
public:
  UnitReachedLocation(BWAPI::Unit* unit, Location* destination, double maxDistance)
    : m_unit(unit)
    , m_destination(*this, destination)
    , m_maxDistance(maxDistance)
  {}

  bool evaluate() const
  {
    return m_destination->isInLocation(m_unit);
  }

protected:
  const BWAPI::Unit* const  m_unit;
  const AutoPtr<const Location> m_destination;
  const double m_maxDistance;

private:
  UnitReachedLocation& operator=(const UnitReachedLocation&);
};

template <class UnitGroup>
class GroupReachedLocation : public Condition
{
public:
	GroupReachedLocation(const UnitGroup& group, Location* destination, double maxDistance)
    : m_group(group)
    , m_destination(*this, destination)
    , m_maxDistance(maxDistance)
  {
  }

  bool evaluate() const
  {
    for(UnitGroup::const_iterator it = m_group.begin();
        it != m_group.end();
        ++it)
    {
     // if((*it)->getDistance(m_destination->getCurrentCenter()) > MAX_GROUP_DISTANCE_TO_DESTINATION)
     //   return false;

      if (!m_destination->isInLocation(*it) && (*it)->getDistance(m_destination->getCurrentCenter()) > m_maxDistance)
        return false;
    }
    return true;
  }

protected:
  const UnitGroup& m_group;
  const AutoPtr<const Location> m_destination;
  const double m_maxDistance;

private:
  GroupReachedLocation& operator=(const GroupReachedLocation&);
};