/*
  CoreLinux++ 
  Copyright (C) 2000 CoreLinux Consortium
  
   The CoreLinux++ Library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public License as
   published by the Free Software Foundation; either version 2 of the
   License, or (at your option) any later version.

   The CoreLinux++ Library Library is distributed in the hope that it will 
   be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public
   License along with the GNU C Library; see the file COPYING.LIB.  If not,
   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   Boston, MA 02111-1307, USA.  
*/   

#if   !defined(__COMMON_HPP)
#include <Common.hpp>
#endif

using namespace corelinux;

#if   !defined(__OBJECTMODEL_HPP)
#include <ObjectModel.hpp>
#endif

#if   !defined(__OBJECTFACTORY_HPP)                            
#include <ObjectFactory.hpp>
#endif

#if   !defined( __DICTIONARY_HPP )
#include <Dictionary.hpp>
#endif

#if   !defined( __MODELER_HPP )
#include <Modeler.hpp>
#endif

//
// Default constructor
//

static   Object   dummy(0);

ObjectModel::ObjectModel( void )
   :
   Facade(),
   theRoot( dummy ),
   theName( "" ),
   theDictionary( NULLPTR ),
   theModeler( NULLPTR )
{
   NEVER_GET_HERE;
}

//
// Proper constructor
//

ObjectModel::ObjectModel( const string &aName )
   :
   Facade(),
   theRoot
      ( 
         ObjectFactory::createObject
            ( 
               ObjectFactory::getNewIdentifier() 
            ) 
      ),
   theName( aName ),
   theDictionary( new Dictionary ),
   theModeler( new Modeler )
{
   ENSURE( theDictionary != NULLPTR );
   ENSURE( theModeler != NULLPTR );
   ENSURE( theRoot.getIdentity() != dummy.getIdentity() );
   theDictionary->addName("Root", theRoot.getIdentity() );
}

//
// Copy constructor
//

ObjectModel::ObjectModel( ObjectModelCref aRef )
   :
   Facade( aRef ),
   theRoot( dummy ),
   theName( "" ),
   theDictionary( NULLPTR ),
   theModeler( NULLPTR )
{
   NEVER_GET_HERE;
}

//
// Destructor
//

ObjectModel::~ObjectModel( void )
{
   ObjectFactory::destroyAllObjects();
   if( theDictionary != NULLPTR )
   {
      delete theDictionary;
      theDictionary = NULLPTR;
   }
   else
   {
      NEVER_GET_HERE;
   }
   if( theModeler != NULLPTR )
   {
      delete theModeler;
      theModeler = NULLPTR;
   }
   else
   {
      NEVER_GET_HERE;
   }
}

//
// Assignment operator
//

ObjectModelRef ObjectModel::operator=( ObjectModelCref )
{
   NEVER_GET_HERE;
   return (*this);
}

//
// Equality operator
//

bool ObjectModel::operator==( ObjectModelCref aRef ) const
{
   return (theName == aRef.getName() );
}

//
// Retrieve my name
//

const string & ObjectModel::getName( void ) const
{
   return theName;
}

//
// Create a new object 
//

void  ObjectModel::createObject( const string &aName ) 
         throw (NameExistException)
{
   Identifier aId( theDictionary->getIdentifierForName(aName) );

   //
   // If the object name doesn't already exist we create it
   // add it's name to the dictionary, and tie a parent to
   // the root.
   //

   if( aId == DwordIdentifier(0) )
   {
      ObjectCref  aObject
         ( 
            ObjectFactory::createObject( ObjectFactory::getNewIdentifier() )
         );

      theDictionary->addName( aName, aObject.getIdentity() );
      theModeler->addParent( aObject.getIdentity(), theRoot.getIdentity() );
   }

   //
   // Otherwise collision alert
   //

   else
   {
      string   emsg(aName);
      emsg += " already exists in dictionary.";
      throw NameExistException(emsg.data(),LOCATION);
   }

}

//
// Destroy an object
//

void  ObjectModel::destroyObject( const string &aName ) 
         throw (NameNotExistException)
{
   DwordIdentifier aId( theDictionary->getIdentifierForName(aName) );

   //
   // If the name exists, we clean it up
   //

   if( aId == theRoot.getIdentity() )
   {
      cerr  << "Can't destroy Root" << endl;
   }
   else if( aId != DwordIdentifier(0) )
   {
      theModeler->removeParents( aId );
      theModeler->removeChildren( aId );
      theDictionary->removeName( aId );
      ObjectFactory::destroyObject( aId );
   }

   //
   // Otherwise we say we can't find it
   //

   else
   {
      string   emsg(aName);
      emsg += " does not exists in dictionary.";
      throw NameNotExistException(emsg.data(),LOCATION);
   }

}

