/***************************************************************************
                          cconfigbase.h  -  description
                             -------------------
    begin                : Sun Jun 15 2003
    copyright            : (C) 2003 by Daniel Muller
    email                : dan at verliba dot cz
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#ifndef CCONFIGBASE_H
#define CCONFIGBASE_H

#include "tchashlistmap.h"
#include "cconfigitembase.h"
#include "cobj.h"
#include <vector>

using std::vector;
using namespace nUtils;

namespace nConfig
{


class cConfigBaseBase;

/**configuration base class
  *@author Daniel Muller
  */
class cConfigBaseBase : public cObj
{
public:
	cConfigBaseBase();
	virtual ~cConfigBaseBase();
	/** save config, to be able to load it after */
	virtual int Save() = 0;
	/** The config load function - whetre from a file, or from database, or whatever
		return >= 0 on success, otherwise error code
	*/
	virtual int Load() = 0;

	/********** typedefs */
	/** the itemlist type */
	// nicked acess
	//typedef tStringHashMap<cConfigItemBase*> tItemHash;
	// numerated access
	typedef vector<size_t> tItemVec;
	typedef tItemVec::iterator tIVIt;

	typedef tcHashListMap<cConfigItemBase*> tItemHash;
	typedef tItemHash::iterator tIHIt;

	// set the base pointer to relative adresses
	void SetBaseTo(void * new_base);

	void *mBasePtr;
	tItemHash mhItems;
	tItemVec  mvItems;
	static hHashStr<size_t> msHasher;

	/**
		Item iterator
	*/
	struct iterator
	{
		iterator(){}
		iterator (class cConfigBaseBase *C,const tIVIt &it):mC(C),mIT(it){}
		cConfigItemBase * operator* () { return mC->mhItems.GetByHash(*mIT);}
		iterator &operator ++(){ mIT++; return *this;}
		iterator(iterator &it){operator=(it);}
		bool operator != (iterator &it){ return mIT != it.mIT;}
		cConfigBaseBase *mC;
		tIVIt mIT;
		iterator &Set(class cConfigBaseBase *C,const tIVIt &it){mC=C;mIT=it; return *this;}
		iterator &operator=(iterator & it){ mIT = it.mIT; mC=it.mC; return *this;}

	};

	iterator mBegin;
	iterator mEnd;
	iterator &begin(){return mBegin.Set(this,mvItems.begin());}
	iterator &end()  {return mEnd.Set(this,mvItems.end());  }
	/** add existing item pointed by the argument at the end of mvItems , and bind a nick to it*/
	cConfigItemBase * Add(const string &, cConfigItemBase *);

	/** bind a nick to a given vaiable */
	void BindNick(int , const string &);


	/** access operators */
	cConfigItemBase * operator[](int);
	cConfigItemBase * operator[](const string &);
};

/*
struct sBasicItemCreator
{
	sBasicItemCreator(){};
	template<class TYPE>
	cConfigItemBase* NewItem(TYPE &var){ return cConfigItemBaseT<TYPE>(var);};
};
*/

/**
This is a base class for every configuration like structure.
You can bind real variables with their names. You can get or affect their values. Convert from/to a std::string
read/write into/from a stream
very useful
@author Daniel Muller
*/
class cConfigBase : public cConfigBaseBase
{
public:
	cConfigBase(){};
	virtual ~cConfigBase(){};

	/** create and add an item of template type with nick too */

	template <class T> cConfigItemBase * Add(const string &name, T &var, const T &def)
	{
		cConfigItemBase * ci = this->Add(name, var);
		*ci=def;
		return ci;
	}

	template <class T> cConfigItemBase * Add(const string &name, T &var)
	{
	   //sBasicItemCreator creator; //@todo the call of the right template function (template virtual)
	   cConfigItemBase * ci;
	   ci = new cConfigItemBaseT<T>(var);//creator.NewItem(var);
	   return this->cConfigBaseBase::Add(name, ci);
	}

	#ifndef NOEXPLICIT_TEMPLATES
	cConfigItemBase * AddItem(const char *name, bool &var);
	cConfigItemBase * AddItem(const char *name, int &var);
	cConfigItemBase * AddItem(const char *name, unsigned &var);
	cConfigItemBase * AddItem(const char *name, long &var);
	cConfigItemBase * AddItem(const char *name, unsigned long &var);
	cConfigItemBase * AddItem(const char *name, __int64 &var);
	cConfigItemBase * AddItem(const char *name, string &var);
	cConfigItemBase * AddItem(const char *name, char* &var);
	#else
	template <class T> cConfigItemBase * AddItem(const char *name, T &var)
	{
		const string Name(name);
		return this->Add(Name, var);
	}
	#endif

	template <class T> cConfigItemBase * AddItem(const char *name, T &var, const T &def)
	{
		const string Name(name);
		return this->Add(Name, var, def);
	}
};

};
#endif
