/**
 *	Json lib
 *	Stringify basic classes
 */
#Const	Version		"2013-12-10"
#Const ScriptName	"Json.Script.txt"

#Include "TextLib" as TextLib

/* ------------------------------------- */
// Functions
/* ------------------------------------- */

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

/* ------------------------------------- */
/** Escapes forbidden characters from a string
 *	WARNING: Use only on really small string,
 *	like the name of a player for example.
 *
 *	@param	_String		The string to escape		
 */
Text Escape(Text _String) {
	declare EscapedString = "";
	declare I = 1;
	declare Length = TextLib::Length(_String);
	
	for (I, 0, Length-1) {
		declare Char = TextLib::SubString(_String, I, 1);
		if (Char == "\"" ||Char == "\\") Char = "\\"^Char;
		EscapedString ^= Char;
	}
	
	return EscapedString;
}

/* ------------------------------------- */
/** Enfold the Json string into {}
 *
 *	@param	_String		The string to enfold		
 */
Text Enfold(Text _String) {
	return """{
	"Timestamp": {{{Now}}},
	{{{_String}}} }""";
}

/* ------------------------------------- */
/** Merge multiple Json string together
 *
 *	@param	_Strings	The strings to merge		
 */
Text Merge(Text[] _Strings) {
	declare String = "";
	
	for (I, 0, _Strings.count - 1) {
		String ^= _Strings[I];
		if (I < _Strings.count - 1) String ^= ",";
	}
	
	return String;
}

/* ------------------------------------- */
/** Create a Json object from merged strings
 *
 *	@param	_Strings	The strings to merge		
 */
Text ObjectMerge(Text _Name, Text[] _Strings) {
	declare String = Merge(_Strings);
	
	String = """
"{{{_Name}}}": 
{
	{{{String}}}
}""";
	
	return String;
}

/* ------------------------------------- */
/** Stringify an Integer
 *
 *	@param	_Name		The name of the stringified object
 *	@param	_User		The integer to stringify
 */
Text Stringify(Text _Name, Integer _Integer) { 
	return """"{{{_Name}}}": {{{_Integer}}}""";
}

/* ------------------------------------- */
/** Stringify a Real
 *
 *	@param	_Name		The name of the stringified object
 *	@param	_User		The real to stringify
 */
Text Stringify(Text _Name, Real _Real) { 
	return """"{{{_Name}}}": {{{_Real}}}""";
}

/* ------------------------------------- */
/** Stringify a boolean
 *
 *	@param	_Name		The name of the stringified object
 *	@param	_User		The boolean to stringify
 */
Text Stringify(Text _Name, Boolean _Boolean) { 
	declare Bool = "";
	
	if (_Boolean) Bool = "true";
	else Bool = "false";
	
	return """"{{{_Name}}}": {{{Bool}}}""";
}

/* ------------------------------------- */
/** Stringify a Text
 *
 *	@param	_Name		The name of the stringified object
 *	@param	_User		The text to stringify
 */
Text Stringify(Text _Name, Text _Text) { 
	return """"{{{_Name}}}": "{{{_Text}}}" """;
}

/* ------------------------------------- */
/** Stringify a Vec2
 *
 *	@param	_Name		The name of the stringified object
 *	@param	_User		The vec2 to stringify
 */
Text Stringify(Text _Name, Vec2 _Vec2) { 
	return """"{{{_Name}}}": [{{{_Vec2.X}}}, {{{_Vec2.Y}}}]""";
}

/* ------------------------------------- */
/** Stringify a Vec3
 *
 *	@param	_Name		The name of the stringified object
 *	@param	_User		The vec3 to stringify
 */
Text Stringify(Text _Name, Vec3 _Vec3) { 
	return """"{{{_Name}}}": [{{{_Vec3.X}}}, {{{_Vec3.Y}}}, {{{_Vec3.Z}}}]""";
}

/* ------------------------------------- */
/** Stringify all CUser values
 *
 *	@param	_Name		The name of the stringified object
 *	@param	_User		The user to stringify
 *	@param	_More		Allow to insert more info about the user
 */
