/**
 *	XmlRpc lib
 *	Simple commons callbacks
 *	And mode specific callbacks
 */
#Const	Version		"2013-05-24"
#Const	ScriptName	"XmlRpc.Script.txt"

#Include "TextLib" as TL

// ---------------------------------- //
// Globales
// ---------------------------------- //
declare Boolean G_UseLibXmlRpc;

// ---------------------------------- //
// Functions
// ---------------------------------- //

// ---------------------------------- //
// Private
// ---------------------------------- //

// ---------------------------------- //
/** Get the current rankings of the players
 *	Format:
 *	Login1:Score1;Login2:Score2;Login3:Score3
 *
 *	@return		The rankings of the player;
 */
Text Private_GetRankings() {
	declare Rankings = "";
	declare Total = 0;
	foreach (Score in Scores) {
		Total += 1;
		Rankings ^= Score.User.Login^":"^Score.RoundPoints+Score.Points;
		if (Total < Scores.count) Rankings ^= ";";
	}
	return Rankings;
}

// ---------------------------------- //
/** Find a player from his login
 *	
 *	@param	_Login	The login of the player to find
 *
 *	@return			The player if found, null otherwise
 */
CSmPlayer Private_FindPlayer(Text _Login) {
	foreach (Player in AllPlayers) {
		if (Player.Login == _Login) return Player;
	}
	return Null;
}

// ---------------------------------- //
/** Hide/Show the alt layers when pressing the alt key
 *
 *	@param	_Action		True -> show, False -> hide
 *	@param	_Login		Login of the player to update
 */
Void Private_ToggleAltMenu(Boolean _Action, Text _Login) {
	declare Player <=> Private_FindPlayer(_Login);
	if (Player == Null) return;
	
	declare UI <=> UIManager.GetUI(Player);
	if (UI == Null) return;
	
	UI.AltMenuNoDefaultScores = !_Action;
	UI.AltMenuNoCustomScores = !_Action;
}

Void Private_ToggleChat(Boolean _Action, Text _Login) {
	if (_Login == "") {
		UIManager.UIAll.OverlayHideChat = !_Action;
	} else {
		declare Player <=> Private_FindPlayer(_Login);
		if (Player == Null) return;
		
		declare UI <=> UIManager.GetUI(Player);
		if (UI == Null) return;
		
		UI.OverlayHideChat = !_Action;
		UI.OverlayHideChat = !_Action;
	}
}

// ---------------------------------- //
/// Wrapper for the SendCallbackArray() method
Void Private_SendCallbackArray(Text _Type, Text[] _Data) {
	//log(Now^"> LibXmlRpc > SendCallbackArray() > Type: "^_Type^" | Data: "^_Data);
	XmlRpc.SendCallbackArray(_Type, _Data);
}

// ---------------------------------- //
// 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;
}

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

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

// ---------------------------------- //
/// Enable the script callbacks
Void Enable() {
	G_UseLibXmlRpc = True;
}

// ---------------------------------- //
/// Disable the script callbacks
Void Disable() {
	G_UseLibXmlRpc = False;
}

// ---------------------------------- //
/** Send the current rankings
 *	Data:
 *	[Rankings]
 */
Void SendRankings() {
	if (!G_UseLibXmlRpc) return;
	
	Private_SendCallbackArray("LibXmlRpc_Rankings", [Private_GetRankings()]);
}

// ---------------------------------- //
/** Send the current rankings
 *	Data:
 *	[Match Team 1, Match Team 2, Map Team 1, Map Team 2]
 */
Void SendScores() {
	if (!G_UseLibXmlRpc) return;
	
	Private_SendCallbackArray("LibXmlRpc_Scores", [
		TL::ToText(UIManager.UIAll.ScoreSummary_MatchPoints1),
		TL::ToText(UIManager.UIAll.ScoreSummary_MatchPoints2),
		TL::ToText(UIManager.UIAll.ScoreSummary_Points1), 
		TL::ToText(UIManager.UIAll.ScoreSummary_Points2)
	]);
}

// ---------------------------------- //
/** Callback sent when starting to load the map
 *	Data:
 *	[Number of the map]
 */
