-------------------------------------------------
-- Staging Room Screen
-------------------------------------------------
include( "IconHookup" );
local IconHookup = IconHookup
local SimpleCivIconHookup = SimpleCivIconHookup

include( "SupportFunctions"  );
local TruncateString = TruncateString

include( "InstanceManager" );
include( "MPGameOptions" );
local SetInLobby = SetInLobby
local ValidateCivSelections = ValidateCivSelections
local GetMaxPlayersForCurrentMap = GetMaxPlayersForCurrentMap
local PopulateMapSizePulldown = PopulateMapSizePulldown
local RefreshMapScripts = RefreshMapScripts
local UpdateGameOptionsDisplay = UpdateGameOptionsDisplay
local GetTurnModeStr = GetTurnModeStr
local GetTurnModeToolTipStr = GetTurnModeToolTipStr

include( "TurnStatusBehavior" ); -- for turn status button behavior
local UpdateTurnStatus = UpdateTurnStatus


local ipairs = ipairs
local math = math
local pairs = pairs
local print = print
local string = string
local table = table
local tostring = tostring

print"Loading Staging Room Screen"

local Controls = Controls
local ContextPtr = ContextPtr
local Network = Network
local PreGame = PreGame
local Matchmaking = Matchmaking
local UIManager = UIManager
local Modding = Modding
local Events = Events

local Players = Players
local Game = Game
local UI = UI
local GetFileName = Path.GetFileName
local NetKicked = NetKicked
local SystemUpdateUIType = SystemUpdateUIType
local OptionsManager = OptionsManager

local GameInfo = GameInfo
local eLClick = Mouse.eLClick
local L = Locale.ConvertTextKey
local SlotClaim = SlotClaim
local SlotStatus = SlotStatus
local GameViewTypes = GameViewTypes
local GameStateTypes = GameStateTypes
local MAX_MAJOR_CIVS = GameDefines.MAX_MAJOR_CIVS

-------------------------------------------------
-- Globals
-------------------------------------------------

local m_SlotInstances = {};
local g_ChatInstances = {};

local g_AdvancedOptionIM = InstanceManager:new( "GameOption", "Text", Controls.AdvancedOptions );
local g_AdvancedOptionsList = {};

local m_HostID;
local m_bIsHost;

local m_PlayerNames = {};
local m_bLaunchReady = false;
local m_bTeamsValid = false;

local m_bEditOptions = false;

local g_fCountdownTimer = -1;  --Start game countdown timer.  Set to -1 when not in use.

local hoursStr = L( "TXT_KEY_HOURS" );
local secondsStr = L( "TXT_KEY_SECONDS" );

local g_SlotIsActive = { [ SlotStatus.SS_COMPUTER or -1] = true, [ SlotStatus.SS_TAKEN or -1] = true }
local g_SlotTypeStrings = {
	[ SlotStatus.SS_COMPUTER or -1] = "TXT_KEY_SLOTTYPE_AI",
	[ SlotStatus.SS_OBSERVER or -1] = "TXT_KEY_SLOTTYPE_OBSERVER",
	[ SlotStatus.SS_CLOSED or -1] = "TXT_KEY_SLOTTYPE_CLOSED",
	[ SlotStatus.SS_TAKEN or -1] = "TXT_KEY_PLAYER_TYPE_HUMAN",
}

-------------------------------------------------
-- Utilities
-------------------------------------------------

local function GetSlotTypeString( playerID )
	return g_SlotTypeStrings[ PreGame.GetSlotStatus( playerID ) ]
		or PreGame.GetSlotClaim( playerID ) == SlotClaim.SLOTCLAIM_RESERVED and (PreGame.IsHotSeatGame() and "TXT_KEY_PLAYER_TYPE_HUMAN" or "TXT_KEY_SLOTTYPE_HUMANREQ")
		or "TXT_KEY_SLOTTYPE_OPEN"
end

local function IsInGameScreen()
	return PreGame.GameStarted() and Matchmaking.IsHost() and PreGame.GetSlotStatus( Matchmaking.GetLocalID() ) == SlotStatus.SS_OBSERVER
end

local function ShowHideInviteButton()
	Controls.InviteButton:SetHide( not PreGame.IsInternetGame() or Network.IsDedicatedServer() )
end

local function BuildPlayerNames()
	local playerList = Matchmaking.GetPlayerList()
	if playerList then
		m_PlayerNames = {}
		for _, v in pairs(playerList) do
			m_PlayerNames[ v.playerID ] = v.playerName
		end
	end
end

local function ShowHideSaveButton()
	local bDisable = g_fCountdownTimer ~= -1; -- Disable the save game button while the countdown is active.
	local bShow = Matchmaking.IsHost();
	Controls.SaveButton:SetHide(not bShow);
	if( bDisable ) then
		Controls.SaveButton:SetDisabled( true );
		Controls.SaveButton:SetAlpha( 0.5 );
	else
		Controls.SaveButton:SetDisabled( false );
		Controls.SaveButton:SetAlpha( 1.0 );
	end

	-- Only show the game configuration tooltip if we'd be saving the game configuration vs. an actual game save.
	if PreGame.GameStarted() then
		Controls.SaveButton:SetToolTipString()
	else
		Controls.SaveButton:LocalizeAndSetToolTip( "TXT_KEY_SAVE_GAME_CONFIGURATION_TT" );
	end
end

local function DoCheckTeams()

	m_bTeamsValid = false
	local teamTest = -1;
	-- Find the team of the first valid player.  We can't simply use the host's team because they could be an observer.
	for i = 0, MAX_MAJOR_CIVS do
		if g_SlotIsActive[ PreGame.GetSlotStatus( i ) ] then
			teamTest = PreGame.GetTeam( i )
			break
		end
	end
	for i = 0, MAX_MAJOR_CIVS do
		if g_SlotIsActive[ PreGame.GetSlotStatus( i ) ] and PreGame.GetTeam( i ) ~= teamTest then
		    m_bTeamsValid = true
			return
		end
	end
end

local function CountPlayers()
	local totalPlayers = 0;
	for i = 0, MAX_MAJOR_CIVS do
		if g_SlotIsActive[ PreGame.GetSlotStatus( i ) ] and PreGame.GetSlotClaim( i ) == SlotClaim.SLOTCLAIM_ASSIGNED then
			totalPlayers = totalPlayers + 1
		end
	end
	return totalPlayers
end

local function ResetCivDetails( playerID )
	PreGame.SetLeaderName( playerID, "" )
	PreGame.SetCivilizationDescription( playerID, "" )
	PreGame.SetCivilizationShortDescription( playerID, "" )
	PreGame.SetCivilizationAdjective( playerID, "" )
end

local function LaunchGame()

	if false and PreGame.IsHotSeatGame() then
		Events.SerialEventStartGame()
print"Events.SerialEventStartGame"
	else
		Matchmaking.LaunchMultiplayerGame()
print"Matchmaking.LaunchMultiplayerGame"
	end
	UIManager:SetUICursor( 1 )
end

-------------------------------------------------
-- Stop Game Launch Countdown
-------------------------------------------------
local function StopCountdown()
	Controls.CountdownButton:SetHide(true);
	g_fCountdownTimer = -1;
	ContextPtr:ClearUpdate();
end

-------------------------------------------------
-- Context OnUpdate
-------------------------------------------------
local function OnUpdate( fDTime )
	-- OnUpdate only runs when the game start countdown is ticking down.
	g_fCountdownTimer = g_fCountdownTimer - fDTime
	if not Network.IsEveryoneConnected() then
		-- not all players are connected anymore.  This is probably due to a player join in progress.
		StopCountdown();
	elseif g_fCountdownTimer <= 0 then
			-- Timer elapsed, launch the game if we're the host.
			if m_bIsHost then
				LaunchGame()
			end

			StopCountdown()
	else
		Controls.CountdownButton:SetHide( false )
		Controls.CountdownButton:LocalizeAndSetText( "TXT_KEY_GAMESTART_COUNTDOWN_FORMAT", math.floor(g_fCountdownTimer) )
	end
end

-------------------------------------------------
-------------------------------------------------
local function GetPlayerIDBySelectionIndex(selectionIndex)
	return selectionIndex == 0 and Matchmaking.GetLocalID() or m_SlotInstances[selectionIndex].playerID
end

local function CivSelected( selectionIndex, civID )
	local playerID = GetPlayerIDBySelectionIndex(selectionIndex)
	if playerID >= 0 then
		PreGame.SetCivilization( playerID, civID )
		Network.BroadcastPlayerInfo()
		UpdateDisplay()
	end
end