Text Stringify(Text _Name, CUser _User, Text _More) {
	declare JSON = "";
	
	declare More = "";
	if (_More != "") More = ","^_More;
	
	if (_User != Null) {
		JSON = """
"{{{_Name}}}":
{
	"ZonePath": "{{{_User.ZonePath}}}",
	"Name": "{{{Escape(_User.Name)}}}",
	"Login": "{{{_User.Login}}}",
	"Language": "{{{_User.Language}}}",
	"ClubLink": "{{{Escape(_User.ClubLink)}}}"
	{{{More}}}
}""";
	} else {
		JSON = """"{{{_Name}}}": null""";
	}
	
	// Missing
	//"Description": "{{{Escape(_User.Description)}}}",
	
	return JSON;
}

/* ------------------------------------- */
/** Stringify all CSmScore values
 *
 *	@param	_Name		The name of the stringified object
 *	@param	_Score		The score to stringify
 *	@param	_More		Allow to insert more info about the score
 */
Text Stringify(Text _Name, CSmScore _Score, Text _More) {
	declare JSON = "";
	
	declare More = "";
	if (_More != "") More = ","^_More;
	
	if (_Score != Null) {
		JSON = """
"{{{_Name}}}":
{
	{{{Stringify("User", _Score.User, "")}}},
	{{{Stringify("IsRegisteredForLadderMatch", _Score.IsRegisteredForLadderMatch)}}},
	"LadderScore": {{{_Score.LadderScore}}},
	"LadderRankSortValue": {{{_Score.LadderRankSortValue}}},
	"Points": {{{_Score.Points}}},
	"RoundPoints": {{{_Score.RoundPoints}}},
	"NbEliminationsInflicted": {{{_Score.NbEliminationsInflicted}}},
	"NbEliminationsTaken": {{{_Score.NbEliminationsTaken}}},
	"NbRespawnsRequested": {{{_Score.NbRespawnsRequested}}},
	"DamageInflicted": {{{_Score.DamageInflicted}}},
	"DamageTaken": {{{_Score.DamageTaken}}}
	{{{More}}}
}""";
	} else {
		JSON = """"{{{_Name}}}": null""";
	}
	
	return JSON;
}

/* ------------------------------------- */
/** Stringify all CSmBase values
 *
 *	@param	_Name		The name of the stringified object
 *	@param	_Base		The base to stringify
 *	@param	_More		Allow to insert more info about the base
 */
Text Stringify(Text _Name, CSmBase _Base, Text _More) {
	declare JSON = "";
	
	declare More = "";
	if (_More != "") More = ","^_More;
	
	if (_Base != Null) {
		JSON = """
"{{{_Name}}}":
{
	"Clan": {{{_Base.Clan}}},
	{{{Stringify("IsActive", _Base.IsActive)}}}
	{{{More}}}
}""";
	} else {
		JSON = """"{{{_Name}}}": null""";
	}
	
	return JSON;
}

/* ------------------------------------- */
/** Stringify all CSmGauge values
 *
 *	@param	_Name		The name of the stringified object
 *	@param	_Gauge		The gauge to stringify
 *	@param	_More		Allow to insert more info about the gauge
 */
Text Stringify(Text _Name, CSmGauge _Gauge, Text _More) {
	declare JSON = "";
	
	declare More = "";
	if (_More != "") More = ","^_More;
	
	if (_Gauge != Null) {
		JSON = """
"{{{_Name}}}":
{
	"Clan": {{{_Gauge.Clan}}},
	"ValueReal": {{{_Gauge.ValueReal}}},
	"Value": {{{_Gauge.Value}}},
	"Max": {{{_Gauge.Max}}},
	"Speed": {{{_Gauge.Speed}}}
	{{{More}}}
}""";
	} else {
		JSON = """"{{{_Name}}}": null""";
	}
	
	return JSON;
}

/* ------------------------------------- */
/** Stringify all CSmBlockPole values
 *
 *	@param	_Name		The name of the stringified object
 *	@param	_BlockPole	The pole to stringify
 *	@param	_More		Allow to insert more info about the pole
 */
