globalize_all_functions

const string PRIVATE_MATCH_PLAYLIST = "private_match"

global struct CustomMatchSettingContainer
{
	string playlistVar
	string defaultValue
	string localizedName
	bool isEnumSetting
	
	// enum setting
	array< string > enumNames
	array< string > enumValues
}

struct {
	array<string> modes = [ // default modes in vanilla
		"tdm",
		"aitdm",
		"cp",
		"at",
		"ctf",
		"lts",
		"ps",
		"speedball",
		"mfd",
		"ttdm",
		"fd_easy",
		"fd_normal",
		"fd_hard",
		"fd_master",
		"fd_insane"
	]
	
	array<string> maps = [ // default maps in vanilla
		"mp_forwardbase_kodai",
		"mp_grave",
		"mp_homestead",
		"mp_thaw",
		"mp_black_water_canal",
		"mp_eden",
		"mp_drydock",
		"mp_crashsite3",
		"mp_complex3",
		"mp_angel_city",
		"mp_colony02",
		"mp_glitch",
		"mp_relic02",
		"mp_wargames",
		"mp_rise",
		"mp_lf_stacks",
		"mp_lf_deck",
		"mp_lf_meadow",
		"mp_lf_traffic",
		"mp_lf_township",
		"mp_lf_uma"
	]
	
	table< string, array< CustomMatchSettingContainer > > customMatchSettingsByCategory // we set these up in sh_private_lobby_modes_init
} file 


void function AddPrivateMatchMode( string mode )
{
	if ( !file.modes.contains( mode ) )
		file.modes.append( mode )
	
	#if CLIENT
		// call this on ui too so the client and ui states are the same
		RunUIScript( "AddPrivateMatchMode", mode ) 
	#endif
}

void function AddPrivateMatchMap( string map )
{
	if ( !file.maps.contains( map ) )
		file.maps.append( map )
	
	#if CLIENT 
		// call this on ui too so the client and ui states are the same
		RunUIScript( "AddPrivateMatchMap", map )
	#endif
}


void function AddPrivateMatchModeSettingArbitrary( string category, string playlistVar, string defaultValue, string localizedName = "" )
{
	if ( localizedName == "" )
		localizedName = "#" + playlistVar

	if ( !( category in file.customMatchSettingsByCategory ) )
		file.customMatchSettingsByCategory[ category ] <- []
	
	bool found = false
	foreach ( CustomMatchSettingContainer setting in file.customMatchSettingsByCategory[ category ] )
	{
		if ( setting.playlistVar == playlistVar )
		{
			found = true
			break
		}
	}
	
	if ( !found )
	{
		CustomMatchSettingContainer setting
		setting.playlistVar = playlistVar
		setting.defaultValue = defaultValue
		setting.localizedName = localizedName
		setting.isEnumSetting = false
		
		file.customMatchSettingsByCategory[ category ].append( setting )
	}
	
	#if CLIENT
		// call this on ui too so the client and ui states are the same
		RunUIScript( "AddPrivateMatchModeSettingArbitrary", category, playlistVar, defaultValue, localizedName )
	#endif
}

void function AddPrivateMatchModeSettingEnum( string category, string playlistVar, array<string> enums, string defaultValue, string localizedName = "" )
{
	if ( localizedName == "" )
		localizedName = "#" + playlistVar

	if ( !( category in file.customMatchSettingsByCategory ) )
		file.customMatchSettingsByCategory[ category ] <- []
		
	bool found = false
	foreach ( CustomMatchSettingContainer setting in file.customMatchSettingsByCategory[ category ] )
	{
		if ( setting.playlistVar == playlistVar )
		{
			found = true
			break
		}
	}
	
	if ( !found )
	{
		CustomMatchSettingContainer setting
		setting.playlistVar = playlistVar
		setting.defaultValue = defaultValue
		setting.localizedName = localizedName
		setting.isEnumSetting = true
		
		foreach ( int i, value in enums )
		{
			setting.enumNames.append( value )
			setting.enumValues.append( string( i ) )
		}
		
		file.customMatchSettingsByCategory[ category ].append( setting )
	}

	#if CLIENT
		// call this on ui too so the client and ui states are the same
		// note: RunUIScript can't take tables, so manually serialize ( sucks, but just how it is ), using \n as a delimeter since i dont believe its ever used in vars
		string serializedString
		foreach ( int i, value in enums )
			serializedString += value + "\n" + string( i ) + "\n"
		
		RunUIScript( "AddPrivateMatchModeSettingEnumUIHack", category, playlistVar, serializedString, defaultValue, localizedName )
	#endif
}