local function InviteSelected( selectionIndex, playerChoiceID )

	local instance = m_SlotInstances[ selectionIndex ];

	if instance then

		if playerChoiceID == -1 then -- AI

			instance.InvitePulldown:GetButton():LocalizeAndSetText( "TXT_KEY_AI_NICKNAME" )

		else -- TODO: Send Invite and Lock Slot

			instance.InvitePulldown:GetButton():LocalizeAndSetText( "TXT_KEY_WAITING_FOR_INVITE_RESPONSE", "TEMP" )
--			instance.InvitePulldown:GetButton():SetText( "Waiting for Player..." );

		end

	end
end

local function OnKickPlayer( selectionIndex )
	UIManager:PushModal( Controls.ConfirmKick, true )
	LuaEvents.SetKickPlayer( GetPlayerIDBySelectionIndex(selectionIndex), m_SlotInstances[selectionIndex].PlayerNameLabel:GetText() )
end

local function OnEditPlayer( selectionIndex )
	UIManager:PushModal( Controls.SetCivNames )
	LuaEvents.SetCivNameEditSlot( GetPlayerIDBySelectionIndex(selectionIndex) )
	UpdateDisplay()
end

local function OnSwapPlayer( selectionIndex )
	Network.SetPlayerDesiredSlot( GetPlayerIDBySelectionIndex(selectionIndex) )
end

local function OnSelectTeam( selectionIndex, playerChoiceID )
	PreGame.SetTeam( GetPlayerIDBySelectionIndex(selectionIndex), playerChoiceID )
	selectionIndex = m_SlotInstances[selectionIndex] or Controls
	selectionIndex.TeamLabel:LocalizeAndSetText( "TXT_KEY_MULTIPLAYER_DEFAULT_TEAM_NAME", playerChoiceID + 1 )
	Network.BroadcastPlayerInfo();
	DoCheckTeams();
end

local function OnHandicapTeam( selectionIndex, handicap )
	PreGame.SetHandicap( GetPlayerIDBySelectionIndex(selectionIndex), handicap )
	selectionIndex = m_SlotInstances[selectionIndex] or Controls
	selectionIndex.HandicapLabel:LocalizeAndSetText( GameInfo.HandicapInfos[handicap].Description )
	Network.BroadcastPlayerInfo()
end

--[[
local function OnPlayerName( selectionIndex, id )
	local playerID = GetPlayerIDBySelectionIndex(selectionIndex);
	if (id == 0) then
		PreGame.SetSlotStatus( playerID, SlotStatus.SS_COMPUTER );
		PreGame.SetHandicap( playerID, 1 );
		PreGame.SetNickName( playerID, "" );
	else
		PreGame.SetSlotStatus( playerID, SlotStatus.SS_TAKEN );
		if (PreGame.GetNickName(playerID) == "") then
			PreGame.SetNickName( playerID, L( "TXT_KEY_MULTIPLAYER_DEFAULT_PLAYER_NAME", playerID + 1 ) );
		end
	end
	Network.BroadcastPlayerInfo();
end
]]

local function SetSlotToAI( playerID )
	PreGame.SetSlotStatus( playerID, SlotStatus.SS_COMPUTER )
	PreGame.SetHandicap( playerID, 1 )
	if PreGame.IsHotSeatGame() then
		-- Reset so the player can force a rebuild
		PreGame.SetNickName( playerID, "" )
		ResetCivDetails( playerID )
	end
end

local function SetSlotToHuman(playerID)
	-- Sets the given playerID slot to be human. Assumes that slot hasn't already been done so.
	PreGame.SetSlotStatus( playerID, SlotStatus.SS_TAKEN )
	PreGame.SetHandicap( playerID, 3 )
	if PreGame.GetNickName(playerID) == "" then
		PreGame.SetNickName( playerID, L( "TXT_KEY_MULTIPLAYER_DEFAULT_PLAYER_NAME", playerID + 1 ) )
	end
end

-- slot type pulldown options for the local player
local g_localSlotTypeOptions = { "TXT_KEY_SLOTTYPE_OPEN", "TXT_KEY_SLOTTYPE_OBSERVER" }
-- slot type pulldown options for non-local players
local g_slotTypeOptions = { "TXT_KEY_SLOTTYPE_OPEN", "TXT_KEY_SLOTTYPE_HUMANREQ", "TXT_KEY_SLOTTYPE_AI", "TXT_KEY_SLOTTYPE_OBSERVER", "TXT_KEY_SLOTTYPE_CLOSED" }

-- Associates an int value with our slotTypes so that we can index them in different pulldowns
local g_SlotVoids = { TXT_KEY_SLOTTYPE_OPEN = 1, TXT_KEY_SLOTTYPE_HUMANREQ = 2, TXT_KEY_PLAYER_TYPE_HUMAN = 3, TXT_KEY_SLOTTYPE_AI = 4, TXT_KEY_SLOTTYPE_OBSERVER = 5, TXT_KEY_SLOTTYPE_CLOSED = 6 }
local g_SlotToolTips = { L"TXT_KEY_SLOTTYPE_OPEN_TT", L"TXT_KEY_SLOTTYPE_HUMANREQ_TT", L"TXT_KEY_SLOTTYPE_HUMAN_TT", L"TXT_KEY_SLOTTYPE_AI_TT", L"TXT_KEY_SLOTTYPE_OBSERVER_TT", L"TXT_KEY_SLOTTYPE_CLOSED_TT" }
local g_SlotReady = {
	function( playerID ) -- TXT_KEY_SLOTTYPE_OPEN
		if not Network.IsPlayerConnected(playerID) then
			-- Can't open a slot occupied by a human.
			PreGame.SetSlotStatus( playerID, SlotStatus.SS_OPEN )
			PreGame.SetSlotClaim( playerID, SlotClaim.SLOTCLAIM_ASSIGNED )
			return true
		end
	end,
	function( playerID ) -- TXT_KEY_SLOTTYPE_HUMANREQ
		PreGame.SetSlotClaim( playerID, SlotClaim.SLOTCLAIM_RESERVED );
		if not Network.IsPlayerConnected(playerID) then
			-- Don't open the slot if someone is already occupying it.
			PreGame.SetSlotStatus( playerID, SlotStatus.SS_OPEN )
			return true
		elseif(Network.IsPlayerConnected(playerID) and PreGame.GetSlotStatus( playerID ) == SlotStatus.SS_OBSERVER) then
			-- Setting human required on an human occupied observer slot switches them to normal player mode.
			SetSlotToHuman( playerID )
			return true
		end
	end,
	function( playerID ) -- TXT_KEY_PLAYER_TYPE_HUMAN
		if PreGame.GetSlotStatus( playerID ) ~= SlotStatus.SS_TAKEN then
			SetSlotToHuman( playerID )
			return true
		end
	end,
	function( playerID ) -- TXT_KEY_SLOTTYPE_AI
		if PreGame.GetMultiplayerAIEnabled() and not Network.IsPlayerConnected( playerID ) then
			-- only switch to AI if AI are enabled in multiplayer.
			SetSlotToAI( playerID )
			return true
		end
	end,
	function( playerID ) -- TXT_KEY_SLOTTYPE_OBSERVER
		PreGame.SetSlotStatus( playerID, SlotStatus.SS_OBSERVER );
		return true
	end,
	function( playerID ) -- TXT_KEY_SLOTTYPE_CLOSED
		if not Network.IsPlayerConnected( playerID ) then
			PreGame.SetSlotStatus( playerID, SlotStatus.SS_CLOSED );
			PreGame.SetSlotClaim( playerID, SlotClaim.SLOTCLAIM_ASSIGNED );
			return true
		end
	end,
}

local function OnSlotType( playerID, id )
	-- NOTE: Slot type pulldowns store the slot's playerID rather than the selection Index in their voids.
	--print("OnSlotType ID:", id, "Player ID:", playerID);
	-- In most cases, changing a slottype resets the player's ready status.
	local resetReadyStatus = g_SlotReady[id]
	if resetReadyStatus and resetReadyStatus( playerID ) then
		PreGame.SetReady( playerID, false )
	end
	UpdateDisplay()
	Network.BroadcastPlayerInfo()
end

-------------------------------------------------
-- Refresh Player List
-------------------------------------------------
local function RefreshPlayerList()
	m_HostID  = Matchmaking.GetHostID();
	m_bIsHost = Matchmaking.IsHost();
	m_bLaunchReady = true;

	-- Get the Current Player List
	local playerTable = Matchmaking.GetPlayerList()

	for i = 1, #m_SlotInstances do
		m_SlotInstances[i].Root:SetHide( true )
	end

	-- Display Each Player
	if playerTable then
		for i, playerInfo in ipairs( playerTable ) do
			m_SlotInstances[i].playerID = playerInfo.playerID
			if playerInfo.playerID == Matchmaking.GetLocalID() then
				UpdateLocalPlayer( playerInfo )
			else
				UpdatePlayer( m_SlotInstances[ i ], playerInfo )
			end
		end
	end

	Controls.SlotStack:CalculateSize();
	Controls.SlotStack:ReprocessAnchoring();
	Controls.ListingScrollPanel:CalculateInternalSize();