Text Stringify(Text _Name, CSmBlockPole _BlockPole, Text _More) {
	declare JSON = "";
	
	declare More = "";
	if (_More != "") More = ","^_More;
	
	if (_BlockPole != Null) {
		JSON = """
"{{{_Name}}}":
{
	"Tag": "{{{Escape(_BlockPole.Tag)}}}",
	"Order": {{{_BlockPole.Order}}},
	"Position": [{{{_BlockPole.Position.X}}}, {{{_BlockPole.Position.Y}}}, {{{_BlockPole.Position.Z}}}],
	"DirFront": [{{{_BlockPole.DirFront.X}}}, {{{_BlockPole.DirFront.Y}}}, {{{_BlockPole.DirFront.Z}}}],
	{{{Stringify("Base", _BlockPole.Base, "")}}},
	{{{Stringify("Captured", _BlockPole.Captured)}}},
	{{{Stringify("Gauge", _BlockPole.Gauge, "")}}}
	{{{More}}}
}""";
	} else {
		JSON = """"{{{_Name}}}": null""";
	}
	
	return JSON;
}

/* ------------------------------------- */
/** Stringify all CSmBlockSpawn values
 *
 *	@param	_Name		The name of the stringified object
 *	@param	_BlockSpawn	The spawn to stringify
 *	@param	_More		Allow to insert more info about the spawn
 */
Text Stringify(Text _Name, CSmBlockSpawn _BlockSpawn, Text _More) {
	declare JSON = "";
	
	declare More = "";
	if (_More != "") More = ","^_More;
	
	if (_BlockSpawn != Null) {
		JSON = """
"{{{_Name}}}":
{
	"Tag": "{{{Escape(_BlockSpawn.Tag)}}}",
	"Order": {{{_BlockSpawn.Order}}},
	"Position": [{{{_BlockSpawn.Position.X}}}, {{{_BlockSpawn.Position.Y}}}, {{{_BlockSpawn.Position.Z}}}],
	"DirFront": [{{{_BlockSpawn.DirFront.X}}}, {{{_BlockSpawn.DirFront.Y}}}, {{{_BlockSpawn.DirFront.Z}}}],
	{{{Stringify("Base", _BlockSpawn.Base, "")}}}
	{{{More}}}
}""";
	} else {
		JSON = """"{{{_Name}}}": null""";
	}
	
	return JSON;
}

/* ------------------------------------- */
/** Stringify all CTeam values
 *
 *	@param	_Name		The name of the stringified object
 *	@param	_Team		The team to stringify
 *	@param	_More		Allow to insert more info about the team
 */
Text Stringify(Text _Name, CTeam _Team, Text _More) {
	declare JSON = "";
	
	declare More = "";
	if (_More != "") More = ","^_More;
	
	if (_Team != Null) {
		JSON = """
"{{{_Name}}}":
{
	"Name": "{{{Escape(_Team.Name)}}}",
	"ZonePath": "{{{Escape(_Team.ZonePath)}}}",
	"City": "{{{Escape(_Team.City)}}}",
	"EmblemUrl": "{{{Escape(_Team.EmblemUrl)}}}",
	"PresentationManialinkUrl": "{{{Escape(_Team.PresentationManialinkUrl)}}}",
	"ColorPrimary": [{{{_Team.ColorPrimary.X}}}, {{{_Team.ColorPrimary.Y}}}, {{{_Team.ColorPrimary.Z}}}],
	"ColorSecondary": [{{{_Team.ColorSecondary.X}}}, {{{_Team.ColorSecondary.Y}}}, {{{_Team.ColorSecondary.Z}}}],
	"ColorText": "{{{_Team.ColorText}}}",
	"ColorizedName": "{{{Escape(_Team.ColorizedName)}}}"
	{{{More}}}
}""";
	} else {
		JSON = """"{{{_Name}}}": null""";
	}
	
	return JSON;
}

