/******************************************************************
  
  Module:  registry.cpp
  
  Author: Sean Craig
  
  Copyright 2005 Sony Online Entertainment.  All rights reserved.
  
*******************************************************************/

//-------------------------------------------------------- Includes
#include "registry.h"
#include "tinyxml.h"
#include "titan.h"
#include "SyScene.h"
#include "SyLoader.h"
#include "SyESFParse.h"       
#include "SyStr.h"
#include "stats.h"
#include "inventory.h"
#include "cameracontroller.h"
#include "TitanPeeringNetwork.h"
#include "graphic.h"
#include "SyDebug.h"
#include "ai/aiblackboard.h"
#include "database.h"

//---------------------------------------------- Class Declarations
//--------------------------------------------------------- Globals
//----------------------------------------- Functions Declarations
//------------------------------------ Member Functions Definitions

//------------------------------------ cLevelObject

cLevelObject::cLevelObject() :
  mID(LEVEL_OBJECT_GAME_ID),
  mpTitan(NULL),
  mpLoader(0),
  mpAIBlackboard(NULL)
{
  InitPropObject( LEVELOBJECT_CLASSID );
}


cLevelObject::~cLevelObject()
{
  delete mpAIBlackboard;
  mpAIBlackboard = NULL;

  delete mpLoader;
  mpLoader = NULL;
}

int           
cLevelObject::InitPropClass()
{
  SyPropClassID ClassID = LEVELOBJECT_CLASSID;

/* Add the class */

  AddClass( ClassID, 
           "cLevelObject", 
            Creator, 
            ClassID, 
            0 ); 
  AddStringProperty(ClassID,0x0000,SyMemberOffset(cLevelObject,mModelName),"mModelName");
  AddStringProperty(ClassID,0x0001,SyMemberOffset(cLevelObject,mCameraName),"mCameraName");
  AddSubObjectPtrProperty(ClassID,0x0002,SyMemberOffset(cLevelObject,mpAIBlackboard),"mpAIBlackboard");

  return 0;
}

SyPropObject* 
cLevelObject::Creator()
{
  SyPropObject *pObject;

  pObject = SyNew cLevelObject();
  if (pObject == NULL)
  {
    SyAssert(0);
    return(NULL);
  }

  return(pObject);
}

void  
cLevelObject::SetCameraName(const char *name)
{
  mCameraName.Init(name);
}

void  
cLevelObject::SetModelName(const char *name)
{
  mModelName.Clear();
  // pull out all but extension
  const char *end_name = &name[strlen(name)-1];
  while (end_name != name && *(end_name-1) != '/') 
  {
    --end_name;
  }
  // change path
  mModelName.Init("data/art/level/");
  mModelName.Concat(end_name);
}

void
cLevelObject::SetRemote(bool bRemote)
{
  SyAssertf(mpAIBlackboard != NULL, "cLevelObject::SetRemote - no blackboard");

  if (mpAIBlackboard)
  {
    mpAIBlackboard->SetRemote(bRemote);
  }
}

#define STREAMING

