//=========================================================================
//  Copyright (c) Kitware, Inc.
//  All rights reserved.
//  See LICENSE.txt for details.
//
//  This software is distributed WITHOUT ANY WARRANTY; without even
//  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
//  PURPOSE.  See the above copyright notice for more information.
//=========================================================================
#include "smtk/model/Manager.h"

#include "smtk/attribute/Attribute.h"
#include "smtk/attribute/System.h"

#include "smtk/model/AttributeAssignments.h"
#include "smtk/model/AuxiliaryGeometry.h"
#include "smtk/model/Chain.h"
#include "smtk/model/DefaultSession.h"
#include "smtk/model/Edge.h"
#include "smtk/model/EdgeUse.h"
#include "smtk/model/EntityIterator.h"
#include "smtk/model/EntityRefArrangementOps.h"
#include "smtk/model/Face.h"
#include "smtk/model/FaceUse.h"
#include "smtk/model/Group.h"
#include "smtk/model/Instance.h"
#include "smtk/model/Loop.h"
#include "smtk/model/Model.h"
#include "smtk/model/SessionRef.h"
#include "smtk/model/Shell.h"
#include "smtk/model/ShellEntity.txx"
#include "smtk/model/StoredResource.h"
#include "smtk/model/Vertex.h"
#include "smtk/model/VertexUse.h"
#include "smtk/model/Volume.h"
#include "smtk/model/VolumeUse.h"

#include "smtk/mesh/Manager.h"

#include "smtk/common/ResourceSet.h"

#include <float.h>

#include <algorithm>
#include <iterator>
#include <map>
#include <set>
#include <vector>

#include <sstream>

//#include <boost/variant.hpp>

using namespace std;
using namespace smtk::common;

