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

//-------------------------------------------------------- Includes
#include "database.h"
#include "stats.h"
#include "droplist.h"
#include "tinyxml.h"
#include "ai\behaviortypes.h"
#include "debris.h"
#include "SyESFParse.h"
//---------------------------------------------- Class Declarations
//----------------------------------------- Functions Declarations
//------------------------------------ Member Functions Definitions

//------------------------------------ cDatabaseSys

cDatabaseSys::cDatabaseSys(Titan *titan) :
  mpTitan(titan)
{
}

cDatabaseSys::~cDatabaseSys()
{
  for (int index = mCharacterMasters.Begin(); index != mCharacterMasters.End();index = mCharacterMasters.Next(index))
  {
    delete mCharacterMasters(index);
  }
  mCharacterMasters.Clear();


  for (int index = mItemMasters.Begin(); index != mItemMasters.End();index = mItemMasters.Next(index))
  {
    delete mItemMasters(index);
  }
  mItemMasters.Clear();
  

  for (int index = mProjectileMasters.Begin(); index != mProjectileMasters.End();index = mProjectileMasters.Next(index))
  {
    delete mProjectileMasters(index);
  }
  mProjectileMasters.Clear();


  for (int index = mPropMasters.Begin(); index != mPropMasters.End();index = mPropMasters.Next(index))
  {
    delete mPropMasters(index);
  }
  mPropMasters.Clear();


  for (int index = mCharacterClasses.Begin(); index != mCharacterClasses.End();index = mCharacterClasses.Next(index))
  {
    delete mCharacterClasses(index);
  }
  mCharacterClasses.Clear();


  for (int index = mLevelMasters.Begin(); index != mLevelMasters.End();index = mLevelMasters.Next(index))
  {
    delete mLevelMasters(index);
  }
  mLevelMasters.Clear();


  for (int index = mTreasureSets.Begin(); index != mTreasureSets.End();index = mTreasureSets.Next(index))
  {
    delete mTreasureSets(index);
  }
  mTreasureSets.Clear();


  for (int index = mDropLists.Begin(); index != mDropLists.End();index = mDropLists.Next(index))
  {
    delete mDropLists(index);
  }
  mDropLists.Clear();

  for (int index = mDebrisMasters.Begin(); index != mDebrisMasters.End();index = mDebrisMasters.Next(index))
  {
    delete mDebrisMasters(index);
  }
  mDebrisMasters.Clear();
}

void                         
cDatabaseSys::Init()
{
  LoadCharacterMasters();
  LoadItemMasters();
  LoadProjectileMasters();
  LoadPropMasters();
  LoadClasses();
  LoadLevels();
  LoadDropLists();
  LoadTreasureSets();
  LoadDebris();

}

void                         
cDatabaseSys::LoadDebrisModels()
{
  if (mpTitan == NULL)
  {
    SyAssertf(0,"Bad Titan Ptr");
    return;
  }
  for (int index = mDebrisMasters.Begin(); index != mDebrisMasters.End();index = mDebrisMasters.Next(index))
  {
    cDebrisMaster *master = mDebrisMasters(index);

    for (int shard = master->mShardMasters.Begin();
          shard != master->mShardMasters.End();
          shard = master->mShardMasters.Next(shard))
    {
      cDebrisShardMaster *shardMaster = master->mShardMasters(shard);
      SyESFParse Parser;
      SyScene *scene = mpTitan->GetScene();
      shardMaster->mSpriteTemplateHandle = Parser.ParseSprite(shardMaster->mModelName, *scene );
      SyAssertf(shardMaster->mSpriteTemplateHandle != -1,
                  "Can't Parse .ESF file '%s' from shard debris",shardMaster->mModelName); 
      
    }
  }
};