void
cLevelObject::Init(Titan *titan)
{
  mpTitan = titan;
  SyESFParse Parser;
  SyScene *scene = titan->GetScene();

  cCameraController *pCameraController = titan->GetCameraController();
  pCameraController->LoadCameraFile(GetCameraName());

  // hack to change path name

  static const int BUFFER_SIZE = 512;
  char buffer[BUFFER_SIZE];
  strncpy(buffer,GetModelName(),BUFFER_SIZE);
  SetModelName(buffer);

#ifdef STREAMING
  if ( !(mpLoader = new SyLoader()) )
  {
    SyAssert(!"new SyLoader failed");
  }

  if ( mpLoader->Init( 
    32 * 1024 * 1024, // buffer size
    1 // number of files
    ) < 0 )
  {
    SyAssert(!"SyLoader::Init failed");
  }

  if ( Parser.ParseWorld( GetModelName(), true/*streaming*/, *scene ) < 0 )
  {
    SyAssert(!"SyESFParse::ParseWorld failed");
  }
  
  if ( mpLoader->Open( 0, GetModelName() ) < 0 )
  {
    SyAssert(!"SyLoader::Open failed");
  }

  SyVect3 startLocation = pCameraController->GetCamera()->GetLocation();
  // use player start location

  cGameObject *start_marker = titan->GetRegistry()->Fetch("playerSpawn");

  if (start_marker != NULL)
  {
    startLocation = start_marker->GetLocation();
  }

  if ( scene->StreamFillCache( startLocation, *mpLoader, 0 ) < 0 )
  {
    SyAssert(!"SyScene::StreamFillCache failed");
  }
  //SyDebug( "Stream %.2f,%.2f,%.2f\n", startLocation.X, startLocation.Y, startLocation.Z );
#else
  if (Parser.ParseWorld(GetModelName(), false/*streaming*/, *scene )<0)
  {
    SyAssert(!"Cannot Load scene file"); // unable to find scene???
  }
#endif // STREAMING

  if (Parser.Parse( "data/fx.esf", *scene ) < 0 )
  {
    SyAssert(!"Cannot Load fx.esf"); // unable to find scene???
  }
  scene->SetResources();             // have scene located resource that were in fx.esf

  // Probably temp - load up a cut scene. #1
  if (Parser.Parse( "data/art/level/prototypecutscene.esf", *scene ) < 0 )
   {
     SyAssert(!"Cannot Load prototypecutscene.esf"); // unable to find scene???
   }

  // Probably temp - load up a cut scene. #2. Cameraless cutscene
  if (Parser.Parse( "data/art/level/prototypecutscenenocamera.esf", *scene ) < 0 )
   {
     SyAssert(!"Cannot Load prototypecutscenenocamera.esf"); // unable to find scene???
   }

  scene->SetMultiPass(mpTitan->GetMultiPass());

  bool bRemote = NULL != mpAIBlackboard;

  if (NULL == mpAIBlackboard)
  {
    mpAIBlackboard = new cAIBlackboard();
  }

  SyAssertf(mpAIBlackboard != NULL, "Blackboard should have been created!");

  if (mpAIBlackboard)
  {
    mpAIBlackboard->Init(this);
    mpAIBlackboard->SetRemote(bRemote);
  }

}

void
cLevelObject::Update()
{
#ifdef STREAMING
  SyScene *scene = mpTitan->GetScene();
  SyVect3 cameraLocation = mpTitan->GetCameraController()->GetCamera()->GetLocation();
  //SyDebug( "Stream %.2f,%.2f,%.2f\n", cameraLocation.X, cameraLocation.Y, cameraLocation.Z );
  if ( scene->Stream( cameraLocation, *mpLoader, 0 ) < 0 )
  {
    SyAssert(!"SyScene::Stream failed");
  }
#endif // STREAMING
}

void
cLevelObject::NetworkReceiveBroadcast(const char *state, int maxlen)
{
  if (mpAIBlackboard)
  {
    mpAIBlackboard->NetworkReceiveBroadcast(state, maxlen);
  }
}

void
cLevelObject::NetworkReceiveMessage(const char *state, int maxlen)
{
  if (mpAIBlackboard)
  {
    mpAIBlackboard->NetworkReceiveMessage(state, maxlen);
  }
}

//------------------------------------ cGameObjRegistry

cGameObjectRegistry::cGameObjectRegistry() : mpLevelObject(NULL)
{
  InitPropObject( GAMEOBJECTREGISTRY_CLASSID );
}


cGameObjectRegistry::~cGameObjectRegistry()
{
  Clear();
}

void
cGameObjectRegistry::Clear()
{
  int curIndex;
  for (curIndex = mObjects.Begin();curIndex != mObjects.End();curIndex = mObjects.Next(curIndex))
  {
    delete mObjects(curIndex);
  }

  mObjects.Clear();
  mNames.Clear();
  delete mpLevelObject;
  mpLevelObject = NULL;
}


