/**
 *	XmlRpc2 library
 */
#Const	Version			"2017-05-03"
#Const	ScriptName	"Libs/Nadeo/XmlRpc2.Script.txt"

// ---------------------------------- //
// Libraries
// ---------------------------------- //
#Include "TextLib" as TL
#Include "Libs/Nadeo/Semver.Script.txt" as Semver
#Include "Libs/Nadeo/Json2.Script.txt" as Json

// ---------------------------------- //
// Constants
// ---------------------------------- //
#Const	C_LatestApiVersion	"2.0.0"
#Const C_AllApiVersions ["2.0.0"]

// ---------------------------------- //
// Globales
// ---------------------------------- //
declare Text[Text] G_Callbacks; ///< Array of callbacks with their descriptions
declare Text[Text] G_Methods; ///< Array of methods with their descriptions

// ---------------------------------- //
// Functions
// ---------------------------------- //
// ---------------------------------- //
// Public
// ---------------------------------- //
// ---------------------------------- //
/**	Return the version number of the script
 *
 *	@return														The version number of the script
 */
Text GetScriptVersion() {
	return Version;
}

// ---------------------------------- //
/**	Return the name of the script
 *
 *	@return														The name of the script
 */
Text GetScriptName() {
	return ScriptName;
}

// ---------------------------------- //
/** Escape special characters for JSON string
 *
 *	@param	_Text											The text to clean
 *
 *	@return														The cleaned text
 */
Text JsonEscapeText(Text _Text) {
	return Json::EscapeText(_Text);
}

// ---------------------------------- //
/** Convert a Text into a JSON string
 *
 *	@param	_Text											The Text to convert
 *
 *	@return														The converted Text
 */
Text JsonGetText(Text _Text) {
	return Json::GetText(_Text);
}

// ---------------------------------- //
/** Convert an array of Text in a JSON string
 *
 *	@param	_TextArray								The array of Text to convert
 *
 *	@return														The converted array of Text
 */
Text JsonGetTextArray(Text[] _TextArray) {
	return Json::GetTextArray(_TextArray);
}

// ---------------------------------- //
/** Convert a Real into a JSON string
 *
 *	@param	_Real											The Real to convert
 *
 *	@return														The converted Real
 */
Text JsonGetReal(Real _Real) {
	return Json::GetReal(_Real);
}

// ---------------------------------- //
/** Convert a Integer into a JSON string
 *
 *	@param	_Integer									The Integer to convert
 *
 *	@return														The converted Integer
 */
Text JsonGetInteger(Integer _Integer) {
	return Json::GetInteger(_Integer);
}

// ---------------------------------- //
/** Convert a Int3 into a JSON string
 *
 *	@param	_Int3											The Int3 to convert
 *
 *	@return														The converted Int3
 */
Text JsonGetInt3(Int3 _Int3) {
	return Json::GetInt3(_Int3);
}

// ---------------------------------- //
/** Convert a Vec3 into a JSON string
 *
 *	@param	_Vec3											The Vec3 to convert
 *
 *	@return														The converted Vec3
 */
Text JsonGetVec3(Vec3 _Vec3) {
	return Json::GetVec3(_Vec3);
}

// ---------------------------------- //
/** Convert a Vec2 into a JSON string
 *
 *	@param	_Vec2											The Vec2 to convert
 *
 *	@return														The converted Vec2
 */
Text JsonGetVec2(Vec2 _Vec2) {
	return Json::GetVec2(_Vec2);
}

// ---------------------------------- //
/** Convert a Boolean into a JSON string
 *
 *	@param	_Boolean									The Boolean to convert
 *
 *	@return														The converted Boolean
 */
Text JsonGetBoolean(Boolean _Boolean) {
	return Json::GetBoolean(_Boolean);
}

// ---------------------------------- //
/** Convert an Ident into a JSON string
 *
 *	@param	_Ident										The Ident to convert
 *
 *	@return														The converted Ident
 */
Text JsonGetIdent(Ident _Ident) {
	return Json::GetIdent(_Ident);
}

// ---------------------------------- //
/** Turn on or off XmlRpc
 *	This state is preserved even after
 *	a script restart. You must explicitely
 *	disable the library if you want to
 *	stop it at start.
 *
 *	@param	_Enabled									True to enable, False to disable
 */
Void Enable(Boolean _Enabled) {
	declare LibXmlRpc2Common_IsEnabled for This = False;
	LibXmlRpc2Common_IsEnabled = _Enabled;
}

// ---------------------------------- //
/// Turn on XmlRpc
Void Enable() {
	Enable(True);
}

// ---------------------------------- //
/// Turn off XmlRpc
Void Disable() {
	Enable(False);
}

