//=============================================================================
//
//   File : libkvipopup.cpp
//   Creation date : Fri Sep 03 2010 15:23:00 CEST by Fabio Bas
//
//   This file is part of the KVIrc irc client distribution
//   Copyright (C) 2001-2010 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
//=============================================================================

#include "KviModule.h"
#include "KviLocale.h"
#include "KviKvsPopupManager.h"

#define GET_KVS_POPUP(LOCKING_CHECK) \
	int iIdx = szPopupName.indexOf(QChar('.')); \
	if(iIdx == 0) \
	{ \
		if(!c->hasSwitch('q',"quiet")) \
			c->warning(__tr2qs_ctx("Empty popup name supplied","kvs")); \
		return true; \
	} \
	if(iIdx > 0) \
	{ \
		if(iIdx == szPopupName.size()) \
		{ \
			if(!c->hasSwitch('q',"quiet")) \
				c->warning(__tr2qs_ctx("Empty subpopup name supplied","kvs")); \
			return true; \
		} \
		szSubPopupName = szPopupName.mid(iIdx+1); \
		szPopupName.truncate(iIdx); \
	} \
	KviKvsPopupMenu * pPopup = KviKvsPopupManager::instance()->lookup(szPopupName); \
	if(!pPopup) \
	{ \
		if(!c->hasSwitch('q',"quiet")) \
			c->warning(__tr2qs_ctx("Popup \"%Q\" does not exist","kvs"),&szPopupName); \
		return true; \
	} \
	if(pPopup->LOCKING_CHECK()) \
	{ \
		if(!c->hasSwitch('q',"quiet")) \
			c->warning(__tr2qs_ctx("Popup menu self-modification is not allowed (the popup is probably open)","kvs")); \
		return true; \
	} \
	if(!szSubPopupName.isEmpty()) \
	{ \
		pPopup = pPopup->findChildPopupByName(szSubPopupName); \
		if(!pPopup) \
		{ \
			if(!c->hasSwitch('q',"quiet")) \
				c->warning(__tr2qs_ctx("Subpopup \"%Q.%Q\" does not exist","kvs"),&szPopupName, &szSubPopupName); \
			return true; \
		} \
		if(pPopup->LOCKING_CHECK()) \
		{ \
			if(!c->hasSwitch('q',"quiet")) \
				c->warning(__tr2qs_ctx("Popup menu self-modification is not allowed (the subpopup is probably open)","kvs")); \
			return true; \
		} \
	}

#define GET_KVS_POPUP_FNC \
	int iIdx = szPopupName.indexOf(QChar('.')); \
	if(iIdx == 0) \
	{ \
		c->warning(__tr2qs_ctx("Empty popup name supplied","kvs")); \
		return true; \
	} \
	if(iIdx > 0) \
	{ \
		if(iIdx == szPopupName.size()) \
		{ \
			c->warning(__tr2qs_ctx("Empty subpopup name supplied","kvs")); \
			return true; \
		} \
		szSubPopupName = szPopupName.mid(iIdx+1); \
		szPopupName.truncate(iIdx); \
	} \
	KviKvsPopupMenu * pPopup = KviKvsPopupManager::instance()->lookup(szPopupName); \
	if(!pPopup) \
	{ \
		c->warning(__tr2qs_ctx("Popup \"%Q\" does not exist","kvs"),&szPopupName); \
		return true; \
	} \
	if(!szSubPopupName.isEmpty()) \
	{ \
		pPopup = pPopup->findChildPopupByName(szSubPopupName); \
		if(!pPopup) \
		{ \
			c->warning(__tr2qs_ctx("Subpopup \"%Q.%Q\" does not exist","kvs"),&szPopupName, &szSubPopupName); \
			return true; \
		} \
	}

/*
	@doc: popup.addItem
	@type:
		command
	@title:
		popup.addItem
	@syntax:
		popup.addItem [-q] (<popupname:string>, <text:string>[, <icon:string>[, <item_id:string>[, <condition:string>]]])
		[{]
			<command>
		[}]
	@short:
		Adds an item to a popup
	@switches:
		!sw: -q | --quiet
		Run quietly: don't print warning and errors
	@description:
		Adds a menu item with visible <text> and the optional <icon> to an already existing popup or
		nested popup named <popupname>. If you want to add an item to a nested popup, use the form
		"popup.item".[br]
		<text> is a string that is evaluated at [cmd]popup[/cmd] call time and may contain
		identifiers and variables.[br]
		<icon> is an optional [doc:image_id]image identifier[/doc].[br]
		<item_id> is the optional item id - if not specified, it will be generated automatically.[br]
		If <condition> is given, it is evaluated at [cmd]popup.show[/cmd] call time and if the
		result is 0, the item is not shown in the physical popup.[br]
		If this item gets clicked, the code inside <command> will be executed.
		<command> can be a simple instruction or an instruction block delimited by curly brackets.[br]
	@seealso:
		[cmd]defpopup[/cmd], [cmd]popup.show[/cmd]
*/