void                         
cDatabaseSys::LoadCharacterMasters()
{
  // load up xml file for characters...
	TiXmlDocument doc( "data/db/character.xml" );
	bool loadOkay = doc.LoadFile();

	if ( !loadOkay )
	{
    SyAssert(0);
    return;
	}
  
	TiXmlNode* node = 0;

  node = doc.FirstChild( "dataroot" );
  SyAssert(node);
	node = node->FirstChild( "Character" );
	SyAssert( node );

  while (node != NULL)
  {
    cStatsCharacterMaster *newmaster = new cStatsCharacterMaster; 
    TiXmlNode* data_node = node->FirstChild("Name");
    SyAssert(data_node);
    const char *name = data_node->FirstChild()->Value();
    newmaster->mID.SetName(name);

    data_node = node->FirstChild("Model");
    if (data_node != NULL)
    {
      const char *model = data_node->FirstChild()->Value();
      if (model[0] != '\0')
      {
        static const char *path = "data/art/character/";
        static const char *extension = ".esf";
        newmaster->mModel = new char[strlen(model)+strlen(path)+strlen(extension)+ 1]; 
        sprintf(newmaster->mModel,"%s%s%s",path,model,extension);
      }
    }

    data_node = node->FirstChild("Lvl");
    SyAssertf(data_node!=NULL,"Missing Data Field 'Level' in character database XML file");
    newmaster->mLevel = atoi(data_node->FirstChild()->Value());

    data_node = node->FirstChild("Class");
    SyAssertf(data_node!=NULL,"Missing Data Field 'Class' in character database XML file");
    newmaster->mClass = SyHashResourceID(data_node->FirstChild()->Value());

    data_node = node->FirstChild("AnimSet");
    SyAssertf(data_node!=NULL,"Missing Data Field 'AnimSet' in character database XML file");
    newmaster->mAnimSet = SyHashResourceID(data_node->FirstChild()->Value());

    data_node = node->FirstChild("AttackDelay");
    if (data_node != NULL)
    {
      newmaster->mAttackDelay = (float)atof(data_node->FirstChild()->Value());
    }

    data_node = node->FirstChild("BlockDelay");
    if (data_node != NULL)
    {
      newmaster->mBlockDelay = (float)atof(data_node->FirstChild()->Value());
    }

    data_node = node->FirstChild("MovementSpeed");
    if (data_node != NULL)
    {
      newmaster->mAttackDelay = (float)atof(data_node->FirstChild()->Value());
    }

    data_node = node->FirstChild("CloseDistance");
    if (data_node != NULL)
    {
      newmaster->mCloseDistance = (float)atof(data_node->FirstChild()->Value());
    }

    data_node = node->FirstChild("CollisionRadiusOverride");
    if (data_node != NULL)
    {
      newmaster->mCollisionRadius =(float) (atof(data_node->FirstChild()->Value()));
    }

    data_node = node->FirstChild("ActivationRadiusOverride");
    if (data_node != NULL)
    {
      newmaster->mActivationRadius =(float) (atof(data_node->FirstChild()->Value()));
    }

    data_node = node->FirstChild("DefendRadiusOverride");
    if (data_node != NULL)
    {
      newmaster->mDefendRadius =(float) (atof(data_node->FirstChild()->Value()));
    }

    data_node = node->FirstChild("TreasureSet");
    if (data_node != NULL)
    {
      newmaster->mTreasureSet = SyHashResourceID(data_node->FirstChild()->Value());
    }

    data_node = node->FirstChild("NaturalRanged");
    if (data_node != NULL)
    {
      newmaster->mNaturalRanged = SyHashResourceID(data_node->FirstChild()->Value());
    }

    data_node = node->FirstChild("BehaviorType");
    if (data_node != NULL)
    {
      int enumVal = 0;
      const char *type = data_node->FirstChild()->Value();
      bool result = ChooseEnum(type,NPC_BEHAVIOR_TYPE_NAMES,NPCBEH_MAXTYPES, enumVal);
      SyAssertf(result,"Unknown BehaviorType type in record '%s' in character.xml",name);
      newmaster->mNPCBehaviorType = (char) enumVal;
    }
    else
    {
      newmaster->mNPCBehaviorType = NPCBEH_CLASSDEFAULT;
    }

    const char *l_NPCFactionNames[] = 
    {
      "Class Default",
      "Monster",
      "Neutral", 
      "Ally",
    };

    static const int NUM_NPCFACTION_NAMES = (sizeof(l_NPCFactionNames) / sizeof (l_NPCFactionNames[0]));

    data_node = node->FirstChild("Faction");
    if (data_node != NULL)
    {
      int enumVal = 0;
      const char *type = data_node->FirstChild()->Value();
      SyAssertf(NUM_NPCFACTION_NAMES == NPCFACTION_MAXTYPES,"Forgot to add NPC Faction type name.");
      bool result = ChooseEnum(type,l_NPCFactionNames,NUM_NPCFACTION_NAMES, enumVal);
      SyAssertf(result,"Unknown Faction type in record '%s' in character.xml",name);
      newmaster->mNPCFaction = (char)enumVal;
    }
    else
    {
      newmaster->mNPCFaction = NPCBEH_CLASSDEFAULT;
    }

    mCharacterMasters.Insert(newmaster->mID.GetID(),newmaster);
    node = node->NextSibling();
  }
}