Void LoadingMap(Integer _Number) {
	if (!G_UseLibXmlRpc) return;
	
	Private_SendCallbackArray("LibXmlRpc_LoadingMap", [TL::ToText(_Number)]);
}

// ---------------------------------- //
/** Callback sent at the beginning of the match
 *	Data:
 *	[Number of the match]
 */
Void BeginMatch(Integer _Number) {
	if (!G_UseLibXmlRpc) return;
	
	Private_SendCallbackArray("LibXmlRpc_BeginMatch", [TL::ToText(_Number)]);
}

// ---------------------------------- //
/** Callback sent at the beginning of the map
 *	Data:
 *	[Number of the map]
 */
Void BeginMap(Integer _Number) {
	if (!G_UseLibXmlRpc) return;
	
	Private_SendCallbackArray("LibXmlRpc_BeginMap", [TL::ToText(_Number)]);
}

// ---------------------------------- //
/** Callback sent at the beginning of the submatch
 *	Data:
 *	[Number of the submatch]
 */
Void BeginSubmatch(Integer _Number) {
	if (!G_UseLibXmlRpc) return;
	
	Private_SendCallbackArray("LibXmlRpc_BeginSubmatch", [TL::ToText(_Number)]);
}

// ---------------------------------- //
/** Callback sent at the beginning of the round
 *	Data:
 *	[Number of the round]
 */
Void BeginRound(Integer _Number) {
	if (!G_UseLibXmlRpc) return;
	
	Private_SendCallbackArray("LibXmlRpc_BeginRound", [TL::ToText(_Number)]);
}

// ---------------------------------- //
/** Callback sent at the beginning of the turn
 *	Data:
 *	[Number of the turn]
 */
Void BeginTurn(Integer _Number) {
	if (!G_UseLibXmlRpc) return;
	
	Private_SendCallbackArray("LibXmlRpc_BeginTurn", [TL::ToText(_Number)]);
}

// ---------------------------------- //
/** Callback sent at the end of the turn
 *	Data:
 *	[Number of the turn]
 */
Void EndTurn(Integer _Number) {
	if (!G_UseLibXmlRpc) return;
	
	SendRankings();
	Private_SendCallbackArray("LibXmlRpc_EndTurn", [TL::ToText(_Number)]);
}

// ---------------------------------- //
/** Callback sent at the end of the round
 *	Data:
 *	[Number of the round]
 */
Void EndRound(Integer _Number) {
	if (!G_UseLibXmlRpc) return;
	
	SendRankings();
	Private_SendCallbackArray("LibXmlRpc_EndRound", [TL::ToText(_Number)]);
}

// ---------------------------------- //
/** Callback sent at the end of the submatch
 *	Data:
 *	[Number of the submatch]
 */
Void EndSubmatch(Integer _Number) {
	if (!G_UseLibXmlRpc) return;
	
	SendRankings();
	Private_SendCallbackArray("LibXmlRpc_EndSubmatch", [TL::ToText(_Number)]);
}

// ---------------------------------- //
/** Callback sent at the end of the map
 *	Data:
 *	[Number of the map]
 */
Void EndMap(Integer _Number) {
	if (!G_UseLibXmlRpc) return;
	
	SendRankings();
	Private_SendCallbackArray("LibXmlRpc_EndMap", [TL::ToText(_Number)]);
}

// ---------------------------------- //
/** Callback sent at the end of the match
 *	Data:
 *	[Number of the match]
 */
Void EndMatch(Integer _Number) {
	if (!G_UseLibXmlRpc) return;
	
	SendRankings();
	Private_SendCallbackArray("LibXmlRpc_EndMatch", [TL::ToText(_Number)]);
}

// ---------------------------------- //
/** Callback sent when a player shoot
 *	Data:
 *	[Shooter login, Weapon number]
 *
 *	Weapon number: 1 -> Laser, 2 -> Rocket, 3 -> Nucleus
 */