static bool popup_kvs_cmd_addItem(KviKvsModuleCallbackCommandCall * c)
{
	QString szPopupName, szSubPopupName, szItemId, szText, szIcon, szCondition;
	KVSM_PARAMETERS_BEGIN(c)
		KVSM_PARAMETER("popupname",KVS_PT_NONEMPTYSTRING,0,szPopupName)
		KVSM_PARAMETER("text",KVS_PT_NONEMPTYSTRING,0,szText)
		KVSM_PARAMETER("icon",KVS_PT_STRING,KVS_PF_OPTIONAL,szIcon)
		KVSM_PARAMETER("item_id",KVS_PT_STRING,KVS_PF_OPTIONAL,szItemId)
		KVSM_PARAMETER("condition",KVS_PT_STRING,KVS_PF_OPTIONAL,szCondition)
	KVSM_PARAMETERS_END(c)

	GET_KVS_POPUP(isHardLocked)

	if(c->callback()->code().trimmed().isEmpty() && !c->hasSwitch('q',"quiet"))
		c->warning(__tr2qs_ctx("Found empty instruction for popup item: maybe you need to fix the script?","kvs"));

	pPopup->addItem(szItemId, c->callback()->code(), szText, szIcon, szCondition);

	KviKvsPopupManager::instance()->emitRefresh(szPopupName);
	return true;
}

/*
	@doc: popup.addPrologue
	@type:
		command
	@title:
		popup.addPrologue
	@syntax:
		popup.addPrologue [-q] (<popupname:string>[, <item_id:string>])
		[{]
			<command>
		[}]
	@short:
		Adds a prologue to a popup
	@switches:
		!sw: -q | --quiet
		Run quietly: don't print warning and errors
	@description:
		Adds a menu prologue to an already existing popup or nested popup named <popupname>. If you
		want to add an item to a nested popup, use the form "popup.item".[br]
		<item_id> is the optional item id - if not specified, it will be generated automatically.[br]
		<command> will be executed just before the popup is filled at [cmd]popup.show[/cmd] command call.
		<command> can be a simple instruction or an instruction block delimited by curly brackets.[br]
		Please note that some instructions are not allowed here, You can't delete the prologue's parent
		popup (calling [cmd]popup.clear[/cmd] or [cmd]popup.destroy[/cmd]) or modify prologues/epilogues
		(calling [cmd]popup.addPrologue[/cmd] or [cmd]popup.addEpilogue[/cmd])
	@seealso:
		[cmd]defpopup[/cmd], [cmd]popup.show[/cmd], [cmd]popup.addEpilogue[/cmd]
*/

static bool popup_kvs_cmd_addPrologue(KviKvsModuleCallbackCommandCall * c)
{
	QString szPopupName, szSubPopupName,szItemId;
	KVSM_PARAMETERS_BEGIN(c)
		KVSM_PARAMETER("popupname",KVS_PT_NONEMPTYSTRING,0,szPopupName)
		KVSM_PARAMETER("item_id",KVS_PT_STRING,KVS_PF_OPTIONAL,szItemId)
	KVSM_PARAMETERS_END(c)

	GET_KVS_POPUP(isSoftLocked)

	if(c->callback()->code().trimmed().isEmpty() && !c->hasSwitch('q',"quiet"))
		c->warning(__tr2qs_ctx("Found empty prologue block: maybe you need to fix the script?","kvs"));

	pPopup->addPrologue(szItemId, c->callback()->code());

	KviKvsPopupManager::instance()->emitRefresh(szPopupName);
	return true;
}