bool 
ChooseEnum(const char *str,const char **name_list,int name_list_size, int& retVal)
{
  for (int ii=0;ii<name_list_size;++ii)
  {
    if (SyStr::Stricmp(name_list[ii],str)==0)
    {
      retVal = ii;
      return true;
    }
  }
  return false;
};

void                         
cDatabaseSys::LoadItemMasters()
{
  // load up xml file for characters...
	TiXmlDocument doc( "data/db/item.xml" );
	bool loadOkay = doc.LoadFile();

	if ( !loadOkay )
	{
    SyAssert(0);
    return;
	}
  
	TiXmlNode* node = 0;

  const char *l_ItemTypenames[] = 
  {
    "Melee", //IT_MELEE,
    "Ranged",//IT_RANGED,
    "Head",//IT_HEAD,
    "Body",//IT_BODY,
    "Feet",//IT_FEET,
    "Accessory",//IT_ACCESSORY,
    "Enhancement",//IT_ENHANCEMENT,
    "Gold",//IT_GOLD,
    "Trinket",//IT_TRINKET,
    "Potion",//IT_POTION,
    
  };

  static const int NUM_ITEM_TYPENAMES = (sizeof(l_ItemTypenames) / sizeof (l_ItemTypenames[0]));
  const char *l_ItemClassnames[] = 
  {
    "Knight", 
    "Mage",
    "Brute",
    "Any",
  };
  static const int NUM_ITEM_CLASSNAMES = (sizeof(l_ItemClassnames) / sizeof (l_ItemClassnames[0]));

  const char *l_NormalDamageTypenames[] = 
  {
    "None",
    "Piercing",
    "Blunt",
    "Slashing"
  };
  static const int NUM_DAMAGE_TYPENAMES = (sizeof(l_NormalDamageTypenames) / sizeof (l_NormalDamageTypenames[0]));


  node = doc.FirstChild( "dataroot" );
  SyAssert(node);
	node = node->FirstChild( "Item" );
	SyAssert( node );

  while (node != NULL)
  {
    cStatsItemMaster *newmaster = new cStatsItemMaster; 
    TiXmlNode* data_node = node->FirstChild("Name");
    SyAssert(data_node);
    const char *name = data_node->FirstChild()->Value();
    newmaster->mID.SetName(name);

    int enumVal = 0;
    data_node = node->FirstChild("Type");
    SyAssert(data_node);
    const char *type = data_node->FirstChild()->Value();
    SyAssertf(NUM_ITEM_TYPENAMES == NUM_ITEM_TYPES,"Forgot to add item typename?");
    bool result = ChooseEnum(type,l_ItemTypenames,NUM_ITEM_TYPENAMES, enumVal);
    SyAssertf(result == true,"Unknown item type in record '%s' in item.xml",name);
    newmaster->mType = (eItemType) enumVal;

    data_node = node->FirstChild("Class");
    if (data_node != NULL)
    {
      int enumVal = 0;
      type = data_node->FirstChild()->Value();
      SyAssertf(NUM_ITEM_CLASSNAMES == NUM_ITEM_CLASSES,"Forgot to add item typename?");
      result = ChooseEnum(type,l_ItemClassnames,NUM_ITEM_CLASSNAMES, enumVal);
      SyAssertf(result == true,"Unknown item class in record '%s' in item.xml",name);
      newmaster->mClass = (eItemClass)enumVal;
    }


    data_node = node->FirstChild("WorldModel");
    if (data_node != NULL)
    {
      const char *model = data_node->FirstChild()->Value();
      if (model[0] != '\0')
      {
        static const char *path = "data/art/item/";
        static const char *extension = ".esf";
        newmaster->mWorldModel = new char[strlen(model)+strlen(path)+strlen(extension)+ 1]; 
        sprintf(newmaster->mWorldModel,"%s%s%s",path,model,extension);
      }
    }

    data_node = node->FirstChild("Icon");
    if (data_node != NULL)
    {
      const char *model = data_node->FirstChild()->Value();
      newmaster->mIcon = new char[strlen(model)+1]; 
      strcpy(newmaster->mIcon,model);
    }
    
    data_node = node->FirstChild("Attach_Model");
    if (data_node != NULL)
    {
      const char *model = data_node->FirstChild()->Value();
      if (model[0] != '\0')
      {
        static const char *path = "data/art/item/";
        static const char *extension = ".esf";
        newmaster->mAttachModel = new char[strlen(model)+strlen(path)+strlen(extension)+ 1]; 
        sprintf(newmaster->mAttachModel,"%s%s%s",path,model,extension);
      }
    }


    data_node = node->FirstChild("Projectile");
    if (data_node != NULL)
    {
      newmaster->mProjectile = SyHashResourceID(data_node->FirstChild()->Value());
    }



    // todo: description id - i18n?
    //data_node = node->FirstChild("Description");
    //SyAssertf(data_node!=NULL,"Missing Data Field in character database XML file");
    //newmaster->mPower[COMBO_SSS] = (float) atof(data_node->FirstChild()->Value());
 
    data_node = node->FirstChild("Value");
    SyAssertf(data_node!=NULL,"Missing 'Value' data field for '%s' in item database XML file", name);
    if (data_node != NULL)
    {
      newmaster->mValue =  atoi(data_node->FirstChild()->Value());
    }

    data_node = node->FirstChild("BaseDamageType");
    if (data_node != NULL)
    {
      int enumVal = 0;
      type = data_node->FirstChild()->Value();
      SyAssertf(NUM_DAMAGE_TYPENAMES == NUM_NORMAL_DAMAGE_TYPES,"Forgot to add item typename?");
      result = ChooseEnum(type,l_NormalDamageTypenames,NUM_NORMAL_DAMAGE_TYPES, enumVal);
      SyAssertf(result == true,"Unknown damage type in record '%s' in item.xml",name);
      newmaster->mBaseDamageType = (eNormalDamageType) enumVal;
    }

    data_node = node->FirstChild("BaseDamageBonus");
    if (data_node != NULL)
    {
      newmaster->mBaseDamageBonus =  atoi(data_node->FirstChild()->Value());
    }

    data_node = node->FirstChild("DefenseBonus");
    if (data_node != NULL)
    {
      newmaster->mDefenseBonus =  atoi(data_node->FirstChild()->Value());
    }

    // todo: enhancements

    mItemMasters.Insert(newmaster->mID.GetID(),newmaster);
    node = node->NextSibling();
  }
}                                            

