/***************************************************************************
 *   Copyright (C) 2003 by Dan Muller                                      *
 *   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 TMYSQLMEMORYLIST_H
#define TMYSQLMEMORYLIST_H

#include <vector>
#include "cconfmysql.h"

using std::vector;
using nConfig::cConfMySQL;

namespace nConfig {

/**

@author Daniel Muller
*/
template<class DataType, class OwnerType> class tMySQLMemoryList : public cConfMySQL
{
public:

	tMySQLMemoryList(cMySQL &mysql, OwnerType *owner, string tablename) :
		cConfMySQL(mysql), mOwner(owner)
	{
		//mTableName = tablename;
		mMySQLTable.mName = tablename;
	}

	virtual ~tMySQLMemoryList(){ this->Empty();}

	virtual void OnStart()
	{
		AddFields();
		SetBaseTo(&mModel);
		CreateTable();
		ReloadAll();
	}

	typedef vector<DataType *> tMyDataType;
	typedef typename tMyDataType::iterator iterator;

	virtual void OnLoadData(DataType &Data)
	{
		Data.OnLoad();
	}

	virtual void OnLoadBack()
	{
		OnLoadData(*mData.back());
	}

	/**
	 * \brief add all field you want in this function
	 * */
	virtual void AddFields()=0;

	/**
	 * \brief empty what is in the memory storage
	 * */
	virtual void Empty() {
		for (typename tMyDataType::iterator it = mData.begin(); it != mData.end(); ++it) {
			if (*it != NULL) {
				delete *it;
				*it = NULL;
			}
		}
		mData.clear();
	}

	/**
	 * \return the number of elements in the list loaded in memory
	 * */
	virtual int Size(){ return mData.size();}

	/**
	 * \brief Loads all data from the database into memory
	 * \return the number of elements loaded
	 * */
	virtual int ReloadAll()
	{
		cQuery Query(mQuery); // make a second wuery for safety reasons
		Empty();
		Query.Clear();
		SelectFields(Query.OStream());
		int n=0;
		db_iterator it;

		PrepareNew();
		for(it = db_begin(Query); it != db_end(); ++it)
		{
			OnLoadBack();
			n++;
			PrepareNew();
		}
		Query.Clear();
		DeleteLast();
		return n;
	}

	/**
	 * \brief Add data into memory and database too, if you add twice same, it may be duplicated
	 * */
	virtual int AddData(DataType const &data)
	{
		DataType *copy = new DataType(data);
		SetBaseTo(copy);
		mData.push_back(copy);
		return SavePK();
	}

	virtual int UpdateData(DataType &data)
	{
		SetBaseTo(&data);
		return UpdatePK();
	}

	/**
	 * \brief Removes data from database, given probably by the PK
	 *
	 * calls ReloadAll, so it may be potentially slow
	 * */
	virtual void DelData(DataType &data)
	{
		SetBaseTo(&data);
		DeletePK();
		ReloadAll();
	}

	virtual bool CompareDataKey(const DataType &D1, const DataType &D2){ return false; }

	virtual DataType *FindData(DataType &ByKey)
	{
		iterator it;
		for (it = begin(); it != end(); ++it)
		{
			if( CompareDataKey(ByKey, *(*it))) return *it;
		}
		return NULL;
	}

	/**
	 * \brief save data on n-th position
	 * */
	void SaveData(int n)
	{
		if (n < mData.size())
		{
			SetBaseTo(mData[n]);
			Save();
		}
	}

	/**
	 * \brief Get the i-th element from the list
	 * */
	DataType * operator[](int i)
	{
		if( i < 0 || i >= Size() ) return NULL;
		return mData[i];
	}

	iterator begin() { return mData.begin();}
	iterator end() { return mData.end();}

protected:
	void PrepareNew()
	{
		DataType *data = new DataType;
		SetBaseTo(data);
		mData.push_back(data);
	}

	int DeleteLast()
	{
		if( !mData.size() ) return 0;
		SetBaseTo(&mModel);
		delete mData.back();
		mData.pop_back();
	}

private:
	tMyDataType mData;

protected:
	/**
	 * The prototype of given data
	 * */
	DataType mModel;

	/**
	 * The owner object of this one
	 * */
	OwnerType *mOwner;
};

};

#endif