end


-------------------------------------------------
-------------------------------------------------
local function UpdatePlayerInfo( instance, playerInfo, playerID, slotTypeOptions )

--	local portraitIndex = 22

	-- Civ & Leader Info
	local activeCivSlot = g_SlotIsActive[ PreGame.GetSlotStatus( playerID ) ]
	local civIndex = PreGame.GetCivilization( playerID )
	if civIndex ~= -1 and activeCivSlot then
		local civ = GameInfo.Civilizations[ civIndex ]
		local leader = civ and GameInfo.Civilization_Leaders{ CivilizationType = civ.Type }()
		leader = leader and GameInfo.Leaders[ leader.LeaderheadType ]
		instance.CivLabel:LocalizeAndSetText( "TXT_KEY_RANDOM_LEADER_CIV", leader and leader.Description or "TXT_KEY_MISC_UNKNOWN", civ and civ.ShortDescription or "TXT_KEY_MISC_UNKNOWN" )
		instance.CivLabel:SetToolTipString()
		IconHookup( leader.PortraitIndex, 64, leader.IconAtlas, instance.Portrait );
		SimpleCivIconHookup( playerID, 64, instance.Icon);

	elseif not activeCivSlot or PreGame.IsCivilizationKeyAvailable( playerID ) then
		-- Random Civ
		instance.CivLabel:LocalizeAndSetText( "TXT_KEY_RANDOM_LEADER" );
		instance.CivLabel:SetToolTipString()
		IconHookup( 22, 64, "LEADER_ATLAS", instance.Portrait )
		SimpleCivIconHookup(-1, 64, instance.Icon);
	else
		-- A player has chosen a civilization we don't have access to
		instance.CivLabel:LocalizeAndSetText( "TXT_KEY_UNAVAILABLE_LEADER" )
		instance.CivLabel:LocalizeAndSetToolTip( "TXT_KEY_UNAVAILABLE_LEADER_HELP", PreGame.GetCivilizationPackageTextKey( playerID ) )
		IconHookup( 22, 64, "LEADER_ATLAS", instance.Portrait )
		SimpleCivIconHookup(-1, 64, instance.Icon);
	end

	-- Team
	local teamID = PreGame.GetTeam(playerID) + 1; -- Real programmers count from zero.
	instance.TeamLabel:LocalizeAndSetText( "TXT_KEY_MULTIPLAYER_DEFAULT_TEAM_NAME", teamID )

	-- Handicap
	local tHandicap = GameInfo.HandicapInfos[ PreGame.GetHandicap( playerID ) ]
	instance.HandicapLabel:LocalizeAndSetText( tHandicap and tHandicap.Description or "TXT_KEY_MISC_UNKNOWN" )

	-- Slot Type
	local slotTypeString = GetSlotTypeString(playerID)
	instance.SlotTypeLabel:LocalizeAndSetText( slotTypeString )
	instance.SlotTypeLabel:SetToolTipString( g_SlotToolTips[ slotTypeString ] )

	-- Refresh slottype pulldown
	local pullDown = instance.SlotTypePulldown
	pullDown:ClearEntries();
	local controls = {};
	local createEntry;
	for _, typeName in ipairs(slotTypeOptions) do
		controls = {};
		createEntry = true;

		if PreGame.IsHotSeatGame() then
			if typeName == "TXT_KEY_SLOTTYPE_HUMANREQ" then
				-- "Human Required" slot type is the "Human" slot type in hotseat mode.
				typeName = "TXT_KEY_PLAYER_TYPE_HUMAN";
			elseif typeName == "TXT_KEY_SLOTTYPE_OBSERVER" or typeName == "TXT_KEY_SLOTTYPE_OPEN" then
				-- in hotseat mode, observer mode not allowed, and open mode is redundent
				createEntry = false;
			end
		elseif Network.IsPlayerConnected( playerID ) then
			-- player is actively occupying this slot
			if typeName == "TXT_KEY_SLOTTYPE_OPEN" then
				-- transform open slottype position to human (for changing from an observer to normal human player)
				typeName = "TXT_KEY_PLAYER_TYPE_HUMAN";
			elseif typeName == "TXT_KEY_SLOTTYPE_CLOSED" or typeName == "TXT_KEY_SLOTTYPE_AI" then
				-- Don't allow those types on human occupied slots.
				createEntry = false;
			end
		end

		if createEntry then
			local i = g_SlotVoids[ typeName ]
			if i then
				pullDown:BuildEntry( "InstanceOne", controls )
				controls.Button:LocalizeAndSetText( typeName )
				controls.Button:SetToolTipString( g_SlotToolTips[ typeName ] )
				controls.Button:SetVoids( playerID, i )
			end
		end
	end

	pullDown:CalculateInternals();
	pullDown:RegisterSelectionCallback( OnSlotType);

	-- Turn Status
	UpdateTurnStatusForPlayerID( playerID )

	return playerInfo.playerName or L( "TXT_KEY_MULTIPLAYER_DEFAULT_PLAYER_NAME", playerID + 1 )
end

