class KFServerListPageInternet extends UT2K4Browser_ServerListPageInternet;

var protected ROMasterServerClient  ROMSC;

var	bool						bQueryRunning;
var	string						CurrentGameType;
var	localized 	string			ServerCountString;
var automated 	KFFilterPanel	FilterPanel;

var array<GameInfo.ServerResponseLine> AllServers;

var bool bFilterEmptyServers;
var bool bFilterFullServers;

function ShowPanel(bool bShow)
{
	if ( bShow )
	{
        if ( bInit )
        {
            sp_Main.SplitterUpdatePositions();
            sp_Detail.SplitterUpdatePositions();
        }

		Browser.t_Header.SetCaption(PanelCaption);
		RefreshFooter(self, string(!bCommonButtonWidth));
    	SetFooterCaption(CurrentFooterCaption);

		Uplink().bInternetQueryRunning = true;
		bQueryRunning = true;
		Refresh();

		bInit = false;
	}
    else if ( !bInit )
    {
    	// Remove all outstanding pings so that they will be repinged when this panel is made active again
    	// Otherwise, we'll get stuck if the new active tab is using the same masterserveruplink
		li_Server.OutstandingPings.Remove(0, li_Server.OutstandingPings.Length);
	}

	SetVisibility(bShow);
}

function InitServerList()
{
	super(UT2k4Browser_ServerListPageBase).InitServerList();
	li_Server.bPresort = True;
}

function BindQueryClient(ServerQueryClient Client)
{
}

function ROMasterServerClient Uplink()
{
	if ( ROMSC == None && PlayerOwner() != None )
	{
		ROMSC = PlayerOwner().Spawn(class'ROMasterServerClient');
		ROMSC.OnReceivedServer		= MyOnReceivedServer;
		ROMSC.OnQueryFinished		= QueryComplete;
		ROMSC.OnReceivedPingInfo	= ReceivedPingInfo;
		ROMSC.OnPingTimeout			= ReceivedPingTimeout;
	}

	return ROMSC;
}

function NewGameType(GUIComponent Sender)
{
	local string SelectedGame;
	local UT2K4Browser_ServersList List;

	if (Sender != Browser.co_GameType)
		return;

	SelectedGame = moComboBox(Sender).GetExtra();
	if (Browser.CurrentGameType ~= SelectedGame)
		return;

	CurrentGameType = moComboBox(Sender).GetText();
	Browser.CurrentGameType = SelectedGame;
	Browser.SaveConfig();

	List = UT2K4Browser_ServersList(Browser.co_GameType.GetObject());

	GameTypeChanged(List);
	BindQueryClient(Browser.Uplink());
	li_Server.AutoPingServers();
}

function GameTypeChanged(UT2K4Browser_ServersList NewList)
{
	local int i;

	if (NewList != None)
	{
		if (li_Server != None)
		{
			li_Server.OnChange = None;
			li_Server.StopPings();
			li_Server.SetAnchor(None);
		}

		lb_Server.InitBaseList(NewList);
	}

	CurrentGameType = Browser.co_GameType.GetText();

	li_Server.Clear();

	// Display any found servers of the current game type
	for (i = 0; i < AllServers.Length; i++)
	{
    	if (AllServers[i].GameType == CurrentGameType ||
    	    InterchangeableGameTypes(AllServers[i].GameType,CurrentGameType) ||
			Browser.co_GameType.GetComponentValue() == KFServerBrowser(Browser).AllTypesClassName )
		{
			DisplayServers(AllServers[i]);
		}
	}

	InitServerList();
}

/* Returns true if the supplied Server is running a gametype that should display even though it is not
what we are filtering for (currently only used in ObjectiveMode / KF Vanilla) */

function bool        InterchangeableGameTypes(string GT1, string GT2)
{
    if(GT1 ~= "Objective Mode" && GT2 == "Killing Floor")
    {
        return true;
    }

    return false;
}

function AddQueryTerm(coerce string Key, coerce string Value, MasterServerClient.EQueryType QueryType)
{
	local MasterServerClient.QueryData QD;
	local int i;

	for ( i = 0; i < Uplink().Query.Length; i++ )
	{
		QD = Uplink().Query[i];
		if ( QD.Key ~= Key && QD.Value ~= Value && QD.QueryType == QueryType )
			return;
	}

	QD.Key			= Key;
	QD.Value		= Value;
	QD.QueryType	= QueryType;

	Uplink().Query[i] = QD;

	if( Key == "freespace" )
    {
        bFilterFullServers = true;
    }
    else if( Key == "currentplayers" )
    {
        bFilterEmptyServers = true;
    }
}

