//
// 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.
//
// Implementation: Simon Chamberland
// Project Manager: Froduald Kabanza
//

#ifndef _TEMPORAL_AND_EXP_H
#define _TEMPORAL_AND_EXP_H

#include "../../ITemporalExp.h"
#include "../../FlatListExp.h"

namespace planning
{
  /// <summary>
  /// This class represents a conjunction of constraint expressions.
  /// </summary>
  class TemporalAndExp : public FlatListExp<ITemporalExp>, public ITemporalExp
  {
  public:
    template <class Iterator>
    TemporalAndExp(size_t n, Iterator elementsBegin, Iterator elementsEnd)
      : FlatListExp<ITemporalExp>(n, s_image, elementsBegin, elementsEnd)
    {
      INITIALIZE_HASH_CODE();
    }

    TemporalAndExp(const ITemporalExp* exp1, const ITemporalExp* exp2)
      : FlatListExp<ITemporalExp>(s_image, exp1, exp2)
    {
      INITIALIZE_HASH_CODE();
    }

    virtual ProgressionValue progress(const IDurativeClosedWorld* world, const Bindings* bindings) const;

    virtual bool evaluateIdle(const IDurativeClosedWorld* world, const Bindings* bindings) const;

  protected:
    virtual size_t _calculateHashCode() const
    {
      return CALCULATE_HASH_CODE(FlatListExp)
           + 95803;
    }

    virtual const IExp* _internalApply(const Bindings* bindings) const;

  private:
    static const std::string s_image;

    ///// <summary>
    ///// Creates a new conjunction of constraint expressions.
    ///// </summary>
    ///// <param name="exps">The constraint expressions associated with the new conjunctive 
    ///// expression.</param>
    //public AndConstraintExp(IEnumerable<IConstraintExp> exps)
    //  : base(exps)
    //{
    //  System.Diagnostics.Debug.Assert(exps != null && !exps.ContainsNull());
    //}

    ///// <summary>
    ///// Creates a new conjunction of constraint expressions.
    ///// </summary>
    ///// <param name="exps">The constraint expressions associated with the new conjunctive 
    ///// expression.</param>
    //public AndConstraintExp(params IConstraintExp[] exps)
    //  : this((IEnumerable<IConstraintExp>)exps)
    //{
    //  System.Diagnostics.Debug.Assert(exps != null && !exps.ContainsNull());
    //}

    ///// <summary>
    ///// Evaluates the progression of this constraint expression in the next worlds.
    ///// The algorithm is: Progress(and formula1 ...) => (and Progress(formula1) ...)
    ///// </summary>
    ///// <param name="world">The current world.</param>
    ///// <param name="bindings">A set of variable bindings.</param>
    ///// <returns>True, false, undefined, or a progressed expression.</returns>
    ///// <seealso cref="IConstraintExp.Progress"/>
    //public virtual ProgressionValue Progress(IReadOnlyDurativeClosedWorld world, LocalBindings bindings)
    //{
    //  ProgressionValue result = ProgressionValue.True;
    //  foreach (IConstraintExp exp in this.m_expressions)
    //  {
    //    result = result & exp.Progress(world, bindings);
    //    if (!result)
    //      break;
    //  }
    //  return result;
    //}

    ///// <summary>
    ///// Evaluates this constraint expression in an idle world, i.e. a world which
    ///// won't be modified by further updates.
    ///// </summary>
    ///// <param name="idleWorld">The (idle) evaluation world.</param>
    ///// <param name="bindings">A set of variable bindings.</param>
    ///// <returns>True, false, or undefined.</returns>
    ///// <seealso cref="IConstraintExp.EvaluateIdle"/>
    //public virtual Bool EvaluateIdle(IReadOnlyDurativeClosedWorld idleWorld, LocalBindings bindings)
    //{
    //  Bool value = Bool.True;
    //  foreach (IConstraintExp exp in this.m_expressions)
    //  {
    //    value = value & exp.EvaluateIdle(idleWorld, bindings);
    //    if (!value)
    //      break;
    //  }
    //  return value;
    //}
  };
}

#endif