/*
	@doc: popup.addEpilogue
	@type:
		command
	@title:
		popup.addEpilogue
	@syntax:
		popup.addEpilogue [-q] (<popupname:string>[, <item_id:string>])
		[{]
			<command>
		[}]
	@short:
		Adds an epilogue to a popup
	@switches:
		!sw: -q | --quiet
		Run quietly: don't print warning and errors
	@description:
		Adds a menu epilogue to an already existing popup or nested popup named <popupname>. If you
		want to add an item to a nested popup, use the form "popup.item".[br]
		<item_id> is the optional item id - if not specified, it will be generated automatically.[br]
		<command> will be executed just after the popup is filled at [cmd]popup.show[/cmd] command call.
		<command> can be a simple instruction or an instruction block delimited by curly brackets.[br]
		Please note that some instructions are not allowed here, You can't delete the prologue's parent
		popup (calling [cmd]popup.clear[/cmd] or [cmd]popup.destroy[/cmd]) or modify prologues/epilogues
		(calling [cmd]popup.addPrologue[/cmd] or [cmd]popup.addEpilogue[/cmd])
	@seealso:
		[cmd]defpopup[/cmd], [cmd]popup.show[/cmd], [cmd]popup.addPrologue[/cmd]
*/

static bool popup_kvs_cmd_addEpilogue(KviKvsModuleCallbackCommandCall * c)
{
	QString szPopupName, szSubPopupName,szItemId;
	KVSM_PARAMETERS_BEGIN(c)
		KVSM_PARAMETER("popupname",KVS_PT_NONEMPTYSTRING,0,szPopupName)
		KVSM_PARAMETER("item_id",KVS_PT_STRING,KVS_PF_OPTIONAL,szItemId)
	KVSM_PARAMETERS_END(c)

	GET_KVS_POPUP(isSoftLocked)

	if(c->callback()->code().trimmed().isEmpty() && !c->hasSwitch('q',"quiet"))
		c->warning(__tr2qs_ctx("Found empty epilogue block: maybe you need to fix the script?","kvs"));

	pPopup->addEpilogue(szItemId, c->callback()->code());

	KviKvsPopupManager::instance()->emitRefresh(szPopupName);
	return true;
}

/*
	@doc: popup.addExtPopup
	@type:
		command
	@title:
		popup.addExtPopup
	@syntax:
		popup.addExtPopup [-q] <popupname:string> <external_popup:string> <text:string> [<icon:string> [<item_id:string> [<condition:string>]]]
	@short:
		Adds an external popup to a popup
	@switches:
		!sw: -q | --quiet
		Run quietly: don't print warning and errors
	@description:
		Adds a nested popup item with visible <text> and the optional <icon> to an already existing popup or
		nested popup named <popupname>. If you want to add an item to a nested popup, use the form
		"popup.item".[br]
		<text> is a string that is evaluated at [cmd]popup[/cmd] call time and may contain
		identifiers and variables.[br]
		<icon> is an optional [doc:image_id]image identifier[/doc].[br]
		<item_id> is the optional item id - if not specified, it will be generated automatically.[br]
		If <condition> is given, it is evaluated at [cmd]popup.show[/cmd] call time and if the
		result is 0, the item is not shown in the physical popup.[br]
		If this item is hovered over, the nested popup <external_popup> will be shown.
	@seealso:
		[cmd]defpopup[/cmd], [cmd]popup.show[/cmd], [cmd]popup.addSubPopup[/cmd]
*/

static bool popup_kvs_cmd_addExtPopup(KviKvsModuleCommandCall * c)
{
	QString szPopupName, szSubPopupName, szItemId, szExtPopupName, szText, szIcon, szCondition;
	KVSM_PARAMETERS_BEGIN(c)
		KVSM_PARAMETER("popupname",KVS_PT_NONEMPTYSTRING,0,szPopupName)
		KVSM_PARAMETER("external_popup",KVS_PT_NONEMPTYSTRING,0,szExtPopupName)
		KVSM_PARAMETER("text",KVS_PT_NONEMPTYSTRING,0,szText)
		KVSM_PARAMETER("icon",KVS_PT_STRING,KVS_PF_OPTIONAL,szIcon)
		KVSM_PARAMETER("item_id",KVS_PT_STRING,KVS_PF_OPTIONAL,szItemId)
		KVSM_PARAMETER("condition",KVS_PT_STRING,KVS_PF_OPTIONAL,szCondition)
	KVSM_PARAMETERS_END(c)

	GET_KVS_POPUP(isHardLocked)

	pPopup->addExtPopup(szItemId, szExtPopupName, szText, szIcon, szCondition);

	KviKvsPopupManager::instance()->emitRefresh(szPopupName);
	return true;
}