// ---------------------------------- //
/** Check if the XmlRpc library is enabled
 *
 *	@return														True if the library is enable, False if it is disabled
 */
Boolean IsEnabled() {
	declare LibXmlRpc2Common_IsEnabled for This = False;
	return LibXmlRpc2Common_IsEnabled;
}

// ---------------------------------- //
/** Set the version of the XmlRpc API
 *
 *	@param	_Version									The version of the API to use
 */
Void SetApiVersion(Text _Version) {
	declare LibXmlRpc2Common_Version for This = C_LatestApiVersion;
	LibXmlRpc2Common_Version = _Version;
}

// ---------------------------------- //
/** Get the selected version of the XmlRpc API
 *
 *	@return														The XmlRpc API version
 */
Text GetApiVersion() {
	declare LibXmlRpc2Common_Version for This = C_LatestApiVersion;
	return LibXmlRpc2Common_Version;
}

// ---------------------------------- //
/** Get the latest version of the XmlRpc API
 *
 *	@return														The latest XmlRpc API version
 */
Text GetLatestApiVersion() {
	return C_LatestApiVersion;
}


// ---------------------------------- //
/** Get all versions of the XmlRpc API
 *
 *	@return														All XmlRpc API versions
 */
Text[] GetAllApiVersions() {
	return C_AllApiVersions;
}

// ---------------------------------- //
/** Register a new callback
 *	A callback must be registered to
 *	be sent with the SendCallback function
 *	If the callback name already exists
 *	the registring is cancelled and
 *	the old callback conserved
 *
 *	@param	_CallbackName							The name of the callback
 *	@param	_CallbackDescription			The description of the callback
 */
Void RegisterCallback(Text _CallbackName, Text _CallbackDescription) {
	if (G_Callbacks.existskey(_CallbackName)) return;
	G_Callbacks[_CallbackName] = _CallbackDescription;
}

// ---------------------------------- //
/** Unregister a callback
 *
 *	@param	_CallbackName							The name of the callback
 */
Void UnregisterCallback(Text _CallbackName) {
	declare Removed = G_Callbacks.removekey(_CallbackName);
}

// ---------------------------------- //
/** Check if a callback is registered
 *
 *	@param	_CallbackName							The name of the callback to check
 *
 *	@return														True if the callback is registered
 *																		False otherwise
 */
Boolean CallbackIsRegistered(Text _CallbackName) {
	return G_Callbacks.existskey(_CallbackName);
}

// ---------------------------------- //
/** Enable or disable a registered callback
 *
 *	@param	_CallbackName							The name of the callback to disable or enable
 *	@param	_Enabled									True to enable, False to disable
 */
Void EnableCallback(Text _CallbackName, Boolean _Enabled) {
	declare LibXmlRpc2Common_DisabledCallbacks for This = Text[];
	// Enable
	if (_Enabled) {
		declare Removed = LibXmlRpc2Common_DisabledCallbacks.remove(_CallbackName);
	} 
	// Disable
	else {
		if (!LibXmlRpc2Common_DisabledCallbacks.exists(_CallbackName)) {
			LibXmlRpc2Common_DisabledCallbacks.add(_CallbackName);
		}
	}
}

// ---------------------------------- //
/** Enable a registered callback
 *
 *	@param	_CallbackName							The name of the callback to enable
 */
Void EnableCallback(Text _CallbackName) {
	EnableCallback(_CallbackName, True);
}

// ---------------------------------- //
/** Disable a registered callback
 *
 *	@param	_CallbackName							The name of the callback to disable
 */
Void DisableCallback(Text _CallbackName) {
	EnableCallback(_CallbackName, False);
}

// ---------------------------------- //
/** Check if a callback is enabled
 *
 *	@param	_CallbackName							The name of the callback to check
 *
 *	@return														True if the callback is enabled, False otherwise
 */
Boolean CallbackIsEnabled(Text _CallbackName) {
	declare LibXmlRpc2Common_DisabledCallbacks for This = Text[];
	return !LibXmlRpc2Common_DisabledCallbacks.exists(_CallbackName);
}

// ---------------------------------- //
/** Check if the given callback can be sent
 *	To be sent the library must be enabled
 *	the callback must be registerd and enabled
 *
 *	@param	_CallbackName							The name of the callback to check
 */
Boolean CanSendCallback(Text _CallbackName) {
	return (
		IsEnabled() && //< Library is enabled
		G_Callbacks.existskey(_CallbackName) && //< Callback is registered
		CallbackIsEnabled(_CallbackName) //< Callback is enable
	);
}

// ---------------------------------- //
/** Send a callback with a Text as data
 *	A callback must have been registered
 *	beforehand to be sent
 *
 *	@param	_CallbackName							The name of the callback
 *	@param	_CallbackData							The callback data
 */