function UpdatePlayer( instance, playerInfo )

	-- Player Listing Entry
	if instance then
		instance.Root:SetHide( false )
		local playerID   = playerInfo.playerID
		local playerName = UpdatePlayerInfo( instance, playerInfo, playerID, g_slotTypeOptions )

		if PreGame.CanReadyLocalPlayer() then
			Controls.LocalReadyCheck:LocalizeAndSetToolTip( "TXT_KEY_MP_READY_CHECK" );
		else
			Controls.LocalReadyCheck:LocalizeAndSetToolTip( "TXT_KEY_MP_READY_CHECK_UNAVAILABLE_DATA_HELP" );
		end

		-------------------------------------------------------------
		-------------------------------------------------------------

		local isReserved = PreGame.GetSlotClaim( playerID ) == SlotClaim.SLOTCLAIM_RESERVED
		local isLocked = isReserved or PreGame.GetSlotClaim( playerID ) == SlotClaim.SLOTCLAIM_ASSIGNED
		local isHuman  = PreGame.GetSlotStatus( playerID ) == SlotStatus.SS_TAKEN
		local isOpen = PreGame.GetSlotStatus( playerID ) == SlotStatus.SS_OPEN
		local isClosed = PreGame.GetSlotStatus( playerID ) == SlotStatus.SS_CLOSED
		local isObserver = PreGame.GetSlotStatus( playerID ) == SlotStatus.SS_OBSERVER
		local isDisabled = isOpen and not isReserved or isClosed or isObserver
		local isEmptyHumanRequiredSlot = isOpen and isReserved
		local isHotSeat = PreGame.IsHotSeatGame()
		local isReady
		local bCantChangeCiv;	-- Can't change civilization
		local bCantChangeTeam;	-- can't change teams
		local bSlotTypeDisabled;

		if isHuman then
			TruncateString(instance.PlayerNameLabel, instance.PlayerNameBox:GetSizeX() -
										 instance.PlayerNameLabel:GetOffsetX(), playerName);
			instance.InvitePulldown:GetButton():SetText( playerName );

			-- You can only change the slot's civ/team if you're in hotseat mode.
			if( isHotSeat ) then
				isReady = PreGame.IsReady( m_HostID ); -- same ready status as host (local player)
				bCantChangeCiv = PreGame.IsReady( m_HostID );
				bCantChangeTeam = PreGame.IsReady( m_HostID );
			else
				isReady = PreGame.IsReady( playerID );
				bCantChangeCiv = true;
				bCantChangeTeam = not m_bIsHost or PreGame.IsReady( m_HostID ); -- The host can override human's team selection
			end

			bSlotTypeDisabled = not m_bIsHost or PreGame.IsReady( m_HostID ); -- The host can override slot types
		else
			isReady = not isEmptyHumanRequiredSlot and -- Empty human required slots block game readiness.
									(isObserver and (PreGame.IsReady( playerID ) or (not Network.IsPlayerConnected( playerID ) and PreGame.IsReady( m_HostID ))) or -- human observers manually ready up if occupied or ready up with the host if empty.
									(not isObserver and PreGame.IsReady( m_HostID )) or -- non-observers share ready status with the host.
									(PreGame.GetLoadFileName() ~= "" and isClosed)); -- prevent closed player slots from blocking game startup when loading save games -tsmith

			if( m_bIsHost ) then
				bSlotTypeDisabled = PreGame.IsReady( m_HostID );

				-- Host can't change the team/civ of open/closed slots.
				bCantChangeCiv = isDisabled or PreGame.IsReady( m_HostID ) or isEmptyHumanRequiredSlot;
				bCantChangeTeam = isDisabled or PreGame.IsReady( m_HostID );
			else
				bSlotTypeDisabled = true;
				bCantChangeCiv = true;
				bCantChangeTeam = true;
			end

			if Network.IsPlayerConnected(playerID) then
						-- Use the player name if a player is network connected to the game (observers only)
				TruncateString( instance.PlayerNameLabel, instance.PlayerNameBox:GetSizeX() - instance.PlayerNameLabel:GetOffsetX(), playerName )
				instance.InvitePulldown:GetButton():SetText( playerName )
			else
				-- The default for non-humans is to display the slot type as the player name.
				local playerNameTextKey = GetSlotTypeString(playerID)
				TruncateString( instance.PlayerNameLabel, instance.PlayerNameBox:GetSizeX() - instance.PlayerNameLabel:GetOffsetX(), L(playerNameTextKey) )
				instance.InvitePulldown:GetButton():LocalizeAndSetText( playerNameTextKey )
			end
		end

		if PreGame.GameStarted() then
			-- Can't change anything after the game has been started.
			bCantChangeCiv = true;
			bCantChangeTeam = true;
			bSlotTypeDisabled = true;
		end

		if not isReady then
			-- You can't auto launch the game if someone isn't ready.
			m_bLaunchReady = false
		end

		instance.EnableCheck:SetCheck( not isDisabled )
		instance.EnableCheck:LocalizeAndSetToolTip( isDisabled and "TXT_KEY_MP_ENABLE_SLOT" or "TXT_KEY_MP_DISABLE_SLOT" )
		instance.LockCheck:SetCheck( isLocked )
		instance.LockCheck:LocalizeAndSetToolTip( isLocked and "TXT_KEY_MP_UNLOCK_SLOT" or "TXT_KEY_MP_LOCK_SLOT" )
		instance.ReadyHighlight:SetHide( isDisabled and not isObserver or not isReady )
		instance.PlayerNameLabel:SetHide( false )
		instance.InvitePulldown:SetHide( true )
		-- Note: You can't change slot types, civs, or teams after the game has started.
		local b = (PreGame.GetLoadFileName() ~= "") or PreGame.GameStarted()
		instance.CivPulldown:SetHide( b or bCantChangeCiv )
		instance.TeamPulldown:SetHide( b or bCantChangeTeam )
		instance.SlotTypePulldown:SetHide( b or bSlotTypeDisabled )
		-- Hide Civ/Team labels for open/closed slots
		instance.TeamLabel:SetHide( isDisabled )
		instance.CivLabel:SetHide( isDisabled )
		instance.HandicapLabel:SetHide( not isHuman )
		instance.HandicapPulldown:SetHide( bCantChangeCiv or not isHuman )
		instance.PingTimeLabel:SetHide( not isHuman )

		if( m_bIsHost ) then
			if( isHotSeat ) then
				instance.KickButton:SetHide( true );
				instance.EditButton:SetHide( isDisabled or not isHuman );
				--instance.EnableCheck:SetHide( false );
				instance.PingTimeLabel:SetHide( true );
				instance.LockCheck:SetHide( true );
			else
				--instance.EnableCheck:SetHide( isHuman or bCantChangeCiv );
				instance.LockCheck:SetHide( isHuman or bCantChangeCiv );
				instance.KickButton:SetHide( not isHuman and not Network.IsPlayerConnected(playerID));
				instance.EditButton:SetHide( true );
			end
		else
			--instance.EnableCheck:SetHide( true );
			instance.LockCheck:SetHide( true );
			instance.KickButton:SetHide( true );
			instance.EditButton:SetHide( true );
		end

		-- Handle swap button highlight
		local highlightSwap = (Network.GetPlayerDesiredSlot(Matchmaking.GetLocalID()) == playerID) -- We want to switch to this slot
			or (Network.GetPlayerDesiredSlot(playerID) == Matchmaking.GetLocalID()); -- They want to switch with us.
		instance.SwapButtonHighAlpha:SetHide( not highlightSwap )
		instance.SwapButton:SetHide( isHotSeat or PreGame.IsReady(Matchmaking.GetLocalID()) or (PreGame.GetSlotStatus(playerID) == SlotStatus.SS_CLOSED) )

		--TEMP: S.S, hiding lock since it doesn't do anything and too many people believe it's the cause of MP probs.
		instance.LockCheck:SetHide( true );

		instance.HostIcon:SetHide( playerID ~= m_HostID );

		-- Player connected indicator
		if(isHuman or isObserver) then
			instance.ConnectionStatus:SetHide(false);
			if(Network.IsPlayerHotJoining(playerID)) then
				-- Player is hot joining.
				instance.ConnectionStatus:SetTextureOffsetVal(0,32)
				instance.ConnectionStatus:LocalizeAndSetToolTip( "TXT_KEY_MP_PLAYER_CONNECTING" )
			elseif(Network.IsPlayerConnected(playerID)) then
				-- fully connected
				instance.ConnectionStatus:SetTextureOffsetVal(0,0)
				instance.ConnectionStatus:LocalizeAndSetToolTip( "TXT_KEY_MP_PLAYER_CONNECTED" )
			else
				-- Not connected
				instance.ConnectionStatus:SetTextureOffsetVal(0,96)
				instance.ConnectionStatus:LocalizeAndSetToolTip( "TXT_KEY_MP_PLAYER_NOTCONNECTED" )
			end
		else
			instance.ConnectionStatus:SetHide(true);
		end

		if not isHotSeat and isHuman then
			UpdatePingTimeLabel( instance.PingTimeLabel, playerID )
		end
	end
end

----------------------------------------------
function UpdateTurnStatusForPlayerID( playerID )
	if Players then
		local player = Players[playerID];
		local instance
		if playerID == Matchmaking.GetLocalID() then
			instance = Controls
		else
			for iSlot, slotElement in pairs( m_SlotInstances ) do
				local slotPlayerID = GetPlayerIDBySelectionIndex(iSlot);
				if slotPlayerID == playerID then
					instance = slotElement;
					break;
				end
			end
		end
		if instance then -- minor civs don't have slot instances.
			UpdateTurnStatus( player, instance.Icon, instance.ActiveTurnAnim, m_SlotInstances )
		end
	end
end

function UpdateTurnStatusForAll()
	UpdateTurnStatusForPlayerID(Matchmaking.GetLocalID());
	for _, instance in pairs( m_SlotInstances ) do
		UpdateTurnStatusForPlayerID(instance.playerID);
	end
end

-------------------------------------------------
function UpdateLocalPlayer( playerInfo )
	--------------------------------------------------------------
	-- Fill In Slot Info
	Controls.RemoveButton:SetHide( true );
	local playerID = Matchmaking.GetLocalID()
	local playerName = UpdatePlayerInfo( Controls, playerInfo, playerID, g_localSlotTypeOptions )

	-------------------------------------------------------------
	-- Refresh slottype pulldown
	-------------------------------------------------------------

	local isHotSeat = PreGame.IsHotSeatGame();
	local isObserver = ( (PreGame.GetSlotStatus( playerID ) == SlotStatus.SS_OBSERVER) );
	-----------------------------------------------------------
	-- Ready Status
	local isReady = PreGame.IsReady( playerID )
	Controls.LocalReadyCheck:SetHide( false )
	if not isReady then
		m_bLaunchReady = false;
	end

	local bCantChangeCiv = isReady or (PreGame.GetLoadFileName() ~= "") or isObserver or PreGame.GameStarted();
	local bCantChangeTeam = isReady or (PreGame.GetLoadFileName() ~= "") or isObserver or PreGame.GameStarted();
	local bSlotTypeDisabled = isReady or (PreGame.GetLoadFileName() ~= "") or isHotSeat or Network.IsDedicatedServer() or PreGame.GameStarted();

	-- Hide Civ/Team/Handicap labels for observers
	Controls.TeamLabel:SetHide( isObserver )
	Controls.CivLabel:SetHide( isObserver )
	Controls.HandicapLabel:SetHide( isObserver )

	Controls.LocalEditButton:SetHide( not isHotSeat )
	Controls.LocalReadyCheck:SetCheck( isReady )
	Controls.ReadyHighlight:SetHide( not isReady )

	TruncateString( Controls.PlayerNameLabel, Controls.PlayerNameBox:GetSizeX() - Controls.PlayerNameLabel:GetOffsetX(), playerName )
	Controls.CivPulldown:SetHide( bCantChangeCiv )
	Controls.TeamPulldown:SetHide( bCantChangeTeam )
	Controls.SlotTypePulldown:SetHide( bSlotTypeDisabled )
	Controls.HandicapPulldown:SetHide( bCantChangeCiv )
	Controls.HostIcon:SetHide( playerID ~= m_HostID )
