class GameSessionDataSystem extends ScriptableSystem
{
	private var m_gameSessionDataModules : array< GameSessionDataModule >;

	private const function GetModule( dataType : EGameSessionDataType ) : GameSessionDataModule
	{
		var i : Int32;
		for( i = 0; i < m_gameSessionDataModules.Size(); i += 1 )
		{
			if( m_gameSessionDataModules[ i ].GetModuleType() == dataType )
			{
				return m_gameSessionDataModules[ i ];
			}
		}
		return NULL;
	}

	private export override function OnAttach()
	{
		Initialize();
	}

	private export override function OnDetach()
	{
		Uninitialize();
	}

	private function Initialize()
	{
		var cameraDeadBodyModule : CameraDeadBodySessionDataModule;
		var cameraTagLimitModule : CameraTagEnemyLimitDataModule;
		cameraDeadBodyModule = new CameraDeadBodySessionDataModule;
		cameraDeadBodyModule.Initialize();
		m_gameSessionDataModules.PushBack( cameraDeadBodyModule );
		cameraTagLimitModule = new CameraTagEnemyLimitDataModule;
		cameraTagLimitModule.Initialize();
		m_gameSessionDataModules.PushBack( cameraTagLimitModule );
	}

	private function Uninitialize()
	{
		var i : Int32;
		for( i = 0; i < m_gameSessionDataModules.Size(); i += 1 )
		{
			m_gameSessionDataModules[ i ].Uninitialize();
		}
	}

	public static function AddDataEntryRequest( context : GameInstance, dataType : EGameSessionDataType, data : Variant )
	{
		var gameSessionDataSystem : GameSessionDataSystem;
		var dataEntryRequest : DataEntryRequest;
		gameSessionDataSystem = ( ( GameSessionDataSystem )( GameInstance.GetScriptableSystemsContainer( context ).Get( 'GameSessionDataSystem' ) ) );
		if( gameSessionDataSystem )
		{
			dataEntryRequest = new DataEntryRequest;
			dataEntryRequest.dataType = dataType;
			dataEntryRequest.data = data;
			gameSessionDataSystem.QueueRequest( dataEntryRequest );
		}
	}

	private export function OnDataEntryRequest( request : DataEntryRequest )
	{
		if( IsDataValid( request.dataType, request.data ) )
		{
			GetModule( request.dataType ).AddEntry( request.data );
		}
		if( !( IsFinal() ) )
		{
			RefreshDebug();
		}
	}

	public static function CheckDataRequest( context : GameInstance, dataType : EGameSessionDataType, dataHelper : Variant ) : Bool
	{
		var gameSessionDataSystem : GameSessionDataSystem;
		var module : GameSessionDataModule;
		gameSessionDataSystem = ( ( GameSessionDataSystem )( GameInstance.GetScriptableSystemsContainer( context ).Get( 'GameSessionDataSystem' ) ) );
		if( gameSessionDataSystem )
		{
			module = gameSessionDataSystem.GetModule( dataType );
			if( module )
			{
				return module.CheckData( dataHelper );
			}
			return false;
		}
		return false;
	}

	protected function IsDataValid( dataType : EGameSessionDataType, data : Variant ) : Bool
	{
		var module : GameSessionDataModule;
		module = GetModule( dataType );
		if( module )
		{
			return module.IsDataValid( data );
		}
		return false;
	}

	private function RefreshDebug()
	{
		var i : Int32;
		for( i = 0; i < m_gameSessionDataModules.Size(); i += 1 )
		{
			m_gameSessionDataModules[ i ].RefreshDebug( GetGameInstance() );
		}
	}

}

class DataEntryRequest extends ScriptableSystemRequest
{
	var dataType : EGameSessionDataType;
	var data : Variant;
}

enum EGameSessionDataType
{
	NONE = 0,
	CameraDeadBody = 1,
	CameraTagLimit = 2,
}

class GameSessionDataModule
{
	protected var m_moduleType : EGameSessionDataType;

	public virtual function Initialize() {}

	public virtual function Uninitialize() {}

	public const function GetModuleType() : EGameSessionDataType
	{
		return m_moduleType;
	}

	public const virtual function IsDataValid( data : Variant ) : Bool
	{
		return false;
	}

	public virtual function AddEntry( data : Variant ) {}

	public const virtual function CheckData( data : Variant ) : Bool
	{
		return false;
	}

	public virtual function RefreshDebug( context : GameInstance ) {}
}

class CameraDeadBodySessionDataModule extends GameSessionDataModule
{
	var m_cameraDeadBodyData : array< CameraDeadBodyInternalData >;

	public override function Initialize()
	{
		m_moduleType = EGameSessionDataType.CameraDeadBody;
	}

	public const override function IsDataValid( data : Variant ) : Bool
	{
		var castedData : CameraDeadBodyData;
		castedData = ( ( CameraDeadBodyData )data );
		if( !( castedData ) )
		{
			return false;
		}
		if( EntityID.IsDefined( castedData.ownerID ) && EntityID.IsDefined( castedData.bodyID ) )
		{
			return true;
		}
		return false;
	}

