#pragma once
#include "../../../../Utils/Process/Process.h"
#include <Exp/ILogicalExp.h>
#include <Exp/IEffect.h>

/**
 * @brief Base class for tactical actions.
 */
class TacticalAction : public virtual Process
{
public:
  /**
   * @brief Constructs a new tactical action.
   */
  TacticalAction(const Process* parent, unsigned int priority);

  virtual ~TacticalAction()
  {
  }

  unsigned int getPriority() const
  {
    return m_priority;
  }

  const planning::ILogicalExp* getPrecondition() const
  {
    return m_precondition;
  }
  
  const planning::IEffect* getEffect() const
  {
    return m_effect;
  }

  void cancel()
  {
    if (!m_isCancelling && !isTerminated())
    {
      SPAR_LOG(LogTypes.LAYER_2_DECISION, "Cancelling action: %s", toString(this).c_str());

      m_isCancelling = true;

      onCancelImplementation();
    }
  }

  // Failures are action-dependent
    
  static const TerminationMode Cancelled;

  static const TerminationMode AllUnitsDestroyed;
  
protected:
  virtual void onStart()
  {
    SPAR_LOG(LogTypes.LAYER_2_DECISION, "Executing action: %s", toString(this).c_str());

    onStartInterface();
    onStartImplementation();
  }

  // THIS METHOD SHOULD ONLY BE CALLED FROM onStart()
  virtual void onStartInterface()
  {
    Process::onStart();
  }

  // THIS METHOD SHOULD ONLY BE CALLED FROM onStart()
  virtual void onStartImplementation() = 0;
  
  virtual void onEnd()
  {
    onEndImplementation();
    onEndInterface();
  }

  // THIS METHOD SHOULD ONLY BE CALLED FROM onEnd()
  virtual void onEndInterface()
  {
    Process::onEnd();
  }

  // THIS METHOD SHOULD ONLY BE CALLED FROM onEnd()
  virtual void onEndImplementation() = 0;

  virtual void onCancelImplementation() = 0;

  virtual void _output(std::ostream& out) const;

  unsigned int m_priority; // higher value -> more priority
  
  bool m_isCancelling;

  AutoPtr<const planning::ILogicalExp> m_precondition;
  AutoPtr<const planning::IEffect> m_effect;
};
