/** 
 *	UI for TeamAttack and TeamRounds
 */

#Const Version		"2017-03-10"
#Const ScriptName	"TeamModes.Script.txt"

#Include "TextLib" as TL
#Include "Libs/Nadeo/Manialink.Script.txt" as Manialink
#Include "Libs/Nadeo/TrackMania/TM2.Script.txt" as TM2

// ---------------------------------- //
// Functions
// ---------------------------------- //
// ---------------------------------- //
// Private
// ---------------------------------- //
Text Private_CreateWindow(Vec2 _Size, Vec3 _Pos, Real _MaxSize, CMlControl::AlignHorizontal _HAlign, CMlControl::AlignVertical _VAlign, Text _Id, Boolean _UseTitle) {
	declare ImgPath = "file://Media/Manialinks/TrackMania/Window";
	declare BgTopLeft = ImgPath^"/tm-structure-topleft.png";
	declare BgTopCenter = ImgPath^"/tm-structure-topcenter.png";
	declare BgTopRight = ImgPath^"/tm-structure-topright.png";
	declare BgCenterRight = ImgPath^"/tm-structure-centerright.png";
	declare BgBottomRight = ImgPath^"/tm-structure-bottomright.png";
	declare BgBottomCenter = ImgPath^"/tm-structure-bottomcenter.png";
	declare BgBottomLeft = ImgPath^"/tm-structure-bottomleft.png";
	declare BgCenterLeft = ImgPath^"/tm-structure-centerleft.png";
	declare BgTitleColorizable = ImgPath^"/tm-structure-titlecolirizable.png";
	declare BgBackground = ImgPath^"/tm-structure-background.png";
	
	declare CornerSize = <_MaxSize, _MaxSize>;
	declare BorderHorizontalSize = <_MaxSize, _MaxSize>;
	declare BorderVerticalSize = <_MaxSize, _MaxSize>;
	
	if (_Size.X < _MaxSize * 3.) {
		CornerSize.X = _Size.X / 3.;
		CornerSize.Y = CornerSize.X;
	}
	
	if (_Size.Y < _MaxSize * 3.) {
		CornerSize.Y = _Size.Y / 3.;
		CornerSize.X = CornerSize.Y;
	}
	
	BorderHorizontalSize.X = _Size.X - CornerSize.X*2.;
	BorderHorizontalSize.Y = CornerSize.Y;
	BorderVerticalSize.Y = _Size.Y - CornerSize.Y*2.;
	BorderVerticalSize.X = CornerSize.X;
	
	declare TitleSize = <CornerSize.X + BorderHorizontalSize.X, BorderHorizontalSize.Y*0.37>;
	declare TitlePos = <CornerSize.X + BorderHorizontalSize.X*0.5, -BorderHorizontalSize.Y*0.27>;
	declare BackgroundPadding = <CornerSize.X*0.1, CornerSize.Y*0.1>;
	declare BackgroundSize = <CornerSize.X*2 + BorderHorizontalSize.X - BackgroundPadding.X*2, CornerSize.Y*2 + BorderVerticalSize.Y - BackgroundPadding.Y*2>;
	
	declare PosAlign = <0., 0.>;
	if (_HAlign == CMlControl::AlignHorizontal::HCenter) {
		PosAlign.X = -_Size.X / 2.;
	} else if (_HAlign == CMlControl::AlignHorizontal::Right) {
		PosAlign.X = -_Size.X;
	}
	if (_VAlign == CMlControl::AlignVertical::VCenter) {
		PosAlign.Y = _Size.Y / 2.;
	} else if (_VAlign == CMlControl::AlignVertical::Bottom) {
		PosAlign.Y = _Size.Y;
	}
	
	declare TitleML = "";
	if (_UseTitle) {
		return """
<frame posn="{{{_Pos.X}}} {{{_Pos.Y}}} {{{_Pos.Z}}}" id="{{{TL::MLEncode(_Id)}}}">
	<frame posn="{{{PosAlign.X}}} {{{PosAlign.Y}}}">
		<frame posn="0 0 -1">
			<quad posn="0 0" sizen="{{{CornerSize.X}}} {{{CornerSize.Y}}}" image="{{{BgTopLeft}}}" />
			<quad posn="{{{CornerSize.X}}} 0" sizen="{{{BorderHorizontalSize.X}}} {{{BorderHorizontalSize.Y}}}" image="{{{BgTopCenter}}}" />
			<quad posn="{{{CornerSize.X+BorderHorizontalSize.X}}} 0" sizen="{{{CornerSize.X}}} {{{CornerSize.Y}}}" image="{{{BgTopRight}}}" />
			<quad posn="{{{CornerSize.X+BorderHorizontalSize.X}}} {{{-CornerSize.Y}}}" sizen="{{{BorderVerticalSize.X}}} {{{BorderVerticalSize.Y}}}" image="{{{BgCenterRight}}}" />
			<quad posn="{{{CornerSize.X+BorderHorizontalSize.X}}} {{{-CornerSize.Y-BorderVerticalSize.Y}}}" sizen="{{{CornerSize.X}}} {{{CornerSize.Y}}}" image="{{{BgBottomRight}}}" />
			<quad posn="{{{CornerSize.X}}} {{{-CornerSize.Y-BorderVerticalSize.Y}}}" sizen="{{{BorderHorizontalSize.X}}} {{{BorderHorizontalSize.Y}}}" image="{{{BgBottomCenter}}}" />
			<quad posn="0 {{{-CornerSize.Y-BorderVerticalSize.Y}}}" sizen="{{{CornerSize.X}}} {{{CornerSize.Y}}}" image="{{{BgBottomLeft}}}" />
			<quad posn="0 {{{-CornerSize.Y}}}" sizen="{{{BorderVerticalSize.X}}} {{{BorderVerticalSize.Y}}}" image="{{{BgCenterLeft}}}" />
			
			<quad posn="{{{BackgroundPadding.X}}} {{{-BackgroundPadding.Y}}} -2" sizen="{{{BackgroundSize.X}}} {{{BackgroundSize.Y}}}" image="{{{BgBackground}}}" />
		</frame>
		<frame posn="{{{TitlePos.X}}} {{{TitlePos.Y}}}">
			<quad posn="0 0 -2" sizen="{{{TitleSize.X}}} {{{TitleSize.Y}}}" halign="center" valign="center" image="{{{BgTitleColorizable}}}" />
			<label sizen="{{{TitleSize.X*0.9}}} {{{TitleSize.Y*0.9}}}" halign="center" valign="center2" textemboss="1" id="Label_Title" />
		</frame>
	</frame>
</frame>""";
	} else {
		return """
<frame posn="{{{_Pos.X}}} {{{_Pos.Y}}} {{{_Pos.Z}}}" id="{{{TL::MLEncode(_Id)}}}">
	<frame posn="{{{PosAlign.X}}} {{{PosAlign.Y}}}">
		<quad posn="0 0" sizen="{{{CornerSize.X}}} {{{CornerSize.Y}}}" rot="180" halign="right" valign="bottom" image="{{{BgBottomRight}}}" />
		<quad posn="{{{CornerSize.X}}} 0" sizen="{{{BorderHorizontalSize.X}}} {{{BorderHorizontalSize.Y}}}" rot="180" halign="right" valign="bottom" image="{{{BgBottomCenter}}}" />
		<quad posn="{{{CornerSize.X+BorderHorizontalSize.X}}} 0" sizen="{{{CornerSize.X}}} {{{CornerSize.Y}}}" rot="180" halign="right" valign="bottom" image="{{{BgBottomLeft}}}" />
		
		<quad posn="{{{CornerSize.X+BorderHorizontalSize.X}}} {{{-CornerSize.Y}}}" sizen="{{{BorderVerticalSize.X}}} {{{BorderVerticalSize.Y}}}" image="{{{BgCenterRight}}}" />
		<quad posn="{{{CornerSize.X+BorderHorizontalSize.X}}} {{{-CornerSize.Y-BorderVerticalSize.Y}}}" sizen="{{{CornerSize.X}}} {{{CornerSize.Y}}}" image="{{{BgBottomRight}}}" />
		<quad posn="{{{CornerSize.X}}} {{{-CornerSize.Y-BorderVerticalSize.Y}}}" sizen="{{{BorderHorizontalSize.X}}} {{{BorderHorizontalSize.Y}}}" image="{{{BgBottomCenter}}}" />
		<quad posn="0 {{{-CornerSize.Y-BorderVerticalSize.Y}}}" sizen="{{{CornerSize.X}}} {{{CornerSize.Y}}}" image="{{{BgBottomLeft}}}" />
		<quad posn="0 {{{-CornerSize.Y}}}" sizen="{{{BorderVerticalSize.X}}} {{{BorderVerticalSize.Y}}}" image="{{{BgCenterLeft}}}" />
		
		<quad posn="{{{BackgroundPadding.X}}} {{{-BackgroundPadding.Y}}} -2" sizen="{{{BackgroundSize.X}}} {{{BackgroundSize.Y}}}" image="{{{BgBackground}}}" />
	</frame>
</frame>""";
	}
	
	return "";
}

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