/* ------------------------------------- */
/** Stringify all CSmPlayer values
 *
 *	@param	_Name		The name of the stringified object
 *	@param	_Player		The player to stringify
 *	@param	_More		Allow to insert more info about the player
 */
Text Stringify(Text _Name, CSmPlayer _Player, Text _More) {
	declare JSON = "";
	
	declare More = "";
	if (_More != "") More = ","^_More;
	
	if (_Player != Null) {
		JSON = """
"{{{_Name}}}":
{
	{{{Stringify("User", _Player.User, "")}}},
	"Login": "{{{_Player.Login}}}",
	"Name": "{{{Escape(_Player.Name)}}}",
	"RequestedClan": {{{_Player.RequestedClan}}},
	{{{Stringify("RequestsSpectate", _Player.RequestsSpectate)}}},
	{{{Stringify("Score", _Player.Score, "")}}},
	"SpawnStatus": "{{{_Player.SpawnStatus}}}",
	{{{Stringify("IsFakePlayer", _Player.IsFakePlayer)}}},
	{{{Stringify("IsTouchingGround", _Player.IsTouchingGround)}}},
	"CurrentClan": {{{_Player.CurrentClan}}},
	"AmmoGain": {{{_Player.AmmoGain}}},
	"AmmoPower": {{{_Player.AmmoPower}}},
	{{{Stringify("AutoSwitchWeapon", _Player.AutoSwitchWeapon)}}},
	"Armor": {{{_Player.Armor}}},
	"ArmorMax": {{{_Player.ArmorMax}}},
	"ArmorGain": {{{_Player.ArmorGain}}},
	"ArmorPower": {{{_Player.ArmorPower}}},
	"Stamina": {{{_Player.Stamina}}},
	"StaminaMax": {{{_Player.StaminaMax}}},
	"StaminaGain": {{{_Player.StaminaGain}}},
	"StaminaPower": {{{_Player.StaminaPower}}},
	"StartTime": {{{_Player.StartTime}}},
	"EndTime": {{{_Player.EndTime}}},
	{{{Stringify("IsHighlighted", _Player.IsHighlighted)}}},
	"ForceColor": [{{{_Player.ForceColor.X}}}, {{{_Player.ForceColor.Y}}}, {{{_Player.ForceColor.Z}}}],
	{{{Stringify("IsUnderground", _Player.IsUnderground)}}},
	{{{Stringify("IsInOffZone", _Player.IsInOffZone)}}},
	{{{Stringify("IsCapturing", _Player.IsCapturing)}}},
	{{{Stringify("BlockPole", _Player.BlockPole, "")}}}
	{{{More}}}
}
""";
	} else {
		JSON = """"{{{_Name}}}": null""";
	}
	
	return JSON;
}

/* ------------------------------------- */
/** Stringify all CSmModeEvent values
 *
 *	@param	_Name		The name of the stringified object
 *	@param	_Event		The event to stringify
 *	@param	_More		Allow to insert more info about the event
 */
Text Stringify(Text _Name, CSmModeEvent _Event, Text _More) {
	declare JSON = "";
	
	declare More = "";
	if (_More != "") More = ","^_More;
	
	if (_Event != Null) {
		JSON = """
"{{{_Name}}}":
{
	"Type": "{{{_Event.Type}}}",
	{{{Stringify("Player", _Event.Player, "")}}},
	"Damage": {{{_Event.Damage}}},
	"ShooterPoints": {{{_Event.ShooterPoints}}},
	{{{Stringify("Shooter", _Event.Shooter, "")}}},
	{{{Stringify("Victim", _Event.Victim, "")}}},
	"WeaponNum": {{{_Event.WeaponNum}}},
	"MissDist": {{{_Event.MissDist}}},
	{{{Stringify("BlockPole", _Event.BlockPole, "")}}}
	{{{More}}}
}
""";
	} else {
		JSON = """"{{{_Name}}}": null""";
	}
	
	return JSON;
}


/* ------------------------------------- */
/* ------------------------------------- */
/// Minimal versions
/* ------------------------------------- */
/* ------------------------------------- */