/*
	@doc: popup.addLabel
	@type:
		command
	@title:
		popup.addLabel
	@syntax:
		popup.addLabel [-q] <popupname:string> <text:string> [<icon:string> [<item_id:string> [<condition:string>]]]
	@short:
		Adds a label to a popup
	@switches:
		!sw: -q | --quiet
		Run quietly: don't print warning and errors
	@description:
		Adds a descriptive label with visible <text> and the optional <icon> to an already existing popup or
		nested popup named <popupname>. If you want to add an item to a nested popup, use the form
		"popup.item". The label acts like a separator - it is not selectable or clickable.[br]
		<text> is a string that is evaluated at [cmd]popup[/cmd] call time and may contain
		identifiers and variables.[br]
		<icon> is an optional [doc:image_id]image identifier[/doc].[br]
		<item_id> is the optional item id - if not specified, it will be generated automatically.[br]
		If <condition> is given, it is evaluated at [cmd]popup.show[/cmd] call time and if the
		result is 0, the item is not shown in the physical popup.[br]
	@seealso:
		[cmd]defpopup[/cmd], [cmd]popup.show[/cmd]
*/

static bool popup_kvs_cmd_addLabel(KviKvsModuleCommandCall * c)
{
	QString szPopupName, szSubPopupName, szItemId, szText, szIcon, szCondition;
	KVSM_PARAMETERS_BEGIN(c)
		KVSM_PARAMETER("popupname",KVS_PT_NONEMPTYSTRING,0,szPopupName)
		KVSM_PARAMETER("text",KVS_PT_NONEMPTYSTRING,0,szText)
		KVSM_PARAMETER("icon",KVS_PT_STRING,KVS_PF_OPTIONAL,szIcon)
		KVSM_PARAMETER("item_id",KVS_PT_STRING,KVS_PF_OPTIONAL,szItemId)
		KVSM_PARAMETER("condition",KVS_PT_STRING,KVS_PF_OPTIONAL,szCondition)
	KVSM_PARAMETERS_END(c)

	GET_KVS_POPUP(isHardLocked)

	pPopup->addLabel(szItemId, szText, szIcon, szCondition);

	KviKvsPopupManager::instance()->emitRefresh(szPopupName);
	return true;
}

/*
	@doc: popup.addSubPopup
	@type:
		command
	@title:
		popup.addSubPopup
	@syntax:
		popup.addSubPopup [-q] (<popupname:string>, <text:string>[, <icon:string>[, <item_id:string>[, <condition:string>]]])
	@short:
		Adds a nested popup to a popup
	@switches:
		!sw: -q | --quiet
		Run quietly: don't print warning and errors
	@description:
		Adds an empty nested popup item with visible <text> and the optional <icon> to an already existing popup or
		nested popup named <popupname>. If you want to add an item to a nested popup, use the form
		"popup.item".[br]
		<text> is a string that is evaluated at [cmd]popup[/cmd] call time and may contain
		identifiers and variables.[br]
		<icon> is an optional [doc:image_id]image identifier[/doc].[br]
		<item_id> is the optional item id - if not specified, it will be generated automatically.[br]
		If <condition> is given, it is evaluated at [cmd]popup.show[/cmd] call time and if the
		result is 0, the item is not shown in the physical popup.[br]
		If this item is hovered over, the nested popup will be shown.
	@seealso:
		[cmd]defpopup[/cmd], [cmd]popup.show[/cmd], [cmd]popup.addExtPopup[/cmd]
*/

static bool popup_kvs_cmd_addSubPopup(KviKvsModuleCommandCall * c)
{
	QString szPopupName, szSubPopupName, szItemId, szText, szIcon, szCondition;
	KVSM_PARAMETERS_BEGIN(c)
		KVSM_PARAMETER("popupname",KVS_PT_NONEMPTYSTRING,0,szPopupName)
		KVSM_PARAMETER("text",KVS_PT_NONEMPTYSTRING,0,szText)
		KVSM_PARAMETER("icon",KVS_PT_STRING,KVS_PF_OPTIONAL,szIcon)
		KVSM_PARAMETER("item_id",KVS_PT_STRING,KVS_PF_OPTIONAL,szItemId)
		KVSM_PARAMETER("condition",KVS_PT_STRING,KVS_PF_OPTIONAL,szCondition)
	KVSM_PARAMETERS_END(c)

	GET_KVS_POPUP(isHardLocked)

	pPopup->addPopup(szItemId, szText, szIcon, szCondition);

	KviKvsPopupManager::instance()->emitRefresh(szPopupName);
	return true;
}

