private void Notify_Browser_Of_Potential_Lobby( CServerLobbyBrowser browser, CServerLobby lobby )
		{
			EPersistenceID browser_id = browser.PlayerID;
			ELobbyID lobby_id = lobby.ID;

			if ( browser.WatchedLobbyCount == MAX_WATCHED_LOBBIES && browser.FirstLobby > lobby_id )
			{
				return;
			}

			if ( browser.Is_Watching ( lobby_id ) )
			{
				return;
			}

			if ( browser.WatchedLobbyCount == MAX_WATCHED_LOBBIES && browser.LastLobby < lobby_id )
			{
				return;
			}

			if ( lobby.Matches_Browse_Criteria( browser.BrowseCriteria ) )
			{

				if ( browser.JoinFirstAvailable )
				{
					CServerLobbyManager.Instance.Join_Lobby_By_Browsing( browser_id, lobby_id );
					return;
				}

				ELobbyID removed_lobby = ELobbyID.Invalid;
				if ( browser.WatchedLobbyCount == MAX_WATCHED_LOBBIES )
				{
					removed_lobby = browser.LastLobby;
					Remove_As_Watcher( removed_lobby, browser_id );
				}

				Insert_As_Watcher( lobby_id, browser_id );

				CServerMessageRouter.Send_Message_To_Player( new CBrowseLobbyAddRemoveMessage( lobby.Create_Summary(), removed_lobby ), browser_id );
			}
		}
		private void Find_Next_Lobby_For( CServerLobbyBrowser browser, ELobbyID removed_lobby, int previous_starting_index )
		{
			EPersistenceID player_id = browser.PlayerID;
			CBrowseLobbyAddRemoveMessage add_remove_message = new CBrowseLobbyAddRemoveMessage( null, removed_lobby );

			if ( browser.WatchedLobbyCount > 0 )
			{
				int new_lobby_index = Get_Sorted_Lobby_Index( browser.LastLobby ) + 1;
				ELobbyID next_match = Find_New_Lobby( browser, new_lobby_index );

				if ( next_match != ELobbyID.Invalid )
				{
					CServerLobby new_lobby = CServerLobbyManager.Instance.Get_Lobby( next_match );
					add_remove_message.Add_Summary( new_lobby.Create_Summary() );
					Add_As_Watcher( next_match, player_id );
				}
			}
			else if ( previous_starting_index > 0 )
			{
				// we just lost the last lobby in our visible set; try browsing backwards from the lost lobby in order to pick up some more
				List< ELobbyID > lobby_list = new List< ELobbyID >();
				Build_Backwards_Set_Aux( browser, previous_starting_index, lobby_list );

				if ( lobby_list.Count > 0 )
				{
					Browse_Lobby_List( browser, lobby_list );
				}

				lobby_list.Apply( id => add_remove_message.Add_Summary( CServerLobbyManager.Instance.Get_Lobby( id ).Create_Summary() ) );
			}

			CServerMessageRouter.Send_Message_To_Player( add_remove_message, player_id );
		}
		private ELobbyID Find_New_Lobby( CServerLobbyBrowser browser, int starting_index )
		{
			for ( int i = starting_index; i < m_SortedLobbies.Count; i++ )
			{
				ELobbyID lobby_id = m_SortedLobbies[ i ];
				CServerLobby lobby = CServerLobbyManager.Instance.Get_Lobby( lobby_id );

				if ( !lobby.Matches_Browse_Criteria( browser.BrowseCriteria ) )
				{
					continue;
				}

				if ( lobby.Check_Join( browser.PlayerID ) != EJoinLobbyFailureReason.None )
				{
					continue;
				}

				return lobby_id;
			}

			return ELobbyID.Invalid;
		}
		private void Build_Backwards_Set_Aux( CServerLobbyBrowser browser, int previous_starting_index, List< ELobbyID > lobby_list )
		{
			for ( int i = previous_starting_index - 1; i >= 0; i-- )
			{
				ELobbyID lobby_id = m_SortedLobbies[ i ];
				CServerLobby lobby = CServerLobbyManager.Instance.Get_Lobby( lobby_id );

				if ( !lobby.Matches_Browse_Criteria( browser.BrowseCriteria ) )
				{
					continue;
				}

				if ( lobby.Check_Join( browser.PlayerID ) != EJoinLobbyFailureReason.None )
				{
					continue;
				}

				lobby_list.Add( lobby_id );
				if ( lobby_list.Count >= MAX_WATCHED_LOBBIES )
				{
					break;
				}
			}

			lobby_list.Reverse();

			if ( lobby_list.Count < MAX_WATCHED_LOBBIES )
			{
				Build_Forwards_Set_Aux( browser, previous_starting_index, lobby_list );
			}
		}
		private bool Browse_Backwards( CServerLobbyBrowser browser, int previous_starting_index )
		{
			List< ELobbyID > lobby_list = new List< ELobbyID >();
			Build_Backwards_Set_Aux( browser, previous_starting_index, lobby_list );

			if ( lobby_list.Count > 0 )
			{
				Browse_Lobby_List( browser, lobby_list );
			}

			return lobby_list.Count > 0;
		}
		private void Browse_Lobby_List( CServerLobbyBrowser browser, List< ELobbyID > lobby_list )
		{
			Clear_Watched_Lobbies( browser.PlayerID );
			lobby_list.Apply( lobby_id => Add_As_Watcher( lobby_id, browser.PlayerID ) );
		}
		private void Handle_Start_Browse_Lobby_Request( CStartBrowseLobbyRequest request, EPersistenceID player_id )
		{
			CConnectedPlayer player = CConnectedPlayerManager.Instance.Get_Active_Player_By_Persistence_ID( player_id );
			if ( player == null )
			{
				return;
			}

			if ( !player.State_Allows_Operation( EConnectedPlayerOperation.Browse_Lobbies ) )
			{
				CServerMessageRouter.Send_Message_To_Player( new CStartBrowseLobbyResponse( request.RequestID, EStartBrowseResult.Invalid_State ), player_id );
				return;
			}			

			CLog.Log( ELoggingChannel.Lobby, ELogLevel.Medium, String.Format( "Player {0} requesting to start browsing lobbies.",
																									CConnectedPlayerManager.Get_Player_Log_Name( player_id ) ) );

			Stop_Browsing( player_id );

			CServerLobbyBrowser browser = new CServerLobbyBrowser( player_id, request.BrowseCriteria, request.JoinFirstAvailable );
			m_Browsers.Add( player_id, browser );

			Browse_Forwards( browser, 0 );

			if ( browser.Has_Matches() && request.JoinFirstAvailable )
			{
				ELobbyID lobby_id = browser.WatchedLobbies.First();
				Stop_Browsing( player_id );
				CServerMessageRouter.Send_Message_To_Player( new CStartBrowseLobbyResponse( request.RequestID, EStartBrowseResult.AutoJoined ), player_id );
				CServerLobbyManager.Instance.Join_Lobby_By_Browsing( player_id, lobby_id );
				return;
			}

			// send initial lobby set
			CStartBrowseLobbyResponse response = new CStartBrowseLobbyResponse( request.RequestID, EStartBrowseResult.Success );
			browser.WatchedLobbies.Apply( lobby_id => response.Add_Summary( Build_Summary( lobby_id ) ) );

			CServerMessageRouter.Send_Message_To_Player( response, player_id );
		}