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

//-------------------------------------------------------- Includes
#include "tuning.h"
#include "tinyxml.h"
#include "SyMath.h"
#include "SyStr.h"
#include "gameerror.h"

//---------------------------------------------- Class Declarations
class cTuningVar
{
public:
  cTuningVar(const char *name) {mName = SyStr::AllocateString(name);};
  virtual ~cTuningVar(){SyStr::FreeString(mName);};

  virtual void Set(const char *value)=0;
  const char *GetName(){return mName;};
protected:
  char *      mName;
};


class cTuningVar_Float : public cTuningVar
{
public:
  cTuningVar_Float(float *value,const char *name) : cTuningVar(name), mValue(value){};

  virtual void Set(const char *value){*mValue = (float)atof(value);}

protected:
  float     *mValue;
};

class cTuningVar_Int : public cTuningVar
{
public:
  cTuningVar_Int(int *value,const char *name) : cTuningVar(name), mValue(value){};

  virtual void Set(const char *value){*mValue = atoi(value);}

protected:
  int     *mValue;
};

class cTuningVar_Angle : public cTuningVar
{
public:
  cTuningVar_Angle(float *value,const char *name) : cTuningVar(name), mValue(value){};

  virtual void Set(const char *value){*mValue = SY_DEG_TO_RAD(atoi(value));}

protected:
  float     *mValue;
};

class cTuningVar_GameID : public cTuningVar
{
public:
  cTuningVar_GameID(tGameID *value,const char *name) : cTuningVar(name), mValue(value){};

  virtual void Set(const char *value){ *mValue = SyHashResourceID(value);}

protected:
  tGameID     *mValue;
};
//----------------------------------------- Global Variable Definitions

cTuningSys gTuningSys; // only one set of tuning variables for all games

//----------------------------------------- Functions Declarations
//------------------------------------ Member Functions Definitions

//------------------------------------ cTuningSys
cTuningSys::~cTuningSys()
{
  Init();
}

void 
cTuningSys::Init()// call before values are added;
{
  int curIndex;
  for (curIndex = mVars.Begin();curIndex != mVars.End();curIndex = mVars.Next(curIndex))
  {
    delete mVars(curIndex);
  }

  mVars.Clear();
}

bool
cTuningSys::LoadValues(const char *filename)
{
  char buffer[512];
  sprintf(buffer,"programming/tuning/%s.xml", filename);
	TiXmlDocument doc( buffer );
	bool loadOkay = doc.LoadFile();

	if ( !loadOkay )
	{
    GAME_ASSERT(ERROR_CODE, false, "Unable to load tuning XML file: %s",buffer);
    return false;
	}
  
	TiXmlNode* node = 0;
  const char *name;
  int curIndex;
  cTuningVar *cur;

  node = doc.FirstChild( "Settings" );
  SyAssert(node);         

  node = node->FirstChild();
  while (node != NULL)
  {
    if (node->Type() != TiXmlNode::COMMENT)
    {
      name = node->Value();
      cur = NULL;

      for (curIndex = mVars.Begin();curIndex != mVars.End();curIndex = mVars.Next(curIndex))
      {
        if (SyStr::Stricmp(mVars(curIndex)->GetName(),name)==0)
        {
          cur = mVars(curIndex);
          break;
        }
      }
      if (cur == NULL)
      {
        GAME_ASSERT(ERROR_DESIGN, false, "Unknown tuning variable '%s'",name);
      }
      else if (node->FirstChild() && node->FirstChild()->Value())
      {
        cur->Set(node->FirstChild()->Value());
      }
    }

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


bool 
cTuningSys::AddFloat(float *var, const char *name)
{
  int curIndex;
  for (curIndex = mVars.Begin();curIndex != mVars.End();curIndex = mVars.Next(curIndex))
  {
    if (SyStr::Stricmp(mVars(curIndex)->GetName(),name)==0)
    {
      GAME_ASSERT(ERROR_CODE, false, "Duplicate tuning variable '%s' added", name);
      return false; // dupe...
    }
  }
  mVars.Add(new cTuningVar_Float(var,name));
  return true;
}

bool 
cTuningSys::AddInt(int *var, const char *name)
{
  int curIndex;
  for (curIndex = mVars.Begin();curIndex != mVars.End();curIndex = mVars.Next(curIndex))
  {
    if (SyStr::Stricmp(mVars(curIndex)->GetName(),name)==0)
    {
      GAME_ASSERT(ERROR_CODE, false, "Duplicate tuning variable '%s' added", name);
      return false; // dupe...
    }
  }
  mVars.Add(new cTuningVar_Int(var,name));

  return true;
}


bool 
cTuningSys::AddAngle(float *var, const char *name)
{
  int curIndex;
  for (curIndex = mVars.Begin();curIndex != mVars.End();curIndex = mVars.Next(curIndex))
  {
    if (SyStr::Stricmp(mVars(curIndex)->GetName(),name)==0)
    {
      GAME_ASSERT(ERROR_CODE, false, "Duplicate tuning variable '%s' added", name);
      return false; // dupe...
    }
  }
  mVars.Add(new cTuningVar_Angle(var,name));

  return true;
}

bool 
cTuningSys::AddGameID(tGameID *var, const char *name)
{
  int curIndex;
  for (curIndex = mVars.Begin();curIndex != mVars.End();curIndex = mVars.Next(curIndex))
  {
    if (SyStr::Stricmp(mVars(curIndex)->GetName(),name)==0)
    {
      GAME_ASSERT(ERROR_CODE, false, "Duplicate tuning variable '%s' added", name);
      return false; // dupe...
    }
  }
  mVars.Add(new cTuningVar_GameID(var,name));
  return true;
}

// EOF