// ---------------------------------- //
/** Create the manialink for the clan info panel
 *
 *	@param	_Result		The result to display in the UI
 *
 *	@return		The manialink
 */
Text GetMLClanInfo(Text _Result) {
	return """
<framemodel id="Framemodel_Player">
	<!--<quad posn="0 0" sizen="4 6" valign="center" image="file://Media/Manialinks/Common/Colorize.dds" colorize="000" id="Quad_TeamColor" />
	<quad posn="4 0" sizen="36 6" valign="center" bgcolor="111a" />-->
	<frame posn="5 0 1">
		<label posn="10 0" sizen="14 6" halign="right" valign="center2" id="Label_Time" />
		<label posn="11 0" sizen="23 6" valign="center2" id="Label_Name" />
	</frame>
</framemodel>
<frame posn="114 72" id="Frame_ClanInfo" hidden="1">
	{{{Private_CreateWindow(<46., 32.>, <-1., 2., -1.>, 20., CMlControl::AlignHorizontal::Left, CMlControl::AlignVertical::Top, "Frame_BgWindow", False)}}}
	<!--<quad sizen="44 29" style="Bgs1InRace" substyle="BgList" />-->
	<frame posn="2 -4.5 1" id="Frame_PlayersList">
		<format textemboss="1" textsize="1.5" />
		<frameinstance posn="0 0" modelid="Framemodel_Player" />
		<frameinstance posn="0 -6" modelid="Framemodel_Player" />
		<frameinstance posn="0 -12" modelid="Framemodel_Player" />
	</frame>
	<frame posn="22 -22 1">
		<format textemboss="1" textsize="1.5" />
		<label sizen="28 5" halign="center" valign="center2" text="{{{_("Average :")}}}" />
		<label posn="0 -4" sizen="28 5" halign="center" valign="center2" text="???" id="Label_AverageTime" />
		<quad posn="-15 -2" sizen="6 6" halign="right" valign="center" style="Icons64x64_1" substyle="ArrowPrev" scriptevents="1" id="Button_Prev" />
		<quad posn="15 -2" sizen="6 6" valign="center" style="Icons64x64_1" substyle="ArrowNext" scriptevents="1" id="Button_Next" />
	</frame>
</frame>
<script><!--
#Include "TextLib" as TL

declare CMlFrame[] Frames_Player;
declare CMlQuad[] Buttons_Pager;
declare CMlLabel Label_AverageTime;
declare Integer PageRange;
declare Integer PageStart;
declare Integer PageEnd;

{{{TM2::InjectMLTimeToText()}}}

CTmScore[] GetMyClanScores() {
	declare Integer[CTmScore] MyClanScoresToSort;
	declare CTmScore[] MyClanScoresNoTime;
	declare CTmScore[] MyClanScoresSorted;
	
	declare netread Integer Net_TeamAttack_CurrentClan as MyCurrentClan for InputPlayer.Score;
	foreach (Score in Scores) {
		declare netread Integer Net_TeamAttack_CurrentClan for Score;
		if (Net_TeamAttack_CurrentClan != MyCurrentClan) continue;
		
		if (Score.{{{_Result}}} == Null || Score.{{{_Result}}}.Time <= 0) {
			MyClanScoresNoTime.add(Score);
		} else {
			MyClanScoresToSort[Score] = Score.{{{_Result}}}.Time;
		}
	}
	MyClanScoresToSort = MyClanScoresToSort.sort();
	
	foreach (Score => Time in MyClanScoresToSort) {
		MyClanScoresSorted.add(Score);
	}
	foreach (Score in MyClanScoresNoTime) {
		MyClanScoresSorted.add(Score);
	}
	
	return MyClanScoresSorted;
}

Void UpdateAverageTime(Integer _Time) {
	if (_Time <= -2) {
		Label_AverageTime.Value = "{{{_("Not enough players")}}}";
	} else {
		Label_AverageTime.Value = TimeToText(_Time);
	}
}

Void UpdateSlot(Integer _SlotNb, CTmScore _Score) {
	if (!Frames_Player.existskey(_SlotNb-1)) return;
	declare Frame_Player <=> Frames_Player[_SlotNb-1];
	
	if (_Score == Null) {
		Frame_Player.Visible = False;
	} else {
		declare Label_Time <=> (Frame_Player.GetFirstChild("Label_Time") as CMlLabel);
		declare Label_Name <=> (Frame_Player.GetFirstChild("Label_Name") as CMlLabel);
	
		Frame_Player.Visible = True;
		Label_Time.Value = TimeToText(_Score.{{{_Result}}}.Time);
		Label_Name.Value = _Score.User.Name;
	}
}

Void UpdatePage(Integer _Shift) {
	declare MyClanScores = GetMyClanScores();
	
	PageStart += _Shift;
	if (PageStart < 1) PageStart = 1;
	else if (PageStart > MyClanScores.count) PageStart = MyClanScores.count;
	PageEnd = PageStart + PageRange - 1;
	if (PageEnd > MyClanScores.count) PageEnd = MyClanScores.count;
	
	Buttons_Pager[0].Visible = False;
	Buttons_Pager[1].Visible = False;
	if (PageStart > 1) {
		Buttons_Pager[0].Visible = True;
	}
	if (PageEnd < MyClanScores.count) {
		Buttons_Pager[1].Visible = True;
	}
	
	//log(Now^"> PageStart: "^PageStart^" | PageEnd: "^PageEnd^" | PageRange: "^PageRange^" | _Shift: "^_Shift^" | MyClanScores.count: "^MyClanScores.count);
	declare I = 1;
	declare K = 1;
	declare AverageTime = -2;
	declare netread Integer Net_TeamAttack_MinPlayerPerClan for Teams[0];
	foreach (Score in MyClanScores) {
		declare netread Integer Net_TeamAttack_AverageTime for Score;
		if (I == 1 && MyClanScores.count >= Net_TeamAttack_MinPlayerPerClan) AverageTime = Net_TeamAttack_AverageTime;
		if (I > PageEnd) break;
		if (I >= PageStart) {
			UpdateSlot(K, Score);
			K += 1;
		}
		I += 1;
	}
	for (J, K, PageRange) {
		UpdateSlot(J, Null);
	}
	
	UpdateAverageTime(AverageTime);
}

main() {
	declare Frame_ClanInfo		<=> (Page.GetFirstChild("Frame_ClanInfo")		as CMlFrame);
	declare Frame_PlayersList	<=> (Page.GetFirstChild("Frame_PlayersList")	as CMlFrame);
	Label_AverageTime			<=> (Page.GetFirstChild("Label_AverageTime")	as CMlLabel);
	Buttons_Pager.add((Page.GetFirstChild("Button_Prev") as CMlQuad));
	Buttons_Pager.add((Page.GetFirstChild("Button_Next") as CMlQuad));
	foreach (Control in Frame_PlayersList.Controls) {
		Frames_Player.add((Control as CMlFrame));
	}
	
	PageRange = Frame_PlayersList.Controls.count;
	PageStart = 1;
	PageEnd = PageStart + PageRange - 1;
	
	declare netread Integer Net_TeamAttack_MinPlayerPerClan for Teams[0];
	
	declare PrevMinPlayerPerClan = -1;
	declare NeedRefresh = False;
	
	foreach (Score in Scores) {
		declare ClanInfo_PrevCurrentClan for Score = -2;
		ClanInfo_PrevCurrentClan = -2;
	}
	
	declare NextUpdate = -1;
	
	while (True) {
		yield;
		if (!PageIsVisible || InputPlayer == Null || InputPlayer.Score == Null) continue;
		
		if (Now >= NextUpdate) {
			NextUpdate = Now + 250;
			declare netread Integer Net_TeamAttack_CurrentClan as MyCurrentClan for InputPlayer.Score;
			foreach (Score in Scores) {
				declare netread Integer Net_TeamAttack_CurrentClan for Score;
				declare ClanInfo_PrevCurrentClan for Score = -2;
				
				if (ClanInfo_PrevCurrentClan != Net_TeamAttack_CurrentClan) {
					if (ClanInfo_PrevCurrentClan == MyCurrentClan || Net_TeamAttack_CurrentClan == MyCurrentClan) {
						NeedRefresh = True;
					}
					ClanInfo_PrevCurrentClan = Net_TeamAttack_CurrentClan;
					
					if (Score.Id == InputPlayer.Score.Id) {
						if (Net_TeamAttack_CurrentClan <= 0) {
							Frame_ClanInfo.Visible = False;
						} else {
							Frame_ClanInfo.Visible = True;
						}
					}
				}
				
				if (Net_TeamAttack_CurrentClan == MyCurrentClan) {
					if (Score.{{{_Result}}} != Null) {
						declare netread Integer Net_TeamAttack_AverageTime for Score;
						declare ClanInfo_PrevBestTime for Score = -2;
						declare ClanInfo_PrevAverageTime for Score = -2;
						if (ClanInfo_PrevBestTime != Score.{{{_Result}}}.Time || ClanInfo_PrevAverageTime != Net_TeamAttack_AverageTime) {
							ClanInfo_PrevBestTime = Score.{{{_Result}}}.Time;
							ClanInfo_PrevAverageTime = Net_TeamAttack_AverageTime;
							NeedRefresh = True;
						}
					}
				}
			}
			
			if (PrevMinPlayerPerClan != Net_TeamAttack_MinPlayerPerClan) {
				PrevMinPlayerPerClan = Net_TeamAttack_MinPlayerPerClan;
				NeedRefresh = True;
			}
			
			if (NeedRefresh) {
				NeedRefresh = False;
				UpdatePage(0);
			}
		}
		
		foreach (Event in PendingEvents) {
			if (Event.Type == CMlEvent::Type::MouseClick) {
				if (Event.ControlId == "Button_Prev") {
					UpdatePage(-PageRange);
				} else if (Event.ControlId == "Button_Next") {
					UpdatePage(PageRange);
				}
			}
		}
	}
}
--></script>""";
}