	public override function AddEntry( data : Variant )
	{
		var i : Int32;
		var castedData : CameraDeadBodyData;
		var newEntry : CameraDeadBodyInternalData;
		castedData = ( ( CameraDeadBodyData )data );
		if( !( castedData ) )
		{
			return;
		}
		for( i = 0; i < m_cameraDeadBodyData.Size(); i += 1 )
		{
			if( m_cameraDeadBodyData[ i ].m_ownerID == castedData.ownerID )
			{
				m_cameraDeadBodyData[ i ].AddEntry( castedData.bodyID );
				return;
			}
		}
		newEntry = new CameraDeadBodyInternalData;
		newEntry.m_ownerID = castedData.ownerID;
		newEntry.AddEntry( castedData.bodyID );
		m_cameraDeadBodyData.PushBack( newEntry );
	}

	public const override function CheckData( data : Variant ) : Bool
	{
		var castedData : CameraDeadBodyData;
		var i : Int32;
		castedData = ( ( CameraDeadBodyData )data );
		for( i = 0; i < m_cameraDeadBodyData.Size(); i += 1 )
		{
			if( m_cameraDeadBodyData[ i ].m_ownerID == castedData.ownerID )
			{
				return m_cameraDeadBodyData[ i ].ContainsEntry( castedData.bodyID );
			}
		}
		return false;
	}

	public override function RefreshDebug( context : GameInstance )
	{
		var i, i1 : Int32;
		var sink : SDOSink;
		sink = GameInstance.GetScriptsDebugOverlaySystem( context ).CreateSink();
		SDOSink.SetRoot( sink, "GameSessionData/CameraDeadBody" );
		for( i = 0; i < m_cameraDeadBodyData.Size(); i += 1 )
		{
			for( i1 = 0; i1 < m_cameraDeadBodyData[ i ].m_bodyIDs.Size(); i1 += 1 )
			{
				SDOSink.PushString( sink, ( EntityID.ToDebugString( m_cameraDeadBodyData[ i ].m_ownerID ) + "/" ) + i1, EntityID.ToDebugString( m_cameraDeadBodyData[ i ].m_bodyIDs[ i1 ] ) );
			}
		}
	}

}

class CameraDeadBodyInternalData
{
	var m_ownerID : EntityID;
	var m_bodyIDs : array< EntityID >;

	public function AddEntry( entryID : EntityID )
	{
		if( !( m_bodyIDs.Contains( entryID ) ) )
		{
			m_bodyIDs.PushBack( entryID );
		}
	}

	public function ContainsEntry( entryID : EntityID ) : Bool
	{
		return m_bodyIDs.Contains( entryID );
	}

}

class CameraDeadBodyData
{
	var dataType : EGameSessionDataType;
	var ownerID : EntityID;
	var bodyID : EntityID;
}

class CameraTagEnemyLimitDataModule extends GameSessionDataModule
{
	var m_cameraLimit : Int32;
	default m_cameraLimit = 5;
	var m_cameraList : array< weak< SurveillanceCamera > >;

	public override function Initialize()
	{
		m_moduleType = EGameSessionDataType.CameraTagLimit;
	}

	public override function Uninitialize() {}

	public const override function IsDataValid( data : Variant ) : Bool
	{
		var castedData : CameraTagLimitData;
		castedData = ( ( CameraTagLimitData )data );
		if( !( castedData ) )
		{
			return false;
		}
		if( castedData.object )
		{
			return true;
		}
		return false;
	}

	public override function AddEntry( data : Variant )
	{
		var castedData : CameraTagLimitData;
		castedData = ( ( CameraTagLimitData )data );
		CleanupNulls();
		if( castedData.add )
		{
			if( !( m_cameraList.Contains( castedData.object ) ) )
			{
				if( m_cameraList.Size() == m_cameraLimit )
				{
					SendCameraTagLockEvent( 0 );
					m_cameraList.Erase( 0 );
				}
				m_cameraList.PushBack( castedData.object );
			}
		}
		else
		{
			if( m_cameraList.Remove( castedData.object ) )
			{
			}
		}
	}

	private function CleanupNulls()
	{
		var i : Int32;
		for( i = m_cameraList.Size() - 1; i >= 0; i -= 1 )
		{
			if( m_cameraList[ i ] == NULL )
			{
				m_cameraList.Erase( i );
			}
		}
	}

	private function SendCameraTagLockEvent( index : Int32 )
	{
		var evt : CameraTagLockEvent;
		evt = new CameraTagLockEvent;
		evt.isLocked = true;
		m_cameraList[ index ].QueueEvent( evt );
	}

	public const override function CheckData( data : Variant ) : Bool
	{
		if( ( ( SurveillanceCamera )data ) )
		{
			return m_cameraList.Contains( ( ( SurveillanceCamera )data ) );
		}
		return false;
	}

	public override function RefreshDebug( context : GameInstance )
	{
		var i : Int32;
		var sink : SDOSink;
		sink = GameInstance.GetScriptsDebugOverlaySystem( context ).CreateSink();
		SDOSink.SetRoot( sink, "GameSessionData/CameraTagLimit" );
		SDOSink.PushInt32( sink, "Limit", m_cameraLimit );
		for( i = 0; i < m_cameraLimit; i += 1 )
		{
			if( i < m_cameraList.Size() )
			{
				SDOSink.PushString( sink, "-" + i, EntityID.ToDebugString( m_cameraList[ i ].GetEntityID() ) );
			}
			else
			{
				SDOSink.PushString( sink, "-" + i, "NONE" );
			}
		}
	}

}

class CameraTagLimitData
{
	var add : Bool;
	var object : weak< SurveillanceCamera >;
}

class CameraTagLockEvent extends Event
{
	var isLocked : Bool;
}

