#ifndef _KVI_MODULE_H_
#define _KVI_MODULE_H_

//=============================================================================
//
//   File : kvi_module.h
//   Creation date : Sat Aug 12 2000 18:34:22 by Szymon Stefanek
//
//   This file is part of the KVirc irc client distribution
//   Copyright (C) 2000-2004 Szymon Stefanek (pragma at kvirc dot net)
//
//   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_command.h"
#include "kvi_parameterlist.h"
#include "kvi_library.h"
#include "kvi_list.h"
#include "kvi_moduleextension.h"
#include "kvi_kvs_moduleinterface.h"

#include <qasciidict.h>

#ifdef COMPILE_CRYPT_SUPPORT
	#include "kvi_crypt.h"
#endif


#ifdef COMPILE_ON_WINDOWS
	#define KVIMODULEEXPORT extern "C" __declspec(dllexport)
	#define KVIMODULEEXPORTDATA KVIMODULEEXPORT
	#define KVIMODULEEXPORTFUNC KVIMODULEEXPORT
#else
	#define KVIMODULEEXPORT extern "C"
	#define KVIMODULEEXPORTDATA
	#define KVIMODULEEXPORTFUNC KVIMODULEEXPORT
#endif

class KviModule;


typedef bool (*KviModuleSystemRoutine)(KviModule *);
typedef bool (*KviModuleCtrlRoutine)(KviModule *,const char *,void *);


typedef struct _KviModuleInfo
{
	const char * szKVIrcVersion; // must match KVI_VERSION if module version checking is in force
	const char * szModuleName;
	const char * szVersion;
	const char * szCopyright;
	const char * szDescription;
	/*
	* This routine is called when the module is loaded
	*/
	KviModuleSystemRoutine init_routine;
	/*
	* This should return true if the module is actually
	* not providing any service and it is safe to unload it
	* to free memory.
	* If this pointer is 0, the standard locking method is used.
	*/
	KviModuleSystemRoutine can_unload;
	/*
	* This is a generic control routine with prototype
	* bool <name>(KviModule * m,const char * operation,void * param)
	* KVIrc uses it to comunicate with bundled modules
	* in most user-build modules this will be 0
	*/
	KviModuleCtrlRoutine   ctrl_routine;
	/*
	* This routine is called when the module is being unloaded
	* Note that the module can be unloaded even if can_unload returns false:
	* that's the user choice, KVIrc can only forcibly unload the module,
	* so better cleanup everything here :)
	*/
	KviModuleSystemRoutine cleanup_routine; // WARNING : g_pApp may be in the destructor and may have no frames open!
} KviModuleInfo;

// NOTE: The init and cleanup routines should NEVER rely on g_pApp existing!
//       so only "initialization and cleanup INTERNAL to the module" goes there!

// A module should be prepared to be unloaded at ANY time, even if it is locked
// or if can_unload returns false; locking is only a "suggestion" to the KVIrc core.

// When unloaded, a module must ensure the destruction of all the resources that depend
// on the module core code

#define KVIRC_MODULE_STRUCTURE_SYMBOL "KVIrc_module_info"

#define KVIRC_MODULE(_szModuleName,_szVersion,_szCopyright,_szDescription,_init_routine,_can_unload,_ctrl_routine,_cleanup_routine) \
	\
	KVIMODULEEXPORTDATA KviModuleInfo KVIrc_module_info= \
	{ \
		KVI_VERSION, \
		_szModuleName, \
		_szVersion, \
		_szCopyright, \
		_szDescription, \
		_init_routine, \
		_can_unload, \
		_ctrl_routine, \
		_cleanup_routine \
	};
	

// old type parsing procedures
typedef bool (*KviModuleCommandParseProc)(KviModule *,KviCommand *);
typedef bool (*KviModuleFunctionParseProc)(KviModule *,KviCommand *,KviParameterList *,KviStr &);
typedef bool (*KviModuleEventParseProc)(KviModule *,KviWindow *,KviParameterList *);