end

-------------------------------------------------
-- Leave the Game
-------------------------------------------------
local function HandleExitRequest()

	StopCountdown() -- Make sure there is no countdown going.

	local isHost = Matchmaking.IsHost();
	Matchmaking.LeaveMultiplayerGame();
	if ( not PreGame.IsHotSeatGame() ) then
		-- Refresh the lobby as we enter it
		if ( PreGame.IsInternetGame() and not isHost ) then
			Matchmaking.RefreshInternetGameList();
		elseif ( not PreGame.IsInternetGame() and not isHost ) then
			Matchmaking.RefreshLANGameList();
		end
	end
	if PreGame.GetLoadFileName() ~= "" then
		-- If there is a load file name, then we may have went in to the staging room with a loaded game
		-- This can set a lot of things we don't want on at this time.

		local bIsInternet = PreGame.IsInternetGame();
		local eGameType = PreGame.GetGameType();

		PreGame.Reset();

		PreGame.SetInternetGame( bIsInternet );
		PreGame.SetGameType(eGameType);
		PreGame.ResetSlots();
	end

	UIManager:DequeuePopup( ContextPtr );
end

-------------------------------------------------
-- Button Callbacks
-------------------------------------------------

Controls.LaunchButton:RegisterCallback( eLClick, LaunchGame );

Controls.LocalEditButton:RegisterCallback( eLClick, function()
	UIManager:PushModal( Controls.SetCivNames )
	LuaEvents.SetCivNameEditSlot( 0 )
end)

Controls.ExitButton:RegisterCallback( eLClick, Events.UserRequestClose.Call )

Controls.InviteButton:RegisterCallback( eLClick, Steam.ActivateInviteOverlay )

Controls.SaveButton:RegisterCallback( eLClick, function()
	UIManager:QueuePopup( Controls.SaveMenu, PopupPriority.SaveMenu )
end)

do
	local GetGameViewRenderType = GetGameViewRenderType
	local SetGameViewRenderType = SetGameViewRenderType
	local ToggleStrategicView = ToggleStrategicView
	Controls.StrategicViewButton:RegisterCallback( eLClick, function()
		if PreGame.GetSlotStatus( Game.GetActivePlayer() ) == SlotStatus.SS_OBSERVER then
			-- Observer gets to toggle the world view completely off.
			local eViewType = GetGameViewRenderType()
			if eViewType == GameViewTypes.GAMEVIEW_NONE then
				SetGameViewRenderType(GameViewTypes.GAMEVIEW_STANDARD)
			else
				if eViewType == GameViewTypes.GAMEVIEW_STANDARD then
					SetGameViewRenderType(GameViewTypes.GAMEVIEW_STRATEGIC)
				else
					SetGameViewRenderType(GameViewTypes.GAMEVIEW_NONE)
				end
			end
		else
			ToggleStrategicView()
		end
	end)
end

Controls.RemoveButton:RegisterCallback( eLClick, function()
	Controls.RemoveButton:SetHide( true )
	local playerID = Matchmaking.GetLocalID()
	ResetCivDetails( playerID )
	local civ = PreGame.GetCivilization( playerID )
	if civ ~= -1 then
		civ = GameInfo.Civilizations[ civ ]
		local leader = civ and GameInfo.Civilization_Leaders{ CivilizationType = civ.Type }()
		leader = leader and GameInfo.Leaders[ leader.LeaderheadType ]
		Controls.Title:LocalizeAndSetText( "TXT_KEY_RANDOM_LEADER_CIV", leader and leader.Description or "TXT_KEY_MISC_UNKNOWN", civ and civ.ShortDescription or "TXT_KEY_MISC_UNKNOWN" )
	else
		Controls.Title:LocalizeAndSetText( "TXT_KEY_RANDOM_LEADER_CIV", "TXT_KEY_RANDOM_LEADER", "TXT_KEY_RANDOM_CIV" )
	end
end)

Controls.PlayersPageTab:RegisterCallback( eLClick, function()
	if m_bEditOptions then
		m_bEditOptions = false
		UpdatePageTabView(true)
	end
end)

Controls.OptionsPageTab:RegisterCallback( eLClick, function()
	if not m_bEditOptions then
		m_bEditOptions = true
		UpdatePageTabView(true)
	end
end)

local function BackButtonClick()
	if not Matchmaking.IsLaunchingGame() then
		-- Can't exit while launching.
		HandleExitRequest()
	end
end
Controls.BackButton:RegisterCallback( eLClick, BackButtonClick )
Controls.HotJoinCancelButton:RegisterCallback( eLClick, BackButtonClick )

Controls.ChatEntry:RegisterCallback( function( text )
	if string.len( text ) > 0 then
		Network.SendChat( text )
	end
	Controls.ChatEntry:ClearString()
end)

Controls.LocalReadyCheck:RegisterCheckHandler( function( bChecked )
	PreGame.SetReady( Matchmaking.GetLocalID(), bChecked )
	Network.BroadcastPlayerInfo()
	UpdateDisplay()
	CheckGameAutoStart()
	ShowHideSaveButton()
end)

----------------------------------------------------------------
-- UPDATE CURRENT SETTINGS
----------------------------------------------------------------
function UpdateDisplay()
	if not ContextPtr:IsHidden() then
		UpdateOptions();
		RefreshPlayerList();
		DoCheckTeams();

		-- Allow the host to manually start the game when loading a game.
		if m_bIsHost and PreGame.GetLoadFileName() ~= "" and not IsInGameScreen() then
			local isEveryoneConnected = Network.IsEveryoneConnected()
			Controls.LaunchButton:SetHide( false )
			Controls.LaunchButton:SetDisabled( not isEveryoneConnected )
			if isEveryoneConnected then
				Controls.LaunchButton:SetToolTipString()
			else
				Controls.LaunchButton:LocalizeAndSetToolTip( "TXT_KEY_LAUNCH_GAME_BLOCKED_PLAYER_JOINING" )
			end
		else
			Controls.LaunchButton:SetHide( true )
		end
	end
end


-------------------------------------------------
-- CHECK FOR GAME AUTO START
-------------------------------------------------
function CheckGameAutoStart()
	-- Check to see if we should start/stop the multiplayer game.
	-- Check to make sure we don't have too many players for this map.
	local bPlayerCountValid = CountPlayers() <= GetMaxPlayersForCurrentMap()

	if m_bLaunchReady and m_bTeamsValid and bPlayerCountValid and not PreGame.GameStarted() and Network.IsEveryoneConnected() then
		-- Everyone has readied up and we can start.
		if PreGame.IsHotSeatGame() then
			-- Hotseat skips the countdown.
			LaunchGame();
		else
			g_fCountdownTimer = 10;
			ContextPtr:SetUpdate( OnUpdate );
		end
	else
		-- We can't autostart now, stop the countdown incase we started it earlier.
		StopCountdown();
	end
end


-------------------------------------------------
-------------------------------------------------
function UpdatePingTimeLabel( kLabel, playerID )
	local iPingTime = Network.GetPingTime( playerID );
	if (iPingTime >= 0) then
		iPingTime = math.clamp(iPingTime, 0, 99999); --limit value to something that can be displayed in 5 chars.
		kLabel:SetHide( false );
		if (iPingTime == 0) then
			kLabel:LocalizeAndSetText("TXT_KEY_STAGING_ROOM_UNDER_1_MS");
		else
			if (iPingTime < 1000) then
				local ms = Locale.Lookup("TXT_KEY_STAGING_ROOM_TIME_MS");
				kLabel:SetText( tostring(iPingTime) .. ms );
			else
--				local s = Locale.Lookup("TXT_KEY_STAGING_ROOM_TIME_S");
				kLabel:SetText( string.format("%.2fs" , (iPingTime / 1000)) );
			end
		end
	else
		kLabel:SetHide( true );
	end
end

