class SetControllerLightColorRequest extends ScriptableSystemRequest
{
	editable var red : Uint8;
	editable var green : Uint8;
	editable var blue : Uint8;
	var notQuest : Bool;
}

class ResetControllerLightColorRequest extends ScriptableSystemRequest
{
	var notQuest : Bool;
}

class LerpToDefaultControllerLightColorRequest extends ScriptableSystemRequest
{
	var notQuest : Bool;
}

class LerpToColorControllerLightRequest extends ScriptableSystemRequest
{
	editable var rgb : Vector3;
	editable var timeToLerp : Float;
	editable var useExponentialCurve : Bool;
}

class ColorLerpTickRequest extends ScriptableSystemRequest
{
}

class PoliceSirenTimerRequest extends ScriptableSystemRequest
{
	var red : Bool;
	var fast : Bool;
	var abort : Bool;
}

class VehicleAboutToExplodeTimerRequest extends ScriptableSystemRequest
{
	var red : Bool;
	var speed : Float;
	var abort : Bool;
}

importonly abstract class IGamepadLightController extends IGameSystem
{
}

import class GamepadLightController extends IGamepadLightController
{
	public import function SetControllerColor( r : Uint8, g : Uint8, b : Uint8 );
	public import function ResetControllerColor();
}

enum ELightState
{
	Reset = 0,
	DefaultColor = 1,
	Police = 2,
	VehicleHealth_Low = 3,
	VehicleHealth_VeryLow = 4,
	Quest = 5,
}

class GamepadLightScriptableSystem extends ScriptableSystem
{
	private persistent var m_controllerCurrentColor : Vector3;
	private var m_controllerStartColor : Vector3;
	private persistent var m_controllerTargetColor : Vector3;
	private persistent var m_currentProgress : Float;
	private persistent var m_useExponentialCurve : Bool;
	private persistent var m_prevTime : Float;
	private persistent var m_currentState : ELightState;
	private persistent var m_prevState : ELightState;
	private persistent var m_timeLimit : Float;
	private var m_currrentId : DelayID;

	private override function OnRestored( saveVersion : Int32, gameVersion : Int32 )
	{
		var lerpEvent : LerpToColorControllerLightRequest;
		var setEvent : SetControllerLightColorRequest;
		setEvent = new SetControllerLightColorRequest;
		setEvent.red = ( ( Uint8 )( m_controllerCurrentColor.X ) );
		setEvent.green = ( ( Uint8 )( m_controllerCurrentColor.Y ) );
		setEvent.blue = ( ( Uint8 )( m_controllerCurrentColor.Z ) );
		OnSetControllerLightColorRequest( setEvent );
		if( ( m_currentProgress > 0.01 ) && ( m_currentProgress < 0.89999998 ) )
		{
			lerpEvent = new LerpToColorControllerLightRequest;
			lerpEvent.rgb = m_controllerTargetColor;
			lerpEvent.timeToLerp = m_timeLimit * ( 1.0 - m_currentProgress );
			lerpEvent.useExponentialCurve = m_useExponentialCurve;
			OnLerpToColorControllerLightRequest( lerpEvent );
		}
	}

	protected function OnSetControllerLightColorRequest( evt : SetControllerLightColorRequest )
	{
		var gamepadLightController : GamepadLightController;
		gamepadLightController = GameInstance.GetGamepadLightController( GetGameInstance() );
		m_controllerCurrentColor = Vector3( evt.red, evt.green, evt.blue );
		gamepadLightController.SetControllerColor( evt.red, evt.green, evt.blue );
	}

	protected function OnResetControllerLightColorRequest( evt : ResetControllerLightColorRequest )
	{
		ChangeState( ELightState.Reset );
		m_controllerCurrentColor = Vector3( 0.0, 0.0, 0.0 );
		GameInstance.GetGamepadLightController( GetGameInstance() ).ResetControllerColor();
	}

	protected function OnLerpToDefaultControllerLightColorRequest( evt : LerpToDefaultControllerLightColorRequest )
	{
		var lerpEvt : LerpToColorControllerLightRequest;
		lerpEvt = new LerpToColorControllerLightRequest;
		lerpEvt.rgb = Vector3( 0.0, 0.0, 0.0 );
		lerpEvt.timeToLerp = 1.0;
		lerpEvt.useExponentialCurve = true;
		OnLerpToColorControllerLightRequest( lerpEvt );
	}