int           
cGameObjectRegistry::InitPropClass()
{
  SyPropClassID ClassID = GAMEOBJECTREGISTRY_CLASSID;

/* Add the class */

  AddClass( ClassID, 
           "cGameObjectRegistry", 
            Creator, 
            ClassID, 
            0 ); 

  AddSubObjectPtrMapProperty<tGameObjectID,cGameObject *>(ClassID,
                                                          0x0000,
                                                          SyMemberOffset(cGameObjectRegistry,mObjects),
                                                          "mObjects",
                                                           SYPROPTYPE_INT32);

  AddSubObjectPtrProperty(ClassID,
                       0x0002,
                       SyMemberOffset(cGameObjectRegistry,mpLevelObject),
                       "mpLevelObject");
  return 0;
}

SyPropObject* 
cGameObjectRegistry::Creator()
{
  SyPropObject *pObject;

  pObject = SyNew cGameObjectRegistry();
  if (pObject == NULL)
  {
    SyAssert(0);
    return(NULL);
  }

  return(pObject);
}


void              
cGameObjectRegistry::LoadLevelXML(const char *xml_filename)  // call before InitGameObjects
{
  const char *l_ObjectTypenames[] = 
  {
    "Player",
    "NPC",
    "Item",
    "Marker",
    "Projectile",
    "Prop"
  };

  static const int NUM_TYPENAMES = (sizeof(l_ObjectTypenames) / sizeof (l_ObjectTypenames[0]));

  SyAssertf(NUM_TYPENAMES==cGameObject::NUM_OBJ_TYPES,"Missing type names in xml parser");

  char buffer[512];
  sprintf(buffer,"data/level/%s",xml_filename);
	TiXmlDocument doc( buffer );
	bool loadOkay = doc.LoadFile();

	if ( !loadOkay )
	{
    SyAssertf(0, "Unable to load XML file '%s'",buffer);
    return;
	}
  
	TiXmlNode* node = 0;
	TiXmlElement* element = 0;

  node = doc.FirstChild( "designPlacement" );
  SyAssert(node);         
	node = node->FirstChild( "level" );
	SyAssert( node );
  element = node->ToElement();

  SyAssertf(element != NULL,"Error reading xml: element expected?");

  delete mpLevelObject;
  mpLevelObject = new cLevelObject;

  // parse level model name
  const char *model = element->Attribute("model"); 
  const char *path = "data/art/level/";
  char ModelName[512];
  sprintf(ModelName,"%s%s",path,model);
  mpLevelObject->SetModelName(ModelName);

  TiXmlNode* camera_node = node->FirstChild("camera");
  SyAssertf(camera_node != NULL, "Camera File Not Defined in Level");
  const char *camera_name = camera_node->FirstChild()->Value();
  char CameraName[512];
  sprintf(CameraName,"%s%s",path,camera_name);
  mpLevelObject->SetCameraName(CameraName);

	node = node->FirstChild( "object" );
	SyAssert( node );

  while (node != NULL)                  
  {
    TiXmlNode* data_node = node->FirstChild("Type");
    const char *type = data_node->FirstChild()->Value();

    cGameObject::tObjectType objType;
    if (type == NULL || type[0] == '\0')
    {
      objType = cGameObject::OBJ_MARKER;
    }
    else
    {
      int enumVal = 0;
      bool result = ChooseEnum(type,l_ObjectTypenames,NUM_TYPENAMES, enumVal);
      if (result)
      {
        objType = (cGameObject::tObjectType)enumVal;
      }
      else
      {
        SyAssertf(0,"Unknown Object Type");
        return;
      }
    }

  
    tGameObjectID id = Create(objType);
    cGameObject *obj = Fetch(id);

    // set name (if there is one)
    data_node = node->FirstChild("Name");
    if (data_node != NULL)
    {
      const char *name = data_node->FirstChild()->Value();
      Name(obj,name);
    }

    // find position

    SyVect3 position;

    TiXmlNode *position_node = node->FirstChild("Position");
    const char *position_str = position_node->FirstChild()->Value();

    position_str += SyStr::GetNextToken(position_str,&position.X);
    position_str += SyStr::GetNextToken(position_str,&position.Y);
    position_str += SyStr::GetNextToken(position_str,&position.Z);
    //sscanf(position_str,"%f,%f,%f",&position.X,&position.Y,&position.Z);

    obj->SetLocation(position);

    // find orientation
    SyVect3 orientation;

    TiXmlNode *orient_node = node->FirstChild("Orientation");
    const char *orientation_str = orient_node->FirstChild()->Value();
    orientation_str += SyStr::GetNextToken(orientation_str,&orientation.X);
    orientation_str += SyStr::GetNextToken(orientation_str,&orientation.Y);
    orientation_str += SyStr::GetNextToken(orientation_str,&orientation.Z);
    //sscanf(orientation_str,"%f,%f,%f",&orientation.X,&orientation.Y,&orientation.Z);

    obj->SetHPR(orientation);
   
    TiXmlNode *master_node = node->FirstChild("Master");
    if (master_node != NULL)
    {
      const char *master_str = master_node->FirstChild()->Value();
      obj->GetStats()->SetMaster(master_str);
    }

    TiXmlNode *item = node->FirstChild("Item");
    while (item != NULL)
    {
      TiXmlNode *master_node = item->FirstChild("Master");
      const char *master_str = master_node->FirstChild()->Value();
      TiXmlNode *quantity_node = item->FirstChild("Quantity");
      int quantity = 1;
      if (quantity_node != NULL)
      {
        quantity = atoi(quantity_node->FirstChild()->Value());
      }

      obj->GetInventory()->Add(SyHashResourceID(master_str),quantity);
      item = item->NextSibling();
    }
    
    InitObject(obj->GetID(),false);

    node = node->NextSibling();
  }

  
  SyAssertf(mpLevelObject!=NULL,"No Level Object???");
  InitObject(cLevelObject::LEVEL_OBJECT_GAME_ID,false);
}


