//
// Copyright (c) 2009 Froduald Kabanza and the Université de Sherbrooke.
// Use of this software is permitted for non-commercial research purposes, and
// it may be copied or applied only for that use. All copies must include this
// copyright message.
// 
// This is a research prototype that has not gone through intensive tests and
// is delivered as is. It may still contain bugs. Froduald Kabanza and the
// Université de Sherbrooke disclaim any responsibility for damage that may be
// caused by using it.
//
// Please note that some files were inspired in part by the PDDL4J library:
// http://www.math-info.univ-paris5.fr/~pellier/software/software.php 
//
// Implementation: Simon Chamberland
// Project Manager: Froduald Kabanza
//

#ifndef _DURATIVE_ACTION_H
#define _DURATIVE_ACTION_H

#include "IAction.h"
#include "../Exp/ILogicalExp.h"
#include "../Exp/INumericExp.h"
#include "../Exp/IEffect.h"

namespace planning
{
  /// <summary>
  /// This interface is implemented by all types of action defined in the PDDL language.
  /// </summary>
  class DurativeAction : public IAction
  {
  public:
    template <class ArgumentIterator, class EffectIterator>
    DurativeAction(const std::string& name, 
                   ArgumentIterator argumentsBegin,
                   ArgumentIterator argumentsEnd,
                   const ILogicalExp* precondition,
                   const IEffect* startEffect,
                   EffectIterator delayedEffectsBegin,
                   EffectIterator delayedEffectsEnd)
      : IAction(name, argumentsBegin, argumentsEnd), m_precondition(precondition), 
        m_startEffect(startEffect), m_delayedEffects(delayedEffectsBegin, delayedEffectsEnd)
    {
      assert(m_precondition != NULL);
      assert(m_startEffect != NULL);

      m_precondition->acquire(this);
      m_startEffect->acquire(this);

      for (std::vector<std::pair<const INumericExp*, const IEffect*>>::const_iterator it = m_delayedEffects.begin();
           it != m_delayedEffects.end();
           ++it)
      {
        it->first->acquire(this);
        it->second->acquire(this);
      }
    }

    ~DurativeAction()
    {
      m_precondition->release(this);
      m_startEffect->release(this);

      for (std::vector<std::pair<const INumericExp*, const IEffect*>>::const_iterator it = m_delayedEffects.begin();
           it != m_delayedEffects.end();
           ++it)
      {
        it->first->release(this);
        it->second->release(this);
      }
    }

    const ILogicalExp* getPrecondition() const
    {
      return m_precondition;
    }

    const IEffect* getStartEffect() const
    {
      return m_startEffect;
    }

    typedef std::vector<std::pair<const INumericExp*, const IEffect*>>::const_iterator delayed_effect_iterator;

    delayed_effect_iterator delayedEffectsBegin() const
    {
      return m_delayedEffects.begin();
    }

    delayed_effect_iterator delayedEffectsEnd() const
    {
      return m_delayedEffects.end();
    }

  protected:
    virtual IGroundAction* instantiateAction(const Bindings* bindings) const;

    const ILogicalExp* m_precondition;

    const IEffect* m_startEffect;

    const std::vector<std::pair<const INumericExp*, const IEffect*>> m_delayedEffects;
  };
}

#endif