void                         
cDatabaseSys::LoadProjectileMasters()
{
  // load up xml file for projectiles...
	TiXmlDocument doc( "data/db/projectile.xml" );
	bool loadOkay = doc.LoadFile();

	if ( !loadOkay )
	{
    SyAssert(0);
    return;
	}
  
	TiXmlNode* node = 0;

  node = doc.FirstChild( "dataroot" );
  SyAssert(node);
	node = node->FirstChild( "Projectile" );
	SyAssert( node );

  while (node != NULL)
  {
    cStatsProjectileMaster *newmaster = new cStatsProjectileMaster; 
    TiXmlNode* data_node = node->FirstChild("Name");
    SyAssert(data_node);
    const char *name = data_node->FirstChild()->Value();
    newmaster->mID.SetName(name);

    data_node = node->FirstChild("Model");
    if (data_node != NULL)
    {
      const char *model = data_node->FirstChild()->Value();
      if (model[0] != '\0')
      {
        static const char *path = "data/art/item/";
        static const char *extension = ".esf";
        newmaster->mModel = new char[strlen(model)+strlen(path)+strlen(extension)+ 1]; 
        sprintf(newmaster->mModel,"%s%s%s",path,model,extension);
      }
    }

    data_node = node->FirstChild("Speed");
    if (data_node != NULL)
    {
      newmaster->mSpeed = (float)atof(data_node->FirstChild()->Value());
    }

    data_node = node->FirstChild("Seeking");
    if (data_node != NULL)
    {
      newmaster->mSeeking = (float)atof(data_node->FirstChild()->Value());
    }

    data_node = node->FirstChild("Gravity");
    if (data_node != NULL)
    {
      newmaster->mGravity =(float) (atof(data_node->FirstChild()->Value()));
    }

    data_node = node->FirstChild("Spins");
    if (data_node != NULL)
    {
      newmaster->mSpins = (atoi(data_node->FirstChild()->Value())==1);
    }

    data_node = node->FirstChild("Penetrates");
    if (data_node != NULL)
    {
      newmaster->mPenetrates = (atoi(data_node->FirstChild()->Value())==1);
    }

    data_node = node->FirstChild("CollisionRadius");
    if (data_node != NULL)
    {
      newmaster->mCollisionRadius =(float) (atof(data_node->FirstChild()->Value()));
    }

    data_node = node->FirstChild("AddCondition");
    if (data_node != NULL)
    {
      const char *conditionName = data_node->FirstChild()->Value();
      if (conditionName[0] != '\0')
      {
        newmaster->mAddCondition = new char[strlen(conditionName)+1]; 
        strcpy(newmaster->mAddCondition, conditionName);
      }
    }

    data_node = node->FirstChild("AddConditionTime");
    if (data_node != NULL)
    {
      newmaster->mAddConditionTimeMS = atoi(data_node->FirstChild()->Value());
    }

    data_node = node->FirstChild("Num");
    if (data_node != NULL)
    {
      newmaster->mNum = atoi(data_node->FirstChild()->Value());
      SyAssertf(newmaster->mNum > 0, "Projectile Num attribute must be at least one for '%s'", name);
      if (newmaster->mNum <= 0)
      {
        newmaster->mNum = 1;
      }
    }

    data_node = node->FirstChild("MaxArc");
    if (data_node != NULL)
    {
      newmaster->mMaxArc = (float)atof(data_node->FirstChild()->Value());
      SyAssertf(newmaster->mMaxArc >= 0.0f, "MaxArc attribute for '%s' must be 0 or more degrees", name);
      if (newmaster->mMaxArc < 0.0)
      {
        newmaster->mMaxArc = 10.0f;
      }
    }

    data_node = node->FirstChild("Acceleration");
    if (data_node != NULL)
    {
      newmaster->mAcceleration = (float)atof(data_node->FirstChild()->Value());
    }

    data_node = node->FirstChild("Orbiting");
    if (data_node != NULL)
    {
      newmaster->mOrbiting = (float)atof(data_node->FirstChild()->Value());
    }

    mProjectileMasters.Insert(newmaster->mID.GetID(),newmaster);
    node = node->NextSibling();
  }
}                                            