/*
	@doc: popup.addSeparator
	@type:
		command
	@title:
		popup.addSeparator
	@syntax:
		popup.addSeparator [-q] <popupname:string> [<item_id:string> [<condition:string>]]
	@short:
		Adds a separator to a popup
	@switches:
		!sw: -q | --quiet
		Run quietly: don't print warning and errors
	@description:
		Adds a separator (typically drawn as a straight line) to an already existing popup or
		nested popup named <popupname>. If you want to add an item to a nested popup, use the form
		"popup.item". The separator is not selectable or clickable.[br]
		<item_id> is the optional item id - if not specified, it will be generated automatically.[br]
		If <condition> is given, it is evaluated at [cmd]popup.show[/cmd] call time and if the
		result is 0, the item is not shown in the physical popup.[br]
	@seealso:
		[cmd]defpopup[/cmd], [cmd]popup.show[/cmd]
*/

static bool popup_kvs_cmd_addSeparator(KviKvsModuleCommandCall * c)
{
	QString szPopupName, szSubPopupName, szItemId, szCondition;
	KVSM_PARAMETERS_BEGIN(c)
		KVSM_PARAMETER("popupname",KVS_PT_NONEMPTYSTRING,0,szPopupName)
		KVSM_PARAMETER("item_id",KVS_PT_STRING,KVS_PF_OPTIONAL,szItemId)
		KVSM_PARAMETER("condition",KVS_PT_STRING,KVS_PF_OPTIONAL,szCondition)
	KVSM_PARAMETERS_END(c)

	GET_KVS_POPUP(isHardLocked)

	pPopup->addSeparator(szItemId, szCondition);

	KviKvsPopupManager::instance()->emitRefresh(szPopupName);
	return true;
}

/*
	@doc: popup.clear
	@type:
		command
	@title:
		popup.clear
	@syntax:
		popup.clear [-q] <popupname:string>
	@short:
		Clears all the items of a popup
	@switches:
		!sw: -q | --quiet
		Run quietly: don't print warning and errors
	@description:
		Removes all the items from an already existing popup or nested popup named <popupname>.
		If you want to clear a nested popup, use the form "popup.item".[br]
	@seealso:
		[cmd]defpopup[/cmd], [cmd]popup.show[/cmd], [fnc]popup.isEmpty[/fnc]
*/

static bool popup_kvs_cmd_clear(KviKvsModuleCommandCall * c)
{
	QString szPopupName, szSubPopupName;
	KVSM_PARAMETERS_BEGIN(c)
		KVSM_PARAMETER("popupname",KVS_PT_NONEMPTYSTRING,0,szPopupName)
	KVSM_PARAMETERS_END(c)

	GET_KVS_POPUP(isSoftLocked)

	pPopup->doClear();

	KviKvsPopupManager::instance()->emitRefresh(szPopupName);
	return true;
}

/*
	@doc: popup.create
	@type:
		command
	@title:
		popup.create
	@syntax:
		popup.create [-q] <popupname:string>
	@short:
		Creates a popup
	@switches:
		!sw: -q | --quiet
		Run quietly: don't print warning and errors
	@description:
		Creates a popup named <popupname>; if the popup already exists, a warning is printed.
		To create a nested popup, use [cmd]popup.addSubPopup[/cmd] instead.
	@seealso:
		[cmd]defpopup[/cmd], [cmd]popup.show[/cmd], [cmd]popup.destroy[/cmd], [fnc]popup.exists[/fnc]
*/

