//
// 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 "GoalModalityExp.h"

#include <stdexcept>
#include <assert.h>

using namespace planning;

bool GoalModalityExp::s_atLeastOneGoalModality = false;
ILogicalExp::PartialWorldSet GoalModalityExp::s_goalWorlds = ILogicalExp::PartialWorldSet();

GoalModalityExp::GoalModalityExp(const ILogicalExp* exp)
  : m_exp(exp)
{
  s_atLeastOneGoalModality = true;
  assert(m_exp != NULL);
  m_exp->acquire(this);

  INITIALIZE_HASH_CODE();
}

GoalModalityExp::~GoalModalityExp()
{
  m_exp->release(this);
}

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

bool GoalModalityExp::evaluate(const Bindings* bindings) const
{
  // TODO: cache result according to bindings?

  // TODO: (a ^ ~a) should return false in all goal worlds... even if predicate not present in dictionary

  bool result = true;
  for (PartialWorldSet::const_iterator it = s_goalWorlds.begin();
       it != s_goalWorlds.end() && result;
       ++it)
  {
    if (!m_exp->evaluate(*it, bindings))
      result = false;
  }
  return result;
}

bool GoalModalityExp::evaluate(const IClosedWorld* world, const Bindings* bindings) const
{
  // Evaluation result does not depend on evaluation world

  return evaluate(bindings);
}

void GoalModalityExp::enumerateSatisfyingWorlds(PartialWorldSet& worlds) const
{
  throw std::runtime_error("GoalModalityExp::enumerateSatisfyingWorlds() is not supported");
}

void GoalModalityExp::_output(std::ostream& out) const
{
  out << "(GOAL " << *m_exp << ")";
}

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

  COMPARE(m_exp, exp.m_exp);

  return 0;
}