void              
cGameObjectRegistry::LoadLevelBinary(const char *filename)   // call before InitGameObjects
{
  char buffer[512];
  sprintf(buffer,"data/level/%s",filename);
  SyObjFile file;
  if (file.Open(buffer,SyObjFile::ROnly)<0)
  {
    SyAssertf(0,"Unable To Open File %s",buffer);
    return;
  }

  Clear();
  mpTitan->GetTitanUI()->ClearScene();
  mpLevelObject = (cLevelObject*)cLevelObject::ReadObject(file);

  cGameObject *obj = (cGameObject*) cGameObject::ReadObject(file);

  while (obj != NULL)
  {
    obj->SetID(mpTitan->GetPeeringNetwork()->ObjectReserveId());
    obj->FixUp(this);
    Add(obj);
    obj = (cGameObject*) cGameObject::ReadObject(file);
  }
  file.Close();

  for (int curIndex = mObjects.Begin();curIndex != mObjects.End();curIndex = mObjects.Next(curIndex))
  {
    obj = mObjects(curIndex);
    if (obj->GetName() != NULL && obj->GetName()[0] != '\0')
    {
      mNames.Insert(obj->GetNameID(),obj);
    }
    InitObject(obj->GetID(),false);
  }

  SyAssertf(mpLevelObject!=NULL,"No Level Object???");
  InitObject(cLevelObject::LEVEL_OBJECT_GAME_ID,false);
}

void
cGameObjectRegistry::InitObject(tGameObjectID id,bool ownerLifetime)
{
    static const int MAX_BUFFER_SIZE = 10*1028;
    char buffer[MAX_BUFFER_SIZE];

    if (id ==cLevelObject::LEVEL_OBJECT_GAME_ID )
    {
        mpLevelObject->Init(mpTitan);
        int bufferSize = NetworkGetState(id,buffer,MAX_BUFFER_SIZE);
        mpTitan->GetPeeringNetwork()->ObjectCreate(cGameObject::OBJ_NPC,cLevelObject::LEVEL_OBJECT_GAME_ID,ownerLifetime,buffer,bufferSize);
    }
    else
    {
        cGameObject *obj= Fetch(id);
        obj->Init();
        if (obj->GetName() != NULL && obj->GetName()[0] != '\0')
        {
          mNames.Insert(obj->GetNameID(),obj);
        }
        int bufferSize = NetworkGetState(id,buffer,MAX_BUFFER_SIZE);
        mpTitan->GetPeeringNetwork()->ObjectCreate(obj->GetType(),obj->GetID(),ownerLifetime,buffer,bufferSize);
    }
};


