#pragma once
#include "UnitAttackBehavior.h"

static const int HIGH_TEMPLAR_PSIONIC_RANGE = 215;
static const int PSIONIC_LEFT_MARKER_WIDTH = 64;
static const int PSIONIC_RIGHT_MARKER_WIDTH = 64;
static const int PSIONIC_ABOVE_MARKER_HEIGHT = 64;
static const int PSIONIC_BELOW_MARKER_HEIGHT = 32;
static const int PSIONIC_DMG_PER_FRAME = 1; // TODO: find correct damages
static const int PSIONIC_FRAME_DURATION = 112;
static const int PSIONIC_TOTAL_DMG = PSIONIC_DMG_PER_FRAME * PSIONIC_FRAME_DURATION;

static const int CASTING_FRAME_COUNT = 5;

class HighTemplarUnitAttackBehavior : public UnitAttackBehaviorT<HighTemplarUnitAttackBehavior>
{
public:
  typedef boost::function<BWAPI::Unit*()> GetUnitToFollow;

protected:
  class WaitPsionicStormOpportunity;
  //class LaunchPsionicStorm;

  // WaitPsionicStormOpportunity state //////////////////////////////////////////////////////////////
  class WaitPsionicStormOpportunity : public BehaviorStateT<HighTemplarUnitAttackBehavior, WaitPsionicStormOpportunity>
  {
  public:
    WaitPsionicStormOpportunity(HighTemplarUnitAttackBehavior& behavior);
    void onEnter() { }
    void onExit() { }

    void onTimer();

  private:
    typedef concatenate_iterators<boost::tuple<std::pair<std::set<const UnitRecord*>::const_iterator, std::set<const UnitRecord*>::const_iterator>,
                                               std::pair<std::set<const UnitRecord*>::const_iterator, std::set<const UnitRecord*>::const_iterator>>, 
                                  const UnitRecord*> UnitIterator;

    std::pair<BWAPI::Position, double> calculateHillClimbing(const std::set<const UnitRecord*>& ownUnits, const std::set<const UnitRecord*>& enemyUnits) const;

    double calculateValueAtPosition(BWAPI::Position center, UnitIterator unitBegin, UnitIterator unitEnd) const;
    double calculateUnitDangerosity(BWAPI::UnitType unitType) const;
    double calculateAllyInfluence(BWAPI::Position center) const;
    
    typedef SCHEDULER_EVENT_HANDLER(WaitPsionicStormOpportunity, onTimer) TimerEvent;
    TimerEvent m_timerEvent;
  public:
    // Events in the boost::tuple are activated/deactivated automatically when on State::onEnter/onExit
    typedef boost::tuple<
      TimerEvent&
    > Events;
    const Events m_events;

    typedef boost::tuple<> Transitions;
    const Transitions m_transitions;
  };

  virtual void _output(std::ostream& out) const
  {
    out << "HighTemplarUnitAttackBehavior(" << *m_unit << ")";
  }

  bool selectTarget(const std::set<BWAPI::Unit*>& enemies);

  static BWAPI::Unit* noUnit()
  {
    return NULL;
  }

  virtual void onStart()
  {
    UnitBehaviorT::onStart();
    m_waitPsionicStorm.enter();
  }

  // Variables

  // States
  WaitPsionicStormOpportunity m_waitPsionicStorm;

  const GetUnitToFollow m_getUnitToFollow;

public:
  HighTemplarUnitAttackBehavior(const Process* parent, unsigned int initialPriority, BWAPI::Unit* unit, GetUnitToFollow getUnitToFollow = noUnit);

  typedef boost::tuple<
    WaitPsionicStormOpportunity&
  > States;
  const States m_states;
};