void                         
cDatabaseSys::LoadPropMasters()
{
  // load up xml file for props...
  TiXmlDocument doc( "data/db/prop.xml" );
  bool loadOkay = doc.LoadFile();

  if ( !loadOkay )
  {
    SyAssert(0);
    return;
  }

  static const char *path = "data/art/prop/";
  static const char *extension = ".esf";

  TiXmlNode* node = 0;

  node = doc.FirstChild( "dataroot" );
  SyAssert(node);
  node = node->FirstChild( "Prop" );
  SyAssert( node );

  while (node != NULL)
  {
    cStatsPropMaster *newmaster = new cStatsPropMaster; 
    TiXmlNode* data_node = node->FirstChild("Name");
    SyAssert(data_node);
    const char *text = data_node->FirstChild()->Value();
    newmaster->mID.SetName(text);

    // read anim set
    data_node = node->FirstChild("AnimSet");
    SyAssertf(data_node!=NULL,"Missing Data Field 'AnimSet' for prop %s in database XML file", newmaster->mID.GetName());
    newmaster->mAnimSet = SyHashResourceID(data_node->FirstChild()->Value());

    // read model name
    data_node = node->FirstChild("Model");
    SyAssertf(data_node!=NULL,"Missing Data Field 'Model' for prop %s in database XML file", newmaster->mID.GetName());
    if (data_node != NULL)
    {
      text = data_node->FirstChild()->Value();
      newmaster->mModelName = new char[strlen(text)+strlen(path)+strlen(extension)+ 1];
      sprintf(newmaster->mModelName,"%s%s%s",path,text,extension);
    }

    // read Maxhealth amt
    data_node = node->FirstChild("MaxHealth");
    if (data_node != NULL)
    {
      newmaster->mMaxHealth = atoi(data_node->FirstChild()->Value());
    }

    // read container flag
    data_node = node->FirstChild("TreasureSet");
    if (data_node != NULL)
    {
      if (data_node->FirstChild()->Value() && strcmp(data_node->FirstChild()->Value(), "0") != 0)
      {
        newmaster->mTreasureSet = SyHashResourceID(data_node->FirstChild()->Value());
      }
    }

    // read activatable flag
    data_node = node->FirstChild("Activates");
    if (data_node != NULL)
    {
      newmaster->mbActivates = atoi(data_node->FirstChild()->Value()) > 0;
    }

    // read explodable flag
    data_node = node->FirstChild("Explodes");
    if (data_node != NULL)
    {
      newmaster->mbExplodes = atoi(data_node->FirstChild()->Value()) > 0;
    }

    data_node = node->FirstChild("Pushable");
    if (data_node != NULL)
    {
      newmaster->mbPushable = atoi(data_node->FirstChild()->Value()) > 0;
    }

    data_node = node->FirstChild("Debris");
    if (data_node != NULL)
    {
      newmaster->mDebris = SyHashResourceID(data_node->FirstChild()->Value());
    }

    data_node = node->FirstChild("Script");
    if (data_node != NULL)
    {
      text = data_node->FirstChild()->Value();
      newmaster->mScriptName = new char[strlen(text)+1];
      sprintf(newmaster->mScriptName,"%s",text);
    }

    mPropMasters.Insert(newmaster->mID.GetID(),newmaster);
    node = node->NextSibling();
  }
}                                            