void 
cGameObjectRegistry::Update(float time)
{
  mpLevelObject->Update();

  int curIndex;
  for (curIndex = mObjects.Begin();curIndex != mObjects.End();curIndex = mObjects.Next(curIndex))
  {
    mObjects(curIndex)->Update(time);
  }
  CheckForDelete();
}

void 
cGameObjectRegistry::CheckForDelete()
{
  int curIndex;
  for (curIndex = mObjects.Begin();curIndex != mObjects.End(); )
  {
    cGameObject *object = mObjects(curIndex);
    if (object->CheckForDelete())
    {
      curIndex = Delete(object->GetID());
    }
    else
    {
      curIndex = mObjects.Next(curIndex);
    }
  }
}

void 
cGameObjectRegistry::Prerender()
{
  int curIndex;
  for (curIndex = mObjects.Begin();curIndex != mObjects.End();curIndex = mObjects.Next(curIndex))
  {
    mObjects(curIndex)->Prerender();
  }
}

tGameObjectID 
cGameObjectRegistry::Create(cGameObject::tObjectType newtype)
{
  cGameObject *newobj = new cGameObject();

  tGameObjectID id = mpTitan->GetPeeringNetwork()->ObjectReserveId();
  newobj->Create(this,id,newtype);
 
  if (Add(newobj))
  {
    return id;
  }
  return ID_NONE;
}


tGameObjectID     
cGameObjectRegistry::NetworkCreate(cGameObject::tObjectType newtype,tGameObjectID id,const char *state,int statelen)
{
  if (id ==cLevelObject::LEVEL_OBJECT_GAME_ID )
  {
    SyObjFile file;
    if (file.Open((void *)state,statelen,statelen,SyObjFile::ROnly)<0)
    {
        SyAssertf(0,"Unable To Open File.");
        return ID_NONE;
    }

    uint16 Type;
    uint16 Version;
    file.ReadBegin(Type,Version);
    delete mpLevelObject;
    mpLevelObject = (cLevelObject*)cLevelObject::ReadObject(file);
    mpLevelObject->Init(mpTitan);
    file.ReadEnd();
    file.Close();
  }
  else
  {
    cGameObject *newobj = new cGameObject();
    newobj->Create(this,id,newtype);
 
    if (!Add(newobj))
    {
        SyAssertf(0,"Unable to add new object");
        return 0;
    }
    NetworkSetState(id,state,statelen);
    cGameObject *obj = Fetch(id);
    SyAssertf(obj!=NULL,"Unable to insert new object???");
    if (obj != NULL)
    {
      obj->SetRemote(true);
      if (obj->GetName() != NULL && obj->GetName()[0] != '\0')
      {
        mNames.Insert(obj->GetNameID(),obj);
      }
      obj->FixUp(this);
      obj->Init();
    }
  }
  return id;
}

void              
cGameObjectRegistry::NetworkDelete(tGameObjectID id)
{
  int index = mObjects.Find(id);
  if (index != mObjects.End())
  { 
    cGameObject *obj = mObjects(index);
    int name_index = mNames.Find(obj->GetNameID());
    if (name_index != mNames.End())
    {
      mNames.Erase(name_index);
    }
    delete obj;
    mObjects.Erase(index);
  }
}


void     
cGameObjectRegistry::NetworkSetState(tGameObjectID id,const char *state,int statelen)
{
  SyObjFile file;
  if (file.Open((void *)state,statelen,statelen,SyObjFile::ROnly)<0)
  {
    SyAssertf(0,"Unable To Open File.");
    return;
  }

  uint16 Type;
  uint16 Version;
  file.ReadBegin(Type,Version);
  if (id ==cLevelObject::LEVEL_OBJECT_GAME_ID )
  {
    delete mpLevelObject;
    mpLevelObject = (cLevelObject*)cLevelObject::ReadObject(file);
    mpLevelObject->Init(mpTitan);
  }
  else
  {
    cGameObject *obj = Fetch(id);
    obj->Reset(file);
  }
  file.ReadEnd();
  file.Close();
}

