//
// 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 _NOT_ATOMIC_FORMULA_APPLICATION
#define _NOT_ATOMIC_FORMULA_APPLICATION

#include "../ILiteral.h"

namespace planning
{
  /// <summary>
  /// A negative atomic formula application unsets an atomic formula from a given world.
  /// Unlike an atomic formula application, a negative atomic formula application can only 
  /// be used as an effect.
  /// </summary>
  class NotAtomicFormulaApplication: public ILiteral
  {
  public:
    /// <summary>
    /// Creates a new negative atomic formula application.
    /// </summary>
    /// <param name="atom">The atomic formula application to unset.</param>
    NotAtomicFormulaApplication(const AtomicFormulaApplication* atom);

    ~NotAtomicFormulaApplication();

    /// <summary>
    /// Gets the predicate associated with this literal.
    /// </summary>
    virtual const AtomicFormula* getAtomicFormula() const;

    /// <summary>
    /// Updates the specified world with this effect.
    /// A negative atomic formula application unsets the appropriate negative atomic formula
    /// application in the specified world.
    /// </summary>
    /// <param name="evaluationWorld">The world to evaluate conditions against. Note that this is 
    /// usually the un-modified version of the world to update.</param>
    /// <param name="updateWorld">The world to update.</param>
    /// <param name="bindings">A set of variable bindings.</param>
    /// <param name="actionContext">The action evaluation context.</param>
    virtual void update(const IClosedWorld* evaluationWorld, 
                        IDurativeClosedWorld* updateWorld, 
                        const Bindings* bindings, 
                        const ActionContext* actionContext) const;

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

    virtual size_t _calculateHashCode() const;

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

    virtual int _internalCompareTo(const IExp& other) const;

  private:
    /// <summary>
    /// The atomic formula application to unset.
    /// </summary>
    const AtomicFormulaApplication* m_atom;

    ///// <summary>
    ///// Retrieves the root atomic formula modified by this atomic formula application.
    ///// </summary>
    ///// <returns>The root atomic formula modified by this atomic formula application.</returns>
    //public HashSet<DescribedFormula> GetModifiedDescribedFormulas()
    //{
    //  return this.m_atom.GetModifiedDescribedFormulas();
    //}

    ///// <summary>
    ///// Returns a typed string representation of this expression.
    ///// </summary>
    ///// <returns>A typed string representation of this expression.</returns>
    //public override string ToTypedString()
    //{
    //  StringBuilder str = new StringBuilder();
    //  str.Append("(not ");
    //  str.Append(this.m_atom.ToTypedString());
    //  str.Append(")");
    //  return str.ToString();
    //}


    //#region IComparable<IExp> Members

    ///// <summary>
    ///// Compares this negative atomic formula application with another expression.
    ///// </summary>
    ///// <param name="other">The other expression to compare this expression to.</param>
    ///// <returns>An integer representing the total order relation between the two expressions.</returns>
    //public override int CompareTo(IExp other)
    //{
    //  int value = base.CompareTo(other);
    //  if (value != 0)
    //    return value;

    //  NotAtomicFormulaApplication otherFormula = (NotAtomicFormulaApplication)other;
    //  return this.m_atom.CompareTo(otherFormula.m_atom);
    //}

    //#endregion
  };
}

#endif