/* ------------------------------------- */
/** Stringify minimal CUser values
 *
 *	@param	_Name		The name of the stringified object
 *	@param	_User		The user to stringify
 *	@param	_More		Allow to insert more info about the user
 */
Text StringifyMinimal(Text _Name, CUser _User, Text _More) {
	declare JSON = "";
	
	declare More = "";
	if (_More != "") More = ","^_More;
	
	if (_User != Null) {
		JSON = """
"{{{_Name}}}":
{
	"Name": "{{{Escape(_User.Name)}}}",
	"Login": "{{{_User.Login}}}"
	{{{More}}}
}""";
	} else {
		JSON = """"{{{_Name}}}": null""";
	}
	
	// Missing
	//"Description": "{{{Escape(_User.Description)}}}",
	
	return JSON;
}

/* ------------------------------------- */
/** Stringify minimal CSmScore values
 *
 *	@param	_Name		The name of the stringified object
 *	@param	_Score		The score to stringify
 *	@param	_More		Allow to insert more info about the score
 */
Text StringifyMinimal(Text _Name, CSmScore _Score, Text _More) {
	declare JSON = "";
	
	declare More = "";
	if (_More != "") More = ","^_More;
	
	if (_Score != Null) {
		JSON = """
"{{{_Name}}}":
{
	{{{StringifyMinimal("User", _Score.User, "")}}},
	"Points": {{{_Score.Points}}},
	"RoundPoints": {{{_Score.RoundPoints}}}
	{{{More}}}
}""";
	} else {
		JSON = """"{{{_Name}}}": null""";
	}
	
	return JSON;
}

/* ------------------------------------- */
/** Stringify minimal CSmBase values
 *
 *	@param	_Name		The name of the stringified object
 *	@param	_Base		The base to stringify
 *	@param	_More		Allow to insert more info about the base
 */
Text StringifyMinimal(Text _Name, CSmBase _Base, Text _More) {
	return Stringify(_Name, _Base, _More);
}

/* ------------------------------------- */
/** Stringify minimal CSmGauge values
 *
 *	@param	_Name		The name of the stringified object
 *	@param	_Gauge		The gauge to stringify
 *	@param	_More		Allow to insert more info about the gauge
 */
Text StringifyMinimal(Text _Name, CSmGauge _Gauge, Text _More) {
	return Stringify(_Name, _Gauge, _More);
}

/* ------------------------------------- */
/** Stringify minimal CSmBlockPole values
 *
 *	@param	_Name		The name of the stringified object
 *	@param	_BlockPole	The pole to stringify
 *	@param	_More		Allow to insert more info about the pole
 */
Text StringifyMinimal(Text _Name, CSmBlockPole _BlockPole, Text _More) {
	declare JSON = "";
	
	declare More = "";
	if (_More != "") More = ","^_More;
	
	if (_BlockPole != Null) {
		JSON = """
"{{{_Name}}}":
{
	"Tag": "{{{Escape(_BlockPole.Tag)}}}",
	"Order": {{{_BlockPole.Order}}},
	{{{Stringify("Captured", _BlockPole.Captured)}}}
	{{{More}}}
}""";
	} else {
		JSON = """"{{{_Name}}}": null""";
	}
	
	return JSON;
}

/* ------------------------------------- */
/** Stringify minimal Pole values from landmark
 *
 *	@param	_Name		The name of the stringified object
 *	@param	_Landmark	The pole to stringify
 *	@param	_More		Allow to insert more info about the pole
 */
Text StringifyMinimal(Text _Name, CSmMapLandmark _Landmark, Text _More) {
	declare JSON = "";
	
	declare More = "";
	if (_More != "") More = ","^_More;
	
	if (_Landmark != Null) {
		JSON = """
"{{{_Name}}}":
{
	"Tag": "{{{Escape(_Landmark.Tag)}}}",
	"Order": {{{_Landmark.Order}}},
	{{{Stringify("Captured", _Landmark.Gauge.Captured)}}}
	{{{More}}}
}""";
	} else {
		JSON = """"{{{_Name}}}": null""";
	}
	
	return JSON;
}

