#pragma once
#include "../../Utils/Functors.h"
#include "../../Utils/ReferenceCounted.h"
#include <BWAPI.h>

template <class T>
struct True : std::unary_function<const T&,bool>
{
  bool operator()(const T&) const { return true; }
};

template <class T>
struct False : std::unary_function<const T&,bool>
{
  bool operator()(const T&) const { return false; }
};

template <class T, class Pred1, class Pred2>
struct And : std::unary_function<const T&,bool>
{
  And(Pred1 pred1, Pred2 pred2)
    : m_pred1(pred1)
    , m_pred2(pred2)
  {}
  bool operator()(const T& t) const
  {
    return m_pred1(t) && m_pred2(t);
  }
private:
  Pred1 m_pred1;
  Pred2 m_pred2;
};

template <class T, class Pred1, class Pred2>
struct Or : std::unary_function<const T&,bool>
{
  Or(Pred1 pred1, Pred2 pred2)
    : m_pred1(pred1)
    , m_pred2(pred2)
  {}
  bool operator()(const T& t) const
  {
    return m_pred1(t) || m_pred2(t);
  }
private:
  Pred1 m_pred1;
  Pred2 m_pred2;
};

template <class UnitType, class Location>
struct IsInLocation : std::unary_function<const UnitType*,bool>
{
  IsInLocation(const Location* location) 
    : m_location(*this, location)
  { }

  const bool operator()(const UnitType* unit) const
  {
    return m_location.isInLocation(unit->getPosition());
  }

protected:
  const AutoPtr<const Location> m_location;
};

template <class UnitType>
struct IsBuilding : std::unary_function<const UnitType*,bool>
{
  bool operator()(const UnitType* unit) const
  {
    return unit->getType().isBuilding();
  }
};

template <class UnitType>
struct IsCompleted : std::unary_function<const UnitType*,bool>
{
  bool operator()(const UnitType* unit) const
  {
    return unit->isCompleted();
  }
};

template <class UnitType>
struct IsCompletedBuilding : std::unary_function<const UnitType*,bool>
{
  bool operator()(const UnitType* unit) const
  {
    return IsBuilding()(unit) && IsCompleted()(unit);
  }
};

template <class UnitType>
struct IsOwnUnit : std::unary_function<const UnitType*,bool>
{
  bool operator()(const UnitType* unit) const
  {
    return unit->getPlayer() == BWAPI::Broodwar->self();
  }
};

template <class UnitType>
struct IsEnemyUnit : std::unary_function<const UnitType*,bool>
{
  bool operator()(const UnitType* unit) const
  {
    return unit->getPlayer() == BWAPI::Broodwar->enemy();
  }
};

template <class UnitType>
struct IsNeutralUnit : std::unary_function<const UnitType*,bool>
{
  bool operator()(const UnitType* unit) const
  {
    return unit->getPlayer() == BWAPI::Broodwar->neutral();
  }
};