#ifndef _KVI_SCRIPTOBJECT_H_
#define _KVI_SCRIPTOBJECT_H_

//
//   File : kvi_scriptobject.h
//   Creation date : Tue Sep 05 2000 09:39:34 by Szymon Stefanek
//
//   This file is part of the KVirc irc client distribution
//   Copyright (C) 1999-2000 Szymon Stefanek (stefanek@tin.it)
//
//   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 opinion) 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.
//

#include "kvi_settings.h"

#include "kvi_string.h"
#include "kvi_parameterlist.h"
#include <qobject.h>
#include "kvi_list.h"
#include <qasciidict.h>

class KviDataContainer;
class KviScriptObject;
class KviCommand;
class KviScriptObjectClass;
class KviWindow;
class QWidget;


// An object function callback
typedef bool (KviScriptObject::*KviScriptObjectFunctionHandlerProc)(KviCommand *,KviParameterList *,KviStr &);
typedef KviScriptObject * (*KviScriptObjectAllocateInstanceProc)(KviScriptObjectClass *,KviScriptObject *,const char *);

#define KVI_SCRIPT_OBJECT_FUNCTION_BUILTIN 1
#define KVI_SCRIPT_OBJECT_FUNCTION_INHERITED 2
#define KVI_SCRIPT_OBJECT_FUNCTION_OVERRIDE 3
#define KVI_SCRIPT_OBJECT_FUNCTION_BUILTINOVERRIDE 4

typedef struct _KviScriptObjectFunctionHandler
{
	KviStr                             szScriptHandler;
	int                                iFlags;	
	KviScriptObjectFunctionHandlerProc proc;
} KviScriptObjectFunctionHandler;

class KVIRC_API KviScriptObjectClass
{
	friend class KviScriptObject;
	friend class KviScriptObjectController;
public:
	KviScriptObjectClass(KviScriptObjectClass * par,const char * name,
			KviScriptObjectAllocateInstanceProc proc,bool bBuiltin);
	~KviScriptObjectClass();
protected:
	KviScriptObjectClass                       * m_pParentClass;
	KviStr                                       m_szName;
	bool                                         m_bBuiltin;
	QAsciiDict<KviScriptObjectFunctionHandler> * m_pFunctionHandlers;
	KviPtrList<KviScriptObjectClass>           * m_pChildClasses;
	KviScriptObjectAllocateInstanceProc          m_allocProc;
protected:
	void registerChildClass(KviScriptObjectClass *c);
	void unregisterChildClass(KviScriptObjectClass *c);
public:
	bool isBuiltin(){ return m_bBuiltin; };
	const char * name(){ return m_szName.ptr(); };
	void registerFunctionHandler(const char * func,
		KviScriptObjectFunctionHandlerProc proc,const char * buffer,
		bool bBuiltin);
	void registerEmptyFunctionHandler(const char * func);
	KviScriptObjectFunctionHandler * lookupFunctionHandler(const char * fName){ return m_pFunctionHandlers->find(fName); };
	KviScriptObject * allocateInstance(KviScriptObject * par,const char* nam,KviCommand * c,KviParameterList * params);
};


class KVIRC_API KviScriptObjectController : public QObject
{
	friend class KviScriptObject;
	friend class KviScriptObjectClass;
	Q_OBJECT
public:
	KviScriptObjectController();
	~KviScriptObjectController();
protected:
	KviPtrList<KviScriptObject>      * m_pTopLevelObjectList;
	QAsciiDict<KviScriptObject>      * m_pObjectDict;
	QAsciiDict<KviScriptObjectClass> * m_pClassDict;
	KviScriptObjectClass             * m_pObjectClass; //base class
protected:
	void registerObject(KviScriptObject *o);
	void unregisterObject(KviScriptObject *o);
	void registerClass(KviScriptObjectClass *c);
	void unregisterClass(KviScriptObjectClass *c);
public:
	void clearInstances();
	void clearUserClasses();
	bool objectExists(KviScriptObject * o);
	void killAllObjectsWithClass(KviScriptObjectClass * cl);
	KviScriptObjectClass * lookupClass(const char * cl);
	KviScriptObject * lookupObject(const char * id){ return m_pObjectDict->find(id); };
//	KviScriptObject * allocateObjectInstance(KviScriptObjectClass * cl,KviScriptObject * par,const char * nam,KviParameterList * params);
//	bool killClass(const char * cl); // false if the class was builtin
};

typedef struct _KviScriptObjectConnection
{
	KviScriptObject * pSourceObject;    // source object (owner of the struct)
	KviScriptObject * pTargetObject;    // target object
	KviStr            szSignal;         // source signal name
	KviStr            szSlot;           // target slot function
} KviScriptObjectConnection;