-------------------------------------------------
-------------------------------------------------
function UpdatePageTabView(bUpdateOnly)
	Controls.Host:SetHide( m_bEditOptions );
	Controls.ListingScrollPanel:SetHide( m_bEditOptions );
	Controls.OptionsScrollPanel:SetHide( not m_bEditOptions );
	Controls.OptionsPageTabHighlight:SetHide( not m_bEditOptions );
	Controls.PlayersPageTabHighlight:SetHide( m_bEditOptions );
	Controls.GameOptionsSummary:SetHide( m_bEditOptions );
	Controls.GameOptionsSummaryTitle:SetHide( m_bEditOptions );
	Controls.VerticalTrim:SetHide( m_bEditOptions );

	-- Update Page Title
	if IsInGameScreen() then
		Controls.TitleLabel:LocalizeAndSetText( "{TXT_KEY_MULTIPLAYER_DEDICATED_SERVER_ROOM:upper}" )
	elseif m_bEditOptions then
		-- Modding ?
		if ContextPtr:LookUpControl("../.."):GetID() == "ModMultiplayerSelectScreen" then
			Controls.TitleLabel:LocalizeAndSetText( "TXT_KEY_MOD_MP_GAME_SETUP_HEADER" )
		else
			Controls.TitleLabel:LocalizeAndSetText( "TXT_KEY_MULTIPLAYER_GAME_SETUP_HEADER" )
		end
	else
		Controls.TitleLabel:LocalizeAndSetText( "{TXT_KEY_MULTIPLAYER_STAGING_ROOM:upper}" )
	end

	if m_bEditOptions then
		Controls.OptionsScrollPanel:SetSizeY( Controls.VerticalTrim:GetSizeY() - 2);
		Controls.OptionsScrollPanel:CalculateInternalSize();

		-- Modding ?
		Controls.ModsButton:SetHide( ContextPtr:LookUpControl("../.."):GetID() ~= "ModMultiplayerSelectScreen" )

		PopulateMapSizePulldown();

		RefreshMapScripts();
		PreGame.SetRandomMapScript(false);	-- Random map scripts is not supported in multiplayer
		UpdateGameOptionsDisplay(bUpdateOnly);
	else
		if PreGame.IsHotSeatGame() then
			-- In case they changed the DLC
			local prevCursor = UIManager:SetUICursor( 1 );
			Modding.ActivateAllowedDLC();
			UIManager:SetUICursor( prevCursor );
			Events.SystemUpdateUI( SystemUpdateUIType.RestoreUI, "StagingRoom" );
		end
	end
end

-------------------------------------------------
-------------------------------------------------
function UpdateOptions()

	-- Set Game Name
	local strGameName = Matchmaking.GetCurrentGameName();
	Controls.NameLabel:SetText( strGameName );

	-- Game State Indicator
	if( PreGame.GameStarted() ) then
		Controls.HotJoinBox:SetHide( false );
		Controls.LoadingBox:SetHide( true );
	elseif( PreGame.GetLoadFileName() ~= "" ) then
		Controls.HotJoinBox:SetHide( true );
	  Controls.LoadingBox:SetHide( false );
  else
		Controls.HotJoinBox:SetHide( true );
	  Controls.LoadingBox:SetHide( true );
	end

	-- Set Max Turns if set
	local maxTurns = PreGame.GetMaxTurns();
	if(maxTurns == 0) then
		Controls.MaxTurns:SetHide(true);
	else
		Controls.MaxTurns:SetHide(false);
		Controls.MaxTurns:LocalizeAndSetText( "TXT_KEY_MAX_TURNS", maxTurns )
	end

	-- Show turn timer value if set.
	if(PreGame.GetGameOption("GAMEOPTION_END_TURN_TIMER_ENABLED") == 1) then
		Controls.TurnTimer:SetHide(false);
		local turnTimerStr = L("TXT_KEY_MP_OPTION_TURN_TIMER");
		local pitBossTurnTime = PreGame.GetPitbossTurnTime();
		if(pitBossTurnTime > 0) then
			turnTimerStr = turnTimerStr .. ": " .. pitBossTurnTime;
			if(PreGame.GetGameOption("GAMEOPTION_PITBOSS") == 1) then
				turnTimerStr = turnTimerStr .. " " .. hoursStr;
			else
				turnTimerStr = turnTimerStr .. " " .. secondsStr;
			end
		end
		Controls.TurnTimer:SetText(turnTimerStr);
	else
		Controls.TurnTimer:SetHide(true);
	end

	-- Set Start Era
	local eraInfo = GameInfo.Eras[ PreGame.GetEra() ]
--	Controls.StartEraLabel:LocalizeAndSetText( "TXT_KEY_START_ERA", eraInfo.Description )
	Controls.StartEraLabel:LocalizeAndSetText( eraInfo and eraInfo.Description or "TXT_KEY_MISC_UNKNOWN" )

	-- Set Turn Mode
	local turnModeStr = GetTurnModeStr();
	Controls.TurnModeLabel:LocalizeAndSetText( turnModeStr );
	Controls.TurnModeLabel:LocalizeAndSetToolTip( GetTurnModeToolTipStr(turnModeStr) );

	-- Set Game Map Type
	if( not PreGame.IsRandomMapScript() ) then
		local mapScriptFileName = Locale.ToLower(PreGame.GetMapScript());
		local mapScript = nil;

		for row in GameInfo.MapScripts{FileName = mapScriptFileName} do
			mapScript = row;
			break;
		end

		if(mapScript ~= nil) then
			Controls.MapTypeLabel:LocalizeAndSetText( mapScript.Name );
			Controls.MapTypeLabel:LocalizeAndSetToolTip( mapScript.Description );
		else
			local mapInfo = UI.GetMapPreview(mapScriptFileName);
			if(mapInfo ~= nil) then
				Controls.MapTypeLabel:LocalizeAndSetText(mapInfo.Name);
				Controls.MapTypeLabel:LocalizeAndSetToolTip( mapInfo.Description );
			else
				-- print("Cannot get info for map or map script - " .. tostring(mapScriptFileName));
				local fileTitle = GetFileName(PreGame.GetMapScript());
				if (fileTitle ~= nil) then
					Controls.MapTypeLabel:SetText("[COLOR_RED]" .. fileTitle .. "[ENDCOLOR]");
					Controls.MapTypeLabel:LocalizeAndSetToolTip( "TXT_KEY_FILE_INFO_NOT_FOUND" );
				end
			end
		end
	end

	if(PreGame.IsRandomMapScript()) then
		Controls.MapTypeLabel:LocalizeAndSetText( "TXT_KEY_RANDOM_MAP_SCRIPT" );
		Controls.MapTypeLabel:LocalizeAndSetToolTip( "TXT_KEY_RANDOM_MAP_SCRIPT_HELP" );
	end

	-- Set Map Size
	if(not PreGame.IsRandomWorldSize() ) then
		local info = GameInfo.Worlds[ PreGame.GetWorldSize() ];
		Controls.MapSizeLabel:LocalizeAndSetText( info.Description );
		Controls.MapSizeLabel:LocalizeAndSetToolTip( info.Help );
	else
		Controls.MapSizeLabel:LocalizeAndSetText( "TXT_KEY_RANDOM_MAP_SIZE" );
		Controls.MapSizeLabel:LocalizeAndSetToolTip( "TXT_KEY_RANDOM_MAP_SIZE_HELP" );
	end

	-- Set Game Pace Slot
	local info = GameInfo.GameSpeeds[ PreGame.GetGameSpeed() ];
	Controls.GameSpeedLabel:LocalizeAndSetText( info.Description );
	Controls.GameSpeedLabel:LocalizeAndSetToolTip( info.Help );

	-- Game Options
	g_AdvancedOptionIM:ResetInstances();
	g_AdvancedOptionsList = {};

	local count = 1;
	-- When there's 8 or more players connected to us (9 player game), warn that it's an unsupported game.

	local totalPlayers = CountPlayers()

	-- Is it a private game?
	if(PreGame.IsPrivateGame()) then
		local controls = g_AdvancedOptionIM:GetInstance();
		g_AdvancedOptionsList[count] = controls;
		controls.Text:LocalizeAndSetText("TXT_KEY_MULTIPLAYER_PRIVATE_GAME");
		count = count + 1;
	end

	if(totalPlayers > 8) then
		local controls = g_AdvancedOptionIM:GetInstance();
		g_AdvancedOptionsList[count] = controls;
		controls.Text:LocalizeAndSetText("TXT_KEY_MULTIPLAYER_UNSUPPORTED_NUMBER_OF_PLAYERS");
		count = count + 1;
	end

	for option in GameInfo.GameOptions{Visible = 1} do
			if( option.Type ~= "GAMEOPTION_END_TURN_TIMER_ENABLED"
					and option.Type ~= "GAMEOPTION_SIMULTANEOUS_TURNS"
					and option.Type ~= "GAMEOPTION_DYNAMIC_TURNS") then
				local savedValue = PreGame.GetGameOption(option.Type);
				if(savedValue ~= nil and savedValue == 1) then
					local controls = g_AdvancedOptionIM:GetInstance();
					g_AdvancedOptionsList[count] = controls;
					controls.Text:LocalizeAndSetText(option.Description);
					count = count + 1;
				end
			end
		end

		-- Update scrollable panel
		Controls.AdvancedOptions:CalculateSize();
		Controls.GameOptionsSummary:CalculateInternalSize();