static bool popup_kvs_cmd_create(KviKvsModuleCommandCall * c)
{
	QString szPopupName, szSubPopupName;
	KVSM_PARAMETERS_BEGIN(c)
		KVSM_PARAMETER("popupname",KVS_PT_NONEMPTYSTRING,0,szPopupName)
	KVSM_PARAMETERS_END(c)

	if(KviKvsPopupManager::instance()->lookup(szPopupName))
	{
		if(!c->hasSwitch('q',"quiet"))
			c->warning(__tr2qs_ctx("The popup \"%Q\" already exists","kvs"),&szPopupName);
		return true;
	}

	KviKvsPopupMenu * pMenu = new KviKvsPopupMenu(szPopupName);
	KviKvsPopupManager::instance()->add(szPopupName,pMenu);

	KviKvsPopupManager::instance()->emitRefresh(szPopupName);
	return true;
}
/*
	@doc: popup.destroy
	@type:
		command
	@title:
		popup.destroy
	@syntax:
		popup.destroy [-q] <popupname:string>
	@short:
		Destroies a popup
	@switches:
		!sw: -q | --quiet
		Run quietly: don't print warning and errors
	@description:
		Destroys a popup named <popupname>.
		To destroy a nested popup, use [cmd]popup.delItem[/cmd] instead.
	@seealso:
		[cmd]defpopup[/cmd], [cmd]popup.show[/cmd], [cmd]popup.create[/cmd], [fnc]popup.exists[/fnc]
*/

static bool popup_kvs_cmd_destroy(KviKvsModuleCommandCall * c)
{
	QString szPopupName, szSubPopupName;
	KVSM_PARAMETERS_BEGIN(c)
		KVSM_PARAMETER("popupname",KVS_PT_NONEMPTYSTRING,0,szPopupName)
	KVSM_PARAMETERS_END(c)

	KviKvsPopupMenu * pPopup = KviKvsPopupManager::instance()->lookup(szPopupName);
	if(!pPopup)
	{
		if(!c->hasSwitch('q',"quiet"))
			c->warning(__tr2qs_ctx("Popup \"%Q\" does not exist","kvs"),&szPopupName);
		return true;
	}
	if(pPopup->isSoftLocked())
	{
		if(!c->hasSwitch('q',"quiet"))
			c->warning(__tr2qs_ctx("Popup menu self-modification is not allowed (the popup is probably open)","kvs"));
		return true;
	}

	KviKvsPopupManager::instance()->remove(szPopupName);

	KviKvsPopupManager::instance()->emitRefresh(szPopupName);
	return true;
}
/*
	@doc: popup.delitem
	@type:
		command
	@title:
		popup.delitem
	@syntax:
		popup.delitem [-d] [-q] <popupname:string> <item_id:string>
	@short:
		Deletes an item from a popup
	@switches:
		!sw: -q | --quiet
		Run quietly
		!sw: -d | --deep
		Search the whole popup tree instead of only the first level
	@description:
		Deletes the item specified by <id> from the poup <popupname>.
		If the -d flag is specified then the item with the specified
		<id> is searched in the whole popup tree (containing submenus)
		otherwise only the first level is searched. [br]
		If the -q flag is specified, the command does not complain
		about non-existent items or popup menus.[br]
		See [cmd]defpopup[/cmd] for more information.[br]
	@seealso:
		[cmd]defpopup[/cmd], [cmd]popup.show[/cmd]
*/


static bool popup_kvs_cmd_delItem(KviKvsModuleCommandCall * c)
{
	QString szPopupName, szSubPopupName,szItemId;
	KVSM_PARAMETERS_BEGIN(c)
		KVSM_PARAMETER("popupname",KVS_PT_NONEMPTYSTRING,0,szPopupName)
		KVSM_PARAMETER("item_id",KVS_PT_NONEMPTYSTRING,0,szItemId)
	KVSM_PARAMETERS_END(c)

	GET_KVS_POPUP(isHardLocked)

	if(!pPopup->removeItemByName(szItemId,c->hasSwitch('d',"deep")))
	{
		if(!c->hasSwitch('q',"quiet"))
			c->warning(__tr2qs_ctx("The menu item with id \"%Q\" does not exist in popup \"%Q\"","kvs"),&szItemId,&szPopupName);
	}

	KviKvsPopupManager::instance()->emitRefresh(szPopupName);
	return true;
}

/*
	@doc: popup.exists
	@type:
		function
	@title:
		$popup.exists
	@syntax:
		$popup.exists(<popupname:string>)
	@short:
		Returns true if a popup exists
	@description:
		Returns true if a popup exists or false otherwise.
	@seealso:
		[cmd]defpopup[/cmd], [cmd]popup.show[/cmd], [cmd]popup.create[/cmd], [cmd]popup.destroy[/cmd]
*/

