//
// 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
//

#include "stdafx.h"
#include "NotAtomicFormulaApplication.h"
#include "../Formula/Described/AtomicFormulaApplication.h"
#include "../../World/IDurativeClosedWorld.h"

#include <assert.h>

using namespace planning;

/// <summary>
/// Creates a new negative atomic formula application.
/// </summary>
/// <param name="atom">The atomic formula application to unset.</param>
NotAtomicFormulaApplication::NotAtomicFormulaApplication(const AtomicFormulaApplication* atom)
  : m_atom(atom)
{
  assert(m_atom != 0);
  m_atom->acquire(this);
  INITIALIZE_HASH_CODE();
}

NotAtomicFormulaApplication::~NotAtomicFormulaApplication()
{
  m_atom->release(this);
}

/// <summary>
/// Gets the predicate associated with this literal.
/// </summary>
const AtomicFormula* NotAtomicFormulaApplication::getAtomicFormula() const
{
  return m_atom->getAtomicFormula();
}

/// <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>
void NotAtomicFormulaApplication::update(const IClosedWorld* evaluationWorld, 
                                         IDurativeClosedWorld* updateWorld, 
                                         const Bindings* bindings, 
                                         const ActionContext* actionContext) const
{
  const AtomicFormulaApplication* groundFormula = m_atom->evaluateArguments(evaluationWorld, bindings);
  updateWorld->unset(groundFormula);
}

void NotAtomicFormulaApplication::_output(std::ostream& out) const
{
  out << "(not " << *m_atom << ")";
}

size_t NotAtomicFormulaApplication::_calculateHashCode() const
{
  return 51 * m_atom->getHashCode()
       + 8530023;
}

const IExp* NotAtomicFormulaApplication::_internalApply(const Bindings* bindings) const
{
  return new NotAtomicFormulaApplication(m_atom->apply(bindings));
}

int NotAtomicFormulaApplication::_internalCompareTo(const IExp& other) const
{
  const NotAtomicFormulaApplication& exp = dynamic_cast<const NotAtomicFormulaApplication&>(other);

  COMPARE(m_atom, exp.m_atom);

  return 0;
}