Void OnShoot(CSmModeEvent _Event) {
	if (!G_UseLibXmlRpc) return;
	
	declare ShooterLogin = "Null";
	if (_Event.Shooter != Null) ShooterLogin = _Event.Shooter.Login;
	declare Data = [ShooterLogin, TL::ToText(_Event.WeaponNum)];
	Private_SendCallbackArray("LibXmlRpc_OnShoot", Data);
}

// ---------------------------------- //
/** Callback sent when a player is hit
 *	Data:
 *	[Shooter login, Victim login, Damage, Weapon number, Shooter points]
 *
 *	Damage: the total damage inflicted to the victim on hit
 *	Weapon number: 1 -> Laser, 2 -> Rocket, 3 -> Nucleus
 *	Shooter points: the number of points scored by the shooter on this hit
 */
Void OnHit(CSmModeEvent _Event) {
	if (!G_UseLibXmlRpc) return;
	
	declare ShooterLogin = "Null";
	declare VictimLogin = "Null";
	if (_Event.Shooter != Null) ShooterLogin = _Event.Shooter.Login;
	if (_Event.Victim != Null) VictimLogin = _Event.Victim.Login;
	declare Data = [ShooterLogin, VictimLogin, TL::ToText(_Event.Damage), TL::ToText(_Event.WeaponNum), TL::ToText(_Event.ShooterPoints)];
	Private_SendCallbackArray("LibXmlRpc_OnHit", Data);
}

// ---------------------------------- //
/** Callback when a shot missed from a few cm a player
 *	Data:
 *	[Shooter login, Victim login, Weapon number, Near miss distance]
 *
 *	Weapon number: 1 -> Laser, 2 -> Rocket, 3 -> Nucleus
 *	Near miss distance: in centimeters
 */
Void OnNearMiss(CSmModeEvent _Event) {
	if (!G_UseLibXmlRpc) return;
	
	declare ShooterLogin = "Null";
	declare VictimLogin = "Null";
	if (_Event.Shooter != Null) ShooterLogin = _Event.Shooter.Login;
	if (_Event.Victim != Null) VictimLogin = _Event.Victim.Login;
	declare Data = [ShooterLogin, VictimLogin, TL::ToText(_Event.WeaponNum), TL::ToText(_Event.MissDist)];
	Private_SendCallbackArray("LibXmlRpc_OnNearMiss", Data);
}

// ---------------------------------- //
/** Callback sent when a player armor is empty (hit, offzone, storm, ...)
 *	Data:
 *	[Shooter login, Victim login, Damage, Weapon number, Shooter points]
 *
 *	Damage: the total damage inflicted to the victim on hit
 *	Weapon number: 1 -> Laser, 2 -> Rocket, 3 -> Nucleus
 *	Shooter points: the number of points scored by the shooter on this elimination
 */
Void OnArmorEmpty(CSmModeEvent _Event) {
	if (!G_UseLibXmlRpc) return;
	
	declare ShooterLogin = "Null";
	declare VictimLogin = "Null";
	if (_Event.Shooter != Null) ShooterLogin = _Event.Shooter.Login;
	if (_Event.Victim != Null) VictimLogin = _Event.Victim.Login;
	declare Data = [ShooterLogin, VictimLogin, TL::ToText(_Event.Damage), TL::ToText(_Event.WeaponNum), TL::ToText(_Event.ShooterPoints)];
	Private_SendCallbackArray("LibXmlRpc_OnArmorEmpty", Data);
}

// ---------------------------------- //
/** Callback sent when a pole is captured
 *	Data:
 *	[List of players on pole at the capture]
 *
 *	List of players: login1;login2;login3;login4
 */
Void OnCapture(CSmModeEvent _Event) {
	if (!G_UseLibXmlRpc) return;
	
	declare PlayersList = "";
	if (_Event.BlockPole != Null) {
		declare Total = 0;
		foreach (PlayerId in _Event.BlockPole.Sector.PlayersIds) {
			Total += 1;
			PlayersList ^= Players[PlayerId].Login;
			if (Total < _Event.BlockPole.Sector.PlayersIds.count) PlayersList ^= ";";
		}
	}
	declare Data = [PlayersList];
	Private_SendCallbackArray("LibXmlRpc_OnCapture", Data);
}