void                         
cDatabaseSys::LoadClasses()
{
  // load up xml file for characters...
	TiXmlDocument doc( "data/db/class_stats.xml" );
	bool loadOkay = doc.LoadFile();

	if ( !loadOkay )
	{
    SyAssert(0);
    return;
	}
  
	TiXmlNode* node = 0;
  node = doc.FirstChild( "dataroot" );
  SyAssert(node);
	node = node->FirstChild( "Class_Stats" );
	SyAssert( node );

  while (node != NULL)
  {
    cCharacterClass *newClass = ParseClass(node);
    if (newClass != NULL)
    {
      mCharacterClasses.Insert(newClass->mName.GetID(),newClass);
    }
    node = node->NextSibling();
  }
}

void                         
cDatabaseSys::LoadLevels()
{
  // load up xml file for characters...
	TiXmlDocument doc( "data/db/level_stats.xml" );
	bool loadOkay = doc.LoadFile();

	if ( !loadOkay )
	{
    SyAssert(0);
    return;
	}
  
	TiXmlNode* node = 0;
  node = doc.FirstChild( "dataroot" );
  SyAssert(node);
	node = node->FirstChild( "Level_Stats" );
	SyAssert( node );

  while (node != NULL)
  {
    cCharacterLevel *newLevel = ParseLevel(node);
    if (newLevel != NULL)
    {
      mLevelMasters.Insert(newLevel->mLevel,newLevel);
    }
    node = node->NextSibling();
  }
}