namespace smtk
{
namespace model
{

/**@name Constructors and destructors.
  *\brief Model manager instances should always be created using the static create() method.
  *
  */
//@{
/// Create a default, empty model manager.
Manager::Manager()
  : m_topology(new UUIDsToEntities)
  , m_floatData(new UUIDsToFloatData)
  , m_stringData(new UUIDsToStringData)
  , m_integerData(new UUIDsToIntegerData)
  , m_arrangements(new UUIDsToArrangements)
  , m_tessellations(new UUIDsToTessellations)
  , m_analysisMesh(new UUIDsToTessellations)
  , m_meshes(smtk::mesh::Manager::create())
  , m_attributeAssignments(new UUIDsToAttributeAssignments)
  , m_sessions(new UUIDsToSessions)
  , m_resources(new ResourceSet)
  , m_globalCounters(2, 1) // first entry is session counter, second is model counter
{
  // TODO: throw() when topology == NULL?
  this->m_log.setFlushToStdout(false);
}

/// Create a model manager using the given storage instances.
Manager::Manager(shared_ptr<UUIDsToEntities> inTopology,
  shared_ptr<UUIDsToArrangements> inArrangements, shared_ptr<UUIDsToTessellations> tess,
  shared_ptr<UUIDsToTessellations> analysismesh, shared_ptr<smtk::mesh::Manager> meshes,
  shared_ptr<UUIDsToAttributeAssignments> attribs)
  : m_topology(inTopology)
  , m_floatData(new UUIDsToFloatData)
  , m_stringData(new UUIDsToStringData)
  , m_integerData(new UUIDsToIntegerData)
  , m_arrangements(inArrangements)
  , m_tessellations(tess)
  , m_analysisMesh(analysismesh)
  , m_meshes(meshes)
  , m_attributeAssignments(attribs)
  , m_sessions(new UUIDsToSessions)
  , m_resources(new ResourceSet)
  , m_globalCounters(2, 1) // first entry is session counter, second is model counter
{
  this->m_log.setFlushToStdout(false);
}

/// Destroying a model manager requires us to release the default attribute manager..
Manager::~Manager()
{
  if (this->m_defaultSession)
  {
    // NB: We must pass "false" for the expungeSession argument because
    // the manager may have 0 shared-pointer references at this point
    // and thus cannot construct trigger callback cursors to notify
    // listeners that deletions are occurring.
    this->unregisterSession(this->m_defaultSession, false);
  }
  this->m_attributeAssignments->clear();
}
//@}

/**@name Direct member access.
  *\brief These methods provide direct access to the class's storage.
  *
  */
//@{
UUIDsToEntities& Manager::topology()
{
  return *this->m_topology.get();
}

const UUIDsToEntities& Manager::topology() const
{
  return *this->m_topology.get();
}

UUIDsToArrangements& Manager::arrangements()
{
  return *this->m_arrangements.get();
}

const UUIDsToArrangements& Manager::arrangements() const
{
  return *this->m_arrangements.get();
}

UUIDsToTessellations& Manager::tessellations()
{
  return *this->m_tessellations.get();
}

const UUIDsToTessellations& Manager::tessellations() const
{
  return *this->m_tessellations.get();
}

UUIDsToTessellations& Manager::analysisMesh()
{
  return *this->m_analysisMesh.get();
}

const UUIDsToTessellations& Manager::analysisMesh() const
{
  return *this->m_analysisMesh.get();
}

smtk::mesh::ManagerPtr Manager::meshes() const
{
  return this->m_meshes;
}

const UUIDsToAttributeAssignments& Manager::attributeAssignments() const
{
  return *this->m_attributeAssignments;
}
//@}

/**\brief Remove the entity with the given \a uid.
  *
  * Returns true upon success, false when the entity did not exist.
  *
  * Note that the implementation is aware of when the Manager
  * is actually a Manager and removes storage from the Manager as
  * well (including tessellation data).
  *
  * **Warning**: Invoking this method naively will likely result
  * in an inconsistent solid model. This does not cascade
  * any changes required to remove dependent entities (i.e.,
  * removing a face does not remove any face-uses or shells that
  * the face participated in, potentially leaving an improper volume
  * boundary). The application is expected to perform further
  * operations to keep the model valid.
  */
SessionInfoBits Manager::erase(const UUID& uid, SessionInfoBits flags)
{
  SessionInfoBits actual = flags;
  if (flags & SESSION_ENTITY_RELATIONS)
    actual |= SESSION_ARRANGEMENTS;

  UUIDWithEntity ent;
  bool haveEnt = false;
  if (actual & (SESSION_ENTITY_TYPE | SESSION_ENTITY_RELATIONS))
  {
    ent = this->m_topology->find(uid);
    if (ent != this->m_topology->end())
    {
      haveEnt = true;
      if (flags & SESSION_ENTITY_TYPE)
      {
        // Trigger an event before the erasure so the observers
        // have a chance to see what's about to disappear.
        this->trigger(
          std::make_pair(DEL_EVENT, ENTITY_ENTRY), EntityRef(this->shared_from_this(), uid));
      }
    }
    else
    { // without an Entity record, we cannot erase these things:
      actual &= ~(SESSION_ENTITY_TYPE | SESSION_ENTITY_RELATIONS);
    }
  }

  if (flags & SESSION_ARRANGEMENTS)
  {
    UUIDWithArrangementDictionary ad = this->arrangements().find(uid);
    if (ad != this->arrangements().end())
    {
      ArrangementKindWithArrangements ak;
      do
      {
        ak = ad->second.begin();
        if (ak == ad->second.end())
          break;
        Arrangements::size_type aidx = ak->second.size();
        if (aidx == 0)
          ad->second.erase(ak);
        else
          for (; aidx > 0; --aidx)
            this->unarrangeEntity(uid, ak->first, static_cast<int>(aidx - 1), false);
        ad = this->arrangements().find(uid); // iterator may be invalidated by unarrangeEntity.
      } while (ad != this->arrangements().end());
    }
  }

  if (actual & SESSION_TESSELLATION)
    this->tessellations().erase(uid);

  if (actual & SESSION_ATTRIBUTE_ASSOCIATIONS)
    this->m_attributeAssignments->erase(uid);

  // TODO: If this entity is a model and has parents, we should make
  //       the parent own the child models? Erase the children? Leave
  //       the children as orphans?

  if (haveEnt)
  {
    // Before removing the entity, loop through its relations and
    // make sure none of them retain any references back to \a uid.
    // However, we cannot erase entries in relatedEntity->relations()
    // because relatedEntity's arrangements reference them by integer
    // index. Thus, we call elideEntityReferences rather than removeEntityReferences.
    this->elideEntityReferences(ent);
  }

  // TODO: Notify observers of property removal?
  if (actual & SESSION_USER_DEFINED_PROPERTIES)
  {
    if (actual & SESSION_FLOAT_PROPERTIES)
      this->m_floatData->erase(uid);
    if (actual & SESSION_STRING_PROPERTIES)
      this->m_stringData->erase(uid);
    if (actual & SESSION_INTEGER_PROPERTIES)
      this->m_integerData->erase(uid);
  }
  else if (actual & SESSION_PROPERTIES)
  {
    SessionRef sref(shared_from_this(), uid);
    if (!sref.isValid())
    {
      Model owningModel(shared_from_this(), this->modelOwningEntity(uid));
      sref = owningModel.session();
    }
    if (sref.session())
      sref.session()->removeGeneratedProperties(EntityRef(shared_from_this(), uid), actual);
  }

  if (haveEnt)
  {
    // TODO: Notify model of entity removal?
    //       Note this can be complicated because removal
    //       of entities in the class destructor prevent us
    //       from obtaining a shared pointer to the manager
    //       to pass to any observers...
    this->m_topology->erase(uid);
  }

  return actual;
}

/**\brief A convenience method for erasing an entity from storage.
  *
  */
SessionInfoBits Manager::erase(const EntityRef& entityref, SessionInfoBits flags)
{
  return this->Manager::erase(entityref.entity(), flags);
}

/**\brief Erase records related to the entity with no clean or safety checks.
  *
  * Returns bit flags indicating what types of data were erased.
  *
  * **Warning**: If \a flags contains SESSION_PROPERTIES and *not* SESSION_USER_DEFINED_PROPERTIES,
  * then \a eref will be queried for its owning model and the model for its owning session.
  * This can lead to problems if relationships have been erased by previous calls to hardErase.
  */
SessionInfoBits Manager::hardErase(const EntityRef& eref, SessionInfoBits flags)
{
  smtk::common::UUID uid(eref.entity());
  if (!uid)
  {
    return SessionInfoBits(0);
  }

  SessionInfoBits actual = flags;
  if (flags & SESSION_ENTITY_RELATIONS)
    actual |= SESSION_ARRANGEMENTS;

  UUIDWithEntity ent;
  if (actual & (SESSION_ENTITY_TYPE | SESSION_ENTITY_RELATIONS))
  {
    if (!this->m_topology->erase(uid))
    { // without an Entity record, we cannot erase these things:
      actual &= ~(SESSION_ENTITY_TYPE | SESSION_ENTITY_RELATIONS);
    }
  }

  if (flags & SESSION_ARRANGEMENTS)
  {
    if (!this->arrangements().erase(uid))
    {
      actual &= ~SESSION_ARRANGEMENTS;
    }
  }

  if (actual & SESSION_TESSELLATION)
  {
    if (!this->tessellations().erase(uid))
    {
      actual &= ~SESSION_TESSELLATION;
    }
  }

  if (actual & SESSION_ATTRIBUTE_ASSOCIATIONS)
  {
    if (!this->m_attributeAssignments->erase(uid))
    {
      actual &= ~SESSION_ATTRIBUTE_ASSOCIATIONS;
    }
  }

  if (actual & SESSION_USER_DEFINED_PROPERTIES)
  {
    if (actual & SESSION_FLOAT_PROPERTIES)
    {
      if (!this->m_floatData->erase(uid))
      {
        actual &= ~SESSION_FLOAT_PROPERTIES;
      }
    }
    if (actual & SESSION_STRING_PROPERTIES)
    {
      if (!this->m_stringData->erase(uid))
      {
        actual &= ~SESSION_STRING_PROPERTIES;
      }
    }
    if (actual & SESSION_INTEGER_PROPERTIES)
    {
      if (!this->m_integerData->erase(uid))
      {
        actual &= ~SESSION_INTEGER_PROPERTIES;
      }
    }
  }
  else if (actual & SESSION_PROPERTIES)
  {
    SessionRef sref(shared_from_this(), uid);
    if (!sref.isValid())
    {
      Model owningModel(shared_from_this(), this->modelOwningEntity(uid));
      sref = owningModel.session();
    }
    if (sref.session())
    {
      sref.session()->removeGeneratedProperties(EntityRef(shared_from_this(), uid), actual);
    }
  }
  return actual;
}

/**\brief A convenience method for erasing a model and its children.
  *
  * This removes the model plus all of its free cells, groups, and
  * submodels from storage.
  * This method will have no effect given an invalid model entity.
  */
SessionInfoBits Manager::eraseModel(const Model& model, SessionInfoBits flags)
{
  if (!model.isValid())
    return SESSION_NOTHING;

  CellEntities free = model.cells();
  for (CellEntities::iterator fit = free.begin(); fit != free.end(); ++fit)
  {
    EntityRefs bdys = fit->lowerDimensionalBoundaries(-1);
    for (EntityRefs::iterator bit = bdys.begin(); bit != bdys.end(); ++bit)
    {
      //std::cout << "Erasing " << bit->flagSummary(0) << " " << bit->entity() << "\n";
      this->erase(bit->entity(), flags);
    }
    //std::cout << "Erasing " << fit->flagSummary(0) << " " << fit->entity() << "\n";
    this->erase(fit->entity(), flags);
  }

  Groups grps = model.groups();
  for (Groups::iterator git = grps.begin(); git != grps.end(); ++git)
  {
    EntityRefs members = git->members<EntityRefs>();
    for (EntityRefs::iterator mit = members.begin(); mit != members.end(); ++mit)
    {
      //std::cout << "Erasing " << mit->flagSummary(0) << " " << mit->entity() << "\n";
      this->erase(mit->entity(), flags);
    }
    //std::cout << "Erasing " << git->flagSummary(0) << " " << git->entity() << "\n";
    this->erase(git->entity(), flags);
  }

  //std::cout << "Erasing " << model.flagSummary(0) << " " << model.entity() << "\n";
  this->erase(model.entity(), flags);

  return true;
}

/// Entity construction
//@{
/// Return a currently-unused UUID (guaranteed not to collide if inserted immediately).
UUID Manager::unusedUUID()
{
  UUID actual;
  do
  {
    actual = this->m_uuidGenerator.random();
  } while (this->m_topology->find(actual) != this->m_topology->end());
  return actual;
}

/// Insert a new cell of the specified \a dimension, returning an iterator with a new, unique UUID.
Manager::iter_type Manager::insertEntityOfTypeAndDimension(BitFlags entityFlags, int dim)
{
  UUID actual = this->unusedUUID();
  return this->setEntityOfTypeAndDimension(actual, entityFlags, dim);
}

/// Insert the specified cell, returning an iterator with a new, unique UUID.
Manager::iter_type Manager::insertEntity(Entity& c)
{
  UUID actual = this->unusedUUID();
  return this->setEntity(actual, c);
}

/**\brief Create and map a new cell of the given \a dimension to the given \a uid.
  *
  * Passing a null or non-unique \a uid is an error here and will throw an exception.
  *
  * Some checking and initialization is performed based on \a entityFlags and \a dim,
  * as described below.
  *
  * If the Manager may be cast to a Manager instance and an entity
  * is expected to have a known, fixed number of arrangements of some sort,
  * those are created here so that entityrefs may always rely on their existence
  * even in the absence of the related UUIDs appearing in the entity's relations.
  * For face cells (CELL_2D) entites, two HAS_USE Arrangements are created to
  * reference FaceUse instances.
  */
Manager::iter_type Manager::setEntityOfTypeAndDimension(
  const UUID& uid, BitFlags entityFlags, int dim)
{
  UUIDsToEntities::iterator it;
  if (uid.isNull())
  {
    std::ostringstream msg;
    msg << "Nil UUID";
    throw msg.str();
  }
  if (((it = this->m_topology->find(uid)) != this->m_topology->end()) &&
    (entityFlags & GROUP_ENTITY) != 0 && dim >= 0 && it->second.dimension() != dim)
  {
    std::ostringstream msg;
    msg << "Duplicate UUID '" << uid << "' of different dimension " << it->second.dimension()
        << " != " << dim;
    throw msg.str();
  }
  std::pair<UUID, Entity> entry(uid, Entity(entityFlags, dim));
  this->prepareForEntity(entry);
  std::pair<Manager::iter_type, bool> result = this->m_topology->insert(entry);

  if (result.second)
  {
    this->trigger(
      std::make_pair(ADD_EVENT, ENTITY_ENTRY), EntityRef(this->shared_from_this(), uid));
  }

  return result.first;
}

/**\brief Map the specified cell \a c to the given \a uid.
  *
  * Passing a nil or non-unique \a uid is an error here and will throw an exception.
  */
Manager::iter_type Manager::setEntity(const UUID& uid, Entity& c)
{
  UUIDsToEntities::iterator it;
  if (uid.isNull())
  {
    std::ostringstream msg;
    msg << "Nil UUID";
    throw msg.str();
  }
  if ((it = this->m_topology->find(uid)) != this->m_topology->end())
  {
    if (it->second.dimension() != c.dimension())
    {
      std::ostringstream msg;
      msg << "Duplicate UUID '" << uid << "' of different dimension " << it->second.dimension()
          << " != " << c.dimension();
      throw msg.str();
    }
    this->removeEntityReferences(it);
    it->second = c;
    this->insertEntityReferences(it);
    return it;
  }
  std::pair<UUID, Entity> entry(uid, c);
  this->prepareForEntity(entry);
  it = this->m_topology->insert(entry).first;
  this->insertEntityReferences(it);
  return it;
}

/// A wrappable version of InsertEntityOfTypeAndDimension
UUID Manager::addEntityOfTypeAndDimension(BitFlags entityFlags, int dim)
{
  return this->insertEntityOfTypeAndDimension(entityFlags, dim)->first;
}

/// A wrappable version of InsertEntity
UUID Manager::addEntity(Entity& cell)
{
  return this->insertEntity(cell)->first;
}

/// A wrappable version of SetEntityOfTypeAndDimension
UUID Manager::addEntityOfTypeAndDimensionWithUUID(const UUID& uid, BitFlags entityFlags, int dim)
{
  return this->setEntityOfTypeAndDimension(uid, entityFlags, dim)->first;
}

/// A wrappable version of SetEntity
UUID Manager::addEntityWithUUID(const UUID& uid, Entity& cell)
{
  return this->setEntity(uid, cell)->first;
}
//@}

/// Shortcuts for inserting cells with default entity flags.
//@{
Manager::iter_type Manager::insertCellOfDimension(int dim)
{
  return this->insertEntityOfTypeAndDimension(CELL_ENTITY, dim);
}

Manager::iter_type Manager::setCellOfDimension(const UUID& uid, int dim)
{
  return this->setEntityOfTypeAndDimension(uid, CELL_ENTITY, dim);
}

UUID Manager::addCellOfDimension(int dim)
{
  return this->addEntityOfTypeAndDimension(CELL_ENTITY, dim);
}

UUID Manager::addCellOfDimensionWithUUID(const UUID& uid, int dim)
{
  return this->addEntityOfTypeAndDimensionWithUUID(uid, CELL_ENTITY, dim);
}
//@}

/// Queries on entities belonging to the solid.
//@{
/// Return the type of entity that the link represents.
BitFlags Manager::type(const UUID& ofEntity) const
{
  UUIDsToEntities::iterator it = this->m_topology->find(ofEntity);
  return (it == this->m_topology->end() ? INVALID : it->second.entityFlags());
}

/// Return the dimension of the manifold that the passed entity represents.
int Manager::dimension(const UUID& ofEntity) const
{
  UUIDsToEntities::iterator it = this->m_topology->find(ofEntity);
  return (it == this->m_topology->end() ? -1 : it->second.dimension());
}

/**\brief Return a name for the given entity ID.
  *
  * This will either return a user-specified name or the "short UUID" name
  * of the entity. It will not assign a name to the entity using the model
  * counters because the method is const.
  */
std::string Manager::name(const UUID& ofEntity) const
{
  if (this->hasStringProperty(ofEntity, "name"))
  {
    smtk::model::StringList const& nprop(this->stringProperty(ofEntity, "name"));
    if (!nprop.empty())
    {
      return nprop[0];
    }
  }
  UUIDsToEntities::iterator it = this->m_topology->find(ofEntity);
  if (it == this->m_topology->end())
  {
    return "invalid id " + ofEntity.toString();
  }
  return Manager::shortUUIDName(it->first, it->second.entityFlags());
}

/**\brief Return the (Dimension+1 or higher)-entities that are the immediate bordants of the passed entity.
  *
  * \sa HigherDimensionalBoundaries
  */
UUIDs Manager::bordantEntities(const UUID& ofEntity, int ofDimension) const
{
  UUIDs result;
  UUIDsToEntities::const_iterator it = this->m_topology->find(ofEntity);
  if (it == this->m_topology->end())
  {
    return result;
  }
  if (ofDimension >= 0 && it->second.dimension() >= ofDimension)
  {
    // can't ask for "higher" dimensional boundaries that are lower than the dimension of this cell.
    return result;
  }
  UUIDsToEntities::const_iterator other;
  for (UUIDArray::const_iterator ai = it->second.relations().begin();
       ai != it->second.relations().end(); ++ai)
  {
    other = this->m_topology->find(*ai);
    if (other == this->m_topology->end())
    { // TODO: silently skip bad relations or complain?
      continue;
    }
    if ((ofDimension >= 0 && other->second.dimension() == ofDimension) ||
      (ofDimension == -2 && other->second.dimension() >= it->second.dimension()))
    { // The dimension is higher, so dumbly push it into the result:
      result.insert(*ai);
    }
    else if ((it->second.entityFlags() & CELL_ENTITY) && (other->second.entityFlags() & USE_ENTITY))
    { // ... or it is a use: follow the use upwards.
      ShellEntities bshells = UseEntity(smtk::const_pointer_cast<Manager>(shared_from_this()), *ai)
                                .boundingShellEntities<ShellEntities>();
      for (ShellEntities::iterator shellIt = bshells.begin(); shellIt != bshells.end(); ++shellIt)
      {
        CellEntity cell = shellIt->boundingCell();
        if (cell.dimension() >= ofDimension)
        {
          result.insert(cell.entity());
        }
      }
    }
  }
  return result;
}

/**\brief Return the (Dimension+1 or higher)-entities that are the immediate bordants of any of the passed entities.
  *
  * \sa HigherDimensionalBoundaries
  */
UUIDs Manager::bordantEntities(const UUIDs& ofEntities, int ofDimension) const
{
  UUIDs result;
  std::insert_iterator<UUIDs> inserter(result, result.begin());
  for (UUIDs::const_iterator it = ofEntities.begin(); it != ofEntities.end(); ++it)
  {
    UUIDs brd = this->bordantEntities(*it, ofDimension);
    std::copy(brd.begin(), brd.end(), inserter);
  }
  return result;
}

/**\brief Return the (Dimension-1 or lower)-entities that are the immediate boundary of the passed entity.
  *
  * \sa LowerDimensionalBoundaries
  */
UUIDs Manager::boundaryEntities(const UUID& ofEntity, int ofDimension) const
{
  UUIDs result;
  UUIDsToEntities::const_iterator it = this->m_topology->find(ofEntity);
  if (it == this->m_topology->end())
  {
    return result;
  }
  if (ofDimension >= 0 && it->second.dimension() <= ofDimension)
  {
    // can't ask for "lower" dimensional boundaries that are higher than the dimension of this cell.
    return result;
  }
  UUIDsToEntities::iterator other;
  for (UUIDArray::const_iterator ai = it->second.relations().begin();
       ai != it->second.relations().end(); ++ai)
  {
    other = this->m_topology->find(*ai);
    if (other == this->m_topology->end())
    { // TODO: silently skip bad relations or complain?
      continue;
    }
    if ((ofDimension >= 0 && other->second.dimension() == ofDimension) ||
      (ofDimension == -2 && other->second.dimension() <= it->second.dimension()))
    {
      result.insert(*ai);
    }
    else if ((it->second.entityFlags() & CELL_ENTITY) && (other->second.entityFlags() & USE_ENTITY))
    { // ... or it is a use: follow the use downwards.
      ShellEntities shells = UseEntity(smtk::const_pointer_cast<Manager>(shared_from_this()), *ai)
                               .shellEntities<ShellEntities>();
      for (ShellEntities::iterator shellIt = shells.begin(); shellIt != shells.end(); ++shellIt)
      {
        CellEntities cells = shellIt->cellsOfUses<CellEntities>();
        for (CellEntities::iterator cellIt = cells.begin(); cellIt != cells.end(); ++cellIt)
        {
          if (cellIt->dimension() <= ofDimension)
          {
            result.insert(cellIt->entity());
          }
        }
        // Add any inner shells owned by this outer shell. Note the iterator math:
        // since shellIt can be invalidated as we add new entries to the vector,
        // we recompute shellIt after insertion.
        std::size_t itposn = shellIt - shells.begin();
        ShellEntities innerShells = shellIt->containedShellEntities<ShellEntities>();
        shells.insert(shells.end(), innerShells.begin(), innerShells.end());
        shellIt = shells.begin() + itposn;
      }
    }
  }
  return result;
}

/**\brief Return the (Dimension-1 or lower)-entities that are the immediate boundary of any of the passed entities.
  *
  * \sa LowerDimensionalBoundaries
  */
UUIDs Manager::boundaryEntities(const UUIDs& ofEntities, int ofDimension) const
{
  UUIDs result;
  std::insert_iterator<UUIDs> inserter(result, result.begin());
  for (UUIDs::const_iterator it = ofEntities.begin(); it != ofEntities.end(); ++it)
  {
    UUIDs bdy = this->boundaryEntities(*it, ofDimension);
    std::copy(bdy.begin(), bdy.end(), inserter);
  }
  return result;
}

/**\brief Return lower-dimensional boundaries of the passed d-dimensional entity.
  *
  * \a lowerDimension may be any dimension < d.
  * Unlike Manager::boundaryEntities(), this method will search the boundaries
  * of the entity's boundaries.
  * For example, a 2-dimensional face normally stores 1-dimensional edges
  * as its immediate boundaries, so if BoundaryEntities() is asked for 0-dimensional
  * entities none will usually be reported (the exception being an isolated vertex
  * lying on the face with no edges attached).
  * But LowerDimensionalBoundaries() will return the corners of the edges when asked
  * for 0-dimensional boundaries.
  *
  * Passing -1 will return all boundary entities of the specified entity,
  * regardless of their dimension.
  */
UUIDs Manager::lowerDimensionalBoundaries(const UUID& ofEntity, int lowerDimension)
{
  UUIDs result;
  UUIDsToEntities::iterator it = this->m_topology->find(ofEntity);
  if (it == this->m_topology->end())
  {
    return result;
  }
  if (it->second.dimension() <= lowerDimension)
  {
    // do nothing
  }
  else
  {
    // FIXME: This only works for the "usual" case where
    //        a cell's relations are dimension (d+1) or
    //        (d-1). We should also collect any out-of-place
    //        relations that match lowerDimension as we go.
    int currentDim = it->second.dimension() - 1;
    int delta = currentDim - lowerDimension;
    result = this->boundaryEntities(ofEntity, currentDim--);
    for (int i = delta; i > 0; --i, --currentDim)
    {
      UUIDs tmp = this->boundaryEntities(result, currentDim);
      if (lowerDimension >= 0)
        result.clear();
      result.insert(tmp.begin(), tmp.end());
    }
  }
  return result;
}

/**\brief Return higher-dimensional bordants of the passed d-dimensional entity.
  *
  * \a higherDimension may be any dimension > d.
  * Unlike Manager::bordantEntities(), this method will search the bordants
  * of the entity's immediate bordants.
  * For example, a 1-dimensional edge normally stores 2-dimensional faces
  * as its immediate bordants, so if BoundaryEntities() is asked for 3-dimensional
  * bordants none will usually be reported (the exception being when the edge
  * is contained completely inside the volume and not attached to any boundary).
  * But HigherDimensionalBoundaries() will return all the volumes the edge borders
  * when asked for 3-dimensional boundaries.
  *
  * Passing -1 will return all bordant entities of the specified entity,
  * regardless of their dimension.
  */
UUIDs Manager::higherDimensionalBordants(const UUID& ofEntity, int higherDimension)
{
  UUIDs result;
  UUIDsToEntities::iterator it = this->m_topology->find(ofEntity);
  if (it == this->m_topology->end())
  {
    return result;
  }
  if (higherDimension >= 0 && it->second.dimension() >= higherDimension)
  {
    // do nothing
  }
  else
  {
    int currentDim = it->second.dimension() + 1;
    int delta = higherDimension < 0 ? 4 : higherDimension - currentDim;
    result = this->bordantEntities(ofEntity, currentDim++);
    for (int i = delta; i > 0; --i, ++currentDim)
    {
      UUIDs tmp = this->bordantEntities(result, currentDim);
      if (higherDimension >= 0)
        result.clear();
      result.insert(tmp.begin(), tmp.end());
    }
  }
  return result;
}

/// Return entities of the requested dimension that share a boundary relationship with the passed entity.
UUIDs Manager::adjacentEntities(const UUID& ofEntity, int ofDimension)
{
  // FIXME: Implement adjacency
  (void)ofEntity;
  (void)ofDimension;
  UUIDs result;
  return result;
}

/// Return all entities of the requested dimension that are present in the solid.
UUIDs Manager::entitiesMatchingFlags(BitFlags mask, bool exactMatch)
{
  UUIDs result;
  for (UUIDWithEntity it = this->m_topology->begin(); it != this->m_topology->end(); ++it)
  {
    BitFlags masked = it->second.entityFlags() & mask;
    if ((masked && mask == ANY_ENTITY) || (!exactMatch && masked) || (exactMatch && masked == mask))
    {
      result.insert(it->first);
    }
  }
  return result;
}

/// Return all entities of the requested dimension that are present in the solid.
UUIDs Manager::entitiesOfDimension(int dim)
{
  UUIDs result;
  for (UUIDWithEntity it = this->m_topology->begin(); it != this->m_topology->end(); ++it)
  {
    if (it->second.dimension() == dim)
    {
      result.insert(it->first);
    }
  }
  return result;
}
//@}

/**\brief Return the smtk::model::Entity associated with \a uid (or NULL).
  *
  * Note that even the const version of this method may invalidate other
  * pointers to Entity records since it may ask a Session instance to fetch
  * a dangling UUID (one marked as existing but un-transcribed) and insert
  * the Entity into Manager. If it is important that Entity pointers remain
  * valid, call with the second argument (\a trySessions) set to false.
  */
//@{
const Entity* Manager::findEntity(const UUID& uid, bool trySessions) const
{
  UUIDWithEntity it = this->m_topology->find(uid);
  if (it == this->m_topology->end())
  {
    // Not in storage... is it in any session's dangling entity list?
    // We use an evil const-cast here because we are working under the fiction
    // that fetching an entity that exists (even if it hasn't been transcribed
    // yet) does not affect storage.
    ManagerPtr self = const_cast<Manager*>(this)->shared_from_this();
    if (trySessions)
    {
      UUIDsToSessions::iterator bit;
      for (bit = self->m_sessions->begin(); bit != self->m_sessions->end(); ++bit)
      {
        if (bit->second->transcribe(EntityRef(self, uid), SESSION_ENTITY_ARRANGED, true))
        {
          it = this->m_topology->find(uid);
          if (it != this->m_topology->end())
            return &it->second;
        }
      }
    }
    return NULL;
  }
  return &it->second;
}

Entity* Manager::findEntity(const UUID& uid, bool trySessions)
{
  UUIDWithEntity it = this->m_topology->find(uid);
  if (it == this->m_topology->end())
  { // Not in storage... is it in any session's dangling entity list?
    ManagerPtr self = const_cast<Manager*>(this)->shared_from_this();
    if (trySessions && self)
    {
      UUIDsToSessions::iterator bit;
      for (bit = self->m_sessions->begin(); bit != self->m_sessions->end(); ++bit)
      {
        if (bit->second->transcribe(EntityRef(self, uid), SESSION_ENTITY_ARRANGED, true))
        {
          it = this->m_topology->find(uid);
          if (it != this->m_topology->end())
            return &it->second;
        }
      }
    }
    return NULL;
  }
  return &it->second;
}
//@}

/// Given an entity \a c, ensure that all of its references contain a reference to it.
void Manager::insertEntityReferences(const UUIDWithEntity& c)
{
  UUIDArray::const_iterator bit;
  Entity* ref;
  for (bit = c->second.relations().begin(); bit != c->second.relations().end(); ++bit)
  {
    ref = this->findEntity(*bit);
    if (ref)
    {
      ref->appendRelation(c->first);
    }
  }
}

/**\brief Given an entity \a c and the ID of one of its related entities \a r,
  *       overwrite the occurrence of \a r in \a c's array of relations with an
  *       invalid UUID.
  *
  * Use this method to avoid the need to rewrite indices into \a c's
  * array of relations held by \a c and potentially other entities related
  * to \a c.
  */
bool Manager::elideOneEntityReference(const UUIDWithEntity& c, const UUID& r)
{
  UUIDArray::const_iterator bit;
  return c->second.invalidateRelation(r) < 0 ? false : true;
}

/**\brief Given an entity \a c, ensure that all of its references
  *       contain <b>no</b> reference to it.
  *
  * This is accomplished by overwriting matching references with
  * UUID::null() rather than removing the reference from the array.
  * We do things this way because indices into the list of
  * relations are used by arrangements and we do not want to
  * rewrite arrangements.
  */
void Manager::elideEntityReferences(const UUIDWithEntity& c)
{
  UUIDArray::const_iterator bit;
  Entity* ref;
  for (bit = c->second.relations().begin(); bit != c->second.relations().end(); ++bit)
  {
    ref = this->findEntity(*bit);
    if (ref)
    {
      UUIDArray::iterator rit;
      for (rit = ref->relations().begin(); rit != ref->relations().end(); ++rit)
      {
        if (*rit == c->first)
        { // TODO: Notify *bit of imminent elision?
          *rit = UUID::null();
        }
      }
    }
  }
}

/// Given an entity \a c, ensure that all of its references contain <b>no</b> reference to it.
void Manager::removeEntityReferences(const UUIDWithEntity& c)
{
  UUIDArray::const_iterator bit;
  Entity* ref;
  for (bit = c->second.relations().begin(); bit != c->second.relations().end(); ++bit)
  {
    ref = this->findEntity(*bit);
    if (ref)
    {
      ref->invalidateRelation(c->first);
    }
  }
}

/**\brief Add entities (specified by their \a uids) to the given group (\a groupId).
  *
  * This will append \a groupId to each entity in \a uids.
  * Note that this does **not** add the proper Arrangement information
  * that Manager::findOrAddEntityToGroup() does, since Manager
  * does not store Arrangement information.
  */
void Manager::addToGroup(const UUID& groupId, const UUIDs& uids)
{
  UUIDWithEntity result = this->m_topology->find(groupId);
  if (result == this->m_topology->end())
  {
    return;
  }

  for (UUIDs::const_iterator it = uids.begin(); it != uids.end(); ++it)
  {
    result->second.appendRelation(*it);
  }
  this->insertEntityReferences(result);
}

/** @name Model property accessors.
  *
  */
///@{
void Manager::setFloatProperty(
  const UUID& entity, const std::string& propName, smtk::model::Float propValue)
{
  smtk::model::FloatList tmp;
  tmp.push_back(propValue);
  this->setFloatProperty(entity, propName, tmp);
}

void Manager::setFloatProperty(
  const UUID& entity, const std::string& propName, const smtk::model::FloatList& propValue)
{
  if (!entity.isNull())
  {
    (*this->m_floatData)[entity][propName] = propValue;
  }
}

smtk::model::FloatList const& Manager::floatProperty(
  const UUID& entity, const std::string& propName) const
{
  if (!entity.isNull())
  {
    FloatData& floats((*this->m_floatData)[entity]);
    return floats[propName];
  }
  static FloatList dummy;
  return dummy;
}

smtk::model::FloatList& Manager::floatProperty(const UUID& entity, const std::string& propName)
{
  if (!entity.isNull())
  {
    FloatData& floats((*this->m_floatData)[entity]);
    return floats[propName];
  }
  static FloatList dummy;
  return dummy;
}

bool Manager::hasFloatProperty(const UUID& entity, const std::string& propName) const
{
  UUIDsToFloatData::const_iterator uit = this->m_floatData->find(entity);
  if (uit == this->m_floatData->end())
  {
    return false;
  }
  FloatData::const_iterator sit = uit->second.find(propName);
  // FIXME: Should we return true even when the array (*sit) is empty?
  return sit == uit->second.end() ? false : true;
}

bool Manager::removeFloatProperty(const UUID& entity, const std::string& propName)
{
  UUIDsToFloatData::iterator uit = this->m_floatData->find(entity);
  if (uit == this->m_floatData->end())
  {
    return false;
  }
  FloatData::iterator sit = uit->second.find(propName);
  if (sit == uit->second.end())
  {
    return false;
  }
  uit->second.erase(sit);
  if (uit->second.empty())
    this->m_floatData->erase(uit);
  return true;
}

const UUIDWithFloatProperties Manager::floatPropertiesForEntity(const UUID& entity) const
{
  return this->m_floatData->find(entity);
}

UUIDWithFloatProperties Manager::floatPropertiesForEntity(const UUID& entity)
{
  return this->m_floatData->find(entity);
}

void Manager::setStringProperty(
  const UUID& entity, const std::string& propName, const smtk::model::String& propValue)
{
  smtk::model::StringList tmp;
  tmp.push_back(propValue);
  this->setStringProperty(entity, propName, tmp);
}

void Manager::setStringProperty(
  const UUID& entity, const std::string& propName, const smtk::model::StringList& propValue)
{
  if (!entity.isNull())
  {
    (*this->m_stringData)[entity][propName] = propValue;
  }
}

smtk::model::StringList const& Manager::stringProperty(
  const UUID& entity, const std::string& propName) const
{
  if (!entity.isNull())
  {
    StringData& strings((*this->m_stringData)[entity]);
    return strings[propName];
  }
  static StringList dummy;
  return dummy;
}

smtk::model::StringList& Manager::stringProperty(const UUID& entity, const std::string& propName)
{
  if (!entity.isNull())
  {
    StringData& strings((*this->m_stringData)[entity]);
    return strings[propName];
  }
  static StringList dummy;
  return dummy;
}

bool Manager::hasStringProperty(const UUID& entity, const std::string& propName) const
{
  UUIDsToStringData::const_iterator uit = this->m_stringData->find(entity);
  if (uit == this->m_stringData->end())
  {
    return false;
  }
  StringData::const_iterator sit = uit->second.find(propName);
  // FIXME: Should we return true even when the array (*sit) is empty?
  return sit == uit->second.end() ? false : true;
}

bool Manager::removeStringProperty(const UUID& entity, const std::string& propName)
{
  UUIDsToStringData::iterator uit = this->m_stringData->find(entity);
  if (uit == this->m_stringData->end())
  {
    return false;
  }
  StringData::iterator sit = uit->second.find(propName);
  if (sit == uit->second.end())
  {
    return false;
  }
  uit->second.erase(sit);
  if (uit->second.empty())
    this->m_stringData->erase(uit);
  return true;
}

const UUIDWithStringProperties Manager::stringPropertiesForEntity(const UUID& entity) const
{
  return this->m_stringData->find(entity);
}

UUIDWithStringProperties Manager::stringPropertiesForEntity(const UUID& entity)
{
  return this->m_stringData->find(entity);
}

void Manager::setIntegerProperty(
  const UUID& entity, const std::string& propName, smtk::model::Integer propValue)
{
  smtk::model::IntegerList tmp;
  tmp.push_back(propValue);
  this->setIntegerProperty(entity, propName, tmp);
}

void Manager::setIntegerProperty(
  const UUID& entity, const std::string& propName, const smtk::model::IntegerList& propValue)
{
  if (!entity.isNull())
  {
    (*this->m_integerData)[entity][propName] = propValue;
  }
}

smtk::model::IntegerList const& Manager::integerProperty(
  const UUID& entity, const std::string& propName) const
{
  if (!entity.isNull())
  {
    IntegerData& integers((*this->m_integerData)[entity]);
    return integers[propName];
  }
  static IntegerList dummy;
  return dummy;
}

smtk::model::IntegerList& Manager::integerProperty(const UUID& entity, const std::string& propName)
{
  if (!entity.isNull())
  {
    IntegerData& integers((*this->m_integerData)[entity]);
    return integers[propName];
  }
  static IntegerList dummy;
  return dummy;
}

bool Manager::hasIntegerProperty(const UUID& entity, const std::string& propName) const
{
  UUIDsToIntegerData::const_iterator uit = this->m_integerData->find(entity);
  if (uit == this->m_integerData->end())
  {
    return false;
  }
  IntegerData::const_iterator sit = uit->second.find(propName);
  // FIXME: Should we return true even when the array (*sit) is empty?
  return sit == uit->second.end() ? false : true;
}

bool Manager::removeIntegerProperty(const UUID& entity, const std::string& propName)
{
  UUIDsToIntegerData::iterator uit = this->m_integerData->find(entity);
  if (uit == this->m_integerData->end())
  {
    return false;
  }
  IntegerData::iterator sit = uit->second.find(propName);
  if (sit == uit->second.end())
  {
    return false;
  }
  uit->second.erase(sit);
  if (uit->second.empty())
    this->m_integerData->erase(uit);
  return true;
}

const UUIDWithIntegerProperties Manager::integerPropertiesForEntity(const UUID& entity) const
{
  return this->m_integerData->find(entity);
}

UUIDWithIntegerProperties Manager::integerPropertiesForEntity(const UUID& entity)
{
  return this->m_integerData->find(entity);
}
///@}

/// Attempt to find a model owning the given entity.
UUID Manager::modelOwningEntity(const UUID& ent) const
{
  std::set<UUID> visited;
  UUID result = this->modelOwningEntityRecursive(ent, visited);
  return result;
}

/// Attempt to find a session owning the given entity.
UUID Manager::sessionOwningEntity(const UUID& ent) const
{
  std::set<UUID> visited;
  UUID result = this->sessionOwningEntityRecursive(ent, visited);
  return result;
}

/**\brief Assign a string property named "name" to every entity without one.
  *
  * This descends sessions and models owned by sessions rather than
  * blindly iterating over UUIDs; it is thus much faster than calling
  * assignDefaultName() on each entity UUID.
  */
void Manager::assignDefaultNames()
{
  // I. Put every UUID into a bin for processing
  UUIDWithEntity it;
  UUIDs models;  // models that have not had all of their children named
  UUIDs orphans; // entities that may or may not be parent-less
  UUIDs named;   // entities with names
  for (it = this->m_topology->begin(); it != this->m_topology->end(); ++it)
  {
    BitFlags etype = it->second.entityFlags();
    if (etype & MODEL_ENTITY)
    {
      models.insert(it->first);
    }
    else
    {
      if (this->hasStringProperty(it->first, "name"))
        named.insert(it->first);
      else
        orphans.insert(it->first);
    }
  }
  UUIDs::iterator uit;
  for (uit = models.begin(); uit != models.end(); ++uit)
  {
    // Assign the owner a name if required. This way,
    // assignDefaultNamesWithOwner can assume the name exists.
    std::string oname;
    if (!this->hasStringProperty(*uit, "name"))
      oname = this->assignDefaultName(*uit);
    else
      oname = this->stringProperty(*uit, "name")[0];

    UUIDWithEntity iit = this->m_topology->find(*uit);
    this->assignDefaultNamesWithOwner(iit, *uit, oname, orphans, false);
  }
  for (uit = orphans.begin(); uit != orphans.end(); ++uit)
  {
    this->assignDefaultName(*uit);
  }
}

/**\brief Assign a string property named "name" to every entity of a model without one.
  *
  * This descends models rather than blindly iterating over UUIDs;
  * it is thus much faster than calling assignDefaultName() on each entity UUID.
  */
void Manager::assignDefaultNamesToModelChildren(const smtk::common::UUID& modelId)
{
  bool oops = true;
  UUIDWithEntity it = this->m_topology->find(modelId);
  if (it != this->m_topology->end())
  {
    Model model(shared_from_this(), modelId);
    if (model.isValid())
    {
      oops = false;
      EntityIterator eit;
      eit.traverse(model, ITERATE_MODELS);
      model.assignDefaultName();
      std::string modelName = model.name();
      UUIDs dummy;
      for (eit.begin(); !eit.isAtEnd(); ++eit)
      {
        if (eit->isSessionRef())
          (*eit).assignDefaultName();
        else
          this->assignDefaultNamesWithOwner(
            this->m_topology->find(eit->entity()), model.entity(), modelName, dummy, true);
      }
    }
  }
  if (oops)
  {
    smtkWarningMacro(this->m_log, "Tried to assign default names to a non-model entity: "
        << EntityRef(shared_from_this(), modelId).name() << ".");
  }
}

/**\brief Assign a string property named "name" to the given entity.
  *
  * If a model can be identified as owning an entity, the default name
  * assigned to the entity will be the model's name followed by a comma
  * and then the name for the entity. The model's per-entity-type counters
  * are used to number entities of the same type (e.g., "Face 13", "Edge 42").
  *
  * Orphan entities (those without owning models) are given names
  * that end with the trailing digits of their UUIDs.
  */
std::string Manager::assignDefaultName(const UUID& uid)
{
  UUIDWithEntity it = this->m_topology->find(uid);
  if (it != this->m_topology->end())
  {
    return this->assignDefaultName(it->first, it->second.entityFlags());
  }
  return std::string();
}

/**\brief Assign a string property named "name" to the given entity.
  *
  * This method is like assignDefaultName() but will not replace any
  * pre-existing name.
  */
std::string Manager::assignDefaultNameIfMissing(const UUID& uid)
{
  UUIDWithEntity it = this->m_topology->find(uid);
  if (it != this->m_topology->end())
  {
    return this->hasStringProperty(uid, "name")
      ? this->name(uid)
      : this->assignDefaultName(it->first, it->second.entityFlags());
  }
  return std::string();
}

void Manager::assignDefaultNamesWithOwner(const UUIDWithEntity& irec, const UUID& owner,
  const std::string& ownersName, std::set<smtk::common::UUID>& remaining, bool nokids)
{
  remaining.erase(irec->first);
  // Assign the item a name if required:
  if (!this->hasStringProperty(irec->first, "name"))
  {
    IntegerList& counts(this->entityCounts(owner, irec->second.entityFlags()));
    if (!this->hasIntegerProperty(irec->first, "pedigree id"))
    {
      int pedigree = Entity::countForType(irec->second.entityFlags(), counts, false);
      this->setIntegerProperty(irec->first, "pedigree id", pedigree);
    }
    std::string defaultName = counts.empty()
      ? this->shortUUIDName(irec->first, irec->second.entityFlags())
      : Entity::defaultNameFromCounters(irec->second.entityFlags(), counts);
    this->setStringProperty(irec->first, "name", defaultName);
  }

  if (nokids)
    return;

  // Now descend the owner and assign its children names.
  // Do not ascend... check that relIt dimension decreases or
  // that certain ownership rules are met.
  UUIDArray::const_iterator relIt;
  BitFlags iflg = irec->second.entityFlags();
  BitFlags idim = iflg & ANY_DIMENSION;
  for (relIt = irec->second.relations().begin(); relIt != irec->second.relations().end(); ++relIt)
  {
    UUIDWithEntity child = this->m_topology->find(*relIt);
    if (child == this->m_topology->end())
      continue;
    BitFlags cflg = child->second.entityFlags();
    bool yesButNoKids = (cflg & GROUP_ENTITY) && (iflg & MODEL_ENTITY);
    if (((cflg & ANY_DIMENSION) < idim && !(iflg & SHELL_ENTITY)) ||
      ((cflg & SHELL_ENTITY) && (iflg & USE_ENTITY)) ||
      ((cflg & USE_ENTITY) && (iflg & CELL_ENTITY)) || yesButNoKids)
    {
      this->assignDefaultNamesWithOwner(child, owner, ownersName, remaining, yesButNoKids);
    }
  }
}

std::string Manager::assignDefaultName(const UUID& uid, BitFlags entityFlags)
{
  // If this entity is a model, give it a top-level name
  // (even if it is a submodel of some other model -- for brevity).
  if (entityFlags & MODEL_ENTITY)
  {
    std::string tmpName;
    if (!this->hasStringProperty(uid, "name"))
    {
      std::ostringstream defaultName;
      defaultName << "Model ";
      int count = this->m_globalCounters[1]++;
      char hexavigesimal[8]; // 7 hexavigesimal digits will cover us up to 2**31.
      int i;
      for (i = 0; count > 0 && i < 7; ++i)
      {
        --count;
        hexavigesimal[i] = 'A' + count % 26;
        count /= 26;
      }
      for (--i; i >= 0; --i)
      {
        defaultName << hexavigesimal[i];
      }
      tmpName = defaultName.str();
      this->setStringProperty(uid, "name", tmpName);
    }
    else
    {
      tmpName = this->stringProperty(uid, "name")[0];
    }
    return tmpName;
  }
  else if (entityFlags & SESSION)
  {
    std::string tmpName;
    if (!this->hasStringProperty(uid, "name"))
    {
      std::ostringstream nameStream;
      SessionRef sref(shared_from_this(), uid);
      Session::Ptr sess = sref.session();
      if (sess)
      {
        // if this is a DefaultSession and there is a remote session name, display that;
        // otherwise, show the local session name.
        DefaultSessionPtr defSess = smtk::dynamic_pointer_cast<DefaultSession>(sess);
        nameStream << (defSess && !defSess->remoteName().empty() ? defSess->remoteName()
                                                                 : sess->name())
                   << " models";
      }
      else
      {
        nameStream << Entity::defaultNameFromCounters(entityFlags, this->m_globalCounters);
      }
      tmpName = nameStream.str();
      this->setStringProperty(uid, "name", tmpName);
    }
    else
    {
      tmpName = this->stringProperty(uid, "name")[0];
    }
    return tmpName;
  }
  // Not a model or session, get its parent's per-type counters:
  UUID owner(this->modelOwningEntity(uid));
  IntegerList& counts(this->entityCounts(owner, entityFlags));
  // Compose a name from the owner and counters:
  if (!this->hasIntegerProperty(uid, "pedigree id"))
  {
    int pedigree = Entity::countForType(entityFlags, counts, false);
    this->setIntegerProperty(uid, "pedigree id", pedigree);
  }
  std::string defaultName = counts.empty() ? this->shortUUIDName(uid, entityFlags)
                                           : Entity::defaultNameFromCounters(entityFlags, counts);
  this->setStringProperty(uid, "name", defaultName);
  return defaultName;
}

std::string Manager::shortUUIDName(const UUID& uid, BitFlags entityFlags)
{
  std::string name = Entity::flagSummaryHelper(entityFlags);
  name += "..";
  std::string uidStr = uid.toString();
  name += uidStr.substr(uidStr.size() - 4);
  return name;
}

/// Return a list of the names of each session subclass whose constructor has been registered with SMTK.
StringList Manager::sessionTypeNames()
{
  return SessionRegistrar::sessionTypeNames();
}

/// Return the list of file types this session can read (currently: a list of file extensions).
StringData Manager::sessionFileTypes(const std::string& bname, const std::string& engine)
{
  return SessionRegistrar::sessionFileTypes(bname, engine);
}

/**\brief Create a session given the type of session to construct.
  *
  * \warning This creates a Session instance without a matching Entity record!
  *          use this method with care; you most probably want createSession
  *          instead.
  */
SessionPtr Manager::createSessionOfType(const std::string& bname)
{
  return SessionRegistrar::createSession(bname);
}

/**\brief Convenience method to create a session without specifying a session ID.
  *
  */
SessionRef Manager::createSession(const std::string& bname)
{
  return this->createSession(bname, SessionRef());
}

/**\brief Create a session, optionally forcing a session ID and/or
  *       registering it with this manager instance.
  *
  */
SessionRef Manager::createSession(
  const std::string& bname, const smtk::model::SessionRef& sessionIdSpec)
{
  if (sessionIdSpec.isValid() && this->sessionData(sessionIdSpec))
    return sessionIdSpec; // Hrm, the specified session already exists...

  SessionPtr result = Manager::createSessionOfType(bname);
  if (result)
  {
    if (!sessionIdSpec.entity().isNull())
      result->setSessionId(sessionIdSpec.entity());
    return this->registerSession(result); // will call result->setManager(this);
  }

  smtkInfoMacro(this->m_log, "Could not create \"" << bname << "\" session.");
  return SessionRef();
}

/// Mark the start of a modeling session by registering the \a session with SMTK backing storage.
SessionRef Manager::registerSession(SessionPtr session)
{
  if (!session)
    return SessionRef();

  UUID sessId = session->sessionId();
  if (sessId.isNull())
    return SessionRef();

  (*this->m_sessions)[sessId] = session;
  Manager::iter_type brec = this->setEntityOfTypeAndDimension(sessId, SESSION, -1);

  session->setManager(this);
  return SessionRef(shared_from_this(), brec->first);
}

/**\brief Mark the end of a modeling session by removing its \a session.
  *
  * This will remove session-member entities if \a expungeSession is true.
  */
bool Manager::unregisterSession(SessionPtr session, bool expungeSession)
{
  if (!session)
    return false;

  UUID sessId = session->sessionId();
  if (sessId.isNull())
    return false;

  if (expungeSession)
  { // Carefully remove all children of session (models, volumes, faces, etc.)
    this->erase(sessId);
  }
  else
  {
    // Remove the session's entity record, properties, and such, but not
    // records, properties, etc. for entities the session owns.
    this->m_topology->erase(sessId);
    this->m_floatData->erase(sessId);
    this->m_stringData->erase(sessId);
    this->m_integerData->erase(sessId);
    this->m_arrangements->erase(sessId);
    this->m_tessellations->erase(sessId);
    this->m_attributeAssignments->erase(sessId);
  }
  return this->m_sessions->erase(sessId) ? true : false;
}

/// Find a session given its session UUID (or NULL).
SessionPtr Manager::sessionData(const smtk::model::SessionRef& sessId) const
{
  if (sessId.entity().isNull())
    return this->m_defaultSession;

  UUIDsToSessions::const_iterator it = this->m_sessions->find(sessId.entity());
  if (it == this->m_sessions->end())
    return SessionPtr();
  return it->second;
}

/// Return a reference to the \a modelId's counter array associated with the given \a entityFlags.
IntegerList& Manager::entityCounts(const UUID& modelId, BitFlags entityFlags)
{
  switch (entityFlags & ENTITY_MASK)
  {
    case CELL_ENTITY:
      return this->integerProperty(modelId, "cell_counters");
    case USE_ENTITY:
      return this->integerProperty(modelId, "use_counters");
    case SHELL_ENTITY:
      return this->integerProperty(modelId, "shell_counters");
    case GROUP_ENTITY:
      return this->integerProperty(modelId, "group_counters");
    case MODEL_ENTITY:
      return this->integerProperty(modelId, "model_counters");
    case INSTANCE_ENTITY:
      return this->integerProperty(modelId, "instance_counters");
    default:
      break;
  }
  return this->integerProperty(modelId, "invalid_counters");
}

/**\brief Initialize storage outside of the topology() table for a new entity.
  *
  * This is an internal method invoked by setEntity and SetEntityOfTypeAndDimension.
  */
void Manager::prepareForEntity(std::pair<UUID, Entity>& entry)
{
  if ((entry.second.entityFlags() & CELL_2D) == CELL_2D)
  {
    if (!this->hasArrangementsOfKindForEntity(entry.first, HAS_USE))
    {
      // Create arrangements to hold face-uses:
      this->arrangeEntity(
        entry.first, HAS_USE, Arrangement::CellHasUseWithIndexSenseAndOrientation(-1, 0, NEGATIVE));
      this->arrangeEntity(
        entry.first, HAS_USE, Arrangement::CellHasUseWithIndexSenseAndOrientation(-1, 0, POSITIVE));
    }
  }
  else if (entry.second.entityFlags() & USE_ENTITY)
  {
    if (!this->hasArrangementsOfKindForEntity(entry.first, HAS_SHELL))
    {
      // Create arrangement to hold parent shell:
      this->arrangeEntity(entry.first, HAS_SHELL, Arrangement::UseHasShellWithIndex(-1));
    }
  }
  else if ((entry.second.entityFlags() & MODEL_ENTITY) == MODEL_ENTITY)
  {
    // New models keep counters indicating their local entity counters
    Integer topoCountsData[] = { 0, 0, 0, 0, 0, 0 };
    Integer groupCountsData[] = { 0, 0, 0 };
    Integer otherCountsData[] = { 0 };
    IntegerList topoCounts(
      topoCountsData, topoCountsData + sizeof(topoCountsData) / sizeof(topoCountsData[0]));
    IntegerList groupCounts(
      groupCountsData, groupCountsData + sizeof(groupCountsData) / sizeof(groupCountsData[0]));
    IntegerList otherCounts(
      otherCountsData, otherCountsData + sizeof(otherCountsData) / sizeof(otherCountsData[0]));
    this->setIntegerProperty(entry.first, "cell_counters", topoCounts);
    this->setIntegerProperty(entry.first, "use_counters", topoCounts);
    this->setIntegerProperty(entry.first, "shell_counters", topoCounts);
    this->setIntegerProperty(entry.first, "group_counters", groupCounts);
    this->setIntegerProperty(entry.first, "model_counters", otherCounts);
    this->setIntegerProperty(entry.first, "instance_counters", otherCounts);
    this->setIntegerProperty(entry.first, "invalid_counters", otherCounts);
  }
}

/**@name Find entities by their property values.
  *\brief Look for entities that have a given property defined and whose value matches one provided.
  *
  * The non-templated variants returning EntityRefArray can be wrapped and used in Python
  * while the templated variants are more useful in C++.
  */
//@{
/// Find entities with an integer property named \a pname whose value is the single value \a pval.
EntityRefArray Manager::findEntitiesByProperty(const std::string& pname, Integer pval)
{
  return this->findEntitiesByPropertyAs<EntityRefArray>(pname, pval);
}

/// Find entities with a floating-point property named \a pname whose value is the single value \a pval.
EntityRefArray Manager::findEntitiesByProperty(const std::string& pname, Float pval)
{
  return this->findEntitiesByPropertyAs<EntityRefArray>(pname, pval);
}

/// Find entities with a string property named \a pname whose value is the single value \a pval.
EntityRefArray Manager::findEntitiesByProperty(const std::string& pname, const std::string& pval)
{
  return this->findEntitiesByPropertyAs<EntityRefArray>(pname, pval);
}

/// Find entities with an integer property named \a pname whose every value matches the array \a pval.
EntityRefArray Manager::findEntitiesByProperty(const std::string& pname, const IntegerList& pval)
{
  return this->findEntitiesByPropertyAs<EntityRefArray>(pname, pval);
}

/// Find entities with a floating-point property named \a pname whose every value matches the array \a pval.
EntityRefArray Manager::findEntitiesByProperty(const std::string& pname, const FloatList& pval)
{
  return this->findEntitiesByPropertyAs<EntityRefArray>(pname, pval);
}

/// Find entities with a string property named \a pname whose every value matches the array \a pval.
EntityRefArray Manager::findEntitiesByProperty(const std::string& pname, const StringList& pval)
{
  return this->findEntitiesByPropertyAs<EntityRefArray>(pname, pval);
}

/*! \fn template<typename Collection> Collection Manager::findEntitiesByPropertyAs(const std::string& pname, Integer pval)
 * \brief Return entities with a property named \a pname whose values match the given \a pval.
 */

/*! \fn template<typename Collection> Collection Manager::findEntitiesByPropertyAs(const std::string& pname, const IntegerList& pval)
 * \brief Return entities with a property named \a pname whose values match the given \a pval.
 */

/*! \fn template<typename Collection> Collection Manager::findEntitiesByPropertyAs(const std::string& pname, Float pval)
 * \brief Return entities with a property named \a pname whose values match the given \a pval.
 */

/*! \fn template<typename Collection> Collection Manager::findEntitiesByPropertyAs(const std::string& pname, const FloatList& pval)
 * \brief Return entities with a property named \a pname whose values match the given \a pval.
 */

/*! \fn template<typename Collection> Collection Manager::findEntitiesByPropertyAs(const std::string& pname, const std::string& pval)
 * \brief Return entities with a property named \a pname whose values match the given \a pval.
 */

/*! \fn template<typename Collection> Collection Manager::findEntitiesByPropertyAs(const std::string& pname, const StringList& pval)
 * \brief Return entities with a property named \a pname whose values match the given \a pval.
 */
//@}

/**\brief Find entities whose type matches the given \a flags.
  *
  * This version can be wrapped and used in Python.
  * It is not named entitiesMatchingFlags (to mirror the
  * templated entitiesMatchingFlagsAs<T>) because our base
  * class, Manager, provides another method of the same
  * name that returns UUIDs rather than EntityRefArray.
  */
EntityRefArray Manager::findEntitiesOfType(BitFlags flags, bool exactMatch)
{
  return this->entitiesMatchingFlagsAs<EntityRefArray>(flags, exactMatch);
}

/**\brief Set the tessellation information and for a given \a cellId.
  *
  * If \a analysis is non-zero (zero is the default), then the
  * Tessellation is treated as an analysis mesh, not a display
  * tessellation.
  *
  * Note that calling this method automatically sets or increments
  * the integer-valued "_tessgen" property on \a cellId.
  * This property enables fast display updates when only a few
  * entity tessellations have changed.
  * If \a generation is a non-NULL pointer (NULL is the default),
  * then the new generation number of the Tessellation is stored at
  * the address provided.
  */
Manager::tess_iter_type Manager::setTessellation(
  const UUID& cellId, const Tessellation& geom, int analysis, int* generation)
{
  if (cellId.isNull())
    throw std::string("Nil cell ID");

  smtk::shared_ptr<UUIDsToTessellations> storage;
  const char* genProp;
  if (!analysis)
  { // store as display tessellation
    storage = this->m_tessellations;
    genProp = SMTK_TESS_GEN_PROP;
  }
  else
  { // store as analysis mesh
    storage = this->m_analysisMesh;
    genProp = SMTK_MESH_GEN_PROP;
  }

  tess_iter_type result = storage->find(cellId);
  if (result == storage->end())
  {
    std::pair<UUID, Tessellation> blank;
    blank.first = cellId;
    result = storage->insert(blank).first;
  }
  result->second = geom;

  // Now set or increment the generation number.
  IntegerList& gen(this->integerProperty(cellId, genProp));
  if (gen.empty())
    gen.push_back(0);
  else
    ++gen[0];
  if (generation)
    *generation = gen[0];

  return result;
}

/**\brief Set the tessellation information and bounding box for a given \a cellId.
  *
  * If \a analysis is non-zero (zero is the default), then the
  * Tessellation is treated as an analysis mesh, not a display
  * tessellation.
  *
  * Note that calling this method automatically sets or increments
  * the integer-valued "_tessgen" property on \a cellId.
  * This property enables fast display updates when only a few
  * entity tessellations have changed.
  * If \a generation is a non-NULL pointer (NULL is the default),
  * then the new generation number of the Tessellation is stored at
  * the address provided.
  */
Manager::tess_iter_type Manager::setTessellationAndBoundingBox(
  const UUID& cellId, const Tessellation& geom, int analysis, int* generation)
{
  if (cellId.isNull())
    throw std::string("Nil cell ID");

  smtk::shared_ptr<UUIDsToTessellations> storage;
  const char* genProp;
  if (!analysis)
  { // store as display tessellation
    storage = this->m_tessellations;
    genProp = SMTK_TESS_GEN_PROP;
  }
  else
  { // store as analysis mesh
    storage = this->m_analysisMesh;
    genProp = SMTK_MESH_GEN_PROP;
  }

  tess_iter_type result = storage->find(cellId);
  if (result == storage->end())
  {
    std::pair<UUID, Tessellation> blank;
    blank.first = cellId;
    result = storage->insert(blank).first;
  }
  result->second = geom;

  // Now set or increment the generation number.
  IntegerList& gen(this->integerProperty(cellId, genProp));
  if (gen.empty())
    gen.push_back(0);
  else
    ++gen[0];
  if (generation)
    *generation = gen[0];

  // Set/upate the bBox
  this->setBoundingBox(cellId, geom.coords());
  return result;
}

/**\brief set the bounding box of a model entity given \a entityId and \a coords.
  *
  * if provided bBox, we would just use the coords as bBox
  *
  * Returns true when a real bBox is set and false otherwise.
  */
bool Manager::setBoundingBox(
  const UUID& cellId, const std::vector<double>& coords, int providedbBox)
{
  smtk::model::FloatList bBox;
  if (providedbBox)
  {
    this->setFloatProperty(cellId, SMTK_BOUNDING_BOX_PROP, coords);
    return true;
  }
  else // calculate boundingBox
  {
    if (coords.size() == 0)
    {
      return false;
    } // nothing to set
    // initialize the bBox
    for (int i = 0; i < 6; i++)
    {
      double tmp = (i % 2 == 1) ? -DBL_MAX : DBL_MAX;
      bBox.push_back(tmp);
    }
    std::vector<double>::size_type pointSize = coords.size() / 3;
    for (size_t i = 0; i < pointSize; ++i)
    {
      bBox[0] = std::min(bBox[0], coords[3 * i]);
      bBox[1] = std::max(bBox[1], coords[3 * i]);
      bBox[2] = std::min(bBox[2], coords[3 * i + 1]);
      bBox[3] = std::max(bBox[3], coords[3 * i + 1]);
      bBox[4] = std::min(bBox[4], coords[3 * i + 2]);
      bBox[5] = std::max(bBox[5], coords[3 * i + 2]);
    }
    this->setFloatProperty(cellId, SMTK_BOUNDING_BOX_PROP, bBox);
    return true;
  }
}

/**\brief Remove the tessellation of the given \a entityId.
  *
  * If the second argument is true, also remove the integer "generation number"
  * property from the entity.
  *
  * Returns true when a tessellation was actually removed and false otherwise.
  */
bool Manager::removeTessellation(const smtk::common::UUID& entityId, bool removeGen)
{
  bool didRemove;
  UUIDWithTessellation tref = this->m_tessellations->find(entityId);
  didRemove = (tref == this->m_tessellations->end());
  if (didRemove)
    this->m_tessellations->erase(tref);

  if (removeGen)
    this->removeIntegerProperty(entityId, SMTK_TESS_GEN_PROP);
  return didRemove;
}

/**\brief Add or replace information about the arrangement of an entity.
  *
  * When \a index is -1, the arrangement is considered new and added to the end of
  * the vector of arrangements of the given \a kind.
  * Otherwise, it should be positive and refer to a pre-existing arrangement to be replaced.
  * The actual \a index location used is returned.
  */
int Manager::arrangeEntity(
  const UUID& entityId, ArrangementKind kind, const Arrangement& arr, int index)
{
  UUIDsToArrangements::iterator cit = this->m_arrangements->find(entityId);
  if (cit == this->m_arrangements->end())
  {
    if (index >= 0)
    { // failure: can't replace information that doesn't exist.
      return -1;
    }
    KindsToArrangements blank;
    cit = this->m_arrangements->insert(std::pair<UUID, KindsToArrangements>(entityId, blank)).first;
  }
  KindsToArrangements::iterator kit = cit->second.find(kind);
  if (kit == cit->second.end())
  {
    if (index >= 0)
    { // failure: can't replace information that doesn't exist.
      return -1;
    }
    Arrangements blank;
    kit = cit->second.insert(std::pair<ArrangementKind, Arrangements>(kind, blank)).first;
  }

  if (index >= 0)
  {
    if (index >= static_cast<int>(kit->second.size()))
    { // failure: can't replace information that doesn't exist.
      return -1;
    }
    kit->second[index] = arr;
  }
  else
  {
    index = static_cast<int>(kit->second.size());
    kit->second.push_back(arr);
  }
  return index;
}

/**\brief Remove an arrangement from an entity, and optionally the entity itself.
  *
  * When no action is taken (because of a missing entityId, a missing arrangement
  * or a bad index), 0 is returned.
  * When a the arrangement is successfully removed, 1 is returned.
  * When \a removeIfLast is true and the entity is removed, 2 is returned.
  * When the related entity specified by the arrangement is also removed (only
  * attempted when \a removeIfLast is true), 3 is returned.
  *
  * **Warning**: Invoking this method naively will likely result
  * in an inconsistent solid model.
  * The caller is expected to perform further operations to keep
  * the model valid.
  */
int Manager::unarrangeEntity(const UUID& entityId, ArrangementKind k, int index, bool removeIfLast)
{
  int result = 0;
  bool canRemoveEntity = false;
  if (index < 0)
    return result;
  UUIDWithArrangementDictionary ad = this->m_arrangements->find(entityId);
  if (ad == this->m_arrangements->end())
    return result;
  ArrangementKindWithArrangements ak = ad->second.find(k);
  if (ak == ad->second.end() || index >= static_cast<int>(ak->second.size()))
    return result;

  ArrangementReferences duals;
  bool hasDuals = this->findDualArrangements(entityId, k, index, duals);

  // TODO: notify relation + entity (or their delegates) of imminent removal?
  std::vector<int> relIdxs;
  Entity* erec;
  if ((ak->second.begin() + index)
        ->relationIndices(relIdxs, (erec = this->findEntity(entityId, false)), k))
  {
    for (std::vector<int>::iterator rit = relIdxs.begin(); rit != relIdxs.end(); ++rit)
    {
      erec->invalidateRelationByIndex(*rit);
    }
  }
  ak->second.erase(ak->second.begin() + index);
  ++result;

  // Now, if we removed the last arrangement of this kind, kill the kind-dictionary entry
  if (ak->second.empty())
  {
    ad->second.erase(ak);
    // Now if we removed the last kind with arrangements in ad, kill the uuid-dictionary entry
    if (ad->second.empty())
    {
      this->m_arrangements->erase(ad);
      canRemoveEntity = true;
    }
  }

  // Now find and remove the dual arrangement (if one exists)
  // This branch should not be taken if we are inside the inner unarrangeEntity call below.
  if (hasDuals)
  {
    // Unarrange every dual to this arrangement.
    bool canIncrement = false;
    for (ArrangementReferences::iterator dit = duals.begin(); dit != duals.end(); ++dit)
    {
      if (this->unarrangeEntity(dit->entityId, dit->kind, dit->index, removeIfLast) == 2)
        canIncrement =
          true; // Only increment result when dualEntity is remove, not the dual arrangement.
    }
    // Only increment once if other entities were removed; we do not indicate how many were removed.
    if (canIncrement)
      ++result;
  }

  // If we removed the last arrangement relating this entity to others,
  // and if the caller has requested it: remove the entity itself.
  if (removeIfLast && canRemoveEntity)
  {
    // TODO: notify entity of removal.
    this->m_topology->erase(entityId);
    ++result;
  }
  return result;
}

/**\brief Erase all arrangements for the given \a entityId.
  *
  * \warning
  * Unlike unarrangeEntity(), this method does not alter arrangements
  * for any other entity and thus can leave previously-bidirectional
  * arrangements as unidirectional.
  *
  * Returns true when \a entity had a non-empty dictionary of
  * arrangements and false otherwise.
  *
  * Note that this does not erase the entry in the map from UUIDs
  * to arrangements, but rather clears the arrangement dictionary
  * for the given UUID.
  */
bool Manager::clearArrangements(const smtk::common::UUID& entityId)
{
  UUIDWithArrangementDictionary iter = this->m_arrangements->find(entityId);
  bool didRemove = (iter != this->m_arrangements->end()) && (!iter->second.empty());
  if (didRemove)
    iter->second.clear();
  return didRemove;
}

/**\brief Returns true when the given \a entity has any arrangements of the given \a kind (otherwise false).
  *
  * Use this to avoid accidentally inserting a new array of arrangements with arrangementsOfKindForEntity().
  * Since this actually requires a lookup, you may pass in a pointer \a arr to an array of arrangements;
  * if true is returned, the pointer will be aimed at the existing array. Otherwise, \a arr will be unchanged.
  */
Arrangements* Manager::hasArrangementsOfKindForEntity(const UUID& entity, ArrangementKind kind)
{
  UUIDWithArrangementDictionary cellEntry = this->m_arrangements->find(entity);
  if (cellEntry != this->m_arrangements->end())
  {
    ArrangementKindWithArrangements useIt = cellEntry->second.find(kind);
    if (useIt != cellEntry->second.end())
    {
      return &useIt->second;
    }
  }
  return NULL;
}

/**\brief This is a const version of hasArrangementsOfKindForEntity().
  */
const Arrangements* Manager::hasArrangementsOfKindForEntity(
  const UUID& entity, ArrangementKind kind) const
{
  UUIDWithArrangementDictionary cellEntry = this->m_arrangements->find(entity);
  if (cellEntry != this->m_arrangements->end())
  {
    ArrangementKindWithArrangements useIt = cellEntry->second.find(kind);
    if (useIt != cellEntry->second.end())
    {
      return &useIt->second;
    }
  }
  return NULL;
}

/**\brief Return an array of arrangements of the given \a kind for the given \a entity.
  *
  * NOTE: This method will create an empty array and attach it to the entity
  * if none exists, thus increasing storage costs. Unless you intend to append
  * new relationships, you should not use this method without first calling
  * hasArrangementsOfKindForEntity() to determine whether the array already exists.
  */
Arrangements& Manager::arrangementsOfKindForEntity(const UUID& entity, ArrangementKind kind)
{
  return (*this->m_arrangements)[entity][kind];
}

/**\brief Retrieve arrangement information for a cell.
  *
  * This version does not allow the arrangement to be altered.
  */
const Arrangement* Manager::findArrangement(
  const UUID& cellId, ArrangementKind kind, int index) const
{
  if (cellId.isNull() || index < 0)
  {
    return NULL;
  }

  UUIDsToArrangements::iterator cit = this->m_arrangements->find(cellId);
  if (cit == this->m_arrangements->end())
  {
    return NULL;
  }

  KindsToArrangements::iterator kit = cit->second.find(kind);
  if (kit == cit->second.end())
  {
    return NULL;
  }

  if (index >= static_cast<int>(kit->second.size()))
  { // failure: can't replace information that doesn't exist.
    return NULL;
  }
  return &kit->second[index];
}

/**\brief Retrieve arrangement information for a cell.
  *
  * This version allows the arrangement to be altered.
  */
Arrangement* Manager::findArrangement(const UUID& cellId, ArrangementKind kind, int index)
{
  if (cellId.isNull() || index < 0)
  {
    return NULL;
  }

  UUIDsToArrangements::iterator cit = this->m_arrangements->find(cellId);
  if (cit == this->m_arrangements->end())
  {
    return NULL;
  }

  KindsToArrangements::iterator kit = cit->second.find(kind);
  if (kit == cit->second.end())
  {
    return NULL;
  }

  if (index >= static_cast<int>(kit->second.size()))
  { // failure: can't replace information that doesn't exist.
    return NULL;
  }
  return &kit->second[index];
}

/**\brief Find an arrangement of type \a kind that relates \a entityId to \a involvedEntity.
  *
  * This method returns the index upon success and a negative number upon failure.
  */
int Manager::findArrangementInvolvingEntity(
  const UUID& entityId, ArrangementKind kind, const UUID& involvedEntity) const
{
  const Entity* src = this->findEntity(entityId);
  if (!src)
    return -1;

  const Arrangements* arr = this->hasArrangementsOfKindForEntity(entityId, kind);
  if (!arr)
    return -1;

  Arrangements::const_iterator it;
  int idx = 0;
  UUIDArray rels;
  for (it = arr->begin(); it != arr->end(); ++it, ++idx, rels.clear())
    if (it->relations(rels, src, kind))
      for (UUIDArray::iterator rit = rels.begin(); rit != rels.end(); ++rit)
        if (*rit == involvedEntity)
          return idx;

  return -1;
}

/**\brief Find the inverse of the given arrangement, if it exists.
  *
  * When an arrangement relates one entity to another, it usually
  * has a dual, or inverse, arrangement stored with the other entity
  * so that the relationship may be discovered given either of the
  * entities involved.
  *
  * Note that the dual is not related to sense or orientation;
  * for example the dual of a face-cell's HAS_USE arrangement is
  * *not* the opposite face. Rather, the dual is the face-use
  * record's HAS_CELL arrangement (pointing from the face-use to
  * the face-cell).
  *
  * Because some relations are one-to-many in nature, it is possible
  * for the dual of a relation to have multiple values. For example,
  * a Shell's HAS_USE arrangement refer to many FaceUse instances.
  * For this reason, findDualArrangements returns an array of duals.
  *
  * This method and smtk::model::Arrangement::relations() are
  * the two main methods which determine how arrangements should be
  * interpreted in context without any prior constraints on the
  * context. (Other methods create and interpret arrangements in
  * specific circumstances where the context is known.)
  */
bool Manager::findDualArrangements(
  const UUID& entityId, ArrangementKind kind, int index, ArrangementReferences& duals) const
{
  if (index < 0)
    return false;

  const Entity* src = this->findEntity(entityId);
  if (!src)
    return false;

  const Arrangements* arr = this->hasArrangementsOfKindForEntity(entityId, kind);
  if (!arr || index >= static_cast<int>(arr->size()))
    return false;

  int relationIdx;
  int sense;
  Orientation orient;

  UUID dualEntityId;
  ArrangementKind dualKind;
  int dualIndex;
  int relStart, relEnd;

  switch (kind)
  {
    case HAS_USE:
      switch (src->entityFlags() & ENTITY_MASK)
      {
        case CELL_ENTITY:
          if ((*arr)[index].IndexSenseAndOrientationFromCellHasUse(relationIdx, sense, orient))
          { // OK, find use's reference to this cell.
            if (relationIdx < 0 || static_cast<int>(src->relations().size()) <= relationIdx)
              return false;
            dualEntityId = src->relations()[relationIdx];
            dualKind = HAS_CELL;
            if ((dualIndex =
                    this->findArrangementInvolvingEntity(dualEntityId, dualKind, entityId)) >= 0)
            {
              duals.push_back(ArrangementReference(dualEntityId, dualKind, dualIndex));
              return true;
            }
          }
          break;
        case SHELL_ENTITY:
          if ((*arr)[index].IndexRangeFromShellHasUse(relStart, relEnd))
          { // Find the use's reference to this shell.
            dualKind = HAS_SHELL;
            for (; relStart != relEnd; ++relStart)
            {
              dualEntityId = src->relations()[relStart];
              if ((dualIndex =
                      this->findArrangementInvolvingEntity(dualEntityId, dualKind, entityId)) >= 0)
                duals.push_back(ArrangementReference(dualEntityId, dualKind, dualIndex));
            }
            if (!duals.empty())
              return true;
          }
          break;
        /*
      bool IndexFromCellEmbeddedInEntity(int& relationIdx) const;
      bool IndexFromCellIncludesEntity(int& relationIdx) const;
      bool IndexFromCellHasShell(int& relationIdx) const;
      bool IndexAndSenseFromUseHasCell(int& relationIdx, int& sense) const;
      bool IndexFromUseHasShell(int& relationIdx) const;
      bool IndexFromUseOrShellIncludesShell(int& relationIdx) const;
      bool IndexFromShellHasCell(int& relationIdx) const;
      bool IndexRangeFromShellHasUse(int& relationBegin, int& relationEnd) const;
      bool IndexFromShellEmbeddedInUseOrShell(int& relationIdx) const;
      bool IndexFromInstanceInstanceOf(int& relationIdx) const;
      bool IndexFromEntityInstancedBy(int& relationIdx) const;
      */
        case USE_ENTITY:
        case GROUP_ENTITY:
        case MODEL_ENTITY:
        case INSTANCE_ENTITY:
          break;
      }
      break;
    case INCLUDES: // INCLUDES/EMBEDDED_IN are always simple and duals; entity type doesn't matter.
    case EMBEDDED_IN:
      if ((*arr)[index].IndexFromSimple(relationIdx))
      { // OK, find use's reference to this cell.
        if (relationIdx < 0 || static_cast<int>(src->relations().size()) <= relationIdx)
          return false;
        dualEntityId = src->relations()[relationIdx];
        dualKind = kind == INCLUDES ? EMBEDDED_IN : INCLUDES;
        if ((dualIndex = this->findArrangementInvolvingEntity(dualEntityId, dualKind, entityId)) >=
          0)
        {
          duals.push_back(ArrangementReference(dualEntityId, dualKind, dualIndex));
          return true;
        }
      }
      break;
    case SUPERSET_OF:
    case SUBSET_OF:
      if ((*arr)[index].IndexFromSimple(relationIdx))
      { // OK, find the related entity's reference to this one.
        if (relationIdx < 0 || static_cast<int>(src->relations().size()) <= relationIdx)
        {
          return false;
        }
        dualEntityId = src->relations()[relationIdx];
        dualKind = (kind == SUPERSET_OF ? SUBSET_OF : SUPERSET_OF);
        if ((dualIndex = this->findArrangementInvolvingEntity(dualEntityId, dualKind, entityId)) >=
          0)
        {
          duals.push_back(ArrangementReference(dualEntityId, dualKind, dualIndex));
          return true;
        }
      }
      break;
    case INSTANCE_OF:
    case INSTANCED_BY:
      if ((*arr)[index].IndexFromSimple(relationIdx))
      { // OK, find the related entity's reference to this one.
        if (relationIdx < 0 || static_cast<int>(src->relations().size()) <= relationIdx)
        {
          return false;
        }
        dualEntityId = src->relations()[relationIdx];
        dualKind = (kind == INSTANCED_BY ? INSTANCE_OF : INSTANCED_BY);
        if ((dualIndex = this->findArrangementInvolvingEntity(dualEntityId, dualKind, entityId)) >=
          0)
        {
          duals.push_back(ArrangementReference(dualEntityId, dualKind, dualIndex));
          return true;
        }
      }
      break;
    case HAS_CELL:
    case HAS_SHELL:
      // These (HAS_CELL, HAS_SHELL) are not duals of each other.
      // Instead, they are the easier half of HAS_USE relations,
      // and is only defined when the source is a use-record.
      if ((src->entityFlags() & ENTITY_MASK) == USE_ENTITY)
      {
        if ((*arr)[index].IndexFromSimple(relationIdx))
        { // OK, find the related entity's reference to this one.
          if (relationIdx < 0 || static_cast<int>(src->relations().size()) <= relationIdx)
          {
            return false;
          }
          dualEntityId = src->relations()[relationIdx];
          dualKind = HAS_USE;
          if ((dualIndex =
                  this->findArrangementInvolvingEntity(dualEntityId, dualKind, entityId)) >= 0)
          {
            duals.push_back(ArrangementReference(dualEntityId, dualKind, dualIndex));
            return true;
          }
        }
      }
      break;
    default:
      smtkErrorMacro(const_cast<Manager*>(this)->log(),
        "Asked to find dual of unknown kind of arrangement: " << kind << ".");
      break;
  }
  return false;
}

/**\brief A method to add bidirectional arrangements between a parent and child.
  *
  */
bool Manager::addDualArrangement(const smtk::common::UUID& parent, const smtk::common::UUID& child,
  ArrangementKind kind, int sense, Orientation orientation)
{
  Entity* erec;
  erec = this->findEntity(parent, false);
  if (!erec)
    return false;
  EntityTypeBits parentType = static_cast<EntityTypeBits>(erec->entityFlags() & ENTITY_MASK);
  int childIndex = erec->findOrAppendRelation(child);

  erec = this->findEntity(child, false);
  if (!erec)
    return false;
  EntityTypeBits childType = static_cast<EntityTypeBits>(erec->entityFlags() & ENTITY_MASK);
  int parentIndex = erec->findOrAppendRelation(parent);

  ArrangementKind dualKind = Dual(parentType, kind);
  if (dualKind == KINDS_OF_ARRANGEMENTS)
    return false;

  this->arrangeEntity(
    parent, kind, Arrangement::Construct(parentType, kind, childIndex, sense, orientation));
  this->arrangeEntity(
    child, dualKind, Arrangement::Construct(childType, dualKind, parentIndex, sense, orientation));
  return true;
}

/**\brief Find a particular arrangement: a cell's HAS_USE with a given sense.
  *
  * The index of the matching arrangement is returned (or -1 if no such sense
  * exists).
  *
  * The sense is a non-negative integer corresponding to a particular
  * use of a cell. However, the model may be altered in a way that some
  * senses are no longer used.
  * Rather than rewrite the cell and cell-use records to keep senses
  * as a continuous integer sequence, we allow "holes" to exist in the
  * list of senses. Just because a cell has a use with sense 5 does not
  * imply that there is also a use with sense 4.
  *
  * You may find all the HAS_USE arrangements of the cell and iterator over
  * them to discover all the sense numbers.
  *
  * There should be no duplicate senses for any given cell with the same orientation
  * except in the case of vertex uses.
  * Vertex uses have no orientation and each sense of a vertex corresponds to
  * a unique connected point-set locus in the neighborhood of the domain with
  * the vertex removed.
  * So, a torus pinched to a conical point at one location on its boundary
  * might have a periodic circular edge terminated by the same vertex at each end.
  * However, the sense of the vertex uses for each endpoint would be different
  * since subtracting the vertex from the bi-conic neighborhood yields distinct
  * connected components. (The components are distinct inside small neighborhoods
  * of the vertex even though the components are connected by an edge; this
  * convention should be followed so that it is possible to compute deflection vectors
  * that will remove the degeneracy of the vertex.)
  */
int Manager::findCellHasUseWithSense(const UUID& cellId, const UUID& use, int sense) const
{
  const Entity* erec = this->findEntity(cellId);
  const Arrangements* arrs = this->hasArrangementsOfKindForEntity(cellId, HAS_USE);
  if (arrs && erec)
  {
    int i = 0;
    for (Arrangements::const_iterator it = arrs->begin(); it != arrs->end(); ++it, ++i)
    {
      int itIdx, itSense;
      Orientation itOrient;
      if (it->IndexSenseAndOrientationFromCellHasUse(itIdx, itSense, itOrient) && itIdx >= 0 &&
        erec->relations()[itIdx] == use && itSense == sense)
      {
        return i;
      }
    }
  }
  return -1;
}

/**\brief Find HAS_USE arrangements of a cell with a given orientation.
  *
  * The indices of the matching arrangements are returned.
  */
std::set<int> Manager::findCellHasUsesWithOrientation(const UUID& cellId, Orientation orient) const
{
  std::set<int> result;
  const Arrangements* arrs = this->hasArrangementsOfKindForEntity(cellId, HAS_USE);
  if (arrs)
  {
    int i = 0;
    for (Arrangements::const_iterator it = arrs->begin(); it != arrs->end(); ++it, ++i)
    {
      int itIdx, itSense;
      Orientation itOrient;
      if (it->IndexSenseAndOrientationFromCellHasUse(itIdx, itSense, itOrient) &&
        itOrient == orient)
      {
        result.insert(i);
      }
    }
  }
  return result;
}

/**\brief Return the UUID of a use record for the
  * given \a cell and \a sense, or NULL if it does not exist.
  */
UUID Manager::cellHasUseOfSenseAndOrientation(const UUID& cell, int sense, Orientation orient) const
{
  const smtk::model::Arrangements* arr;
  if ((arr = this->hasArrangementsOfKindForEntity(cell, HAS_USE)) && !arr->empty())
  { // See if any of this cell's uses match our sense.
    for (smtk::model::Arrangements::const_iterator ait = arr->begin(); ait != arr->end(); ++ait)
    {
      int itIdx;
      int itSense;
      Orientation itOrient;
      ait->IndexSenseAndOrientationFromCellHasUse(itIdx, itSense, itOrient);
      if (itSense == sense && itOrient == orient)
      {
        return this->findEntity(cell)->relations()[itIdx];
      }
    }
  }
  return UUID::null();
}

/**\brief Find a use record for the given \a cell and \a sense,
  * creating one if it does not exist or replacing it if \a replacement is non-NULL.
  *
  */
UUID Manager::findCreateOrReplaceCellUseOfSenseAndOrientation(
  const UUID& cell, int sense, Orientation orient, const UUID& replacement)
{
  Entity* entity = this->findEntity(cell);
  if (!entity)
  {
    return UUID::null();
  }
  smtk::model::Arrangements& arr(this->arrangementsOfKindForEntity(cell, HAS_USE));

  // See if any of this cell's uses match our sense...
  int arrIdx = -1;
  smtk::model::Arrangements::const_iterator ait;
  int relIdx = -1;
  int arrCtr = 0;
  for (ait = arr.begin(); ait != arr.end(); ++ait, ++arrCtr)
  {
    int itIdx;
    int itSense;
    Orientation itOrient;
    ait->IndexSenseAndOrientationFromCellHasUse(itIdx, itSense, itOrient);
    if (itSense == sense && itOrient == orient)
    {
      relIdx = itIdx;
      if (itIdx >= 0)
      { // Found a valid use. If we have a replacement, use it.
        if (!replacement.isNull())
        {
          this->unarrangeEntity(cell, HAS_USE, arrCtr, false);
          arrIdx = arrCtr;
          break;
        }
        else if (!entity->relations()[itIdx] || !this->findEntity(entity->relations()[itIdx]))
        { // The arrangement is valid but it references a NULL entity.
          arrIdx = arrCtr;
          break;
        }
        // TODO... emit signals for unarrangement/rearrangement
        return entity->relations()[itIdx];
      }
      else
      { // We found an existing but invalid use... replace it below.
        arrIdx = arrCtr;
        break;
      }
    }
  }

  // ...nope, we need to create a new use with
  // the specified sense relative to the cell.
  // Note that there may still be an entry in arr
  // which we should overwrite (with itIdx == -1).
  UUID use;
  if (replacement.isNull())
  {
    use =
      this
        ->insertEntityOfTypeAndDimension(USE_ENTITY | entity->dimensionBits(), entity->dimension())
        ->first;
    // We must re-fetch entity since inserting the use
    // may have invalidated our reference to it.
    entity = this->findEntity(cell);
    if (relIdx >= 0)
      entity->relations()[relIdx] = use;
    else
      relIdx = entity->findOrAppendRelation(use);
  }
  else
  {
    use = replacement;
    if (relIdx >= 0)
      entity->relations()[relIdx] = use;
    else
      relIdx = entity->findOrAppendRelation(use);
  }

  if (arrIdx >= 0)
  { // We found an existing use and need to replace it.
    this->arrangeEntity(cell, HAS_USE,
      Arrangement::CellHasUseWithIndexSenseAndOrientation(relIdx, sense, orient), arrIdx);
    // Does the use already have a reference back to the cell?
    this->arrangeEntity(use, HAS_CELL, Arrangement::UseHasCellWithIndexAndSense(
                                         this->findEntity(use)->findOrAppendRelation(cell), sense));
  }
  else
  {
    // We did not find an arrangement of the specified
    // sense and orientation... append it, adding
    // the use to the cell and the cell to the use:
    this->arrangeEntity(cell, HAS_USE, Arrangement::CellHasUseWithIndexSenseAndOrientation(
                                         entity->appendRelation(use), sense, orient),
      arrIdx);
    Entity* useEnt = this->findEntity(use);
    this->arrangeEntity(
      use, HAS_CELL, Arrangement::UseHasCellWithIndexAndSense(useEnt->appendRelation(cell), sense));
  }

  return use;
}

/**\brief Return the UUIDs of all shells included by the given cell-use or shell.
  *
  * Cell-uses of dimension d may include shells that span dimensions d and (d-1).
  * Shells may include other shells of the same dimensionality.
  * These relationships define a hierarchy that enumerate the oriented boundary of
  * the top-level cell-use.
  */
UUIDs Manager::useOrShellIncludesShells(const UUID& cellUseOrShell) const
{
  UUIDs shells;
  const Entity* ent = this->findEntity(cellUseOrShell);
  if (ent && (ent->entityFlags() & (USE_ENTITY | SHELL_ENTITY)))
  {
    const UUIDArray& rels(ent->relations());
    const smtk::model::Arrangements* arr;
    if ((arr = this->hasArrangementsOfKindForEntity(cellUseOrShell, INCLUDES)) && !arr->empty())
    {
      for (smtk::model::Arrangements::const_iterator ait = arr->begin(); ait != arr->end(); ++ait)
      {
        int itIdx;
        ait->IndexFromUseOrShellIncludesShell(itIdx);
        // Only insert if the inclusion is a shell
        if ((ent = this->findEntity(rels[itIdx])) && (ent->entityFlags() & SHELL_ENTITY))
        {
          shells.insert(rels[itIdx]);
        }
      }
    }
  }
  return shells;
}

/**\brief Add a new shell to the specified \a useOrShell entity as an inclusion.
  *
  * Cell-uses *include* shells relating the use to a grouping of lower-dimensional uses.
  * Each shell included directly by a cell-use represents a disconnected component
  * of the cell.
  * Shells may also include other shells of the same dimensionality representing voids
  * or material within voids for odd or even depths from the parent cell-use, respectively.
  */
UUID Manager::createIncludedShell(const UUID& useOrShell)
{
  Entity* entity = this->findEntity(useOrShell);
  if (!entity)
  {
    return UUID::null();
  }
  int shellDim = (entity->entityFlags() & USE_ENTITY || entity->entityFlags() & CELL_ENTITY)
    ?
    // k-shells span dimensions (d, d-1), where d = dimension of the cell/cell-use:
    entity->dimensionBits() | (entity->dimensionBits() >> 1)
    :
    // included k-shell must have same dimension as parent:
    entity->dimensionBits();
  int indexOfNewShell = static_cast<int>(entity->relations().size());
  UUIDWithEntity shell = this->insertEntityOfTypeAndDimension(SHELL_ENTITY | shellDim, -1);
  this->arrangeEntity(
    useOrShell, INCLUDES, Arrangement::UseOrShellIncludesShellWithIndex(indexOfNewShell));
  // We must re-find the entity record since insertEntityOfTypeAndDimension
  // invalidates entity when SMTK_HASH_STORAGE is true:
  this->findEntity(useOrShell)->appendRelation(shell->first);
  this->arrangeEntity(
    shell->first, EMBEDDED_IN, Arrangement::ShellEmbeddedInUseOrShellWithIndex(
                                 static_cast<int>(shell->second.relations().size())));
  shell->second.appendRelation(useOrShell);

  return shell->first;
}

/** Add a shell to \a parentUseOrShell as an inclusion unless it already exists.
  *
  * Returns true when adding the shell was necessary.
  * Returns false if either entity does not exist or the shell was already owned by the parent.
  */
bool Manager::findOrAddIncludedShell(const UUID& parentUseOrShell, const UUID& shellToInclude)
{
  Entity* parEnt = this->findEntity(parentUseOrShell);
  Entity* shlEnt = this->findEntity(shellToInclude);
  if (!parEnt || !shlEnt)
  {
    return false;
  }

  int indexOfShell =
    this->findArrangementInvolvingEntity(parentUseOrShell, INCLUDES, shellToInclude);
  if (indexOfShell >= 0)
    return false;

  // Didn't find it. Add both forward and inverse relations.
  this->arrangeEntity(parentUseOrShell, INCLUDES,
    Arrangement::UseOrShellIncludesShellWithIndex(parEnt->appendRelation(shellToInclude)));
  this->arrangeEntity(shellToInclude, EMBEDDED_IN,
    Arrangement::ShellEmbeddedInUseOrShellWithIndex(shlEnt->appendRelation(parentUseOrShell)));

  return true;
}

/**\brief Add a cell-use to a shell if it is not already contained in the shell.
  *
  * Note that cell-uses may have relations to shells of 2 different dimensions.
  * This method should only be called when adding d-dimensional
  * use-records to a shell bridging dimensions (d, d+1).
  * For example, call this method when adding an edge-use to a loop and not
  * when setting the edge-use associated with a chain.
  * Use the findOrAddIncludedShell() method to do the latter.
  *
  * The reason for this is that d-shells must have exactly one parent
  * cell-use (or cell, for d=3), but may have many child cell-uses
  * that are one dimension lower.
  * A different type of relationship (INCLUDES/EMBEDDED_IN vs HAS_USE/HAS_SHELL)
  * is employed depending on the dimension so that the distinction can be made
  * easily.
  */
bool Manager::findOrAddUseToShell(const UUID& shell, const UUID& use)
{
  Entity* shellEnt;
  Entity* useEnt;
  // Check that the shell and use are valid and that the use has the proper dimension for the shell.
  if ((shellEnt = this->findEntity(shell)) && (useEnt = this->findEntity(use)))
  {
    // Verify that the cell-use uses the lower dimension-bit of the shell.
    // E.g., if the shell spans dimensions 1 and 2, the use must be of dimension 1.
    if ((shellEnt->dimensionBits() & useEnt->dimensionBits()) < shellEnt->dimensionBits())
    {
      // Now, is the use already listed in a HAS_USE relationship?
      int anum = -1;
      int srsize = static_cast<int>(shellEnt->relations().size());
      Arrangements* arr = this->hasArrangementsOfKindForEntity(shell, HAS_USE);
      if (srsize && arr)
      {
        int a = 0;
        for (Arrangements::const_iterator ait = arr->begin(); ait != arr->end(); ++ait, ++a)
        {
          int i0, i1;
          ait->IndexRangeFromShellHasUse(i0, i1);
          for (int ii = i0; ii < i1; ++ii)
          {
            if (shellEnt->relations()[ii] == use)
              return false; // The shell already has the use-record. Do nothing.
          }
          // OK, does this HAS_USE arrangement go to the end of shellEnt->relations()?
          if (i1 == srsize)
          { // Yes, so we can extend it below instead of adding a new HAS_USE.
            anum = a;
          }
        }
      }
      // So far, no existing HAS_USE arrangement contained it;
      // add the use to the shell.
      shellEnt->appendRelation(use);
      if (anum >= 0)
      { // We can "extend" an existing arrangement to include the use.
        int i0, i1;
        (*arr)[anum].IndexRangeFromShellHasUse(i0, i1);
        (*arr)[anum] = Arrangement::ShellHasUseWithIndexRange(i0, i1 + 1);
      }
      else
      { // Create a new arrangement
        this->arrangeEntity(
          shell, HAS_USE, Arrangement::ShellHasUseWithIndexRange(srsize, srsize + 1));
      }
      // Now set the inverse relationship (the cell-use mapping to its parent shell).
      // Every cell-use must have a HAS_SHELL relation which we overwrite --
      // except in the case of vertex-use where we add a new relation since
      // they may have multiple HAS_SHELL relationships.
      int shellIdx = -1;
      bool previousShell = true; // Was there a previous, valid HAS_SHELL arrangement? Assume so.
      Arrangement* a;
      if ((a = this->findArrangement(use, HAS_SHELL, 0)))
      {
        a->IndexFromUseHasShell(shellIdx);
        if (shellIdx < 0)
        {
          shellIdx = useEnt->findOrAppendRelation(shell);
          *this->findArrangement(use, HAS_SHELL, 0) = Arrangement::UseHasShellWithIndex(shellIdx);
          previousShell = false;
        }
      }
      else
      {
        shellIdx = this->arrangeEntity(use, HAS_SHELL, Arrangement::UseHasShellWithIndex(-1));
        previousShell = false;
      }
      // Here is where vertex-uses are handled differently:
      // If we aren't replacing an invalid (-1) index in the arrangement,
      // then we should create a new arrangement instead of overwrite
      // what's at shellIdx in useEnt->relations().
      if (isVertexUse(useEnt->entityFlags()) && previousShell)
      {
        shellIdx = this->arrangeEntity(
          use, HAS_SHELL, Arrangement::UseHasShellWithIndex(useEnt->findOrAppendRelation(shell)));
      }
      else
      {
        useEnt->relations()[shellIdx] = shell;
      }
      return true;
    }
    // FIXME: Should we throw() when dimension is wrong?
  }
  // garbage-in => garbage-out
  // FIXME: Should we throw() here?
  return false;
}

/**\brief Add an entity to a cell as a geometric inclusion.
  *
  * This attempts to add relationships and arrangements to
  * both the \a cell and \a inclusion that indicate the
  * latter is geometrically interior to the \a cell.
  *
  * Thus, the \a inclusion must have a dimension less-than
  * or equal to the \a cell.
  */
bool Manager::findOrAddInclusionToCellOrModel(const UUID& cell, const UUID& inclusion)
{
  Entity* cellEnt;
  Entity* incEnt;
  // Check that the cell and inclusion are valid and that the inclusion has the proper dimension for the cell.
  if ((cellEnt = this->findEntity(cell)) && (incEnt = this->findEntity(inclusion)))
  {
    // Verify that the inclusion has a lower-or-equal than the cell.
    // E.g., if the cell has dimension 2, the inclusion must be of dimension 2 or less.
    if (cellEnt->dimensionBits() >= incEnt->dimensionBits())
    {
      // Now, is the inclusion already listed in a INCLUDES relationship?
      int srsize = static_cast<int>(cellEnt->relations().size());
      Arrangements* arr = this->hasArrangementsOfKindForEntity(cell, INCLUDES);
      if (srsize && arr)
      {
        int a = 0;
        for (Arrangements::const_iterator ait = arr->begin(); ait != arr->end(); ++ait, ++a)
        {
          int i;
          ait->IndexFromCellIncludesEntity(i);
          if (i >= 0 && cellEnt->relations()[i] == inclusion)
          {
            return false; // The cell already has the inclusion-record. Do nothing.
          }
        }
      }
      // No existing INCLUDES arrangement contained it;
      // add the inclusion to the cell.
      cellEnt->appendRelation(inclusion);
      this->arrangeEntity(cell, INCLUDES, Arrangement::CellIncludesEntityWithIndex(srsize));
      // Now set the inverse relationship (the cell-inclusion mapping to its parent cell).
      // Every cell-inclusion must have a matching EMBEDDED_IN relation.
      int cellIdx = incEnt->findOrAppendRelation(cell);
      this->arrangeEntity(
        inclusion, EMBEDDED_IN, Arrangement::CellEmbeddedInEntityWithIndex(cellIdx));
      return true;
    }
    // FIXME: Should we throw() when dimension is wrong?
  }
  // garbage-in => garbage-out
  // FIXME: Should we throw() here?
  return false;
}

/**\brief Add an entity as a subset of a group.
  *
  * Note that no group/partition constraints are enforced.
  * Returns true when the entity was successfully added (or already existed)
  * and false upon failure (such as when \a grp or \a ent are invalid).
  */
bool Manager::findOrAddEntityToGroup(const UUID& grp, const UUID& ent)
{
  Group group(shared_from_this(), grp);
  EntityRef member(shared_from_this(), ent);
  int count = 0;
  if (group.isValid() && member.isValid())
  {
    count = static_cast<int>(group.members<EntityRefs>().count(member));
    if (count == 0)
    {
      EntityRefArrangementOps::findOrAddSimpleRelationship(group, SUPERSET_OF, member);
      EntityRefArrangementOps::findOrAddSimpleRelationship(member, SUBSET_OF, group);
      ++count;
    }
  }
  return count > 0 ? true : false;
}

/**@name Attribute association
  *\brief Associate and disassociate attribute values to entities.
  */
//@{
/**\brief Report whether an entity has been assigned an attribute.
  *
  */
bool Manager::hasAttribute(const UUID& attribId, const UUID& toEntity)
{
  UUIDWithAttributeAssignments it = this->m_attributeAssignments->find(toEntity);
  if (it == this->m_attributeAssignments->end())
  {
    return false;
  }
  return it->second.isAssociated(attribId);
}

/**\brief Assign an attribute to an entity.
  *
  * This returns true when the attribute association is
  * valid (whether it was previously associated or not)
  * and false otherwise.
  */
bool Manager::associateAttribute(
  smtk::attribute::SystemPtr sys, const UUID& attribId, const UUID& toEntity)
{
  bool allowed = true;
  if (sys)
  {
    attribute::AttributePtr att = sys->findAttribute(attribId);
    if (!att || !att->associateEntity(toEntity))
    {
      allowed = false;
    }
    this->m_attributeSystems.insert(sys);
  }
  if (allowed)
    (*this->m_attributeAssignments)[toEntity].associateAttribute(attribId);
  return allowed;
}

/**\brief Unassign an attribute from an entity.
  *
  */
bool Manager::disassociateAttribute(
  smtk::attribute::SystemPtr sys, const UUID& attribId, const UUID& fromEntity, bool reverse)
{
  bool didRemove = false;
  UUIDWithAttributeAssignments ref = this->m_attributeAssignments->find(fromEntity);
  if (ref == this->m_attributeAssignments->end())
  {
    return didRemove;
  }
  if ((didRemove = ref->second.disassociateAttribute(attribId)))
  {
// If the AttributeAssignments instance is now empty, remove it.
// (Only do this for std::map storage, as it triggers assertion
// failures in sparsehash for no discernable reason.)
#ifndef SMTK_HASH_STORAGE
    if (ref->second.attributes().empty())
    {
      this->m_attributeAssignments->erase(ref);
    }
#endif
    // Notify the Attribute of the removal
    if (reverse && sys)
    {
      smtk::attribute::AttributePtr attrib = sys->findAttribute(attribId);
      // FIXME: Should we check that the manager's refManager
      //        is this Manager instance?
      if (attrib)
      {
        attrib->disassociateEntity(fromEntity, false);
      }
    }
  }
  return didRemove;
}

/**\brief Insert the attributes associated with \a modelEntity into the \a associations set.
  *
  * Returns true when modelEntity had any attributes (whether they were already
  * present in \a associations or not) in any attribute system and false otherwise.
  *
  * Note that attribute UUIDs may not be stored in any of the attribute systems
  * (e.g., when a model was loaded from a save file but the attributes were not),
  * in which case this method will return false even though attribute UUIDs were
  * stored on the model entity.
  * This way, a return value of true ensures that the set contains at least one entry.
  */
bool Manager::insertEntityAssociations(
  const EntityRef& modelEntity, std::set<smtk::attribute::AttributePtr>& associations)
{
  bool didFind = false;
  auto eait = this->m_attributeAssignments->find(modelEntity.entity());
  if (eait == this->m_attributeAssignments->end() || eait->second.attributes().empty())
  {
    return didFind;
  }
  for (auto attribId : eait->second.attributes())
  {
    for (auto attribSys : this->m_attributeSystems)
    {
      smtk::attribute::System::Ptr asys = attribSys.lock();
      smtk::attribute::AttributePtr att;
      if (asys && (att = asys->findAttribute(attribId)))
      {
        associations.insert(att);
        didFind = true;
        break; // no need to check other attribute systems (attributes are unique across systems).
      }
    }
  }
  return didFind;
}

// A convenience method that calls insertEntityAssociations and returns a newly-constructed set.
std::set<smtk::attribute::AttributePtr> Manager::associations(const EntityRef& modelEntity)
{
  std::set<smtk::attribute::AttributePtr> result;
  this->insertEntityAssociations(modelEntity, result);
  return result;
}
//@}

/**@name Unbacked entity insertion methods
  *\brief Methods to insert entities into the local storage independent of a session.
  *
  * The methods that start with "add" will generate a UUID for you and return
  * a entityref to the new entity.
  * Methods that start with "insert" accept a UUID and will return a entityref to
  * the new entity (or the existing entity if it matches the entity type being
  * created). If you specify a UUID in use by an entity of a different type, an
  * invalid entityref will be returned.
  * Finally, methods that start with "set" will either modify an existing entity
  * or create a new one as required. The "set" methods are used to modify arrangements
  * that may have been created as part of constructing other entities (e.g., calling
  * addFace() creates arrangements for 2 face-uses; you can then use setFaceUse to
  * replace any existing use records with the one you specify).
  */
//@{
/// Add a vertex to the manager (without any relationships) at the given \a uid.
Vertex Manager::insertVertex(const UUID& uid)
{
  return Vertex(shared_from_this(), this->setEntityOfTypeAndDimension(uid, CELL_ENTITY, 0)->first);
}

/// Add an edge to the manager (without any relationships) at the given \a uid.
Edge Manager::insertEdge(const UUID& uid)
{
  return Edge(shared_from_this(), this->setEntityOfTypeAndDimension(uid, CELL_ENTITY, 1)->first);
}

/// Add a face to the manager (without any relationships) at the given \a uid.
Face Manager::insertFace(const UUID& uid)
{
  return Face(shared_from_this(), this->setEntityOfTypeAndDimension(uid, CELL_ENTITY, 2)->first);
}

/// Add a volume to the manager (without any relationships) at the given \a uid.
Volume Manager::insertVolume(const UUID& uid)
{
  return Volume(shared_from_this(), this->setEntityOfTypeAndDimension(uid, CELL_ENTITY, 3)->first);
}

/// Add an edge to the manager (without any relationships)
Vertex Manager::addVertex()
{
  return Vertex(shared_from_this(), this->addEntityOfTypeAndDimension(CELL_ENTITY, 0));
}

/// Add an edge to the manager (without any relationships)
Edge Manager::addEdge()
{
  return Edge(shared_from_this(), this->addEntityOfTypeAndDimension(CELL_ENTITY, 1));
}

/**\brief Add a face to the manager (without any relationships)
  *
  * While this method does not add any relations, it
  * does create two HAS_USE arrangements to hold
  * FaceUse instances (assuming the Manager may be
  * downcast to a Manager instance).
  */
Face Manager::addFace()
{
  return Face(shared_from_this(), this->addEntityOfTypeAndDimension(CELL_ENTITY, 2));
}

/// Add a volume to the manager (without any relationships)
Volume Manager::addVolume()
{
  return Volume(shared_from_this(), this->addEntityOfTypeAndDimension(CELL_ENTITY, 3));
}

/// Insert a VertexUse at the specified \a uid.
VertexUse Manager::insertVertexUse(const UUID& uid)
{
  return VertexUse(
    shared_from_this(), this->setEntityOfTypeAndDimension(uid, USE_ENTITY, 0)->first);
}

/// Create a VertexUse with the specified \a uid and replace \a src's VertexUse.
VertexUse Manager::setVertexUse(const UUID& uid, const Vertex& src, int sense)
{
  VertexUse vertUse = this->insertVertexUse(uid);
  this->findCreateOrReplaceCellUseOfSenseAndOrientation(src.entity(), sense, POSITIVE, uid);
  return vertUse;
}

/// Insert a EdgeUse at the specified \a uid.
EdgeUse Manager::insertEdgeUse(const UUID& uid)
{
  return EdgeUse(shared_from_this(), this->setEntityOfTypeAndDimension(uid, USE_ENTITY, 1)->first);
}

/// Create a EdgeUse with the specified \a uid and replace \a src's EdgeUse.
EdgeUse Manager::setEdgeUse(const UUID& uid, const Edge& src, int sense, Orientation o)
{
  EdgeUse edgeUse = this->insertEdgeUse(uid);
  this->findCreateOrReplaceCellUseOfSenseAndOrientation(src.entity(), sense, o, uid);
  return edgeUse;
}

/// Insert a FaceUse at the specified \a uid.
FaceUse Manager::insertFaceUse(const UUID& uid)
{
  return FaceUse(shared_from_this(), this->setEntityOfTypeAndDimension(uid, USE_ENTITY, 2)->first);
}

/// Create a FaceUse with the specified \a uid and replace \a src's FaceUse.
FaceUse Manager::setFaceUse(const UUID& uid, const Face& src, int sense, Orientation o)
{
  FaceUse faceUse = this->insertFaceUse(uid);
  this->findCreateOrReplaceCellUseOfSenseAndOrientation(src.entity(), sense, o, uid);
  return faceUse;
}

/// Insert a VolumeUse at the specified \a uid.
VolumeUse Manager::insertVolumeUse(const UUID& uid)
{
  return VolumeUse(
    shared_from_this(), this->setEntityOfTypeAndDimension(uid, USE_ENTITY, 3)->first);
}

/// Create a VolumeUse with the specified \a uid and replace \a src's VolumeUse.
VolumeUse Manager::setVolumeUse(const UUID& uid, const Volume& src)
{
  VolumeUse volUse = this->insertVolumeUse(uid);
  this->findCreateOrReplaceCellUseOfSenseAndOrientation(src.entity(), 0, POSITIVE, uid);
  return volUse;
}

/// Add a vertex-use to the manager (without any relationships)
VertexUse Manager::addVertexUse()
{
  return VertexUse(shared_from_this(), this->addEntityOfTypeAndDimension(USE_ENTITY, 0));
}

/// Find or add a vertex-use to the manager with a relationship back to a vertex.
VertexUse Manager::addVertexUse(const Vertex& src, int sense)
{
  if (src.isValid() && src.manager().get() == this)
  {
    return VertexUse(src.manager(),
      this->findCreateOrReplaceCellUseOfSenseAndOrientation(src.entity(), sense, POSITIVE));
  }
  return VertexUse(); // invalid vertex use if source vertex was invalid or from a different manager.
}

/// Add an edge-use to the manager (without any relationships)
EdgeUse Manager::addEdgeUse()
{
  return EdgeUse(shared_from_this(), this->addEntityOfTypeAndDimension(USE_ENTITY, 1));
}

/// Find or add a edge-use to the manager with a relationship back to a edge.
EdgeUse Manager::addEdgeUse(const Edge& src, int sense, Orientation orient)
{
  if (src.isValid() && src.manager().get() == this)
  {
    return EdgeUse(src.manager(),
      this->findCreateOrReplaceCellUseOfSenseAndOrientation(src.entity(), sense, orient));
  }
  return EdgeUse(); // invalid edge use if source edge was invalid or from a different manager.
}

/// Add a face-use to the manager (without any relationships)
FaceUse Manager::addFaceUse()
{
  return FaceUse(shared_from_this(), this->addEntityOfTypeAndDimension(USE_ENTITY, 2));
}

/// Find or add a face-use to the manager with a relationship back to a face.
FaceUse Manager::addFaceUse(const Face& src, int sense, Orientation orient)
{
  if (src.isValid() && src.manager().get() == this)
  {
    return FaceUse(src.manager(),
      src.manager()->findCreateOrReplaceCellUseOfSenseAndOrientation(src.entity(), sense, orient));
  }
  return FaceUse(); // invalid face use if source face was invalid or from a different manager.
}

/// Add a volume-use to the manager (without any relationships)
VolumeUse Manager::addVolumeUse()
{
  return VolumeUse(shared_from_this(), this->addEntityOfTypeAndDimension(USE_ENTITY, 3));
}

/// Find or add a volume-use to the manager with a relationship back to a volume.
VolumeUse Manager::addVolumeUse(const Volume& src)
{
  if (src.isValid() && src.manager().get() == this)
  {
    return VolumeUse(src.manager(),
      src.manager()->findCreateOrReplaceCellUseOfSenseAndOrientation(src.entity(), 0, POSITIVE));
  }
  return VolumeUse(); // invalid volume use if source volume was invalid or from a different manager.
}

/// Insert a Chain at the specified \a uid.
Chain Manager::insertChain(const UUID& uid)
{
  return Chain(shared_from_this(),
    this->setEntityOfTypeAndDimension(uid, SHELL_ENTITY | DIMENSION_0 | DIMENSION_1, -1)->first);
}

/// Find or add a chain to the manager with a relationship back to its owning edge-use.
Chain Manager::setChain(const UUID& uid, const EdgeUse& use)
{
  Chain chain = this->insertChain(uid);
  this->findOrAddIncludedShell(use.entity(), uid);
  return chain;
}

/// Find or add a chain to the manager with a relationship back to its owning chain.
Chain Manager::setChain(const UUID& uid, const Chain& parent)
{
  Chain chain = this->insertChain(uid);
  this->findOrAddIncludedShell(parent.entity(), uid);
  return chain;
}

/// Insert a Loop at the specified \a uid.
Loop Manager::insertLoop(const UUID& uid)
{
  return Loop(shared_from_this(),
    this->setEntityOfTypeAndDimension(uid, SHELL_ENTITY | DIMENSION_1 | DIMENSION_2, -1)->first);
}

/// Find or add a chain to the manager with a relationship back to its owning face-use.
Loop Manager::setLoop(const UUID& uid, const FaceUse& use)
{
  Loop loop = this->insertLoop(uid);
  this->findOrAddIncludedShell(use.entity(), uid);
  return loop;
}

/// Find or add a chain to the manager with a relationship back to its owning loop.
Loop Manager::setLoop(const UUID& uid, const Loop& parent)
{
  Loop loop = this->insertLoop(uid);
  this->findOrAddIncludedShell(parent.entity(), uid);
  return loop;
}

/// Insert a Shell at the specified \a uid.
Shell Manager::insertShell(const UUID& uid)
{
  return Shell(shared_from_this(),
    this->setEntityOfTypeAndDimension(uid, SHELL_ENTITY | DIMENSION_2 | DIMENSION_3, -1)->first);
}

/// Find or add a chain to the manager with a relationship back to its owning volume-use.
Shell Manager::setShell(const UUID& uid, const VolumeUse& use)
{
  Shell shell = this->insertShell(uid);
  this->findOrAddIncludedShell(use.entity(), uid);
  return shell;
}

/// Find or add a chain to the manager with a relationship back to its owning shell.
Shell Manager::setShell(const UUID& uid, const Shell& parent)
{
  Shell shell = this->insertShell(uid);
  this->findOrAddIncludedShell(parent.entity(), uid);
  return shell;
}

/// Add a 0/1-d shell (a vertex chain) to the manager (without any relationships)
Chain Manager::addChain()
{
  return Chain(shared_from_this(),
    this->addEntityOfTypeAndDimension(SHELL_ENTITY | DIMENSION_0 | DIMENSION_1, -1));
}

/// Add a 0/1-d shell (a vertex chain) to the manager with a relation to its edge use
Chain Manager::addChain(const EdgeUse& eu)
{
  if (eu.isValid() && eu.manager().get() == this)
  {
    return Chain(eu.manager(), eu.manager()->createIncludedShell(eu.entity()));
  }
  return Chain();
}

/// Add a 0/1-d shell (a vertex chain) to the manager with a relation to its edge use
Chain Manager::addChain(const Chain& c)
{
  if (c.isValid() && c.manager().get() == this)
  {
    return Chain(c.manager(), c.manager()->createIncludedShell(c.entity()));
  }
  return Chain();
}

/// Add a 1/2-d shell (an edge loop) to the manager (without any relationships)
Loop Manager::addLoop()
{
  return Loop(shared_from_this(),
    this->addEntityOfTypeAndDimension(SHELL_ENTITY | DIMENSION_1 | DIMENSION_2, -1));
}

/// Add a 1/2-d shell (an edge loop) to the manager with a relation to its parent face use
Loop Manager::addLoop(const FaceUse& fu)
{
  if (fu.isValid() && fu.manager().get() == this)
  {
    return Loop(fu.manager(), fu.manager()->createIncludedShell(fu.entity()));
  }
  return Loop();
}

/// Add a 1/2-d shell (an edge loop) to the manager with a relation to its parent loop
Loop Manager::addLoop(const Loop& lp)
{
  if (lp.isValid() && lp.manager().get() == this)
  {
    return Loop(lp.manager(), lp.manager()->createIncludedShell(lp.entity()));
  }
  return Loop();
}

/// Add a 2/3-d shell (a face-shell) to the manager (without any relationships)
Shell Manager::addShell()
{
  return Shell(shared_from_this(),
    this->addEntityOfTypeAndDimension(SHELL_ENTITY | DIMENSION_2 | DIMENSION_3, -1));
}

/// A convenience method to find or create a volume use for the volume plus a shell.
Shell Manager::addShell(const Volume& v)
{
  VolumeUse vu;
  if (!v.uses<VolumeUses>().empty())
  {
    vu = v.uses<VolumeUses>()[0];
  }
  if (!vu.isValid())
  {
    vu = this->addVolumeUse(v);
  }
  return this->addShell(vu);
}

/// Add a 2/3-d shell (an face shell) to the manager with a relation to its volume
Shell Manager::addShell(const VolumeUse& v)
{
  if (v.isValid() && v.manager().get() == this)
  {
    return Shell(v.manager(), v.manager()->createIncludedShell(v.entity()));
  }
  return Shell();
}

/**\brief Add an entity group to the manager (without any relationships).
  *
  * Any non-zero bits set in \a extraFlags are OR'd with entityFlags() of the group.
  * This is an easy way to constrain the entities allowed to be members
  * of the group.
  *
  * You may also specify a \a name for the group. If \a name is empty, then no
  * name is assigned.
  */
Group Manager::insertGroup(const UUID& uid, int extraFlags, const std::string& groupName)
{
  UUIDWithEntity result = this->setEntityOfTypeAndDimension(uid, GROUP_ENTITY | extraFlags, -1);
  if (result == this->m_topology->end())
    return Group();

  if (!groupName.empty())
    this->setStringProperty(uid, "name", groupName);

  return Group(shared_from_this(), uid);
}

/// Add a group, creating a new UUID in the process. \sa insertGroup().
Group Manager::addGroup(int extraFlags, const std::string& groupName)
{
  UUID uid = this->unusedUUID();
  return this->insertGroup(uid, extraFlags, groupName);
}

/// Add auxiliary geometry (of the given \a dim, which may be -1) to the manager with the specified \a uid.
AuxiliaryGeometry Manager::insertAuxiliaryGeometry(const smtk::common::UUID& uid, int dim)
{
  UUIDWithEntity result = this->setEntityOfTypeAndDimension(uid, AUX_GEOM_ENTITY, dim);
  if (result == this->m_topology->end())
  {
    return AuxiliaryGeometry();
  }
  return AuxiliaryGeometry(shared_from_this(), uid);
}

/// Add auxiliary geometry (of the given \a dim, which may be -1) to the manager.
AuxiliaryGeometry Manager::addAuxiliaryGeometry(int dim)
{
  UUID uid = this->unusedUUID();
  return this->insertAuxiliaryGeometry(uid, dim);
}

/// Add auxiliary geometry (of the given \a dim, which may be -1) to the manager, embedded in its \a parent.
AuxiliaryGeometry Manager::addAuxiliaryGeometry(const Model& parent, int dim)
{
  Model mutableParent(parent);
  AuxiliaryGeometry auxGeom = this->addAuxiliaryGeometry(dim);
  mutableParent.addAuxiliaryGeometry(auxGeom);
  return auxGeom;
}

/// Add auxiliary geometry (of the given \a dim, which may be -1) to the manager, embedded in its \a parent.
AuxiliaryGeometry Manager::addAuxiliaryGeometry(const AuxiliaryGeometry& parent, int dim)
{
  AuxiliaryGeometry mutableParent(parent);
  AuxiliaryGeometry auxGeom = this->addAuxiliaryGeometry(dim);
  mutableParent.embedEntity(auxGeom);
  return auxGeom;
}

/**\brief Add a model to the manager.
  *
  * The model will have the specified \a embeddingDim set as an integer property
  * named "embedding dimension." This is the dimension of the space in which
  * vertex coordinates live.
  *
  * A model may also be given a parametric dimension
  * which is the maximum parametric dimension of any cell inserted into the model.
  * The parametric dimension is the rank of the space spanned by the shape functions
  * (for "parametric" meshes) or (for "discrete" meshes) barycentric coordinates of cells.
  *
  * You may also specify a \a name for the model. If \a name is empty, then no
  * name is assigned.
  *
  * A model maintains counters used to number model entities by type (uniquely within the
  * model). Any entities related to the model (directly or indirectly via topological
  * relationships) may have these numbers assigned as names by calling assignDefaultNames().
  */
Model Manager::insertModel(
  const UUID& uid, int parametricDim, int embeddingDim, const std::string& modelName)
{
  UUIDWithEntity result = this->setEntityOfTypeAndDimension(uid, MODEL_ENTITY, parametricDim);
  if (result == this->m_topology->end())
    return Model();

  if (embeddingDim > 0)
  {
    this->setIntegerProperty(uid, "embedding dimension", embeddingDim);
  }

  if (!modelName.empty())
    this->setStringProperty(uid, "name", modelName);
  else
    this->assignDefaultName(uid, this->type(uid));

  return Model(shared_from_this(), uid);
}

/// Add a model, creating a new UUID at the time. \sa insertModel().
Model Manager::addModel(int parametricDim, int embeddingDim, const std::string& modelName)
{
  UUID uid = this->unusedUUID();
  return this->insertModel(uid, parametricDim, embeddingDim, modelName);
}

/**\brief Add an instance of some model entity to the manager.
  *
  * An instance is a reference to some other item in the manager.
  * Any entity may be instanced, but generally models are instanced
  * as part of a scene graph.
  */
Instance Manager::addInstance()
{
  UUID uid = this->addEntityOfTypeAndDimension(INSTANCE_ENTITY, -1);
  return Instance(shared_from_this(), uid);
}

/**\brief Add an instance with the given prototype to the manager.
  *
  * The prototype \a object (the parent of the instance)
  * is a reference to some other item in the manager.
  * Any entity may be instanced, but generally models are instanced
  * as part of a scene graph.
  */
Instance Manager::addInstance(const EntityRef& object)
{
  if (object.isValid())
  {
    UUID uid = this->addEntityOfTypeAndDimension(INSTANCE_ENTITY, -1);
    int iidx = this->findEntity(object.entity())->findOrAppendRelation(uid);
    int oidx = this->findEntity(uid)->findOrAppendRelation(object.entity());
    this->arrangeEntity(uid, INSTANCE_OF, Arrangement::InstanceInstanceOfWithIndex(oidx));
    this->arrangeEntity(
      object.entity(), INSTANCED_BY, Arrangement::InstanceInstanceOfWithIndex(iidx));
    return Instance(shared_from_this(), uid);
  }
  return Instance();
}
//@}

/**\brief Unregister a session from the model manager.
  *
  */
bool Manager::closeSession(const SessionRef& sref)
{
  if (sref.manager().get() == this)
  {
    UUIDsToSessions::iterator us = this->m_sessions->find(sref.entity());
    if (us != this->m_sessions->end())
    {
      EntityRefs all; // a set of all entities in the session
      Models models = sref.models<Models>();
      EntityIterator eit;
      eit.traverse(models.begin(), models.end(), ITERATE_MODELS);
      for (eit.begin(); !eit.isAtEnd(); ++eit)
      {
        if (!eit->isSessionRef())
        {
          all.insert(*eit);
        }
      }
      for (auto ent : all)
      {
        this->hardErase(ent);
      }
      bool didClose = this->unregisterSession(sref.session(), true);
      return didClose;
    }
  }
  else
  {
    smtkErrorMacro(this->log(), "Asked to close session ("
        << sref.name() << ") "
        << "owned by a different manager (" << sref.manager().get() << " vs " << this << ")!");
  }
  return false;
}

/**\brief Return an array of all the sessions this manager owns.
  *
  */
SessionRefs Manager::sessions() const
{
  SessionRefs result;
  UUIDsToSessions::const_iterator it;
  for (it = this->m_sessions->begin(); it != this->m_sessions->end(); ++it)
    result.push_back(SessionRef(smtk::const_pointer_cast<Manager>(shared_from_this()), it->first));
  return result;
}

/**@name Callback methods
  *\brief These methods provide observers with a way to register
  *       and receive notifications of modeling events.
  *
  * Events have 1 of 3 different signatures based on the type of event:
  *
  * + When a single entity is modified independently of changes to others,
  *   a ConditionCallback is invoked.
  * + When a one-to-one relationship between two entities is affected,
  *   a OneToOneCallback is invoked.
  * + When a one-to-many (or a many-to-one) relationship between entities
  *   is affected, a OneToManyCallback is invoked.
  */
//@{
/// Request notification from this manager instance when \a event occurs.
void Manager::observe(ManagerEventType event, ConditionCallback functionHandle, void* callData)
{
  if (event.first == ANY_EVENT)
  {
    int i;
    int iend = static_cast<int>(ANY_EVENT);
    for (i = static_cast<int>(ADD_EVENT); i != iend; ++i)
    {
      event.first = static_cast<ManagerEventChangeType>(i);
      this->observe(event, functionHandle, callData);
    }

    return;
  }

  this->m_conditionTriggers.insert(
    ConditionTrigger(event, ConditionObserver(functionHandle, callData)));
}

/// Request notification from this manager instance when \a event occurs.
void Manager::observe(ManagerEventType event, OneToOneCallback functionHandle, void* callData)
{
  if (event.first == ANY_EVENT)
  {
    int i;
    int iend = static_cast<int>(ANY_EVENT);
    for (i = static_cast<int>(ADD_EVENT); i != iend; ++i)
    {
      event.first = static_cast<ManagerEventChangeType>(i);
      this->observe(event, functionHandle, callData);
    }

    return;
  }

  this->m_oneToOneTriggers.insert(
    OneToOneTrigger(event, OneToOneObserver(functionHandle, callData)));
}

/// Request notification from this manager instance when \a event occurs.
void Manager::observe(ManagerEventType event, OneToManyCallback functionHandle, void* callData)
{
  if (event.first == ANY_EVENT)
  {
    int i;
    int iend = static_cast<int>(ANY_EVENT);
    for (i = static_cast<int>(ADD_EVENT); i != iend; ++i)
    {
      event.first = static_cast<ManagerEventChangeType>(i);
      this->observe(event, functionHandle, callData);
    }

    return;
  }

  this->m_oneToManyTriggers.insert(
    OneToManyTrigger(event, OneToManyObserver(functionHandle, callData)));
}

/// Request notification from this manager instance when \a event occurs.
void Manager::observe(OperatorEventType event, BareOperatorCallback functionHandle, void* callData)
{
  if (event != CREATED_OPERATOR)
  {
    smtkWarningMacro(this->m_log,
      "The model manager only allows observation of CREATED_OPERATOR, not " << event << ".");
    return;
  }

  this->m_operatorTriggers.insert(
    BareOperatorTrigger(event, BareOperatorObserver(functionHandle, callData)));
}

/// Decline further notification from this manager instance when \a event occurs.
void Manager::unobserve(ManagerEventType event, ConditionCallback functionHandle, void* callData)
{
  if (event.first == ANY_EVENT)
  {
    int i;
    int iend = static_cast<int>(ANY_EVENT);
    for (i = static_cast<int>(ADD_EVENT); i != iend; ++i)
    {
      event.first = static_cast<ManagerEventChangeType>(i);
      this->unobserve(event, functionHandle, callData);
    }

    return;
  }

  this->m_conditionTriggers.erase(
    ConditionTrigger(event, ConditionObserver(functionHandle, callData)));
}

/// Decline further notification from this manager instance when \a event occurs.
void Manager::unobserve(ManagerEventType event, OneToOneCallback functionHandle, void* callData)
{
  if (event.first == ANY_EVENT)
  {
    int i;
    int iend = static_cast<int>(ANY_EVENT);
    for (i = static_cast<int>(ADD_EVENT); i != iend; ++i)
    {
      event.first = static_cast<ManagerEventChangeType>(i);
      this->unobserve(event, functionHandle, callData);
    }

    return;
  }

  this->m_oneToOneTriggers.erase(
    OneToOneTrigger(event, OneToOneObserver(functionHandle, callData)));
}

/// Decline further notification from this manager instance when \a event occurs.
void Manager::unobserve(ManagerEventType event, OneToManyCallback functionHandle, void* callData)
{
  if (event.first == ANY_EVENT)
  {
    int i;
    int iend = static_cast<int>(ANY_EVENT);
    for (i = static_cast<int>(ADD_EVENT); i != iend; ++i)
    {
      event.first = static_cast<ManagerEventChangeType>(i);
      this->unobserve(event, functionHandle, callData);
    }

    return;
  }

  this->m_oneToManyTriggers.erase(
    OneToManyTrigger(event, OneToManyObserver(functionHandle, callData)));
}

/// Decline further notification from this manager instance when \a event occurs.
void Manager::unobserve(
  OperatorEventType event, BareOperatorCallback functionHandle, void* callData)
{
  this->m_operatorTriggers.erase(
    BareOperatorTrigger(event, BareOperatorObserver(functionHandle, callData)));
}

/// Called by this Manager instance or EntityRef instances referencing it when \a event occurs.
void Manager::trigger(ManagerEventType event, const smtk::model::EntityRef& src)
{
  std::set<ConditionTrigger>::const_iterator begin = this->m_conditionTriggers.lower_bound(
    ConditionTrigger(event, ConditionObserver(ConditionCallback(), static_cast<void*>(NULL))));
  std::set<ConditionTrigger>::const_iterator end =
    this->m_conditionTriggers.upper_bound(ConditionTrigger(
      std::make_pair(event.first, static_cast<ManagerEventRelationType>(event.second + 1)),
      ConditionObserver(ConditionCallback(), static_cast<void*>(NULL))));
  for (std::set<ConditionTrigger>::const_iterator it = begin; it != end; ++it)
    (*it->second.first)(it->first, src, it->second.second);
}

/// Called by this Manager instance or EntityRef instances referencing it when \a event occurs.
void Manager::trigger(
  ManagerEventType event, const smtk::model::EntityRef& src, const smtk::model::EntityRef& related)
{
  std::set<OneToOneTrigger>::const_iterator begin = this->m_oneToOneTriggers.lower_bound(
    OneToOneTrigger(event, OneToOneObserver(OneToOneCallback(), static_cast<void*>(NULL))));
  std::set<OneToOneTrigger>::const_iterator end =
    this->m_oneToOneTriggers.upper_bound(OneToOneTrigger(
      std::make_pair(event.first, static_cast<ManagerEventRelationType>(event.second + 1)),
      OneToOneObserver(OneToOneCallback(), static_cast<void*>(NULL))));
  for (std::set<OneToOneTrigger>::const_iterator it = begin; it != end; ++it)
    (*it->second.first)(it->first, src, related, it->second.second);
}

/// Called by this Manager instance or EntityRef instances referencing it when \a event occurs.
void Manager::trigger(ManagerEventType event, const smtk::model::EntityRef& src,
  const smtk::model::EntityRefArray& related)
{
  std::set<OneToManyTrigger>::const_iterator begin = this->m_oneToManyTriggers.lower_bound(
    OneToManyTrigger(event, OneToManyObserver(OneToManyCallback(), static_cast<void*>(NULL))));
  std::set<OneToManyTrigger>::const_iterator end =
    this->m_oneToManyTriggers.upper_bound(OneToManyTrigger(
      std::make_pair(event.first, static_cast<ManagerEventRelationType>(event.second + 1)),
      OneToManyObserver(OneToManyCallback(), static_cast<void*>(NULL))));
  for (std::set<OneToManyTrigger>::const_iterator it = begin; it != end; ++it)
    (*it->second.first)(it->first, src, related, it->second.second);
}

/// Called by this Manager instance or Session instances referencing it when \a event occurs.
void Manager::trigger(OperatorEventType event, const smtk::model::Operator& src)
{
  std::set<BareOperatorTrigger>::const_iterator begin =
    this->m_operatorTriggers.lower_bound(BareOperatorTrigger(
      event, BareOperatorObserver(BareOperatorCallback(), static_cast<void*>(NULL))));
  for (std::set<BareOperatorTrigger>::const_iterator it = begin;
       it != this->m_operatorTriggers.end() && it->first == event; ++it)
    (*it->second.first)(it->first, src, it->second.second);
}
//@}

template <typename T>
std::string uniqueResourceName(EntityRef ent, const T& preexisting, int& counter)
{
  std::string prefix = ent.isModel() ? "model" : "aux-geom";
  std::string result;
  do
  {
    std::ostringstream ns;
    ns << prefix << (++counter);
    result = ns.str();
  } while (preexisting.find(result) != preexisting.end());
  return result;
}

/// An internal method that iterates over entities discovering resources.
void Manager::computeResources()
{
  int counter = 0;
  EntityRefArray subresources;
  subresources = this->findEntitiesOfType(MODEL_ENTITY | AUX_GEOM_ENTITY | SESSION,
    /* exactMatch */ false);

  std::vector<std::string> vpre = this->m_resources->resourceIds();
  std::set<std::string> preexistingIds(vpre.begin(), vpre.end());
  std::map<std::string, std::string> urlsToResourceNames;
  ResourcePtr rsrc;
  StoredResourcePtr srsrc;
  for (auto preId : preexistingIds)
  {
    if (this->m_resources->get(preId, rsrc) &&
      (srsrc = smtk::dynamic_pointer_cast<StoredResource>(rsrc)))
    {
      urlsToResourceNames[srsrc->url()] = preId;
    }
  }

  std::set<std::string> usedResources;
  std::map<std::string, std::string>::iterator lookup;
  std::string url;
  for (auto ent : subresources)
  {
    if (ent.hasStringProperty("url") && !(url = ent.stringProperty("url")[0]).empty())
    {
      if ((lookup = urlsToResourceNames.find(url)) == urlsToResourceNames.end())
      { // Insert resource:
        std::string newResourceName = uniqueResourceName(ent, preexistingIds, counter);
        srsrc = StoredResource::create();
        srsrc->setURL(url);
        if (ent.isModel())
        {
          srsrc->markModified(ent.as<Model>().isModified());
        }
        else if (ent.isAuxiliaryGeometry())
        {
          srsrc->markModified(ent.as<AuxiliaryGeometry>().isModified());
        }
        else
        { // Assume it's modified if not on disk, otherwise unmodified
          srsrc->markModified(srsrc->exists(this->m_resources->linkStartPath()));
        }
        this->m_resources->addResource(srsrc, newResourceName, "",
          ent.isAuxiliaryGeometry() ? ResourceSet::AUX_GEOM_RESOURCE : ResourceSet::MODEL_RESOURCE);
        urlsToResourceNames[url] = newResourceName;
      }
      std::string rsrcName = urlsToResourceNames[url];
      usedResources.insert(rsrcName);
      if (this->m_resources->get(rsrcName, rsrc) &&
        (srsrc = std::dynamic_pointer_cast<StoredResource>(rsrc)))
      {
        srsrc->addEntity(ent);
      }
    }
    if (ent.hasStringProperty("smtk_url") && !(url = ent.stringProperty("smtk_url")[0]).empty())
    {
      if ((lookup = urlsToResourceNames.find(url)) == urlsToResourceNames.end())
      { // Insert resource:
        std::string newResourceName = uniqueResourceName(ent, preexistingIds, counter);
        srsrc = StoredResource::create();
        srsrc->setURL(url);
        if (ent.isModel())
        {
          srsrc->markModified(ent.as<Model>().isModified());
        }
        else if (ent.isAuxiliaryGeometry())
        {
          srsrc->markModified(ent.as<AuxiliaryGeometry>().isModified());
        }
        else
        { // Assume it's modified if not on disk, otherwise unmodified
          srsrc->markModified(srsrc->exists(this->m_resources->linkStartPath()));
        }
        this->m_resources->addResource(srsrc, newResourceName, "", ResourceSet::MODEL_RESOURCE);
        urlsToResourceNames[url] = newResourceName;
      }
      std::string rsrcName = urlsToResourceNames[url];
      usedResources.insert(rsrcName);
      if (this->m_resources->get(rsrcName, rsrc) &&
        (srsrc = std::dynamic_pointer_cast<StoredResource>(rsrc)))
      {
        srsrc->addEntity(ent);
      }
    }
  }

  // Remove resources no longer present
  for (auto used : usedResources)
  {
    preexistingIds.erase(used);
  }
  if (!preexistingIds.empty())
  {
    for (auto unused : preexistingIds)
    {
      smtkDebugMacro(this->log(), "Erasing unused resource \"" << unused << "\"");
      this->m_resources->removeResource(unused);
    }
  }
}

/// Internal method used by modelOwningEntity to prevent infinite recursion
UUID Manager::modelOwningEntityRecursive(const UUID& ent, std::set<UUID>& visited) const
{
  if (visited.find(ent) != visited.end())
  {
    return UUID::null(); // We've already search here with no result.
  }
  visited.insert(ent);

  UUID uid(ent);
  UUIDsToEntities::const_iterator it = this->m_topology->find(uid);
  if (it != this->m_topology->end())
  {
    // If we have a use or a shell, get the associated cell, if any
    smtk::model::BitFlags etype = it->second.entityFlags();
    switch (etype & ENTITY_MASK)
    {
      case AUX_GEOM_ENTITY:
      {
        ManagerPtr self = const_cast<Manager*>(this)->shared_from_this();
        EntityRef aux(self, ent);
        for (aux = aux.embeddedIn(); aux.isValid(); aux = aux.embeddedIn())
        {
          if (aux.isModel())
          {
            return aux.entity();
          }
        }
        return UUID();
      }
      break;
      case GROUP_ENTITY:
      {
        // If we have a superset arrangement, ask for supersets and traverse upwards.
        ManagerPtr self = const_cast<Manager*>(this)->shared_from_this();
        EntityRefArray supersets;
        EntityRefArrangementOps::appendAllRelations(
          EntityRef(self->shared_from_this(), ent), SUBSET_OF, supersets);
        if (!supersets.empty())
        {
          EntityRef super;
          for (EntityRefArray::iterator spit = supersets.begin(); spit != supersets.end(); ++spit)
          {
            if (spit->isModel())
              return spit->entity();
          }
          // No models are in my superset... traverse up the first superset to find a model:
          for (auto ssentry = supersets.begin(); ssentry != supersets.end(); ++ssentry)
          {
            UUID result = this->modelOwningEntityRecursive(ssentry->entity(), visited);
            if (result)
            {
              return result;
            }
          }
        }

        // Assume the first relationship that is a group or model is our owner.
        // Keep going up parent groups until we hit the top.
        for (UUIDArray::const_iterator sit = it->second.relations().begin();
             sit != it->second.relations().end(); ++sit)
        {
          UUIDsToEntities::const_iterator subentity = this->topology().find(*sit);
          if (subentity != this->topology().end() && subentity->first != uid)
          {
            if (subentity->second.entityFlags() & MODEL_ENTITY)
              return subentity->first;
            if (subentity->second.entityFlags() & GROUP_ENTITY)
            { // Switch to finding relations of the group (assume it is our parent)
              uid = subentity->first;
              it = this->m_topology->find(uid);
              sit = it->second.relations().begin();
            }
          }
        }
      }
      break;
      case INSTANCE_ENTITY:
        // Look for any relationship. We assume the first one is our prototype.
        for (UUIDArray::const_iterator sit = it->second.relations().begin();
             sit != it->second.relations().end(); ++sit)
        {
          UUIDsToEntities::const_iterator subentity = this->topology().find(*sit);
          if (subentity != this->topology().end() && subentity->first != uid)
          {
            if (subentity->second.entityFlags() & MODEL_ENTITY)
              return subentity->first;
            UUID result = this->modelOwningEntityRecursive(subentity->first, visited);
            if (result)
            {
              return result;
            }
            break;
          }
        }
        break;
      case SHELL_ENTITY:
        // Loop for a relationship to a use.
        for (UUIDArray::const_iterator sit = it->second.relations().begin();
             sit != it->second.relations().end(); ++sit)
        {
          UUIDsToEntities::const_iterator subentity = this->topology().find(*sit);
          if (subentity != this->topology().end() &&
            smtk::model::isUseEntity(subentity->second.entityFlags()))
          {
            it = subentity;
            break;
          }
        }
      // Now fall through and look for the use's relationship to a cell.
      case USE_ENTITY:
        // Look for a relationship to a cell
        for (UUIDArray::const_iterator sit = it->second.relations().begin();
             sit != it->second.relations().end(); ++sit)
        {
          UUIDsToEntities::const_iterator subentity = this->topology().find(*sit);
          if (subentity != this->topology().end() &&
            smtk::model::isCellEntity(subentity->second.entityFlags()))
          {
            it = subentity;
            break;
          }
        }
        break;
      case MODEL_ENTITY:
        // For models, life is tricky. Without arrangement information, we cannot
        // know whether a related model is a child or a parent. Two models might
        // point to each other, which could throw us into an infinite loop. So,
        // we attempt to cast ourselves to Manager and identify a parent model.
        {
          // Although const_pointer_cast is evil, changing the entityref classes
          // to accept any type of shared_ptr<X/X const> is more evil.
          ManagerPtr self = smtk::const_pointer_cast<Manager>(shared_from_this());
          return Model(self, ent).parent().entity();
        }
        break;
      // Remaining types should all have a direct relationship with a model if they are free:
      default:
      case CELL_ENTITY:
        break;
    }
    // Now look for a direct relationship with a model.
    // If none exists, look for relationships with higher-dimensional entities
    // and check *them* for models.
    int dim;
    UUIDs uids;
    uids.insert(it->first);
    for (dim = it->second.dimension(); dim >= 0 && dim < 4; ++dim)
    {
      for (UUIDs::iterator uit = uids.begin(); uit != uids.end(); ++uit)
      {
        const Entity* bordEnt = this->findEntity(*uit);
        if (!bordEnt)
          continue;
        for (UUIDArray::const_iterator rit = bordEnt->relations().begin();
             rit != bordEnt->relations().end(); ++rit)
        {
          const Entity* relEnt = this->findEntity(*rit);
          if (relEnt && relEnt != bordEnt && (relEnt->entityFlags() & MODEL_ENTITY))
          {
            return *rit;
          }
        }
      }
      // FIXME: This is slow. Avoid calling bordantEntities().
      uids = this->bordantEntities(uids, dim + 1);
    }
  }
  return UUID::null();
}

/// Attempt to find a session owning the given entity.
UUID Manager::sessionOwningEntityRecursive(const UUID& ent, std::set<UUID>& visited) const
{
  if (visited.find(ent) != visited.end())
  {
    return UUID::null(); // We've already been here with no result
  }
  visited.insert(ent);

  const Entity* erec = this->findEntity(ent);
  if (erec)
  {
    // Traverse up to the owning model
    UUID uid = isModel(erec->entityFlags()) ? ent : modelOwningEntity(ent);
    // The parent of a model should be another model or session.

    // If we have a superset arrangement, ask for supersets and traverse upwards.
    ManagerPtr self = const_cast<Manager*>(this)->shared_from_this();
    EntityRefArray supersets;
    EntityRefArrangementOps::appendAllRelations(
      EntityRef(self->shared_from_this(), uid), SUBSET_OF, supersets);
    if (!supersets.empty())
    {
      EntityRef super;
      for (EntityRefArray::iterator spit = supersets.begin(); spit != supersets.end(); ++spit)
      {
        if (spit->isSessionRef())
          return spit->entity();
      }
      // No sessions are in my superset... traverse up the first superset to find one:
      for (auto ssentry = supersets.begin(); ssentry != supersets.end(); ++ssentry)
      {
        UUID result = this->sessionOwningEntityRecursive(ssentry->entity(), visited);
        if (result)
        {
          return result;
        }
      }
    }

    // Assume the first relationship that is a session or model is our owner.
    // Keep going up parents until we hit the top.
    UUIDsToEntities::const_iterator it = this->m_topology->find(uid);
    for (UUIDArray::const_iterator sit = it->second.relations().begin();
         sit != it->second.relations().end(); ++sit)
    {
      UUIDsToEntities::const_iterator subentity = this->topology().find(*sit);
      if (subentity != this->topology().end() && subentity->first != uid)
      {
        if (isSessionRef(subentity->second.entityFlags()))
          return subentity->first;
        if (isModel(subentity->second.entityFlags()))
        { // Switch to finding relations of the model (assume it is our parent)
          uid = subentity->first;
          it = this->m_topology->find(uid);
          sit = it->second.relations().begin();
        }
      }
    }
    return uid;
  }
  return UUID::null();
}

} // namespace model
} //namespace smtk
