/***************************************************************************
 *   Copyright (C) 2004 by Daniel 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.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#ifndef NCONFIGLISTCONSOLE_H
#define NCONFIGLISTCONSOLE_H

#include "cdccommand.h"
#include "ccmdr.h"

using namespace nCmdr;

namespace nDirectConnect{ class cConnDC;}
using namespace nDirectConnect;

namespace nConfig
{

/**
a console that parses commands for Lists based on tMySQLMemoryList

@author Daniel Muller
*/
template <class DATA_TYPE, class LIST_TYPE, class OWNER_TYPE>
class tListConsole
{
public:
	tListConsole(void *owner):
		mOwner((OWNER_TYPE *)owner),
		mCmdr(this)
	{}

	virtual ~tListConsole(){};

	enum { eLC_ADD, eLC_DEL, eLC_MOD, eLC_LST, eLC_FREE };

	virtual void AddCommands()
	{
		mCmdAdd.Init(int(eLC_ADD), CmdId(eLC_ADD), GetParamsRegex(eLC_ADD), &mcfAdd);
		mCmdDel.Init(eLC_DEL, CmdId(eLC_DEL), GetParamsRegex(eLC_DEL), &mcfDel);
		mCmdMod.Init(eLC_MOD, CmdId(eLC_MOD), GetParamsRegex(eLC_MOD), &mcfMod);
		mCmdLst.Init(eLC_LST, CmdId(eLC_LST), "", &mcfLst);
		mCmdr.Add(&mCmdAdd);
		mCmdr.Add(&mCmdDel);
		mCmdr.Add(&mCmdMod);
		mCmdr.Add(&mCmdLst);
	}

	virtual int DoCommand(const string &str, cConnDC * conn)
	{
		ostringstream os;
		if(mCmdr.ParseAll(str, os, conn) >= 0)
		{
			mOwner->mServer->DCPublicHS(os.str().data(),conn);
			return 1;
		}
		return 0;
	}


	virtual const char * GetParamsRegex(int) = 0;
	virtual LIST_TYPE *GetTheList() = 0;
	virtual const char *CmdSuffix() {return "";}
	virtual const char *CmdPrefix() {return "\\+";}
	virtual void ListHead(ostream *os){}

	virtual const char *CmdWord(int cmd)
	{
		switch(cmd)
		{
			case eLC_ADD: return "add"; break;
			case eLC_DEL: return "del"; break;
			case eLC_MOD: return "mod"; break;
			case eLC_LST: return "lst"; break;
			default: return "???";
		}
	}

	virtual const char *CmdId(int cmd)
	{
		static string id;
		id = CmdPrefix();
		id += CmdWord(cmd);
		id += CmdSuffix();
		if(cmd != eLC_LST) id += " ";
		return id.data();
	}

	class cfBase;

	virtual bool ReadDataFromCmd(cfBase *cmd, int CmdID, DATA_TYPE &data) = 0;

protected:


	class cfBase : public ::cDCCommand::sDCCmdFunc
	{
		public:
		tListConsole<DATA_TYPE, LIST_TYPE, OWNER_TYPE> *GetConsole(){
			return (tListConsole<DATA_TYPE, LIST_TYPE, OWNER_TYPE> *)(mCommand->mCmdr->mOwner);
		}
		virtual LIST_TYPE *GetTheList() { if(GetConsole() != NULL) return GetConsole()->GetTheList();}

	};

	class cfAdd : public cfBase
	{
		virtual bool operator()()
		{
			DATA_TYPE Data;
			if ( GetConsole() &&  GetConsole()->ReadDataFromCmd(this, eLC_ADD, Data)) {
				LIST_TYPE *list = this->GetTheList();
				if (list) {
					if (!list->FindData(Data)) {
						if (list->AddData(Data)) {
							list->OnLoadBack();
							(*mOS) << "Successully added: " << Data << "\r\n";
							return true;
						} else {
							(*mOS) << "Error: Cannot add";
						}
					} else {
						(*mOS) << "Error: Already exists";
					}
				}
			} else {
				(*mOS) << "Error in data you provided.";
			}
			return false;
		}
	} mcfAdd;

	class cfDel : public cfBase
	{
		virtual bool operator()()
		{
			DATA_TYPE Data;
			if ( GetConsole() && GetConsole()->ReadDataFromCmd(this, eLC_DEL, Data))
			{
				if (this->GetTheList() && this->GetTheList()->FindData(Data))
				{
					this->GetTheList()->DelData(Data);
					(*mOS) << "Deleted successfuly";
					return true;
				}
			}
			return false;
		}
	} mcfDel;

	class cfMod : public cfBase
	{
		virtual bool operator()()
		{
			DATA_TYPE Data, * pOrig;
			if ( GetConsole() && GetConsole()->ReadDataFromCmd(this, eLC_MOD, Data))
			{
				if (this->GetTheList() && (pOrig = this->GetTheList()->FindData(Data)))
				{
					GetConsole()->ReadDataFromCmd(this, eLC_MOD, *pOrig);
					(*mOS) << "Successully modified: " << Data << "\r\n";
					return true;
				}
			}
			return false;
		}
	} mcfMod;

	class cfLst : public cfBase
	{
		virtual bool operator()()
		{
			DATA_TYPE *pData;
			GetConsole()->ListHead(mOS);
			for(int i = 0; i < this->GetTheList()->Size(); i++)
			{
				pData = (*this->GetTheList())[i];
				(*mOS) << (*pData) << "\r\n";
			}

			return true;
		}
	} mcfLst;

	cDCCommand mCmdAdd;
	cDCCommand mCmdDel;
	cDCCommand mCmdMod;
	cDCCommand mCmdLst;

	OWNER_TYPE *mOwner;
	cCmdr mCmdr;
};

};

#endif