void                         
cDatabaseSys::LoadDropLists()
{
  // load up xml file for characters...
	TiXmlDocument doc( "data/db/drop_list.xml" );
	bool loadOkay = doc.LoadFile();

	if ( !loadOkay )
	{
    SyAssert(0);
    return;
	}
  
	TiXmlNode* node = 0;
  node = doc.FirstChild( "dataroot" );
  SyAssert(node);
	node = node->FirstChild( "Drop_List" );
	SyAssert( node );

  while (node != NULL)
  {
    cDropList *newDropList = ParseDropList(this,node);
    if (newDropList != NULL)
    {
      mDropLists.Insert(newDropList->mName.GetID(),newDropList);
    }
    node = node->NextSibling();
  }
}


void                         
cDatabaseSys::LoadTreasureSets()
{
  // load up xml file for characters...
	TiXmlDocument doc( "data/db/treasure_set.xml" );
	bool loadOkay = doc.LoadFile();

	if ( !loadOkay )
	{
    SyAssert(0);
    return;
	}
  
	TiXmlNode* node = 0;
  node = doc.FirstChild( "dataroot" );
  SyAssert(node);
	node = node->FirstChild( "Treasure_Set" );
	SyAssert( node );

  while (node != NULL)
  {
    cTreasureSet *newTreasureSet = ParseTreasureSet(this,node);
    if (newTreasureSet != NULL)
    {
      mTreasureSets.Insert(newTreasureSet->mName.GetID(),newTreasureSet);
    }
    node = node->NextSibling();
  }
}