typedef KviPtrList<KviScriptObjectConnection> KviScriptObjectConnectionList;
typedef KviPtrListIterator<KviScriptObjectConnection> KviScriptObjectConnectionListIterator;

class KVIRC_API KviScriptObject : public QObject
{
	friend class KviScriptObjectController;
	friend class KviScriptObjectClass;
	Q_OBJECT
public:
	KviScriptObject(KviScriptObjectClass * cla,KviScriptObject * par,const char * nam);
	virtual ~KviScriptObject();
protected:
	KviPtrList<KviScriptObject>                     * m_pChildList;
	KviStr                                       m_szId;
	KviScriptObjectClass                       * m_pClass;
	bool                                         m_bInDelayedDeath;
	KviDataContainer                           * m_pDataContainer;
	QAsciiDict<KviScriptObjectFunctionHandler> * m_pFunctionHandlers;
	QObject                                    * m_pObject;
	bool                                         m_bObjectOwner; // do we have to destroy it ?
	QAsciiDict<KviScriptObjectConnectionList>  * m_pSignalDict;  // emitted signals
	KviScriptObjectConnectionList              * m_pConnectionList;    // signals connected to this object's slots
	KviStr                                       m_szSignalSender; // current signal sender object
	KviStr                                       m_szSignalName;
public:
	bool connectSignal(const char * sigName,KviScriptObject * target,const char * slotName);
	bool disconnectSignal(const char * sigName,KviScriptObjectConnection * con);
	bool disconnectSignal(const char * sigName,KviScriptObject * target,const char * slotName);
	void emitSignal(const char * sigName,KviStr * pBuffer = 0,KviParameterList * params = 0,KviCommand *c = 0);
	void setSignalName(const char * s){ m_szSignalName = s; };
	const char * signalSender(){ return m_szSignalSender.ptr(); };
	void setSignalSender(const char * s){ m_szSignalSender = s; };
	QObject * object() const { return m_pObject; };
	KviScriptObject * parentObject(){ return (KviScriptObject *)parent(); };
	QWidget * parentScriptWidget();
	void setObject(QObject * o,bool bIsOwned = true);
	const char * id(){ return m_szId.ptr(); };
	bool die();
	bool dieNow();
	KviDataContainer * dataContainer(){ return m_pDataContainer; };
	KviScriptObjectClass * getClass(const char * classOverride = 0);
	KviScriptObjectFunctionHandler * lookupFunctionHandler(const char * funcName,
		const char * classOverride = 0);
	void registerPrivateImplementation(const char * fncName,const char * buffer);
	bool callEventFunction(const char * fncName,KviStr * pBuffer = 0,KviParameterList * params = 0,KviWindow * wnd = 0);
	KviScriptObject * findChild(const char * cl,const char * n);
	void killAllChildrenWithClass(KviScriptObjectClass *cl);
protected:

	void registerConnection(KviScriptObjectConnection * con);
	bool unregisterConnection(KviScriptObjectConnection * con);

	virtual bool init(KviCommand * c);
	void registerChild(KviScriptObject * c);
	void unregisterChild(KviScriptObject *c);
	virtual bool eventFilter(QObject *o,QEvent *e); //necessary ?
	virtual void timerEvent(QTimerEvent *e);
protected:
	bool functionName(KviCommand *c,KviParameterList * params,KviStr &buffer);
	bool functionStartTimer(KviCommand *c,KviParameterList * params,KviStr &buffer);
	bool functionKillTimer(KviCommand *c,KviParameterList * params,KviStr &buffer);
	bool functionKillTimers(KviCommand *c,KviParameterList * params,KviStr &buffer);
	bool functionClassName(KviCommand *c,KviParameterList * params,KviStr &buffer);
	bool functionFindChild(KviCommand *c,KviParameterList * params,KviStr &buffer);
	bool functionChildCount(KviCommand *c,KviParameterList * params,KviStr &buffer);
	bool functionEmit(KviCommand *c,KviParameterList * params,KviStr &buffer);
	bool functionChildren(KviCommand *c,KviParameterList * params,KviStr &buffer);
	bool functionSignalSender(KviCommand *c,KviParameterList * params,KviStr &buffer);
	bool functionSignalName(KviCommand *c,KviParameterList * params,KviStr &buffer);
	bool functionDestructor(KviCommand *c,KviParameterList * params,KviStr &buffer);
	bool functionParent(KviCommand *c,KviParameterList * params,KviStr &buffer);
protected slots:
	void delayedDie();
	void objectDestroyed();
};


extern KVIRC_API KviScriptObjectController * g_pScriptObjectController;


#endif //_KVI_SCRIPTOBJECT_H_