void function AddPrivateMatchModeSettingEnumUIHack( string category, string playlistVar, string serializedEnumPairs, string defaultValue, string localizedName )
{
	// this fucking sucks, but RunUIScript won't take tables, so we serialize to a string
	// we use \n as a delimeter and basically serialize to an array
	array<string> serializedArray = split( serializedEnumPairs, "\n" )
	array<string> enums = []

	for ( int i = 0; i < serializedArray.len(); i += 2 )
	{
		enums.append( serializedArray[i] )
	}

	AddPrivateMatchModeSettingEnum( category, playlistVar, enums, defaultValue, localizedName )
}

// Sorts specific gamemode settings to the end of the list
int function SortMatchSettings( string categoryA, string categoryB )
{
	if ( StartsWith( categoryA, "#PL_" ) || StartsWith( categoryA, "#GAMEMODE_" ) )
		return 1
	else if ( StartsWith( categoryB, "#PL_" ) || StartsWith( categoryB, "#GAMEMODE_" ) )
		return 0
	return 0
}

array< string > function GetPrivateMatchSettingCategories( bool uiAllowAllModeCategories = false )
{
	array< string > categories
	foreach ( string k, v in file.customMatchSettingsByCategory )
	{
		#if UI
		bool differentPlaylist = StartsWith( k, "#PL_" ) && k.slice( 4 ) != PrivateMatch_GetSelectedMode()
		bool differentGamemode = StartsWith( k, "#GAMEMODE_" ) && k.slice( 10 ) != PrivateMatch_GetSelectedMode()
		if ( differentPlaylist || differentGamemode )
			continue
		#endif
		categories.append( k )
	}

	categories.sort( SortMatchSettings )
	return categories
}

array< CustomMatchSettingContainer > function GetPrivateMatchCustomSettingsForCategory( string category )
{
	return file.customMatchSettingsByCategory[ category ]
}


array<string> function GetPrivateMatchModes()
{
	//array<string> modesArray
	//
	//int numModes = GetPlaylistGamemodesCount( PRIVATE_MATCH_PLAYLIST )
	//for ( int modeIndex = 0; modeIndex < numModes; modeIndex++ )
	//{
	//	modesArray.append( GetPlaylistGamemodeByIndex( PRIVATE_MATCH_PLAYLIST, modeIndex ) )
	//}
	
	//return modesArray
	
	return file.modes
}

int function GetPrivateMatchModeIndex( string modeName )
{
	//int indexForName = 0
	//
	//int numModes = GetPlaylistGamemodesCount( PRIVATE_MATCH_PLAYLIST )
	//for ( int modeIndex = 0; modeIndex < numModes; modeIndex++ )
	//{
	//	if ( GetPlaylistGamemodeByIndex( PRIVATE_MATCH_PLAYLIST, modeIndex ) != modeName )
	//		continue
	//
	//	indexForName = modeIndex;
	//	break
	//}
	//
	//return indexForName
	
	return file.modes.find( modeName )
}