Void SendCallback(Text _CallbackName, Text _CallbackData) {
	if (!CanSendCallback(_CallbackName)) return;
	XmlRpc.SendCallback(_CallbackName, _CallbackData);
}

// ---------------------------------- //
/** Send a callback with an array 
 *	of Text as data
 *	A callback must have been registered
 *	beforehand to be sent
 *
 *	@param	_CallbackName							The name of the callback
 *	@param	_CallbackData							The callback data
 */
Void SendCallback(Text _CallbackName, Text[] _CallbackData) {
	if (!CanSendCallback(_CallbackName)) return;
	XmlRpc.SendCallbackArray(_CallbackName, _CallbackData);
}

// ---------------------------------- //
/** Get a list of all registered callbacks
 *
 *	@return														An array with the names of all registered callbacks
 */
Text[] GetCallbacks() {
	declare Text[] CallbacksList;
	
	foreach (CallbackName => CallbackDescription in G_Callbacks) {
		CallbacksList.add(CallbackName);
	}
	
	return CallbacksList;
}

// ---------------------------------- //
/** Get a list of all enabled callbacks
 *
 *	@return														An array with the names of all enabled callbacks
 */
Text[] GetEnabledCallbacks() {
	declare LibXmlRpc2Common_DisabledCallbacks for This = Text[];
	declare CallbacksList = Text[];
	
	foreach (CallbackName => CallbackDescription in G_Callbacks) {
		if (!LibXmlRpc2Common_DisabledCallbacks.exists(CallbackName)) {
			CallbacksList.add(CallbackName);
		}
	}
	
	return CallbacksList;
}

// ---------------------------------- //
/** Get a list of all disabled callbacks
 *
 *	@return														An array with the names of all disabled callbacks
 */
Text[] GetDisabledCallbacks() {
	declare LibXmlRpc2Common_DisabledCallbacks for This = Text[];
	return LibXmlRpc2Common_DisabledCallbacks;
}

// ---------------------------------- //
/** Get help for a given callback
 *
 *	@param	_CallbackName							The name of the callback to get help for
 *
 *	@return														A Text describing the callback
 */
Text GetCallbackHelp(Text _CallbackName) {
	if (!G_Callbacks.existskey(_CallbackName)) return "";
	return G_Callbacks[_CallbackName];
}

// ---------------------------------- //
/** Register a new method
 *	If the method name already exists
 *	the registring is cancelled and
 *	the old method conserved
 *
 *	@param	_MethodName							The name of the method
 *	@param	_MethodDescription			The description of the method
 */
Void RegisterMethod(Text _MethodName, Text _MethodDescription) {
	if (G_Methods.existskey(_MethodName)) return;
	G_Methods[_MethodName] = _MethodDescription;
}

// ---------------------------------- //
/** Unregister a method
 *
 *	@param	_MethodName							The name of the method
 */
Void UnregisterMethod(Text _MethodName) {
	declare Removed = G_Methods.removekey(_MethodName);
}

// ---------------------------------- //
/** Check if a method is registered
 *
 *	@param	_MethodName								The name of the method to check
 *
 *	@return														True if the method is registered
 *																		False otherwise
 */
Boolean MethodIsRegistered(Text _MethodName) {
	return G_Methods.existskey(_MethodName);
}

// ---------------------------------- //
/** Get a list of all registered methods
 *
 *	@return														An array with the names of all registered methods
 */
Text[] GetMethods() {
	declare MethodsList = Text[];
	
	foreach (MethodName => MethodDescription in G_Methods) {
		MethodsList.add(MethodName);
	}
	
	return MethodsList;
}

// ---------------------------------- //
/** Get help for a given method
 *
 *	@param	_MethodName								The name of the method to get help for
 */
Text GetMethodHelp(Text _MethodName) {
	if (!G_Methods.existskey(_MethodName)) return "";
	return G_Methods[_MethodName];
}

// ---------------------------------- //
/**	Generate the documentation of all
 *	registered callbacks and methods
 *
 *	@return														The documentation
 */
Text GenerateDocumentation() {
	declare Callbacks = "";
	foreach (Callback => Doc in G_Callbacks) {
		Callbacks ^= """
### {{{Callback}}}
"""^Doc;
	}
	declare Methods = "";
	foreach (Method => Doc in G_Methods) {
		Methods ^= """
### {{{Method}}}
"""^Doc;
	}
	
	return """
XmlRpc scripted callbacks and methods
=====================================

Callbacks
---------
{{{Callbacks}}}

Methods
-------
{{{Methods}}}
""";
}

// ---------------------------------- //
/// Unload the library
Void Unload() {
	G_Callbacks.clear();
	G_Methods.clear();
}

// ---------------------------------- //
/// Load the library
Void Load() {
	Unload();
}