function bool ValidateQueryItem(CustomFilter.EDataType FilterType, MasterServerClient.QueryData Data)
{
	local int i;

	if ( Data.QueryType == QT_Disabled )
	{
		return false;
	}

	switch ( FilterType )
	{
		case DT_Unique:
			for ( i = 0; i < Uplink().Query.Length; i++ )
			{
				if ( Uplink().Query[i].Key == Data.Key )
				{
					return false;
				}
			}

   			return true;

		case DT_Ranged:
			if ( Data.QueryType == QT_NotEquals )
			{
				return false;
			}

			for (i = 0; i < Uplink().Query.Length; i++)
			{
				if (Uplink().Query[i].Key == Data.Key)
				{
					if (Data.QueryType == QT_Equals)
					   return false;

  					switch (Uplink().Query[i].QueryType)
					{
						case QT_GreaterThan:
							if (Data.QueryType == QT_GreaterThanEquals)
								return false;

						case QT_GreaterThanEquals:
							if (Data.QueryType == QT_GreaterThan)
								return false;

							if (Uplink().Query[i].Value >= Data.Value)
							   return false;

                            break;

						case QT_LessThan:
						     if (Data.QueryType == QT_LessThanEquals)
						        return false;

						case QT_LessThanEquals:
						     if (Data.QueryType == QT_LessThan)
						        return false;

			                 if (Uplink().Query[i].Value <= Data.Value)
			                    return false;

					}

					break;
				}
			}

			return true;

		case DT_Multiple:
		     for (i = 0; i < Uplink().Query.Length; i++)
		         if ((Uplink().Query[i].Key == Data.Key) &&
		         	 (Uplink().Query[i].Value == Data.Value))
		               return false;

			return true;
	}

	return false;
}

function NotifyLevelChange()
{
	if ( ROMSC != none )
	{
		ROMSC.Stop();
		ROMSC.Destroy();
		ROMSC = none;
	}
}

function MyOnReceivedServer(GameInfo.ServerResponseLine s)
{
	local int i;

	SetTimer(60.0);

    AllServers.Insert(AllServers.Length, 1);
    AllServers[AllServers.Length - 1] = s;

	if ( s.GameType != CurrentGameType &&
		 Browser.co_GameType.GetComponentValue() != KFServerBrowser(Browser).AllTypesClassName )
	{
		return;
	}

	for ( i = 0; i < li_Server.Servers.Length; i++ )
	{
		if ( s.IP == li_Server.Servers[i].IP && s.Port == li_Server.Servers[i].Port )
		{
			return;
		}
	}

	DisplayServers(s);
	li_Server.AutoPingServers();

	SetFooterCaption(Repl(ServerCountString, "%NumServers%", Uplink().ResultCount));
}

function DisplayServers(out GameInfo.ServerResponseLine s)
{
	li_Server.MyOnReceivedServer(s);
	li_Server.AddedItem();
	li_Server.SortList();
}

function PruneServerIfInvalid( int ServerID, out GameInfo.ServerResponseLine s )
{
    if( bFilterFullServers )
    {
        if( s.CurrentPlayers >= s.MaxPlayers )
        {
            li_Server.RemoveServerAt( ServerID );
        }
    }

    if( bFilterEmptyServers )
    {
        if( s.CurrentPlayers == 0 )
        {
            li_Server.RemoveServerAt( ServerID );
        }
    }
}

// We have list of servers from master server and are going to start pinging
function QueryComplete( MasterServerClient.EResponseInfo ResponseInfo, int Info )
{
	li_Server.MyQueryFinished(ResponseInfo, Info);

	switch ( ResponseInfo )
	{
		case RI_Success:
			SetFooterCaption(Repl(QueryCompleteString, "%NumServers%", Uplink().ResultCount));
			break;

		case RI_AuthenticationFailed:
			SetFooterCaption(AuthFailString);
			break;

		case RI_ConnectionFailed:
	    	UT2K4ServerBrowser(PageOwner).GetFromServerCache(li_Server);
	    	li_Server.FakeFinished();
			SetFooterCaption(ConnFailString);
			break;

		case RI_ConnectionTimeout:
	    	UT2K4ServerBrowser(PageOwner).GetFromServerCache(li_Server);
	    	li_Server.FakeFinished();
			SetFooterCaption(ConnTimeoutString);
			break;

		case RI_MustUpgrade:
			SetFooterCaption(MustUpgradeString);
			break;
	}

	li_Server.SortList();
}