array<string> function GetPrivateMatchMapsForMode( string modeName )
{
	//array<string> mapsArray
	//
	//int modeIndex = GetPrivateMatchModeIndex( modeName )
	//int numMaps = GetPlaylistGamemodeByIndexMapsCount( PRIVATE_MATCH_PLAYLIST, modeIndex )
	//for ( int mapIndex = 0; mapIndex < numMaps; mapIndex++ )
	//{
	//	mapsArray.append( GetPlaylistGamemodeByIndexMapByIndex( PRIVATE_MATCH_PLAYLIST, modeIndex, mapIndex ) )
	//}
	//
	//return mapsArray
	
	array<string> maps
	
	// use the private match playlist for this if the gamemode is in it already
	int privatePlaylistModeIndex = GetPrivateMatchModeIndex( modeName )
	if ( privatePlaylistModeIndex < GetPlaylistGamemodesCount( PRIVATE_MATCH_PLAYLIST ) )
	{
		for ( int i = 0; i < GetPlaylistGamemodeByIndexMapsCount( PRIVATE_MATCH_PLAYLIST, privatePlaylistModeIndex ); i++ )
			maps.append( GetPlaylistGamemodeByIndexMapByIndex( PRIVATE_MATCH_PLAYLIST, privatePlaylistModeIndex, i ) )
	}
	else
	{
		int numMaps = GetPlaylistGamemodeByIndexMapsCount( modeName, 0 )
		for ( int i = 0; i < numMaps; i++ )
			maps.append( GetPlaylistGamemodeByIndexMapByIndex( modeName, 0, i ) )
	}
		
	return maps
}

// never called
/*array<string> function GetPrivateMatchModesForMap( string mapName )
{
	array<string> modesArray

	int numModes = GetPlaylistGamemodesCount( PRIVATE_MATCH_PLAYLIST )
	for ( int modeIndex = 0; modeIndex < numModes; modeIndex++ )
	{
		int numMaps = GetPlaylistGamemodeByIndexMapsCount( PRIVATE_MATCH_PLAYLIST, modeIndex )
		for ( int mapIndex = 0; mapIndex < numMaps; mapIndex++ )
		{
			if ( GetPlaylistGamemodeByIndexMapByIndex( PRIVATE_MATCH_PLAYLIST, modeIndex, mapIndex ) != mapName )
				continue

			modesArray.append( GetPlaylistGamemodeByIndex( PRIVATE_MATCH_PLAYLIST, modeIndex ) )
		}
	}

	return modesArray
}*/


string function GetPrivateMatchMapForIndex( int index )
{
	array<string> mapsArray = GetPrivateMatchMaps()

	if ( index >= mapsArray.len() || index < 0 )
		return ""

	return mapsArray[index]
}

string function GetPrivateMatchModeForIndex( int index )
{
	array<string> modesArray = GetPrivateMatchModes()

	if ( index >= modesArray.len() || index < 0 )
		return ""

	return modesArray[index]
}

int function GetPrivateMatchMapIndex( string mapName )
{
	array<string> mapsArray = GetPrivateMatchMaps()
	for ( int index = 0; index < mapsArray.len(); index++ )
	{
		if ( mapsArray[index] == mapName )
			return index
	}

	return 0
}
/*
int function GetPrivateMatchModeIndex( string modeName )
{
	array<string> modesArray = GetPrivateMatchModes()
	for ( int index = 0; index < modesArray.len(); index++ )
	{
		if ( modesArray[index] == modeName )
			return index
	}

	return 0
}
*/

array<string> function GetPrivateMatchMaps()
{
	//array<string> mapsArray
	//
	//int numModes = GetPlaylistGamemodesCount( PRIVATE_MATCH_PLAYLIST )
	//for ( int modeIndex = 0; modeIndex < numModes; modeIndex++ )
	//{
	//	int numMaps = GetPlaylistGamemodeByIndexMapsCount( PRIVATE_MATCH_PLAYLIST, modeIndex )
	//	for ( int mapIndex = 0; mapIndex < numMaps; mapIndex++ )
	//	{
	//		string mapName = GetPlaylistGamemodeByIndexMapByIndex( PRIVATE_MATCH_PLAYLIST, modeIndex, mapIndex )
	//		if ( mapsArray.contains( mapName ) )
	//			continue
	//
	//		mapsArray.append( mapName )
	//	}
	//}
	//
	//return mapsArray
	
	return file.maps
}