static bool popup_kvs_fnc_exists(KviKvsModuleFunctionCall * c)
{
	QString szPopupName, szSubPopupName;
	KVSM_PARAMETERS_BEGIN(c)
		KVSM_PARAMETER("popupname",KVS_PT_NONEMPTYSTRING,0,szPopupName)
	KVSM_PARAMETERS_END(c)

	int iIdx = szPopupName.indexOf(QChar('.'));
	if(iIdx == 0)
	{
		c->warning(__tr2qs_ctx("Empty subpopup name supplied","kvs"));
		return true;
	}
	if(iIdx > 0)
	{
		if(iIdx == szPopupName.size())
		{
			c->warning(__tr2qs_ctx("Empty subpopup name supplied","kvs"));
			return true;
		}
		szSubPopupName = szPopupName.mid(iIdx+1);
		szPopupName.truncate(iIdx);
	}
	KviKvsPopupMenu * pPopup = KviKvsPopupManager::instance()->lookup(szPopupName);
	if(!pPopup)
	{
		c->returnValue()->setBoolean(false);
		return true;
	}
	if(!szSubPopupName.isEmpty())
	{
		pPopup = pPopup->findChildPopupByName(szSubPopupName);
		if(!pPopup)
		{
			c->returnValue()->setBoolean(false);
			return true;
		}
	}

	c->returnValue()->setBoolean(true);
	return true;
}

/*
	@doc: popup.isEmpty
	@type:
		function
	@title:
		$popup.isEmpty
	@syntax:
		$popup.isEmpty(<popupname:string>)
	@short:
		Returns true if a popup is empty
	@description:
		Returns true if a popup is empty or false otherwise.
	@seealso:
		[cmd]defpopup[/cmd], [cmd]popup.show[/cmd], [cmd]popup.clear[/cmd]
*/

static bool popup_kvs_fnc_isEmpty(KviKvsModuleFunctionCall * c)
{
	QString szPopupName, szSubPopupName;
	KVSM_PARAMETERS_BEGIN(c)
		KVSM_PARAMETER("popupname",KVS_PT_NONEMPTYSTRING,0,szPopupName)
	KVSM_PARAMETERS_END(c)

	GET_KVS_POPUP_FNC

	c->returnValue()->setBoolean(pPopup->isEmpty());
	return true;
}

/*
	@doc: popup.currentItemId
	@type:
		function
	@title:
		$popup.currentItemId
	@syntax:
		$popup.currentItemId()
	@short:
		Returns the popup item id that owns the executing code
	@description:
		When called inside a popup item's callback, this function returns the id of the popup item.
		Outside of callback code, $null is returned. 
	@examples:
		[example]
			#clean any previous popup by the same name
			setmenu test
			popup.clear test
			popup.destroy test
			#create the popup
			popup.create test
			popup.addPrologue(test)
			{
				# loop ten times
				foreach(%i,0,1,2,3,4,5,6,7,8,9)
				{
					# delete previous created item to avoid duplication
					popup.delItem test %i
					# create a test item using %i as its "item id"
					popup.addItem(test, item%i, , %i)
					{
						#get back "item id" inside the callback
						debug "chosen item $popup.currentItemId()";
					}
				}
			}
			setmenu test test
		[/example]
	@seealso:
		[cmd]popup.show[/cmd], [cmd]popup.addItem[/cmd]
*/

static bool popup_kvs_fnc_currentItemId(KviKvsModuleFunctionCall * c)
{
	QString * pPopupId = c->context()->popupId();
	if(pPopupId)
	{
		c->returnValue()->setString(pPopupId);
	} else {
		c->returnValue()->setNothing();
	}
	return true;
}

/*
	@doc: popup.show
	@type:
		command
	@title:
		popup.show
	@syntax:
		popup.show [-p=<screen_coordinates:string>] <popup_name:string> [<parameter1:variant> [<parameter2:variant> [...]]]
	@short:
		Shows a popup menu
	@switches:
		!sw: -p=<screen_coordinates:string> | --point=<screen_coordinates:string>
	@description:
		Shows the popup menu <popup_name> at the current cursor position,
		eventually passing the [parameters]. Please note that you can't
		use this command inside one of the [cmd]defpopup[/cmd] command
		handlers for <popup_name>. In other words, you can't "popup
		a popup" while it is being popped up. :) (This would
		be an endless recursive behaviour).[br]
		If the -p switch is used, then <screen_coordinates> must be
		in the form <x>,<y> and will be used as screen coordinates
		for the placement of the popup (instead of the current cursor position).[br]
	@seealso:
		[cmd]defpopup[/cmd]
*/