function ReceivedPingInfo( int ServerID, ServerQueryClient.EPingCause PingCause, GameInfo.ServerResponseLine s )
{
	Super.ReceivedPingInfo( ServerID, PingCause, S);

	// only remove servers that have been updated by auto-ping as opposed to clicking,
	// because we don't want clicked servers to disappear
	if( PingCause == PC_AutoPing )
	{
	    PruneServerIfInvalid( ServerID, s );
	}
}

event Timer()
{
	if ( bQueryRunning )
	{
		bQueryRunning = false;
		Uplink().Stop();
		QueryComplete(RI_Success, 0);
	}
}

function Refresh()
{
	local int i, j;
	local string TmpString;
	local array<CustomFilter.AFilterRule> Rules;
	local MasterServerClient.QueryData QueryItem;


	if ( bQueryRunning )
	{
		SetTimer(0.0);
		Uplink().Stop();
		bQueryRunning=false;
		return;
	}
	else
	{
		bQueryRunning = true;
	}

	ResetQueryClient(Uplink());

    if ( li_Server == none )
    {
        InitServerList();
    }
    else
    {
		li_Server.StopPings();
		li_Server.InvalidatePings();
    }

    li_Server.Clear();
    AllServers.Remove(0, AllServers.Length);

	// Add any extra filtering to the query
	for ( i = 0; i < FilterMaster.AllFilters.Length; i++ )
	{
		if ( FilterMaster.IsActiveAt(i) )
		{
			Rules = FilterMaster.GetFilterRules(i);
			for ( j = 0; j < Rules.Length; j++ )
			{
				QueryItem = Rules[j].FilterItem;
				if ( ValidateQueryItem(Rules[j].FilterType, QueryItem) )
				{
					TmpString = QueryItem.Value;
					if ( QueryItem.QueryType < 2 )
					{
						class'CustomFilter'.static.ChopClass(TmpString);
					}
					AddQueryTerm(QueryItem.Key, TmpString, QueryItem.QueryType);
				}
			}
		}
	}

	// Run query
	Uplink().StartQuery(CTM_Query);
	SetFooterCaption(StartQueryString);
}

function ResetQueryClient( ServerQueryClient Client )
{
    Super.ResetQueryClient( Client );

    bFilterFullServers = false;
    bFilterEmptyServers = false;
}

function UpdateStatusPingCount()
{
    CheckJoinButton(li_Server.IsValid());
    CheckSpectateButton(li_Server.IsValid());
}

function CancelPings()
{
    Uplink().CancelPings();
    SetFooterCaption(ReadyString);
}

function PingServer(int listid, ServerQueryClient.EPingCause PingCause, GameInfo.ServerResponseLine s)
{
    if( PingCause == PC_Clicked )
        Uplink().PingServer( listid, PingCause, s.IP, s.QueryPort, QI_RulesAndPlayers, s );
    else
        Uplink().PingServer( listid, PingCause, s.IP, s.QueryPort, QI_Ping, s );
}

function CloseMSConnection()
{
	if ( Browser != None )
	{
		Uplink().CancelPings();
	    Uplink().Stop();
	}
}

function int GetCurrentServerDifficulty()
{
    local int Flags;

    // Beginner        32
    // Normal          64
    // Hard            128
    // Suicidal        256
    // Hell On Earth   512

    Flags = li_Server.Servers[ li_Server.CurrentListId() ].Flags;
    if( (Flags & 512) != 0 )
    {
        return 4;
    }
    else if( (Flags & 256) != 0 )
    {
        return 3;
    }
    else if( (Flags & 128) != 0 )
    {
        return 2;
    }
    else if( (Flags & 64) != 0 )
    {
        return 1;
    }

    return 0;
}

defaultproperties
{
	ServerCountString="Received: %NumServers% Servers"

	Begin Object Class=GUISplitter Name=HorzSplitter
        WinTop=0.012910
        WinHeight=0.876881
		WinWidth=1.000000
        WinLeft=0.000000
        bNeverFocus=True
        bAcceptsInput=True
        DefaultPanels(0)="GUI2K4.UT2K4Browser_ServerListBox"
        DefaultPanels(1)="XInterface.GUISplitter"
        SplitOrientation=SPLIT_Vertical
        SplitAreaSize=8
        RenderWeight=1
        MaxPercentage=0.9
        IniOption="@Internal"
        OnCreateComponent=InternalOnCreateComponent
        OnLoadIni=InternalOnLoadIni
        OnReleaseSplitter=InternalReleaseSplitter
    End Object
    sp_Main=HorzSplitter

	Begin Object Class=KFFilterPanel Name=PanelFilter
		//Caption="Filters"
		WinTop=0.8905
		WinLeft=0.00
		WinWidth=1.0
		WinHeight=0.107
		TabOrder=3
	End Object
	FilterPanel=PanelFilter
}