array<string> function GetPlaylistMaps( string playlistName )
{
	array<string> mapsArray

	int numModes = GetPlaylistGamemodesCount( playlistName )
	for ( int modeIndex = 0; modeIndex < numModes; modeIndex++ )
	{
		int numMaps = GetPlaylistGamemodeByIndexMapsCount( playlistName, modeIndex )
		for ( int mapIndex = 0; mapIndex < numMaps; mapIndex++ )
		{
			string mapName = GetPlaylistGamemodeByIndexMapByIndex( playlistName, modeIndex, mapIndex )
			if ( mapsArray.contains( mapName ) )
				continue

			mapsArray.append( mapName )
		}
	}

	return mapsArray
}


bool function MapSettings_SupportsTitans( string mapName )
{
	if ( mapName.find( "mp_lf_") != null )
		return false

	if ( mapName.find( "coliseum" ) != null )
		return false;

	return true
}

bool function MapSettings_SupportsAI( string mapName )
{
	if ( mapName.find( "mp_lf_") != null )
		return false

	if ( mapName.find( "coliseum" ) != null )
		return false;

	return true
}


bool function ModeSettings_RequiresTitans( string modeName )
{
	switch ( modeName )
	{
		case "lts":
			return true
	}

	return false
}

bool function ModeSettings_RequiresAI( string modeName )
{
	switch ( modeName )
	{
		case "aitdm":
		case "at":
			return true
	}
	
	if ( modeName.find( "fd" ) == 0 ) // bob edit: unsure if this keeps vanilla compatibility, but just make sure fd modes are counted as requiring ai
		return true

	return false
}

#if !CLIENT
string function PrivateMatch_GetSelectedMap()
{
	var mapIndex = level.ui.privatematch_map
	string mapName = GetPrivateMatchMapForIndex( expect int(mapIndex) )

	return mapName
}


string function PrivateMatch_GetSelectedMode()
{
	var modeIndex = level.ui.privatematch_mode
	string modeName = GetPrivateMatchModeForIndex( expect int(modeIndex) )

	return modeName
}
#endif

bool function PrivateMatch_IsValidMapModeCombo( string mapName, string modeName )
{
	array<string> mapsForMode = GetPrivateMatchMapsForMode( modeName )

	return mapsForMode.contains( mapName )
}

// end private match stuff

int function Player_GetMaxMatchmakingDelay( entity player )
{
	//	return GetCurrentPlaylistVarInt( "matchmaking_delay", 0 )
	return 300
}

int function Player_GetRemainingMatchmakingDelay( entity player )
{
	int lastLeaveTime = player.GetPersistentVarAsInt( PERSISTENCE_LAST_LEAVE_TIME )

	return Player_GetMaxMatchmakingDelay( player ) - (GetCurrentTimeForPersistence() - lastLeaveTime)
}

int function Player_NextAvailableMatchmakingTime( entity player )
{
	#if MP
	int lastLeaveTime = player.GetPersistentVarAsInt( PERSISTENCE_LAST_LEAVE_TIME )
	if ( GetCurrentTimeForPersistence() - lastLeaveTime < Player_GetMaxMatchmakingDelay( player ) )
	{
		return Player_GetRemainingMatchmakingDelay(	player )
	}
	#endif

	return 0
}

int function GetCurrentTimeForPersistence()
{
	// Returns the unix timestap offset to the timezone we want to use
	return GetUnixTimestamp() + DAILY_RESET_TIME_ZONE_OFFSET * SECONDS_PER_HOUR
}