end


-------------------------------------------------
-------------------------------------------------
function PopulateCivPulldown( pullDown, playerID )

	pullDown:ClearEntries();

	------------------------------------------------------------------------------------------------
	-- set up the random slot
	------------------------------------------------------------------------------------------------
	local controls = {};
	pullDown:BuildEntry( "InstanceOne", controls );
	controls.Button:SetVoids( playerID, -1 );
	controls.Button:LocalizeAndSetText( "TXT_KEY_RANDOM_LEADER" )
	controls.Button:LocalizeAndSetToolTip( "TXT_KEY_RANDOM_LEADER_HELP" )


	local civEntries = {};
	for civ in GameInfo.Civilizations{ Playable = 1 } do
		local leader = civ and GameInfo.Civilization_Leaders{ CivilizationType = civ.Type }()
		leader = leader and GameInfo.Leaders[ leader.LeaderheadType ]
		table.insert( civEntries,	{ 	ID = civ.ID,
										Title = L("TXT_KEY_RANDOM_LEADER_CIV", leader and leader.Description or "TXT_KEY_MISC_UNKNOWN", civ.ShortDescription),
										Description = L(civ.Description),
									} )
	end

	table.sort(civEntries, function(a,b) return Locale.Compare(a.Title, b.Title) == -1; end);

	for _,v in ipairs( civEntries ) do
		local controls = {};
		pullDown:BuildEntry( "InstanceOne", controls );
		controls.Button:SetVoids( playerID, v.ID );
		controls.Button:SetText( v.Title )
		controls.Button:GetTextControl():SetTruncateWidth( controls.Button:GetSizeX() - 20 )
		controls.Button:SetToolTipString( v.Description )
	end

	pullDown:CalculateInternals();
	pullDown:RegisterSelectionCallback( CivSelected );
end


-------------------------------------------------
-- TODO: This only gets called once.  We need something more dynamic.
-------------------------------------------------
local function PopulateInvitePulldown( pullDown, playerID )

	local controls = {};
	pullDown:ClearEntries();
	pullDown:BuildEntry( "InstanceOne", controls );
	controls.Button:LocalizeAndSetText( "TXT_KEY_AI_NICKNAME" )
	controls.Button:SetVoids( playerID, -1 )

	local friendList = Matchmaking.GetFriendList();

	if friendList then
		-- Populate with Steam friends.
		for i = 1, #friendList do
			local controls = {};
			pullDown:BuildEntry( "InstanceOne", controls );
			controls.Button:SetText( "Invite " .. friendList[i].playerName );
			controls.Button:SetVoids( playerID, friendList[i].steamID );
		end
	end

	pullDown:CalculateInternals();
	pullDown:RegisterSelectionCallback( InviteSelected );

end


-------------------------------------------------
-------------------------------------------------
function PopulateTeamPulldown( pullDown, playerID )

	local playerTable = Matchmaking.GetPlayerList();
	local count = 0;

	pullDown:ClearEntries();

	-- Display Each Player
	if playerTable then
		count = #playerTable;

		for i = 1, count, 1 do

			local controls = {};
			pullDown:BuildEntry( "InstanceOne", controls );

			controls.Button:LocalizeAndSetText( "TXT_KEY_MULTIPLAYER_DEFAULT_TEAM_NAME", i )
			controls.Button:SetVoids( playerID, i-1 ); -- TODO: playerID is really more like the slot position.

		end

		pullDown:CalculateInternals();
		pullDown:RegisterSelectionCallback( OnSelectTeam );
	end

end


-------------------------------------------------
-------------------------------------------------
function PopulateHandicapPulldown( pullDown, playerID )

	pullDown:ClearEntries();

	for info in GameInfo.HandicapInfos() do
		if ( info.Type ~= "HANDICAP_AI_DEFAULT" ) then
			local controls = {};
			pullDown:BuildEntry( "InstanceOne", controls );

			controls.Button:LocalizeAndSetText( info.Description )
			controls.Button:LocalizeAndSetToolTip( info.Help );
			controls.Button:SetVoids( playerID, info.ID );
		end
	end

	pullDown:CalculateInternals();
	pullDown:RegisterSelectionCallback( OnHandicapTeam );

end

-------------------------------------------------
-------------------------------------------------

--------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------
-- Chat
--------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------

-------------------------------------------------
-------------------------------------------------
local bFlipper = false;
function OnChat( fromPlayer, toPlayer, text, eTargetType )
	if( ContextPtr:IsHidden() == false and m_PlayerNames[ fromPlayer ] ~= nil ) then
		local controls = {};
		ContextPtr:BuildInstanceForControl( "ChatEntry", controls, Controls.ChatStack );

		table.insert( g_ChatInstances, controls );
		if( #g_ChatInstances > 100 ) then

			Controls.ChatStack:ReleaseChild( g_ChatInstances[ 1 ].Box );
			table.remove( g_ChatInstances, 1 );
		end

		controls.String:SetText( m_PlayerNames[ fromPlayer ] .. ": " .. text );
		controls.Box:SetSizeY( controls.String:GetSizeY() + 15 );
		controls.Box:ReprocessAnchoring();

		if( bFlipper ) then
			controls.Box:SetColorChannel( 3, 0.4 );
		end
		bFlipper = not bFlipper;

		Events.AudioPlay2DSound( "AS2D_IF_MP_CHAT_DING" );

		Controls.ChatStack:CalculateSize();
		Controls.ChatScroll:CalculateInternalSize();
		Controls.ChatScroll:SetScrollValue( 1 );
	end
end

----------------------------------------------------------------
----------------------------------------------------------------
local function OnEnable( bIsCheck, slotNumber )
	local playerID = GetPlayerIDBySelectionIndex( slotNumber );

	if PreGame.GetMultiplayerAIEnabled() then
		if( bIsCheck ) then
			SetSlotToAI( playerID )
		else
			PreGame.SetSlotStatus( playerID, SlotStatus.SS_CLOSED )
		end
	end
	UpdateDisplay();
	Network.BroadcastPlayerInfo();
end

local function OnLock( bIsCheck, slotNumber )
	PreGame.SetSlotClaim( GetPlayerIDBySelectionIndex( slotNumber ), bIsCheck and SlotClaim.SLOTCLAIM_RESERVED or SlotClaim.SLOTCLAIM_UNASSIGNED )
	UpdateDisplay();
end

-----------------------------------------------------------------
-- Adjust for resolution
-----------------------------------------------------------------
local function AdjustScreenSize()

	local _, screenY = UIManager:GetScreenSizeVal()
	local TOP_COMPENSATION = (screenY - 768) * 0.3 + 52
	local height = screenY - 108 - TOP_COMPENSATION - (Controls.ChatBox:IsHidden() and 80 or 240)
			--		TOP_FRAME							BOTTOM_COMPENSATION
	Controls.MainGrid:SetSizeY( screenY - TOP_COMPENSATION )
	Controls.ListingScrollPanel:SetSizeY( height - 113 ) -- LOCAL_SLOT_COMPENSATION
	Controls.ListingScrollPanel:CalculateInternalSize()
	Controls.GameOptionsSummary:SetSizeY( height - 8 )
	Controls.GameOptionsSummary:CalculateInternalSize()
	Controls.VerticalTrim:SetSizeY( height )
end


-------------------------------------------------
-- Event Handlers
-------------------------------------------------
local eventHooks = {

	AIProcessingStartedForPlayer = UpdateTurnStatusForPlayerID,
	AIProcessingEndedForPlayer = UpdateTurnStatusForPlayerID,
	NewGameTurn = UpdateTurnStatusForAll,
	RemotePlayerTurnEnd = UpdateTurnStatusForAll,
	GameMessageChat = OnChat,

	MultiplayerHotJoinStarted = function()
		-- Display hot joining popup if we're a hot joiner.
		if Network.IsPlayerHotJoining( Matchmaking.GetLocalID() ) then
			Controls.HotJoinPopup:SetHide(false)
		end
	end,

	MultiplayerHotJoinCompleted = function()
		-- Remove hot join popup on completion.
		Controls.HotJoinPopup:SetHide(true)
		-- The hot joiner's network connection status needs to be updated.
		RefreshPlayerList()
	end,

	MultiplayerGameLaunched = function()
		UIManager:DequeuePopup( ContextPtr )
	end,

	ConnectedToNetworkHost = function( playerID )
		BuildPlayerNames();
		UpdateDisplay();
		OnChat( playerID, -1, L( "TXT_KEY_CONNECTED" ) )
	end,

	MultiplayerGamePlayerUpdated = function()
		BuildPlayerNames(); -- Player names need to be rebuilt because this event could have been for a player ID swap.
		UpdateDisplay();
		UpdatePageTabView(true);
		ShowHideInviteButton();
		ShowHideSaveButton();
		CheckGameAutoStart(); -- Player disconnects can affect the game start countdown.
	end,

	MultiplayerGamePlayerDisconnected = function( playerID )
		OnChat( playerID, -1, L( Network.IsPlayerKicked(playerID) and "TXT_KEY_KICKED" or "TXT_KEY_DISCONNECTED" ) )
		ShowHideInviteButton()
	end,

	MultiplayerGameHostMigration = function( playerID )
		OnChat( playerID, -1, L( "TXT_KEY_HOST_MIGRATION" ) )
	end,

	PreGameDirty = function()
		UpdateDisplay()
		UpdatePageTabView( true )
		CheckGameAutoStart()  -- Check for autostart because this event could to due to a ready status changing.
	end,

	MultiplayerPingTimesChanged = function()
		if not PreGame.IsHotSeatGame() then
			-- Get the Current Player List
			local playerTable = Matchmaking.GetPlayerList();

			-- Display Each Player
			if( playerTable ) then
				for i, playerInfo in ipairs( playerTable ) do
					local playerID = playerInfo.playerID;

					if( playerID ~= Matchmaking.GetLocalID() ) then
						local instance = m_SlotInstances[ i ];
						if (instance ~= nil and not instance.Root:IsHidden()) then

							local isHuman  = (PreGame.GetSlotStatus( playerID ) == SlotStatus.SS_TAKEN ) or
											  (PreGame.GetSlotStatus( playerID ) == SlotStatus.SS_OPEN );

							if ( isHuman ) then
								UpdatePingTimeLabel( instance.PingTimeLabel, playerID );
							end
						end
					end
				end
			end
		end
	end,

	PlayerVersionMismatchEvent = function( playerID, playerName, bIsHost )
		if bIsHost then
			Events.FrontEndPopup.CallImmediate( L( "TXT_KEY_MP_VERSION_MISMATCH_FOR_HOST", playerName ) );
			Matchmaking.KickPlayer( playerID );
		else
			Events.FrontEndPopup.CallImmediate( L( "TXT_KEY_MP_VERSION_MISMATCH_FOR_PLAYER" ) );
			HandleExitRequest();
		end
	end,

	MultiplayerGameAbandoned = function(eReason)
		if UI.GetCurrentGameState() == GameStateTypes.CIV5_GS_MAIN_MENU then
			-- Still in the front end
			if eReason == NetKicked.BY_HOST then
				Events.FrontEndPopup.CallImmediate( "TXT_KEY_MP_KICKED" )
			elseif eReason == NetKicked.NO_HOST then
				Events.FrontEndPopup.CallImmediate( "TXT_KEY_MP_HOST_LOST" )
			else
				Events.FrontEndPopup.CallImmediate( "TXT_KEY_MP_NETWORK_CONNECTION_LOST" )
			end
			HandleExitRequest()
		end
	end,

	SystemUpdateUI = function( type )--, tag, iData1, iData2, strData1 )
		if type == SystemUpdateUIType.ScreenResize then
			AdjustScreenSize();
		end
	end,
}