	protected function OnLerpToColorControllerLightRequest( evt : LerpToColorControllerLightRequest )
	{
		var gamepadLightController : GamepadLightController;
		var newR : Uint8;
		var newG : Uint8;
		var newB : Uint8;
		gamepadLightController = GameInstance.GetGamepadLightController( GetGameInstance() );
		if( m_currrentId != DelayID.GetInvalidDelayID() )
		{
			m_currrentId = DelayID.GetInvalidDelayID();
			m_controllerCurrentColor = m_controllerTargetColor;
			m_useExponentialCurve = false;
			newR = ( ( Uint8 )( m_controllerCurrentColor.X ) );
			newG = ( ( Uint8 )( m_controllerCurrentColor.Y ) );
			newB = ( ( Uint8 )( m_controllerCurrentColor.Z ) );
			gamepadLightController.SetControllerColor( newR, newG, newB );
			GameInstance.GetDelaySystem( GetGameInstance() ).CancelCallback( m_currrentId );
		}
		m_currentProgress = 0.0;
		m_timeLimit = evt.timeToLerp;
		m_controllerStartColor = m_controllerCurrentColor;
		m_controllerTargetColor = evt.rgb;
		m_useExponentialCurve = evt.useExponentialCurve;
		OnColorLerpTickRequest( NULL );
	}

	private function OnColorLerpTickRequest( evt : ColorLerpTickRequest )
	{
		var gamepadLightController : GamepadLightController;
		var delta : Float;
		var request : ColorLerpTickRequest;
		var tempProgress : Float;
		var newR : Uint8;
		var newG : Uint8;
		var newB : Uint8;
		gamepadLightController = GameInstance.GetGamepadLightController( GetGameInstance() );
		delta = 0.01;
		if( m_currentProgress > 1.0 )
		{
			m_currrentId = DelayID.GetInvalidDelayID();
			m_controllerCurrentColor = m_controllerTargetColor;
			m_useExponentialCurve = false;
			newR = ( ( Uint8 )( m_controllerCurrentColor.X ) );
			newG = ( ( Uint8 )( m_controllerCurrentColor.Y ) );
			newB = ( ( Uint8 )( m_controllerCurrentColor.Z ) );
			gamepadLightController.SetControllerColor( newR, newG, newB );
			return;
		}
		if( evt )
		{
			delta = EngineTime.ToFloat( GameInstance.GetSimTime( GetGameInstance() ) ) - m_prevTime;
		}
		m_prevTime = EngineTime.ToFloat( GameInstance.GetSimTime( GetGameInstance() ) );
		m_currentProgress += ( delta / m_timeLimit );
		tempProgress = ( ( m_currentProgress > 1.0 ) ? ( 1.0 ) : ( ( ( m_currentProgress < 0.0 ) ? ( 0.0 ) : ( m_currentProgress ) ) ) );
		if( m_useExponentialCurve )
		{
			m_controllerCurrentColor = Vector3.Lerp( m_controllerStartColor, m_controllerTargetColor, ExponentialEaseInAndOut( tempProgress ) );
		}
		else
		{
			m_controllerCurrentColor = Vector3.Lerp( m_controllerStartColor, m_controllerTargetColor, tempProgress );
		}
		newR = ( ( Uint8 )( m_controllerCurrentColor.X ) );
		newG = ( ( Uint8 )( m_controllerCurrentColor.Y ) );
		newB = ( ( Uint8 )( m_controllerCurrentColor.Z ) );
		gamepadLightController.SetControllerColor( newR, newG, newB );
		request = new ColorLerpTickRequest;
		m_currrentId = GameInstance.GetDelaySystem( GetGameInstance() ).DelayScriptableSystemRequest( 'GamepadLightScriptableSystem', request, delta );
	}

	private function ExponentialEaseInAndOut( x : Float ) : Float
	{
		var epsilon : Float;
		epsilon = 0.001;
		if( x > 1.0 )
		{
			x = 1.0;
		}
		if( x < 0.0 )
		{
			x = 0.0;
		}
		return ( ( AbsF( x ) < epsilon ) ? ( 0.0 ) : ( ( ( AbsF( x - 1.0 ) < epsilon ) ? ( 1.0 ) : ( ( ( x < 0.5 ) ? ( PowF( 2.0, ( 20.0 * x ) - 10.0 ) / 2.0 ) : ( ( 2.0 - PowF( 2.0, ( -20.0 * x ) + 10.0 ) ) / 2.0 ) ) ) ) ) );
	}

	private function ChangeState( newState : ELightState ) : Bool
	{
		if( m_currentState == newState )
		{
			return false;
		}
		if( ( m_currentState == ELightState.Reset || m_currentState == ELightState.DefaultColor ) || newState == ELightState.Quest )
		{
			m_prevState = m_currentState;
			m_currentState = newState;
			return true;
		}
		if( m_currentState == ELightState.Quest )
		{
			return false;
		}
		if( newState == ELightState.Police && m_currentState == ELightState.VehicleHealth_VeryLow )
		{
			return false;
		}
		m_prevState = m_currentState;
		m_currentState = newState;
		return true;
	}