/* ------------------------------------- */
/** Stringify minimal CSmBlockSpawn values
 *
 *	@param	_Name		The name of the stringified object
 *	@param	_BlockSpawn	The spawn to stringify
 *	@param	_More		Allow to insert more info about the spawn
 */
Text StringifyMinimal(Text _Name, CSmBlockSpawn _BlockSpawn, Text _More) {
	declare JSON = "";
	
	declare More = "";
	if (_More != "") More = ","^_More;
	
	if (_BlockSpawn != Null) {
		JSON = """
"{{{_Name}}}":
{
	"Tag": "{{{Escape(_BlockSpawn.Tag)}}}",
	"Order": {{{_BlockSpawn.Order}}}
	{{{More}}}
}""";
	} else {
		JSON = """"{{{_Name}}}": null""";
	}
	
	return JSON;
}

/* ------------------------------------- */
/** Stringify minimal CTeam values
 *
 *	@param	_Name		The name of the stringified object
 *	@param	_Team		The team to stringify
 *	@param	_More		Allow to insert more info about the team
 */
Text StringifyMinimal(Text _Name, CTeam _Team, Text _More) {
	declare JSON = "";
	
	declare More = "";
	if (_More != "") More = ","^_More;
	
	if (_Team != Null) {
		JSON = """
"{{{_Name}}}":
{
	"Name": "{{{Escape(_Team.Name)}}}",
	"ColorPrimary": [{{{_Team.ColorPrimary.X}}}, {{{_Team.ColorPrimary.Y}}}, {{{_Team.ColorPrimary.Z}}}],
	"ColorSecondary": [{{{_Team.ColorSecondary.X}}}, {{{_Team.ColorSecondary.Y}}}, {{{_Team.ColorSecondary.Z}}}],
	"ColorText": "{{{_Team.ColorText}}}",
	"ColorizedName": "{{{Escape(_Team.ColorizedName)}}}"
	{{{More}}}
}""";
	} else {
		JSON = """"{{{_Name}}}": null""";
	}
	
	return JSON;
}

/* ------------------------------------- */
/** Stringify minimal CSmPlayer values
 *
 *	@param	_Name		The name of the stringified object
 *	@param	_Player		The player to stringify
 *	@param	_More		Allow to insert more info about the player
 */
Text StringifyMinimal(Text _Name, CSmPlayer _Player, Text _More) {
	declare JSON = "";
	
	declare More = "";
	if (_More != "") More = ","^_More;
	
	if (_Player != Null) {
		JSON = """
"{{{_Name}}}":
{
	"Login": "{{{_Player.Login}}}",
	"Name": "{{{Escape(_Player.Name)}}}",
	"CurrentClan": {{{_Player.CurrentClan}}},
	"Armor": {{{_Player.Armor}}},
	"ArmorMax": {{{_Player.ArmorMax}}},
	{{{Stringify("IsTouchingGround", _Player.IsTouchingGround)}}},
	{{{Stringify("IsCapturing", _Player.IsCapturing)}}},
	{{{Stringify("IsInOffZone", _Player.IsInOffZone)}}}
	{{{More}}}
}""";
	} else {
		JSON = """"{{{_Name}}}": null""";
	}
	
	return JSON;
}

/* ------------------------------------- */
/** Stringify minimal CSmModeEvent values
 *
 *	@param	_Name		The name of the stringified object
 *	@param	_Event		The event to stringify
 *	@param	_More		Allow to insert more info about the event
 */
Text StringifyMinimal(Text _Name, CSmModeEvent _Event, Text _More) {
	declare JSON = "";
	
	declare More = "";
	if (_More != "") More = ","^_More;
	
	if (_Event != Null) {
		JSON = """
"{{{_Name}}}":
{
	"Type": "{{{_Event.Type}}}",
	"Damage": {{{_Event.Damage}}},
	"WeaponNum": {{{_Event.WeaponNum}}}
	{{{More}}}
}
""";
	} else {
		JSON = """"{{{_Name}}}": null""";
	}
	
	return JSON;
}