void
cDatabaseSys::LoadDebris()
{
  // load up debris group xml... 
  static const char *filename = "data/db/debris_groups.xml";
	TiXmlDocument doc( filename );
	bool loadOkay = doc.LoadFile();

	if ( !loadOkay )
	{
    SyAssertf(0,"Unable to load %s",filename);
    return;
	}
  
	TiXmlNode* node = 0;
  node = doc.FirstChild( "dataroot" );
  SyAssert(node);
	node = node->FirstChild( "DebrisGroup" );
	SyAssert( node );

  while (node != NULL)
  {
    cDebrisMaster *newmaster = new cDebrisMaster;
    TiXmlNode* data_node = node->FirstChild("Name");
    SyAssert(data_node);
    const char *text = data_node->FirstChild()->Value();
    newmaster->mID.SetName(text);

    data_node = node->FirstChild("Radius");
    if (data_node != NULL)
    {
      newmaster->mRadius = (float)atof(data_node->FirstChild()->Value());
    }

    if (newmaster != NULL)
    {
      mDebrisMasters.Insert(newmaster->mID.GetID(),newmaster);
    }
    node = node->NextSibling();
  }

	TiXmlDocument shard_doc( "data/db/debris_shards.xml" );
	loadOkay = shard_doc.LoadFile();

	if ( !loadOkay )
	{
    SyAssert(0);
    return;
	}
  
	node = 0;
  node = shard_doc.FirstChild( "dataroot" );
  SyAssert(node);
	node = node->FirstChild( "DebrisShard" );
	SyAssert( node );

  while (node != NULL)
  {
    cDebrisShardMaster *newmaster = new cDebrisShardMaster;
    TiXmlNode* data_node = node->FirstChild("Model");
    SyAssert(data_node);
    const char *text = data_node->FirstChild()->Value();


    // parse model

    if (text[0] != '\0')
    {

      // todo: wait to load debris models?

      static const char *path = "data/art/prop/debris/";
      static const char *extension = ".esf";
      newmaster->mModelName = new char[strlen(path)+strlen(text)+strlen(extension)+ 1]; 
      sprintf(newmaster->mModelName,"%s%s%s",path,text,extension);

    }
    data_node = node->FirstChild("Quantity");
    if (data_node != NULL)
    {
      newmaster->mQuantity = atoi(data_node->FirstChild()->Value()) ;
    }

    data_node = node->FirstChild("Radius");
    if (data_node != NULL)
    {
      newmaster->mRadius =(float)atof(data_node->FirstChild()->Value()) ;
    }

    data_node = node->FirstChild("Scale");
    if (data_node != NULL)
    {
      newmaster->mScale = (float)atof(data_node->FirstChild()->Value()) ;
    }

    data_node = node->FirstChild("Height");
    if (data_node != NULL)
    {
      newmaster->mHeight = (float) atof(data_node->FirstChild()->Value()) ;
    }

    data_node = node->FirstChild("GroupName");

    tGameID id =SyHashResourceID(data_node->FirstChild()->Value());
    cDebrisMaster  *group = const_cast<cDebrisMaster*>(GetDebrisMaster(id));

    if (group == NULL)
    {
      SyAssertf(0,"Bad group '%s' in debris shard xml file.",data_node->FirstChild()->Value());
      delete newmaster;
    }
    else
    {
      group->mShardMasters.Add(newmaster);
    }

    node = node->NextSibling();
  }
};


const cStatsCharacterMaster *
cDatabaseSys::GetCharacterMaster(tGameID id)
{
  int index = mCharacterMasters.Find(id);
  if (index == mCharacterMasters.End())
  {
    return NULL;
  }
  return mCharacterMasters(index);
}

const cStatsItemMaster *
cDatabaseSys::GetItemMaster(tGameID id)
{
  int index = mItemMasters.Find(id);
  if (index == mItemMasters.End())
  {
    return NULL;
  }
  return mItemMasters(index);
}

const cStatsProjectileMaster *
cDatabaseSys::GetProjectileMaster(tGameID id)
{
  int index = mProjectileMasters.Find(id);
  if (index == mProjectileMasters.End())
  {
    return NULL;
  }
  return mProjectileMasters(index);
}

const cStatsPropMaster *
cDatabaseSys::GetPropMaster(tGameID id)
{
  int index = mPropMasters.Find(id);
  if (index == mPropMasters.End())
  {
    return NULL;
  }
  return mPropMasters(index);
}


const cCharacterClass                *
cDatabaseSys::GetCharacterClass(tGameID class_name)
{
  int index = mCharacterClasses.Find(class_name);

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

const cCharacterLevel              *
cDatabaseSys::GetCharacterLevel(int level)
{
  int index = mLevelMasters.Find(level);

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

cDropList              *
cDatabaseSys::GetDropList(tGameID id)
{
  int index = mDropLists.Find(id);

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

cTreasureSet              *
cDatabaseSys::GetTreasureSet(tGameID id)
{
  int index = mTreasureSets.Find(id);

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

const cDebrisMaster              *
cDatabaseSys::GetDebrisMaster(tGameID id)
{
  int index = mDebrisMasters.Find(id);

  if (index == mDebrisMasters.End())
  {
    return NULL;
  }
  return mDebrisMasters(index);
}
// EOF
