//
// 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 "PrimitiveType.h"
#include "../Object.h"

using namespace planning;

PrimitiveType PrimitiveType::s_objectType("object");

PrimitiveType::PrimitiveType(const std::string &name)
  : m_name(name)
{
  //
  // This constructor should only be used by the object type
  //
  // Never going to be released
  _markAsStatic();
}

PrimitiveType::PrimitiveType(const std::string &name, Type *superType)
  : m_name(name)
{
  assert(superType != NULL);

  superType->addSubType(this);
}

PrimitiveType::~PrimitiveType()
{
  clearObjects();
}

bool PrimitiveType::isSubsetOf(const Type* other) const
{
  return other->isSupersetOf(this);
}

bool PrimitiveType::isSupersetOf(const PrimitiveType* other) const
{
  bool superset = (this == other);
  for (std::set<PrimitiveType*>::const_iterator it = m_subTypes.begin();
       !superset && it != m_subTypes.end();
       ++it)
  {
    superset = (*it)->isSupersetOf(other);
  }
  return superset;
}

bool PrimitiveType::intersectsWith(const PrimitiveType* other) const
{
  return this->isSupersetOf(other) || other->isSupersetOf(this);
}

bool PrimitiveType::intersectsWith(const Type* other) const
{
  return other->intersectsWith(this);
}

void PrimitiveType::addSubType(PrimitiveType *type)
{
  std::pair<std::set<PrimitiveType*>::iterator, bool> result = m_subTypes.insert(type);
  assert(result.second);
}

const std::string& PrimitiveType::getName() const
{
  return m_name;
}

void PrimitiveType::clearObjects()
{
  Type::clearObjects();
  memory::release(this, m_objects.begin(), m_objects.end());
  m_objects.clear();
}

void PrimitiveType::addObject(const Object* object)
{
  object->acquire(this);
  m_objects.insert(object);
}

void PrimitiveType::retrieveDomain(stdext::hash_set<const Object*>& domain)
{
  domain.insert(m_objects.begin(), m_objects.end());

  for (std::set<PrimitiveType*>::const_iterator it = m_subTypes.begin();
       it != m_subTypes.end();
       ++it)
  {
    (*it)->cacheDomain();

    domain.insert((*it)->domainBegin(), (*it)->domainEnd());
  }
}

void PrimitiveType::_output(std::ostream& out) const
{
  out << m_name;
}