class KVIRC_API KviModule : public KviKvsModuleInterface
{
	friend class QAsciiDict<KviModule>;
	friend class KviModuleManager;
	friend class KviUserParser;
protected:
	KviModule(kvi_library_t handle,KviModuleInfo * info,const char * name,const char * filename);
	~KviModule();
private:
	KviStr                                     m_szName;
	KviStr                                     m_szFileName;
	KviModuleInfo                            * m_pModuleInfo;
	kvi_library_t                              m_dlHandle;
	QAsciiDict<KviModuleCommandParseProc>    * m_pCommandDict;
	QAsciiDict<KviModuleFunctionParseProc>   * m_pFunctionDict;
	KviModuleCommandParseProc                * m_pGenericCommandParseProc;
	KviModuleFunctionParseProc               * m_pGenericFunctionParseProc;
	bool                                       m_bLocked;
	long int                                   m_lastAccessTime;
protected:
	KviModuleCommandParseProc * findCommandParseProc(const char * cmd){ return m_pCommandDict->find(cmd); };
	KviModuleFunctionParseProc * findFunctionParseProc(const char * cmd){ return m_pFunctionDict->find(cmd); };
	void updateAccessTime();
	unsigned int secondsSinceLastAccess();
public:
	// name of this module: always low case , single word
	const char    * name(){ return m_szName.ptr(); };
	// filename of this module (with NO path): formatted as "libkvi%s.so",name()
	const char    * filename(){ return m_szFileName.ptr(); };
	kvi_library_t   handle(){ return m_dlHandle; };
	KviModuleInfo * moduleInfo(){ return m_pModuleInfo; };
	void            lock(){ m_bLocked = true; }; // multiple locks equal a single lock
	void            unlock(){ m_bLocked = false; }; // multiple locks equal a single unlock
	bool            isLocked(){ return m_bLocked; };
	void          * getSymbol(const char * symname);
	bool            ctrl(const char * operation,void * param);

	void completeCommand(const QString &cmd,KviPtrList<QString> * matches);
	void completeFunction(const QString &cmd,KviPtrList<QString> * matches);

	void setGenericCommandParseProc(KviModuleCommandParseProc proc);
	void setGenericFunctionParseProc(KviModuleFunctionParseProc proc);
	KviModuleCommandParseProc * genericCommandParseProc(){ return m_pGenericCommandParseProc; };
	KviModuleFunctionParseProc * genericFunctionParseProc(){ return m_pGenericFunctionParseProc; };	

	void getDefaultConfigFileName(KviStr &buffer);
	void getDefaultConfigFileName(QString &szBuffer);

	static void unregisterMetaObject(const char * metaObjName);

	void registerEventHandler(int evIdx,KviModuleEventParseProc proc);
	void unregisterEventHandler(int evIdx);
	void registerRawNumericEventHandler(int evIdx,KviModuleEventParseProc proc);
	void unregisterRawNumericEventHandler(int evIdx);
	void unregisterAllEventHandlers();


	void registerCommand(const char * cmd,KviModuleCommandParseProc proc);
	void unregisterCommand(const char * cmd);
	void unregisterAllCommands();

	void registerFunction(const char * fnc,KviModuleFunctionParseProc proc);
	void unregisterFunction(const char * fnc);
	void unregisterAllFunctions();

#ifdef COMPILE_CRYPT_SUPPORT
	void registerCryptEngine(KviCryptEngineDescription * d);
	void unregisterCryptEngine(const char * szName);
	void unregisterCryptEngines();
#endif

	KviModuleExtensionDescriptor * registerExtension(const KviStr &szType,const KviStr &szName,const QString &szVisibleName,KviModuleExtensionAllocRoutine r);
	KviModuleExtensionDescriptor * registerExtension(const KviStr &szType,const KviStr &szName,const QString &szVisibleName,KviModuleExtensionAllocRoutine r,const QPixmap &icon);
	KviModuleExtensionDescriptor * findExtensionDescriptor(const KviStr &szType,const KviStr &szName);
	void unregisterAllExtensions();
};

#endif //_KVI_MODULE_H_