//
// Change the name of the object
//

void  ObjectModel::changeName
   ( 
      const string &aOldName, 
      const string &aNewName 
   ) throw( NameExistException, NameNotExistException )
{

   DwordIdentifier aIdOld( theDictionary->getIdentifierForName(aOldName) );
   DwordIdentifier aIdNew( theDictionary->getIdentifierForName(aNewName) );

   //
   // We validate that the old name exists and the new
   // name is not taken.
   //

   if( aIdOld == DwordIdentifier(0) )
   {
      string   emsg(aOldName);
      emsg += " does not exists in dictionary.";
      throw NameNotExistException(emsg.data(),LOCATION);
   }
   else if( aIdNew != DwordIdentifier(0) )
   {
      string   emsg(aNewName);
      emsg += " already exists in dictionary.";
      throw NameExistException(emsg.data(),LOCATION);
   }

   //
   // All clear, change the name
   //

   else
   {
      theDictionary->changeName( aIdOld, aNewName );
   }

}

//
// Add a parent to an object
//

void  ObjectModel::addParent
   ( 
      const string &aChild, 
      const string &aParent 
   ) throw (NameNotExistException)
{
   DwordIdentifier aIdChild( theDictionary->getIdentifierForName(aChild) );
   DwordIdentifier aIdParent( theDictionary->getIdentifierForName(aParent) );

   if( aIdChild == DwordIdentifier(0) )
   {
      string   emsg(aChild);
      emsg += " does not exists in dictionary.";
      throw NameNotExistException(emsg.data(),LOCATION);

   }
   else if( aIdParent == DwordIdentifier(0) )
   {
      string   emsg(aParent);
      emsg += " does not exists in dictionary.";
      throw NameNotExistException(emsg.data(),LOCATION);

   }
   else
   {
      theModeler->addParent( aIdChild, aIdParent );
   }

}

//
// Removes parent from object
//

void  ObjectModel::removeParent
   ( 
      const string &aChild, 
      const string &aParent 
   ) throw (NameNotExistException)
{
   DwordIdentifier aIdChild( theDictionary->getIdentifierForName(aChild) );
   DwordIdentifier aIdParent( theDictionary->getIdentifierForName(aParent) );

   if( aIdChild == DwordIdentifier(0) )
   {
      string   emsg(aChild);
      emsg += " does not exists in dictionary.";
      throw NameNotExistException(emsg.data(),LOCATION);

   }
   else if( aIdParent == DwordIdentifier(0) )
   {
      string   emsg(aParent);
      emsg += " does not exists in dictionary.";
      throw NameNotExistException(emsg.data(),LOCATION);

   }
   else
   {
      theModeler->removeParent( aIdChild, aIdParent );
   }
}

//
// Dump information about object
//

void  ObjectModel::display( const string &aObject, ostream &aStream ) 
                     throw (NameNotExistException)
{
   DwordIdentifier aId( theDictionary->getIdentifierForName(aObject) );

   if( aId != DwordIdentifier(0) )
   {
      Count aParentCount( theModeler->getParentCount(aId) );

      aStream << aObject << " is a object with " << 
          aParentCount << " parents :" << endl;
      if( aParentCount > 0 )
      {
         IdVector aParentVector( theModeler->getParents(aId) );
         
         for( Count x=0; x < aParentCount; ++x )
         {
            aStream << "Parent " << x+1 << " : " <<
               theDictionary->getNameForIdentifier( aParentVector[x] ) <<
               endl;
         }
      }
   }
   else
   {
      string   emsg(aObject);
      emsg += " does not exists in dictionary.";
      throw NameNotExistException(emsg.data(),LOCATION);
   }
}

void  ObjectModel::display( ostream &aStream )
{
   aStream  << "Dumping all objects in " << this->getName() << endl;

   NameMapCref          aMap( theDictionary->getMap() );
   NameMapConstIterator begin( aMap.begin() );
   NameMapConstIterator end( aMap.end() );
   while( begin != end )
   {
      if( (*begin).first != theRoot.getIdentity() )
      {
         this->display( (*begin).second, aStream );
      }
      else
      {
         ;  // do nothing
      }
      ++begin;
   }
}

/*
   Common rcs information do not modify
   $Author: frankc $
   $Revision: 1.2 $
   $Date: 2000/03/01 03:28:18 $
   $Locker:  $
*/