// ---------------------------------- //
/** Create the manialink for the clan selection menu
 *
 *	@return		The manialink
 */
Text GetMLClanSelection() {
	declare ClansList = "";
	declare I = 0;
	for (I, 0, 4) {
		ClansList ^= """<frameinstance posn="{{{I*45}}} 0" modelid="Framemodel_Clan" class="Frame_Clan" id="{{{I+1}}}" />""";
	}
	
	return """
<framemodel id="Framemodel_Clan">
	<frame>
		<format textemboss="1" textsize="2" />
		{{{Private_CreateWindow(<44., 42.>, <0., 0., -1.>, 20., CMlControl::AlignHorizontal::HCenter, CMlControl::AlignVertical::Top, "Frame_BgWindow", True)}}}
		<!--<quad posn="0 0 -1" sizen="40 40" halign="center" style="Bgs1InRace" substyle="BgList" />
		<quad posn="0 0 -2" sizen="40 40" halign="center" style="Bgs1InRace" substyle="BgList" />
		<quad posn="0 0 -3" sizen="40 40" halign="center" style="Bgs1InRace" substyle="BgList" />
		<label posn="0 -4.5" sizen="25 5" halign="center" valign="center2" textsize="3" id="Label_ClanName" />-->
		<quad posn="-14 -3.5" sizen="6 6" halign="right" valign="center" style="Icons64x64_1" substyle="ArrowPrev" scriptevents="1" id="Button_PlayersPrev" />
		<quad posn="14 -3.5" sizen="6 6" valign="center" style="Icons64x64_1" substyle="ArrowNext" scriptevents="1" id="Button_PlayersNext" />
		<frame posn="0 -10" id="Frame_PlayersNames">
			<label posn="-18 0" sizen="36 5" />
			<label posn="-18 -6" sizen="36 5" />
			<label posn="-18 -12" sizen="36 5" />
		</frame>
		<label posn="0 -28" halign="center" textsize="1.5" text="4/5 (min : 3)" scriptevents="1" id="Label_Count" />
		<frame id="Frame_JoinClan">
			<label posn="0 -32" halign="center" style="CardButtonSmallS" text="{{{_("Join")}}}" scriptevents="1" id="Button_JoinClan" />
			<frame posn="0 -35" hidden="1" id="Button_JoinClanDisabled">				
				<quad sizen="27 5" halign="center" valign="center" bgcolor="333" />
				<label posn="0 0 1" sizen="24 5" halign="center" valign="center2" style="TextButtonSmall" textcolor="aaa" text="{{{_("Full")}}}" />
			</frame>
		</frame>
		<label posn="0 -32" halign="center" style="CardButtonSmallS" text="{{{_("|Leave the team|Leave")}}}" scriptevents="1" hidden="1" id="Button_LeaveClan" />
	</frame>
</framemodel>
<frame posn="0 -74 10" hidden="1" id="Frame_Global">
	<frame posn="0 0 1" id="Frame_Toggle">
		<label halign="center" style="CardButtonSmallXL" text="{{{_("Team selection (F6)")}}}" scriptevents="1" id="Button_ToggleClanSelection" />
	</frame>
	<frame posn="0 -72 0" scale="0.9" hidden="1" id="Frame_ClanSelection">
		<frame posn="0 8" id="Frame_CreateClan">
			<label halign="center" style="CardButtonSmallXL" text="{{{_("Create a team")}}}" scriptevents="1" id="Button_CreateClan" />
			<frame posn="0 -3" hidden="1" id="Button_CreateClanDisabled">
				<quad posn="0 0 -1" sizen="51 5" halign="center" valign="center" bgcolor="333" />
				<label sizen="48 5" halign="center" valign="center2" style="TextButtonSmall" textcolor="aaa" text="{{{_("Maximum number of clans reached")}}}" />
			</frame>
		</frame>
		<frame posn="-90 56" id="Frame_ClansList">
			{{{ClansList}}}
		</frame>
		<frame posn="0 35" id="Frame_ClansListCtrl">
			<quad posn="-108 0" sizen="20 20" halign="right" valign="center" style="Icons64x64_1" substyle="ShowLeft" scriptevents="1" id="Button_ClansPrev" />
			<quad posn="108 0" sizen="20 20" valign="center" style="Icons64x64_1" substyle="ShowRight" scriptevents="1" id="Button_ClansNext" />
		</frame>
	</frame>
</frame>
<script><!--
{{{Manialink::Includes(["MathLib" => "ML", "TextLib" => "TL"])}}}

declare CMlFrame[] Frames_Clan;
declare CMlQuad[] Buttons_PagerClan;
declare Integer PageRange;
declare Integer PageStart;
declare Integer PageEnd;
declare Int3[Integer] PagesProperties;

{{{Manialink::Animations(["EaseOutBack", "EaseInExp"])}}}

Integer[] GetClans() {
	declare Clans = Integer[];
	foreach (Score in Scores) {
		declare netread Integer Net_TeamAttack_CurrentClan for Score;
		if (Net_TeamAttack_CurrentClan > 0 && !Clans.exists(Net_TeamAttack_CurrentClan)) Clans.add(Net_TeamAttack_CurrentClan);
	}
	return Clans;
}

CTmScore[] GetClanScores(Integer _Clan) {
	declare CTmScore[] ThisClanScores;
	foreach (Score in Scores) {
		declare netread Integer Net_TeamAttack_CurrentClan for Score;
		if (Net_TeamAttack_CurrentClan == _Clan) ThisClanScores.add(Score);
	}
	return ThisClanScores;
}

Void UpdateSlotPlayers(Integer _SlotNb, CTmScore _Score, CMlFrame _Frame) {
	//log(Now^"> Players > _SlotNb: "^_SlotNb^" | _Score: "^_Score);
	if (_Frame == Null) return;
	if (!_Frame.Controls.existskey(_SlotNb-1)) return;
	declare Label_Name <=> (_Frame.Controls[_SlotNb-1] as CMlLabel);
	if (Label_Name == Null) return;
	
	if (_Score == Null) {
		Label_Name.Visible = False;
	} else {
		Label_Name.Visible = True;
		Label_Name.Value = _Score.User.Name;
	}
}

Void UpdatePagePlayers(Integer _Shift, Integer _SlotNb, Integer _Clan) {
	if (_Clan <= 0) return;
	if (!Frames_Clan.existskey(_SlotNb-1)) return;
	declare Frame_Clan <=> Frames_Clan[_SlotNb-1];
	if (Frame_Clan == Null) return;
	
	declare Frame_PlayersNames	<=> (Frame_Clan.GetFirstChild("Frame_PlayersNames")	as CMlFrame);
	declare Button_PlayersPrev	<=> (Frame_Clan.GetFirstChild("Button_PlayersPrev")	as CMlQuad);
	declare Button_PlayersNext	<=> (Frame_Clan.GetFirstChild("Button_PlayersNext")	as CMlQuad);
	declare Label_Count			<=> (Frame_Clan.GetFirstChild("Label_Count")		as CMlLabel);
	
	if (True) {
		declare PlayersPageRange for Button_PlayersPrev = Frame_PlayersNames.Controls.count;
		declare PlayersClan for Button_PlayersPrev = 0;
		declare PlayersSlot for Button_PlayersPrev = 0;
		
		PlayersPageRange = Frame_PlayersNames.Controls.count;
		PlayersClan = _Clan;
		PlayersSlot = _SlotNb;
	}
	if (True) {
		declare PlayersPageRange for Button_PlayersNext = Frame_PlayersNames.Controls.count;
		declare PlayersClan for Button_PlayersNext = 0;
		declare PlayersSlot for Button_PlayersNext = 0;
		
		PlayersPageRange = Frame_PlayersNames.Controls.count;
		PlayersClan = _Clan;
		PlayersSlot = _SlotNb;
	}
	
	if (!PagesProperties.existskey(_Clan)) {
		PagesProperties[_Clan] = <1, Frame_PlayersNames.Controls.count, 0>;
	}
	declare PlayersPageRange for Frame_Clan = Frame_PlayersNames.Controls.count;
	declare PlayersPageStart = PagesProperties[_Clan].X;
	declare PlayersPageEnd = PagesProperties[_Clan].Y;
	
	declare netread Integer Net_TeamAttack_MinPlayerPerClan for Teams[0];
	declare netread Integer Net_TeamAttack_MaxPlayerPerClan for Teams[0];
	declare ThisClanScores = GetClanScores(_Clan);
	
	PlayersPageStart += _Shift;
	if (PlayersPageStart < 1) PlayersPageStart = 1;
	else if (PlayersPageStart > ThisClanScores.count) PlayersPageStart = ThisClanScores.count;
	PlayersPageEnd = PlayersPageStart + PlayersPageRange - 1;
	if (PlayersPageEnd > ThisClanScores.count) PlayersPageEnd = ThisClanScores.count;
	
	PagesProperties[_Clan].X = PlayersPageStart;
	PagesProperties[_Clan].Y = PlayersPageEnd;
	
	Button_PlayersPrev.Visible = False;
	Button_PlayersNext.Visible = False;
	if (PlayersPageStart > 1) {
		Button_PlayersPrev.Visible = True;
	}
	if (PlayersPageEnd < ThisClanScores.count) {
		Button_PlayersNext.Visible = True;
	}
	
	
	declare LabelValue = ThisClanScores.count^"/";
	if (Net_TeamAttack_MaxPlayerPerClan > 0) LabelValue ^= TL::ToText(Net_TeamAttack_MaxPlayerPerClan);
	else LabelValue ^= "-";
	if (Net_TeamAttack_MinPlayerPerClan > 0) LabelValue ^= " (min : "^Net_TeamAttack_MinPlayerPerClan^")";
	Label_Count.Value = LabelValue;
	
	declare Button_JoinClan			<=> (Frame_Clan.GetFirstChild("Button_JoinClan")			as CMlLabel);
	declare Button_JoinClanDisabled	<=> (Frame_Clan.GetFirstChild("Button_JoinClanDisabled")	as CMlLabel);
	if (ThisClanScores.count >= Net_TeamAttack_MaxPlayerPerClan) {
		Button_JoinClan.Visible = False;
		Button_JoinClanDisabled.Visible = True;
	} else {
		Button_JoinClan.Visible = True;
		Button_JoinClanDisabled.Visible = False;
	}
	
	//log(Now^"> Players > PlayersPageStart: "^PlayersPageStart^" | PlayersPageEnd: "^PlayersPageEnd^" | PlayersPageRange: "^PlayersPageRange^" | ThisClanScores.count: "^ThisClanScores.count^" | _Shift: "^_Shift^" | _SlotNb: "^_SlotNb^" | _Clan: "^_Clan);
	
	declare I = 1;
	declare K = 1;
	foreach (Score in ThisClanScores) {
		if (I > PlayersPageEnd) break;
		if (I >= PlayersPageStart) {
			UpdateSlotPlayers(K, Score, Frame_PlayersNames);
			K += 1;
		}
		I += 1;
	}
	for (J, K, PlayersPageRange) {
		UpdateSlotPlayers(J, Null, Frame_PlayersNames);
	}
}

Void UpdateSlotClan(Integer _SlotNb, Integer _Clan) {
	//log(Now^"> Clan > Slot: "^_SlotNb^" | Clan: "^_Clan);
	
	if (!Frames_Clan.existskey(_SlotNb-1)) return;
	declare Frame_Clan <=> Frames_Clan[_SlotNb-1];
	if (Frame_Clan == Null) return;
	
	if (_Clan <= 0) {
		Frame_Clan.Visible = False;
	} else {
		Frame_Clan.Visible = True;
		
		declare Label_ClanName <=> (Frame_Clan.GetFirstChild("Label_Title") as CMlLabel);
		declare Frame_JoinClan <=> (Frame_Clan.GetFirstChild("Frame_JoinClan") as CMlFrame);
		declare Button_JoinClan <=> (Frame_Clan.GetFirstChild("Button_JoinClan") as CMlLabel);
		declare Button_LeaveClan <=> (Frame_Clan.GetFirstChild("Button_LeaveClan") as CMlLabel);
		
		if (InputPlayer.Score != Null) {
			declare netread Integer Net_TeamAttack_CurrentClan for InputPlayer.Score;
			if (_Clan == Net_TeamAttack_CurrentClan) {
				Frame_JoinClan.Visible = False;
				Button_LeaveClan.Visible = True;
			} else {
				Frame_JoinClan.Visible = True;
				Button_LeaveClan.Visible = False;
			}
		}
		
		declare ClanSelection_Clan for Button_JoinClan = 0;
		ClanSelection_Clan = _Clan;
		
		Label_ClanName.Value = TL::Compose("%1 %2", "{{{_("Team")}}}", TL::ToText(_Clan));
		
		UpdatePagePlayers(0, _SlotNb, _Clan);
	}
}

Void UpdatePageClan(Integer _Shift, Boolean _Focus) {
	declare Clans = GetClans().sort();
	
	if (_Focus && InputPlayer != Null && InputPlayer.Score != Null) {
		declare netread Integer Net_TeamAttack_CurrentClan for InputPlayer.Score;
		declare Key = Clans.keyof(Net_TeamAttack_CurrentClan) + 1;
		if (Key > 0) {
			PageStart = ((Key / PageRange) * PageRange) + 1;
			if (Key % PageRange == 0) PageStart -= PageRange;
		} else {
			PageStart += _Shift;
		}
	} else {
		PageStart += _Shift;
	}
	
	if (PageStart < 1) PageStart = 1;
	else if (PageStart > Clans.count) PageStart = Clans.count;
	PageEnd = PageStart + PageRange - 1;
	if (PageEnd > Clans.count) PageEnd = Clans.count;
	
	Buttons_PagerClan[0].Visible = False;
	Buttons_PagerClan[1].Visible = False;
	if (PageStart > 1) {
		Buttons_PagerClan[0].Visible = True;
	}
	if (PageEnd < Clans.count) {
		Buttons_PagerClan[1].Visible = True;
	}
	
	declare Integer[] ToRemove;
	foreach (Clan => PageProperties in PagesProperties) {
		if (!Clans.exists(Clan)) ToRemove.add(Clan);
	}
	foreach (Clan in ToRemove) {
		declare Removed = PagesProperties.removekey(Clan);
	}
	
	declare netread Integer Net_TeamAttack_MaxClanNb for Teams[0];
	declare Button_CreateClan			<=> (Page.GetFirstChild("Button_CreateClan")			as CMlFrame);
	declare Button_CreateClanDisabled	<=> (Page.GetFirstChild("Button_CreateClanDisabled")	as CMlFrame);
	if (Net_TeamAttack_MaxClanNb <= 0 || Clans.count < Net_TeamAttack_MaxClanNb) {
		Button_CreateClan.Visible = True;
		Button_CreateClanDisabled.Visible = False;
	} else {
		Button_CreateClan.Visible = False;
		Button_CreateClanDisabled.Visible = True;
	}
	
	//log(Now^"> Clan > PageStart: "^PageStart^" | PageEnd: "^PageEnd^" | PageRange: "^PageRange^" | _Shift: "^_Shift^" | _Focus: "^_Focus^" | Clans: "^Clans);
	
	declare I = 1;
	declare K = 1;
	foreach (Clan in Clans) {
		if (I > PageEnd) break;
		if (I >= PageStart) {
			UpdateSlotClan(K, Clan);
			K += 1;
		}
		I += 1;
	}
	for (J, K, PageRange) {
		UpdateSlotClan(J, 0);
	}
}

Void UpdatePageClan(Integer _Shift) {
	UpdatePageClan(_Shift, False);
}

Void JoinClan(Integer _Clan) {
	declare netread Integer Net_TeamAttack_SynchroServer for Teams[0];
	declare netwrite Integer Net_TeamAttack_SynchroClient for UI;
	declare netwrite Integer Net_TeamAttack_UpdateJoin for UI;
	declare netwrite Integer Net_TeamAttack_JoinClan for UI;
	
	Net_TeamAttack_SynchroClient = Net_TeamAttack_SynchroServer;
	Net_TeamAttack_UpdateJoin = Now;
	Net_TeamAttack_JoinClan = _Clan;
}

Void CreateClan() {
	declare netread Integer Net_TeamAttack_SynchroServer for Teams[0];
	declare netwrite Integer Net_TeamAttack_SynchroClient for UI;
	declare netwrite Integer Net_TeamAttack_UpdateCreate for UI;
	
	Net_TeamAttack_SynchroClient = Net_TeamAttack_SynchroServer;
	Net_TeamAttack_UpdateCreate = Now;
}

Void ToggleVisibility(CMlFrame _Frame) {
	declare Status for _Frame = 1;
	if (Status == 0) {
		LibManialink_Anim({{{Manialink::Inject("""<frame posn="0 -72 0" scale="0.9" hidden="1" id="Frame_ClanSelection" />""")}}}, 250, "EaseInExp");
		Status = 1;
	} else {
		LibManialink_Anim({{{Manialink::Inject("""<frame posn="0 0 0" scale="1" hidden="0" id="Frame_ClanSelection" />""")}}}, 250, "EaseOutBack");
		Status = 0;
	}
}

main() {
	declare Frame_Global		<=> (Page.GetFirstChild("Frame_Global")			as CMlFrame);
	declare Frame_ClanSelection	<=> (Page.GetFirstChild("Frame_ClanSelection")	as CMlFrame);
	declare Frame_ClansList		<=> (Page.GetFirstChild("Frame_ClansList")		as CMlFrame);
	Buttons_PagerClan.add((Page.GetFirstChild("Button_ClansPrev") as CMlQuad));
	Buttons_PagerClan.add((Page.GetFirstChild("Button_ClansNext") as CMlQuad));	
	
	declare I = 1;
	foreach (Control in Frame_ClansList.Controls) {
		declare Frame_Clan <=> (Control as CMlFrame);
		if (Frame_Clan == Null) continue;
		Frames_Clan.add(Frame_Clan);
		
		declare Button_JoinClan <=> Frame_Clan.GetFirstChild("Button_JoinClan");
		if (Button_JoinClan != Null) {
			declare ClanSelection_Clan for Button_JoinClan = 0;
			ClanSelection_Clan = TL::ToInteger(Frame_Clan.ControlId);
		}
		
		declare Frame_PlayersNames <=> (Frame_Clan.GetFirstChild("Frame_PlayersNames") as CMlFrame);
		declare Button_PlayersPrev <=> (Frame_Clan.GetFirstChild("Button_PlayersPrev") as CMlQuad);
		declare Button_PlayersNext <=> (Frame_Clan.GetFirstChild("Button_PlayersNext") as CMlQuad);
		if (Frame_PlayersNames != Null && Button_PlayersPrev != Null && Button_PlayersNext != Null) {
			if (True) {
				declare PlayersPageRange for Button_PlayersPrev = Frame_PlayersNames.Controls.count;
				declare PlayersClan for Button_PlayersPrev = 0;
				declare PlayersSlot for Button_PlayersPrev = 0;
				
				PlayersPageRange = Frame_PlayersNames.Controls.count;
				PlayersClan = 0;
				PlayersSlot = 0;
			}
			if (True) {
				declare PlayersPageRange for Button_PlayersNext = Frame_PlayersNames.Controls.count;
				declare PlayersClan for Button_PlayersNext = 0;
				declare PlayersSlot for Button_PlayersNext = 0;
				
				PlayersPageRange = Frame_PlayersNames.Controls.count;
				PlayersClan = 0;
				PlayersSlot = 0;
			}
		}
		
		I += 1;
	}
	
	// Init phase
	while (!PageIsVisible || InputPlayer == Null || InputPlayer.Score == Null) yield;
	Frame_Global.Visible = True;
	if (InputPlayer != Null && InputPlayer.Score != Null) {
		declare netread Integer Net_TeamAttack_CurrentClan for InputPlayer.Score;
		if (Net_TeamAttack_CurrentClan <= 0) ToggleVisibility(Frame_ClanSelection); //Frame_ClanSelection.Visible = True;
		else Frame_ClanSelection.Visible = False;
	}	
	foreach (Score in Scores) {
		declare ClanSelection_PrevCurrentClan for Score = 0;
		ClanSelection_PrevCurrentClan = -2;
	}
	
	declare netread Integer Net_TeamAttack_MinPlayerPerClan for Teams[0];
	declare netread Integer Net_TeamAttack_MaxPlayerPerClan for Teams[0];
	declare netread Integer Net_TeamAttack_MaxClanNb for Teams[0];
	
	PageRange = Frames_Clan.count;
	PageStart = 1;
	PageEnd = PageStart + PageRange - 1;
	
	declare PrevMinPlayerPerClan = -1;
	declare PrevMaxPlayerPerClan = -1;
	declare PrevMaxClanNb = -1;
	declare RefreshPage = False;
	declare Focus = False;
	
	UpdatePageClan(0);
	
	while (True) {
		yield;
		LibManialink_AnimLoop();
		
		if (!PageIsVisible || InputPlayer == Null) continue;
		
		if (Frame_ClanSelection.Visible) {
			foreach (Score in Scores) {
				declare netread Integer Net_TeamAttack_CurrentClan for Score;
				declare ClanSelection_PrevCurrentClan for Score = 0;
				
				if (ClanSelection_PrevCurrentClan != Net_TeamAttack_CurrentClan) {
					RefreshPage = True;
					ClanSelection_PrevCurrentClan = Net_TeamAttack_CurrentClan;
					
					if (Net_TeamAttack_CurrentClan > 0 && InputPlayer.Score != Null && InputPlayer.Score.Id == Score.Id) Focus = True;
				}
			}
			
			if (
				PrevMinPlayerPerClan != Net_TeamAttack_MinPlayerPerClan 
				|| PrevMaxPlayerPerClan != Net_TeamAttack_MaxPlayerPerClan
				|| PrevMaxClanNb != Net_TeamAttack_MaxClanNb
			) {
				PrevMinPlayerPerClan = Net_TeamAttack_MinPlayerPerClan;
				PrevMaxPlayerPerClan = Net_TeamAttack_MaxPlayerPerClan;
				PrevMaxClanNb = Net_TeamAttack_MaxClanNb;
				RefreshPage = True;
			}
		}
		
		if (RefreshPage) {
			RefreshPage = False;
			UpdatePageClan(0, Focus);
			Focus = False;
		}
		
		foreach (Event in PendingEvents) {
			if (Event.Type == CMlEvent::Type::MouseClick) {
				if (Event.ControlId == "Button_JoinClan") {
					declare ClanSelection_Clan for Event.Control = 0;
					JoinClan(ClanSelection_Clan);
				} else if (Event.ControlId == "Button_CreateClan") {
					CreateClan();
				} else if (Event.ControlId == "Button_LeaveClan") {
					JoinClan(0);
				} else if (Event.ControlId == "Button_ToggleClanSelection") {
					ToggleVisibility(Frame_ClanSelection);
				} else if (Event.ControlId == "Button_ClansNext") {
					UpdatePageClan(PageRange);
				} else if (Event.ControlId == "Button_ClansPrev") {
					UpdatePageClan(-PageRange);
				} else if (Event.ControlId == "Button_PlayersNext") {
					declare PlayersPageRange for Event.Control = 1;
					declare PlayersClan for Event.Control = 0;
					declare PlayersSlot for Event.Control = 0;
					UpdatePagePlayers(PlayersPageRange, PlayersSlot, PlayersClan);
				} else if (Event.ControlId == "Button_PlayersPrev") {
					declare PlayersPageRange for Event.Control = 1;
					declare PlayersClan for Event.Control = 0;
					declare PlayersSlot for Event.Control = 0;
					UpdatePagePlayers(-PlayersPageRange, PlayersSlot, PlayersClan);
				}
			} else if (Event.Type == CMlEvent::Type::KeyPress) {
				if (Event.KeyName == "F6") {
					ToggleVisibility(Frame_ClanSelection);
				} else if (Frame_ClanSelection.Visible) {
					if (Event.KeyName == "1" || Event.KeyName == "Numpad1") {
						JoinClan(1);
					}
				}
			} else if (Event.Type == CMlEvent::Type::MouseOver) {
				if (Event.ControlId == "Button_ClansNext") {
					(Event.Control as CMlQuad).Substyle = "ShowRight2";
				} else if (Event.ControlId == "Button_ClansPrev") {
					(Event.Control as CMlQuad).Substyle = "ShowLeft2";
				}
			} else if (Event.Type == CMlEvent::Type::MouseOut) {
				if (Event.ControlId == "Button_ClansNext") {
					(Event.Control as CMlQuad).Substyle = "ShowRight";
				} else if (Event.ControlId == "Button_ClansPrev") {
					(Event.Control as CMlQuad).Substyle = "ShowLeft";
				}
			}
		}
	}
}
--></script>""";
}