// ---------------------------------- //
/** Callback sent when a player press the respawn button
 *	Data:
 *	[Player login]
 */
Void OnPlayerRequestRespawn(CSmModeEvent _Event) {
	if (!G_UseLibXmlRpc) return;
	
	declare PlayerLogin = "Null";
	if (_Event.Player != Null) PlayerLogin = _Event.Player.Login;
	declare Data = [PlayerLogin];
	Private_SendCallbackArray("LibXmlRpc_OnPlayerRequestRespawn", Data);
}

// ---------------------------------- //
// Listening on XmlRpc port
// ---------------------------------- //

// ---------------------------------- //
/// Wait for XmlRpc callbacks
Void Loop() {
	if (!G_UseLibXmlRpc) return;
	
	foreach (Event in XmlRpc.PendingEvents) {
		if (Event.Type == CXmlRpcEvent::EType::Callback) {
			switch (Event.Param1) {
				// Get the current rankings
				case "LibXmlRpc_GetRankings"	: SendRankings();
				case "LibXmlRpc_DisableAltMenu"	: Private_ToggleAltMenu(False, Event.Param2);
				case "LibXmlRpc_EnableAltMenu"	: Private_ToggleAltMenu(True, Event.Param2);
				case "LibXmlRpc_GetScores"		: SendScores();
				case "LibXmlRpc_ShowChat"		: Private_ToggleChat(True, Event.Param2);
				case "LibXmlRpc_HideChat"		: Private_ToggleChat(False, Event.Param2);
			}
		}
	}
}

// ---------------------------------- //
// Mode dependent callbacks
// ---------------------------------- //

// ---------------------------------- //
/// Royal

// ---------------------------------- //
/**	Send a callback on points update in royal
 *	Data:
 *	[Player login, Type of points, number of points]
 *	
 *	Type of points: Hit, Pole, Survival
 *
 *	@param	_Player		The player who'll receive the points
 *	@param	_Type		The type of points received
 *	@param	_Points		The number of points received
 */
Void Royal_UpdatePoints(CSmPlayer _Player, Text _Type, Integer _Points) {
	if (!G_UseLibXmlRpc) return;
	
	declare PlayerLogin = "Null";
	if (_Player != Null) PlayerLogin = _Player.Login;
	if (_Type == "") return;
	
	declare Data = [PlayerLogin, _Type, TL::ToText(_Points)];
	Private_SendCallbackArray("Royal_UpdatePoints", Data);
}

// ---------------------------------- //
/** Send a callback on player spawn
 *	Data:
 *	[Player login, Type of spawn]
 *
 *	Type of spawn: 0 -> normal, 1 -> early
 *
 *	@param	_Player		The spawned player
 *	@param	_Type		The type of spawn
 */
Void Royal_SpawnPlayer(CSmPlayer _Player, Integer _Type) {
	if (!G_UseLibXmlRpc) return;
	
	declare PlayerLogin = "Null";
	if (_Player != Null) PlayerLogin = _Player.Login;
	
	declare Data = [PlayerLogin, TL::ToText(_Type)];
	Private_SendCallbackArray("Royal_SpawnPlayer", Data);
}

Void Royal_RoundWinner(Ident _UserId) {
	if (!G_UseLibXmlRpc) return;
	if (!Users.existskey(_UserId)) return;
	
	declare Data = [Users[_UserId].Login];
	Private_SendCallbackArray("Royal_RoundWinner", Data);
}

// ---------------------------------- //
/// Time attack

// ---------------------------------- //
/** Send a callback on player start
 *	Data:
 *	[Player login]
 *
 *	@param	_Player		The starting player
 */
Void TimeAttack_OnStart(CSmPlayer _Player) {
	if (!G_UseLibXmlRpc) return;
	
	declare PlayerLogin = "Null";
	if (_Player != Null) PlayerLogin = _Player.Login;
	declare Data = [PlayerLogin];
	Private_SendCallbackArray("TimeAttack_OnStart", Data);
}