static bool popup_kvs_cmd_show(KviKvsModuleCommandCall * c)
{
	QString szPopupName, szSubPopupName;
	KVSM_PARAMETERS_BEGIN(c)
		KVSM_PARAMETER("popup_name",KVS_PT_NONEMPTYSTRING,0,szPopupName)
	KVSM_PARAMETERS_END(c)

	// copy parameters
	KviKvsVariantList * pPopupParams = new KviKvsVariantList();
	c->params()->first();
	while(KviKvsVariant * v = c->params()->next())pPopupParams->append(new KviKvsVariant(*v));

	KviKvsPopupMenu * pMenu = KviKvsPopupManager::instance()->lookup(szPopupName);

	if(!pMenu)
	{
		delete pPopupParams;
		pPopupParams = 0;
		c->error(__tr2qs_ctx("Popup %Q is not defined","kvs"),&szPopupName);
		return false;
	}

	if(pMenu->isSoftLocked())
	{
		delete pPopupParams;
		pPopupParams = 0;
		c->error(__tr2qs_ctx("A popup menu cannot be popped up twice","kvs"));
		return false;
	}

	QPoint pnt = QCursor::pos();

	KviKvsVariant * pCoords = c->getSwitch('p',"point");
	if(pCoords)
	{
		QString szCoords;
		pCoords->asString(szCoords);

		int idx = szCoords.indexOf(',');
		bool bCoordsOk = true;
		if(idx == -1)bCoordsOk = false;
		else {
			QString szX = szCoords.left(idx);
			szCoords.remove(0,idx + 1);
			bool bOk1,bOk2;
			int iX = szX.toInt(&bOk1);
			int iY = szCoords.toInt(&bOk2);
			if(bOk1 && bOk2)pnt = QPoint(iX,iY);
			else bCoordsOk = false;
		}

		if(!bCoordsOk)c->warning(__tr2qs_ctx("Invalid syntax for screen coordinates, using cursor position","kvs"));
	}

	pMenu->doPopup(pnt,c->window(),pPopupParams);
	return true;
}

static bool popup_module_init(KviModule *m)
{
	KVSM_REGISTER_CALLBACK_COMMAND(m,"addItem",popup_kvs_cmd_addItem);
	KVSM_REGISTER_CALLBACK_COMMAND(m,"addPrologue",popup_kvs_cmd_addPrologue);
	KVSM_REGISTER_CALLBACK_COMMAND(m,"addEpilogue",popup_kvs_cmd_addEpilogue);

	KVSM_REGISTER_SIMPLE_COMMAND(m,"addExtPopup",popup_kvs_cmd_addExtPopup);
	KVSM_REGISTER_SIMPLE_COMMAND(m,"addLabel",popup_kvs_cmd_addLabel);
	KVSM_REGISTER_SIMPLE_COMMAND(m,"addSubPopup",popup_kvs_cmd_addSubPopup);
	KVSM_REGISTER_SIMPLE_COMMAND(m,"addSeparator",popup_kvs_cmd_addSeparator);

	KVSM_REGISTER_SIMPLE_COMMAND(m,"clear",popup_kvs_cmd_clear);
	KVSM_REGISTER_SIMPLE_COMMAND(m,"create",popup_kvs_cmd_create);
	KVSM_REGISTER_SIMPLE_COMMAND(m,"delItem",popup_kvs_cmd_delItem);
	KVSM_REGISTER_SIMPLE_COMMAND(m,"destroy",popup_kvs_cmd_destroy);
	KVSM_REGISTER_SIMPLE_COMMAND(m,"show",popup_kvs_cmd_show);

	KVSM_REGISTER_FUNCTION(m,"exists",popup_kvs_fnc_exists);
	KVSM_REGISTER_FUNCTION(m,"isEmpty",popup_kvs_fnc_isEmpty);
	KVSM_REGISTER_FUNCTION(m,"currentItemId",popup_kvs_fnc_currentItemId);

	return true;
}

static bool popup_module_cleanup(KviModule *)
{
	return true;
}

static bool popup_module_can_unload(KviModule *)
{
	return true;
}

KVIRC_MODULE(
	"Userlist",                                               // module name
	"4.0.0",                                                // module version
	"Copyright (C) 2010 Fabio Bas (ctrlaltca at gmail dot com)", // author & (C)
	"KVIrc popup management functions",
	popup_module_init,
	popup_module_can_unload,
	0,
	popup_module_cleanup,
	0
)