ContextPtr:SetShowHideHandler( function( bIsHide, bIsInit )
--print( "StagingScreen SetShowHideHandler", bIsHide, bIsInit )
	if bIsInit then
		-- Create slot instances.
		for i = 1, MAX_MAJOR_CIVS do
			local instance = {};
			ContextPtr:BuildInstanceForControl( "PlayerSlot", instance, Controls.SlotStack );
			instance.Root:SetHide( true );
			instance.LockCheck:RegisterCheckHandler( OnLock );
			instance.EnableCheck:RegisterCheckHandler( OnEnable );
			instance.EnableCheck:SetVoid1( i );
			instance.KickButton:RegisterCallback( eLClick, OnKickPlayer );
			instance.KickButton:SetVoid1( i );
			instance.EditButton:RegisterCallback( eLClick, OnEditPlayer );
			instance.EditButton:SetVoid1( i );
			instance.SwapButton:RegisterCallback( eLClick, OnSwapPlayer );
			instance.SwapButton:SetVoid1( i );
			m_SlotInstances[i] = instance;
		end
	end
	-- Show background image if this is the ingame dedicated server screen.
	local isInGameScreen = IsInGameScreen()
	Controls.AtlasLogo:SetHide( bIsHide or not isInGameScreen )
	if bIsHide then
		for event, hook in pairs(eventHooks) do
			Events[ event ].Remove( hook )
		end
		Controls.ChatStack:DestroyAllChildren()
	else
-- [[
		-- Activate only the DLC allowed for this MP game.  Mods will also deactivated/activate too.
		if not ContextPtr:IsHotLoad() then
			local prevCursor = UIManager:SetUICursor( 1 );
			local _ = Modding.ActivateAllowedDLC();
			UIManager:SetUICursor( prevCursor );

			-- Send out an event to continue on, as the ActivateDLC may have swapped out the UI
			Events.SystemUpdateUI( SystemUpdateUIType.RestoreUI, "StagingRoom" );
		end
--]]
		if not isInGameScreen and
			Matchmaking.IsHost() and
			PreGame.GetGameOption("GAMEOPTION_PITBOSS") == 1 and
			OptionsManager.GetTurnNotifySmtpHost_Cached() ~= "" and
			OptionsManager.GetTurnNotifySmtpPassword_Cached() == ""
		then
			-- Display email smtp password prompt if we're hosting a pitboss game and the password is blank.
			UIManager:PushModal(Controls.ChangeSmtpPassword, true);
		end

		if PreGame.IsHotSeatGame()then
			-- If Hot Seat, just 'ready' the host
			Controls.LocalReadyCheck:SetHide(true);
			PreGame.SetReady( Matchmaking.GetLocalID() );
			-- Hide the chat panel
			Controls.ChatBox:SetHide( true );
		else
			Controls.ChatBox:SetHide( false );
		end

		SetInLobby( true );
		m_bEditOptions = false;
		Controls.ExitButton:SetHide( isInGameScreen )
		Controls.BackButton:SetHide( isInGameScreen )
		Controls.StrategicViewButton:SetHide( not isInGameScreen )
		ShowHideInviteButton();
		UpdatePageTabView(true);
		StopCountdown(); -- Make sure the countdown is stopped if we're toggling the hide status of the screen.

		AdjustScreenSize();

		ValidateCivSelections();
		-- Populate the civs for the slots.  This can change so it must be done every time.
		for i = 1, MAX_MAJOR_CIVS do

			local instance = m_SlotInstances[i];
			instance.Root:SetHide( true );

			PopulateCivPulldown( instance.CivPulldown, i );
			PopulateInvitePulldown( instance.InvitePulldown, i );
			PopulateTeamPulldown( instance.TeamPulldown, i );
			PopulateHandicapPulldown( instance.HandicapPulldown, i );

			instance.EnableCheck:SetVoid1( i );
			instance.KickButton:SetVoid1( i );
			instance.EditButton:SetVoid1( i );

		end
		-- Setup Local Slot
		PopulateCivPulldown( Controls.CivPulldown, 0 );
		PopulateTeamPulldown( Controls.TeamPulldown, 0 );
		PopulateHandicapPulldown( Controls.HandicapPulldown, 0 );

		BuildPlayerNames();
		UpdateDisplay();
		ShowHideSaveButton();
		UIManager:SetUICursor( 0 );
		for event, hook in pairs(eventHooks) do
			Events[ event ].Add( hook )
		end
	end
end)

----------------------------------------------------------------
-- Input Handler
----------------------------------------------------------------
do
	local KeyDown = KeyEvents.KeyDown
	local KeyUp = KeyEvents.KeyUp
	local VK_ESCAPE = Keys.VK_ESCAPE
	local VK_TAB = Keys.VK_TAB
	local VK_RETURN = Keys.VK_RETURN
	ContextPtr:SetInputHandler( function( uiMsg, wParam )
		if uiMsg == KeyDown and wParam == VK_ESCAPE then
			if not Matchmaking.IsLaunchingGame() then
				HandleExitRequest()
			end
			return true
		elseif uiMsg == KeyUp and (wParam == VK_TAB or wParam == VK_RETURN) then
			Controls.ChatEntry:TakeFocus()
			return true
		end
	end)
end