unsigned int               
cGameObjectRegistry::NetworkGetState(tGameObjectID id,char *state, int maxlen)
{
  int curLoc = 0;
  SyObjFile file;
  if (file.Open(state,maxlen,curLoc,SyObjFile::WOnlyCreate)<0)
  {
    SyAssertf(0,"Unable To Open File.");
    return (unsigned)-1;
  }

  uint16 Type = 0x0001;
  uint16 Version = 0x0002;
  file.WriteBegin( Type,Version );
  if (id ==cLevelObject::LEVEL_OBJECT_GAME_ID )
  {
    mpLevelObject->WriteObject(file);
  }
  else
  {
    cGameObject *obj = Fetch(id);
    if (obj == NULL)
    {
      SyAssertf(0,"Asking for state of object i don't have.");
      return 0;
    }
    obj->GetState(file);
  }
  uint64 Size;
  file.WriteEnd(); // Size includes the object header
  Size=file.FileSize();
  file.Close();
  return (unsigned int)Size;
}

unsigned int      
cGameObjectRegistry::NetworkReceiveBroadcast(tGameObjectID id,const char *state, int maxlen)
{
  if (cLevelObject::LEVEL_OBJECT_GAME_ID == id)
  {
    SyAssertf(mpLevelObject!=NULL,"No Level while receiving net broadcast");

    if (mpLevelObject != NULL)
    {
      mpLevelObject->NetworkReceiveBroadcast(state, maxlen);
    }
  }
  else
  {
    cGameObject *obj_ptr = Fetch(id);
    SyAssertf(obj_ptr!=NULL,"Unknown object");
    if (obj_ptr != NULL)
    {
      obj_ptr->NetworkReceiveBroadcast(state,maxlen);
    }
  }

  return true;
}

unsigned int      
cGameObjectRegistry::NetworkReceiveMessage(tGameObjectID id,const char *state, int maxlen)
{
  if (cLevelObject::LEVEL_OBJECT_GAME_ID == id)
  {
    SyAssertf(mpLevelObject!=NULL,"No Level while receiving net msg");

    if (mpLevelObject != NULL)
    {
      mpLevelObject->NetworkReceiveMessage(state, maxlen);
    }
  }
  else
  {
    cGameObject *obj_ptr = Fetch(id);
    // quite possible to receive message for object that's been deleted.
    if (obj_ptr != NULL)
    {
      obj_ptr->NetworkReceiveMessage(state,maxlen);
    }
  }
  return true;
}

unsigned int      
cGameObjectRegistry::NetworkTakeOwnership(tGameObjectID id)
{
  if (id == cLevelObject::LEVEL_OBJECT_GAME_ID)
  {
    SyAssertf(mpLevelObject!=NULL,"cGameObjectRegistry::NetworkTakeOwnership - no level");
    if (mpLevelObject)
    {
      mpLevelObject->SetRemote(false);
    }

    return true;
  }
  cGameObject *obj_ptr = Fetch(id);
  SyAssertf(obj_ptr!=NULL,"Unknown object");
  if (obj_ptr != NULL)
  {
    SyAssertf(obj_ptr->IsRemote(),"Taking ownership of object i already own???");
    obj_ptr->SetRemote(false); 
  }
  return true;
}

void
cGameObjectRegistry::NetworkRequestOwnership(tGameObjectID id, int requestingPeerId)
{
        // NOTE: you should do what it takes on the application end to relinquish ownership (ie. quit trying to control the object) at this point.
        // the next notification you will get after calling ObjectTransferOwnership is an NetworkSetState callback which is the full state of the object under
        // the new ownership
    // TODO: do as noted above

        // somebody is requesting ownership of the specified object (which we own), we should generally transfer ownership
    mpTitan->GetPeeringNetwork()->ObjectTransferOwnership(id, requestingPeerId);
}

