#pragma once
#include "../../../../PerceptualState/World/CurrentWorld.h"
#include "../../../Layer2Actions/Interface/Actions/Research.h"
#include "../../Interface/TechSet.h"
#include "Layer3Process.h"

#pragma region TODO-PLANNING-REFACTOR

//
// Input: techs to acquire
//

class ResourcesSaturation;

class ProgressTechProcess : public Layer3Process
{
protected:
  struct TechActionWrapper
  {
    TechActionWrapper(TacticalAction* techAction)
      : m_techAction(techAction)
    {}
    TacticalAction* const m_techAction;
    std::map<SparObject*, TechActionWrapper>::const_iterator m_posInContainer;

  private:
    //const member prevent the use of the assigment operator
    TechActionWrapper& operator= (const TechActionWrapper&);

  };
  struct transform_to_pair : std::unary_function<std::pair<SparObject*, TechActionWrapper>, std::pair<const SparObject*, const TacticalAction*>>
  {
    result_type operator()(const argument_type& wrapper) const
    {
      return std::make_pair(wrapper.first, wrapper.second.m_techAction);
    }
  };

public:
  ProgressTechProcess(const Process* parent)
    : Layer3Process(parent, Scheduler::SCHEDULING_MEDIUM_PRIORITY, 10, 2)
    , m_techActionTerminateEventHandler(*this)
  {
  }

  ~ProgressTechProcess()
  {
    for (std::map<SparObject*, TechActionWrapper>::const_iterator it = m_currentTechActions.begin(); it != m_currentTechActions.end(); ++it)
    {
      delete it->second.m_techAction;
    }
  }

  void onNewTargetTechs(const TechSet& targetTechs)
  {
    unused(targetTechs);

    // Stuff will be updated during the next start()
  }

  virtual void run();

  /////////
  // GUI //
  /////////
  typedef boost::transform_iterator<transform_to_pair, std::map<SparObject*, TechActionWrapper>::const_iterator> TechActionIterator;
  std::pair<TechActionIterator, TechActionIterator> getCurrentTechActions() const
  {
    return std::make_pair(boost::make_transform_iterator(m_currentTechActions.begin(), transform_to_pair()),
                          boost::make_transform_iterator(m_currentTechActions.end(), transform_to_pair()));
  }

protected:
  virtual void _output(std::ostream& out) const
  {
    out << "Progress techs";
  }

  void onTechActionTerminate(void* data);

  static std::set<SparObject*> getRootTechsToAcquire(SparObject* target);
  static void getRootTechsToAcquireImpl(SparObject* target, std::set<SparObject*>& visited, std::set<SparObject*>& result);
  bool shouldResearchTech(SparObject* tech, const ResourcesSaturation& saturation) const;

  EVENT_HANDLER(ProgressTechProcess, onTechActionTerminate) m_techActionTerminateEventHandler;

  std::map<SparObject*, TechActionWrapper> m_currentTechActions;
};

#pragma endregion