// ---------------------------------- //
/** Send a callback when a player cross a checkpoint
 *	Data:
 *	[Player login, time on checkpoint]
 *
 *	@param	_Player		The player crossing the checkpoint
 *	@param	_Time		The time at the checkpoint
 */
Void TimeAttack_OnCheckpoint(CSmPlayer _Player, Integer _Time) {
	if (!G_UseLibXmlRpc) return;
	
	declare PlayerLogin = "Null";
	if (_Player != Null) PlayerLogin = _Player.Login;
	declare Data = [PlayerLogin, TL::ToText(_Time)];
	Private_SendCallbackArray("TimeAttack_OnCheckpoint", Data);
}

// ---------------------------------- //
/** Send a callback when a player cross the finish line
 *	Data:
 *	[Player login, time at finish]
 *
 *	@param	_Player		The player crossing the finsih line
 *	@param	_Time		The time at the finish
 */
Void TimeAttack_OnFinish(CSmPlayer _Player, Integer _Time) {
	if (!G_UseLibXmlRpc) return;
	
	declare PlayerLogin = "Null";
	if (_Player != Null) PlayerLogin = _Player.Login;
	declare Data = [PlayerLogin, TL::ToText(_Time)];
	Private_SendCallbackArray("TimeAttack_OnFinish", Data);
}

// ---------------------------------- //
/** Send a callback when a player want to restart (respawn, elimination)
 *	Data:
 *	[Player login, time of restart]
 *
 *	@param	_Player		The restarting player
 *	@param	_Time		The time of the restart
 */
Void TimeAttack_OnRestart(CSmPlayer _Player, Integer _Time) {
	if (!G_UseLibXmlRpc) return;
	
	declare PlayerLogin = "Null";
	if (_Player != Null) PlayerLogin = _Player.Login;
	declare Data = [PlayerLogin, TL::ToText(_Time)];
	Private_SendCallbackArray("TimeAttack_OnRestart", Data);
}

// ---------------------------------- //
/// Joust

// ---------------------------------- //
/** Send a callback when a player touch a pole to reload
 *	Data:
 *	[Player login}
 *
 *	@param	_Player		The player who reloaded
 */
Void Joust_OnReload(CSmPlayer _Player) {
	if (!G_UseLibXmlRpc) return;
	
	declare PlayerLogin = "Null";
	if (_Player != Null) PlayerLogin = _Player.Login;
	declare Data = [PlayerLogin];
	Private_SendCallbackArray("Joust_OnReload", Data);
}

// ---------------------------------- //
/** Send a callback with the two selected players for the round
 *	Data:
 *	[Player login 1, Player login 2]
 *
 *	@param	_Player1	The first player
 *	@param	_Player2	The second player
 */
Void Joust_SelectedPlayers(CSmPlayer _Player1, CSmPlayer _Player2) {
	if (!G_UseLibXmlRpc) return;
	
	declare Player1Login = "Null";
	if (_Player1 != Null) Player1Login = _Player1.Login;
	declare Player2Login = "Null";
	if (_Player2 != Null) Player2Login = _Player2.Login;
	declare Data = [Player1Login, Player2Login];
	Private_SendCallbackArray("Joust_SelectedPlayers", Data);
}

// ---------------------------------- //
/** Send a callback with the result of the round
 *	Data:
 *	[Result player 1, Result player 2]
 *
 *	Result player format: login:score
 *
 *	@param	_Player1	The first player
 *	@param	_Score1		The score of the first player
 *	@param	_Player2	The second player
 *	@param	_Score2		The score of the second player
 */
Void Joust_RoundResult(CSmPlayer _Player1, Integer _Score1, CSmPlayer _Player2, Integer _Score2) {
	if (!G_UseLibXmlRpc) return;
	
	declare Player1Login = "Null";
	if (_Player1 != Null) Player1Login = _Player1.Login;
	declare Player2Login = "Null";
	if (_Player2 != Null) Player2Login = _Player2.Login;
	declare Data = [Player1Login^":"^_Score1, Player2Login^":"^_Score2];
	Private_SendCallbackArray("Joust_RoundResult", Data);
}