	public static function UpdatePoliceSiren( gi : GameInstance, heatStage : EPreventionHeatStage )
	{
		var siren : PoliceSirenTimerRequest;
		var gamepadLightScriptableSystem : GamepadLightScriptableSystem;
		siren = new PoliceSirenTimerRequest;
		gamepadLightScriptableSystem = ( ( GamepadLightScriptableSystem )( GameInstance.GetScriptableSystemsContainer( gi ).Get( 'GamepadLightScriptableSystem' ) ) );
		if( heatStage == EPreventionHeatStage.Heat_0 )
		{
			if( gamepadLightScriptableSystem.ChangeState( ELightState.DefaultColor ) )
			{
				gamepadLightScriptableSystem.OnResetControllerLightColorRequest( NULL );
			}
			return;
		}
		if( !( gamepadLightScriptableSystem.ChangeState( ELightState.Police ) ) )
		{
			return;
		}
		siren.red = true;
		siren.fast = true;
		siren.abort = false;
		gamepadLightScriptableSystem.OnPoliceSirenTimerRequest( siren );
	}

	private function OnPoliceSirenTimerRequest( siren : PoliceSirenTimerRequest )
	{
		var lerp : LerpToColorControllerLightRequest;
		var preventionSystem : PreventionSystem;
		lerp = new LerpToColorControllerLightRequest;
		preventionSystem = ( ( PreventionSystem )( GameInstance.GetScriptableSystemsContainer( GetGameInstance() ).Get( 'PreventionSystem' ) ) );
		siren.red = !( siren.red );
		siren.abort = m_currentState != ELightState.Police;
		siren.fast = !( preventionSystem.IsPoliceUnawareOfThePlayerExactLocation() );
		if( siren.abort )
		{
			OnResetControllerLightColorRequest( NULL );
			return;
		}
		lerp.timeToLerp = 0.30000001;
		lerp.rgb = ( ( siren.red ) ? ( Vector3( 255.0, 0.0, 0.0 ) ) : ( Vector3( 0.0, 0.0, 255.0 ) ) );
		lerp.useExponentialCurve = true;
		OnLerpToColorControllerLightRequest( lerp );
		GameInstance.GetDelaySystem( GetGameInstance() ).DelayScriptableSystemRequest( 'GamepadLightScriptableSystem', siren, ( ( siren.fast ) ? ( 0.31 ) : ( 0.62 ) ) );
	}

	public static function TriggerVehicleExplosionWarningSiren( gi : GameInstance )
	{
		var request : VehicleAboutToExplodeTimerRequest;
		var gamepadLightScriptableSystem : GamepadLightScriptableSystem;
		gamepadLightScriptableSystem = ( ( GamepadLightScriptableSystem )( GameInstance.GetScriptableSystemsContainer( gi ).Get( 'GamepadLightScriptableSystem' ) ) );
		if( !( gamepadLightScriptableSystem.ChangeState( ELightState.VehicleHealth_Low ) ) )
		{
			return;
		}
		request = new VehicleAboutToExplodeTimerRequest;
		request.red = true;
		request.speed = 0.30000001;
		gamepadLightScriptableSystem.OnVehicleAboutToExplodeTimerRequest( request );
	}

	private function OnVehicleAboutToExplodeTimerRequest( eminentExplosion : VehicleAboutToExplodeTimerRequest )
	{
		var preventionSystem : PreventionSystem;
		var lerp : LerpToColorControllerLightRequest;
		var player : PlayerPuppet;
		var playerVehicle : weak< VehicleObject >;
		var vehicleDamage : Int32;
		preventionSystem = ( ( PreventionSystem )( GameInstance.GetScriptableSystemsContainer( GetGameInstance() ).Get( 'PreventionSystem' ) ) );
		lerp = new LerpToColorControllerLightRequest;
		player = GetPlayer( GetGameInstance() );
		VehicleComponent.GetVehicle( player.GetGame(), player.GetEntityID(), playerVehicle );
		eminentExplosion.red = !( eminentExplosion.red );
		if( eminentExplosion.red && ( eminentExplosion.speed > 0.1 ) )
		{
			eminentExplosion.speed -= 0.09;
		}
		if( playerVehicle )
		{
			vehicleDamage = playerVehicle.GetBlackboard().GetInt( GetAllBlackboardDefs().Vehicle.DamageState );
			eminentExplosion.abort = vehicleDamage < 2;
		}
		else
		{
			eminentExplosion.abort = true;
		}
		if( eminentExplosion.abort )
		{
			OnResetControllerLightColorRequest( NULL );
			UpdatePoliceSiren( GetGameInstance(), preventionSystem.GetHeatStage() );
			return;
		}
		lerp.timeToLerp = eminentExplosion.speed;
		lerp.rgb = ( ( eminentExplosion.red ) ? ( Vector3( 255.0, 0.0, 0.0 ) ) : ( Vector3( 0.0, 0.0, 0.0 ) ) );
		lerp.useExponentialCurve = true;
		OnLerpToColorControllerLightRequest( lerp );
		GameInstance.GetDelaySystem( GetGameInstance() ).DelayScriptableSystemRequest( 'GamepadLightScriptableSystem', eminentExplosion, ( ( ( ( Bool )eminentExplosion.speed ) ) ? ( 0.30000001 ) : ( 0.1 ) ) );
	}

}