bool
cGameObjectRegistry::Name(cGameObject *obj, const char *name)
{
  if (obj == NULL)
  {
    return false;
  }

  // make sure object is registered
  int index = mObjects.Find(obj->GetID());
  if (index == mObjects.End())
  {            
    if (!Add(obj))
    {
      return false;
    }
  }


  // check to see if we're already named
  if (obj->GetName() != NULL)
  {
    index = mNames.Find(obj->GetNameID());
    if (index != mObjects.End())
    {
      if (mNames(index)==obj)
      {
        mNames.Erase(index);
      }
      else
      {
        // name already registerd to someone else!
        SyAssertf(0,"Duplicate name registration");
        return false;
      }
    }
  }

  obj->SetName(name);
  mNames.Insert(obj->GetNameID(),obj);
  return true;
}

int
cGameObjectRegistry::Delete(tGameObjectID erased)
{
  int index = mObjects.Find(erased);
  if (index != mObjects.End())
  { 
    cGameObject *obj = mObjects(index);
    int name_index = mNames.Find(obj->GetNameID());
    if (name_index != mNames.End())
    {
      mNames.Erase(name_index);
    }
    mpTitan->GetPeeringNetwork()->ObjectDestroy(erased);
    delete obj;
    return mObjects.Erase(index);
  }  
  return index;
}
  
bool
cGameObjectRegistry::Add(cGameObject *obj)
{
  if (obj == NULL)
  {
    return false;
  }

  int index = mObjects.Find(obj->GetID());
  if (index == mObjects.End())
  {
    mObjects.Insert(obj->GetID(),obj);
    return true;
  }
  return false;
}


cGameObject *  
cGameObjectRegistry::Fetch(tGameObjectID id)
{
  int index = mObjects.Find(id);

  if (index == mObjects.End())
  {
    return NULL;
  }

  return mObjects(index);
}

cGameObject *  
cGameObjectRegistry::Fetch(const char *name)
{
  tGameID id = SyHashResourceID(name);
  int index = mNames.Find(id);

  if (index == mNames.End())
  {
    return NULL;
  }

  SyAssertf(strcmp(mNames(index)->GetName(),name)==0,"Registry Error: Registered name does not match actual name?");
  return mNames(index);
}

cGameObject *     
cGameObjectRegistry::FetchByActorHandle(SyActorHandle handle)
{
  int curIndex;
  for (curIndex = mObjects.Begin();curIndex != mObjects.End();curIndex = mObjects.Next(curIndex))
  {
    if (mObjects(curIndex)->GetGraphic()->GetActorHandle() == handle)
    {
      return mObjects(curIndex);
    }
  }
  return NULL;
}

void              
cGameObjectRegistry::SaveGame()
{
  SyObjFile file;
  file.Open("test.sav",SyObjFile::WOnlyCreate);

  mpLevelObject->WriteObject(file);

  for (int curIndex = mObjects.Begin();curIndex != mObjects.End();curIndex = mObjects.Next(curIndex))
  {
    mObjects(curIndex)->WriteObject(file);
  }
  file.Close();

}

void              
cGameObjectRegistry::LoadGame()
{
  SyObjFile file;
  if (file.Open("test.sav",SyObjFile::ROnly)<0)
  {
    SyAssertf(0,"Unable To Open File");
    return;
  }

  Clear();
  mpTitan->GetTitanUI()->ClearScene();
  mpLevelObject = (cLevelObject*)cLevelObject::ReadObject(file);

  cGameObject *obj = (cGameObject*) cGameObject::ReadObject(file);

  while (obj != NULL)
  {
    obj->FixUp(this);
    Add(obj);
    obj = (cGameObject*) cGameObject::ReadObject(file);
  }
  file.Close();

  for (int curIndex = mObjects.Begin();curIndex != mObjects.End();curIndex = mObjects.Next(curIndex))
  {
    obj = mObjects(curIndex);
    if (obj->GetName() != NULL && obj->GetName()[0] != '\0')
    {
      mNames.Insert(obj->GetNameID(),obj);
    }
    obj->Init();
  }
  mpLevelObject->Init(mpTitan);
  
}


//////////////////////////////////////////////////////////////////////////////////////////// Global Funcs

void 
RegPropClasses_Registry()
{
  cLevelObject::InitPropClass();
  cAIBlackboard::InitPropClass();
  cGameObjectRegistry::InitPropClass();
  RegPropClasses_GameObj();
}
// EOF
