class VehicleColorSelectionInitFinishedEvent extends Event
{
}

class VehicleColorSelectionSliderHoldEvent extends Event
{
	var direction : Int32;
}

class VehicleColorSelectionUpdateEvent extends Event
{
}

struct vehicleColorSelectorPointerDef
{
	editable var m_pointerRoot : inkWidgetRef;
	editable var m_pointerCircleRadius : Float;
	editable var m_paintOnSelection : Bool;
	editable var m_partToPaint : inkWidgetRef;
}

enum vehicleColorSelectorActiveMode
{
	None = 0,
	Primary = 1,
	Secondary = 2,
	Lights = 3,
}

enum vehicleColorSelectorMenuCloseReason
{
	Apply = 0,
	Reset = 1,
	Cancel = 2,
}

class vehicleColorSelectorGameController extends inkGameController
{
	private editable var m_CursorRootContainerRef : inkWidgetRef;
	private editable var m_CursorRootOffsetPoint : inkWidgetRef;
	private editable var m_colorPaletteRef : inkWidgetRef;
	private editable var m_stickerPaletteRef : inkWidgetRef;
	editable var m_colorWheelColorA : inkWidgetRef;
	editable var m_colorWheelColorB : inkWidgetRef;
	editable var m_colorWheelColorLights : inkWidgetRef;
	private editable var m_colorPickerA : vehicleColorSelectorPointerDef;
	private editable var m_selectedColorPointerA : vehicleColorSelectorPointerDef;
	private editable var m_colorPickerB : vehicleColorSelectorPointerDef;
	private editable var m_selectedColorPointerB : vehicleColorSelectorPointerDef;
	private editable var m_colorPickerLights : vehicleColorSelectorPointerDef;
	private editable var m_selectedColorPointerLights : vehicleColorSelectorPointerDef;
	private editable var m_mouseHitColor1Ref : inkWidgetRef;
	private editable var m_mouseHitColor2Ref : inkWidgetRef;
	private editable var m_mouseHitLightsRef : inkWidgetRef;
	private editable var m_targetColorPrintA : inkWidgetRef;
	private editable var m_targetColorPrintB : inkWidgetRef;
	private const editable var m_targetColorPrintLights : array< inkWidgetRef >;
	protected var m_timeDilationProfile : String;
	default m_timeDilationProfile = "radialMenu";
	private var m_introAnimation : CName;
	default m_introAnimation = 'Intro';
	private var m_cancelAnimation : CName;
	default m_cancelAnimation = 'Cancel';
	private var m_applyAnimation : CName;
	default m_applyAnimation = 'Apply';
	private editable var m_titleTextMain : inkTextRef;
	private editable var m_titleTextNumber : inkTextRef;
	private editable var m_brightnessBarContainer : inkWidgetRef;
	private editable var m_brightnessBarFill : inkWidgetRef;
	private editable var m_brightnessPointer : inkWidgetRef;
	private editable var m_sliderInputHintUp : inkWidgetRef;
	private editable var m_sliderInputHintDown : inkWidgetRef;
	private editable var m_modeChangeBack : inkWidgetRef;
	private editable var m_modeChangeNext : inkWidgetRef;
	private editable var m_applyContainerWidget : inkWidgetRef;
	private editable var m_resetContainerWidget : inkWidgetRef;
	private editable var m_vehicleUnknownPane : inkWidgetRef;
	private editable var m_vehicleBrandIcon : inkImageRef;
	protected var m_popupData : inkGameNotificationData;
	private var m_systemRequestsHandler : weak< inkISystemRequestsHandler >;
	private var m_player : weak< PlayerPuppet >;
	private var m_gameInstance : GameInstance;
	private var m_timeSystem : TimeSystem;
	private var m_vehicle : weak< VehicleObject >;
	private var m_vvcComponent : weak< vehicleVisualCustomizationComponent >;
	private var m_animProxy : inkAnimProxy;
	private var m_fakeUpdateProxy : inkAnimProxy;
	private var m_SBBarProxy : inkAnimProxy;
	private var m_LightsFocusProxy : inkAnimProxy;
	private var m_stickersPage : weak< inkWidget >;
	private var m_isInMenuCallbackID : CallbackHandle;
	private var m_activeMode : vehicleColorSelectorActiveMode;
	default m_activeMode = vehicleColorSelectorActiveMode.Primary;
	private var m_previousMode : vehicleColorSelectorActiveMode;
	private var m_currentAngle : Float;
	private var m_colorADefined : Bool;
	private var m_colorBDefined : Bool;
	private var m_lightsDefined : Bool;
	private var m_targetColorAngleA : Float;
	private var m_targetColorAngleB : Float;
	private var m_targetColorAngleLights : Float;
	private var m_targetColorASaturation : Float;
	private var m_targetColorBSaturation : Float;
	private var m_targetColorABrightness : Float;
	private var m_targetColorBBrightness : Float;
	private var m_axisInputCache : Vector2;
	private var m_inputEnabled : Bool;
	default m_inputEnabled = false;
	private var m_sbBarShown : Bool;
	private var m_sbSliderLenght : Float;
	default m_sbSliderLenght = 756.0f;
	private var m_axisInputThreshold : Float;
	default m_axisInputThreshold = 0.1;
	private var m_currentSBSliderPositionA : Float;
	private var m_currentSBSliderPositionB : Float;
	private var m_mouseInputEnabled : Bool;
	private var m_hoveredOver : Bool;
	default m_hoveredOver = false;
	private var m_SBSliderStepPad : Float;
	default m_SBSliderStepPad = 18.0f;
	private var m_SBSliderStepMouse : Float;
	default m_SBSliderStepMouse = 18.0f;
	private var m_sliderHold : Bool;
	private var m_sliderHoldDamp : Int32;
	private var m_sliderPadHoldAccelerationTreshhold : Int32;
	default m_sliderPadHoldAccelerationTreshhold = 50;
	private var m_storedSelectedColorID : Int32;
	private var m_cachedNewColorA : Color;
	private var m_cachedNewColorB : Color;
	private var m_cachedNewColorLights : Color;
	private var m_CloseReason : vehicleColorSelectorMenuCloseReason;
	private var m_unsupportedVehicle : Bool;

	protected event OnInitialize()
	{
		var initEvent : VehicleColorSelectionInitFinishedEvent;
		var lightsEvent : VehicleLightQuestToggleEvent;
		var deadzoneConfig : ConfigVarFloat;
		var uiSystemBB : IBlackboard;
		m_popupData = ( ( inkGameNotificationData )( GetRootWidget().GetUserData( 'inkGameNotificationData' ) ) );
		m_player = ( ( PlayerPuppet )( GetPlayerControlledObject() ) );
		m_player.RegisterInputListener( this, '__DEVICE_CHANGED__' );
		m_gameInstance = m_player.GetGame();
		m_vehicle = m_player.GetMountedVehicle();
		m_vvcComponent = m_player.GetVehicleVisualCustomizationComponent();
		m_currentSBSliderPositionA = 0.0;
		m_currentSBSliderPositionB = 0.0;
		uiSystemBB = GetBlackboardSystem().Get( GetAllBlackboardDefs().UI_System );
		m_isInMenuCallbackID = uiSystemBB.RegisterDelayedListenerBool( GetAllBlackboardDefs().UI_System.IsInMenu, this, 'OnIsInMenuChanged' );
		deadzoneConfig = ( ( ConfigVarFloat )( GameInstance.GetSettingsSystem( m_player.GetGame() ).GetVar( '/controls', 'Axis_DeadzoneInner' ) ) );
		m_axisInputThreshold = deadzoneConfig.GetValue();
		RegisterToGlobalInputCallback( 'OnPostOnRelease', this, 'OnGlobalInputReleased' );
		RegisterToGlobalInputCallback( 'OnPostOnPress', this, 'OnGlobalPressInput' );
		RegisterToGlobalInputCallback( 'OnPostOnRelative', this, 'OnMouseInput' );
		RegisterToGlobalInputCallback( 'OnPostOnAxis', this, 'OnGlobalAxisInput' );
		inkWidgetRef.RegisterToCallback( m_mouseHitColor1Ref, 'OnHoverOver', this, 'OnHoverOverColorWheel1' );
		inkWidgetRef.RegisterToCallback( m_mouseHitColor2Ref, 'OnHoverOver', this, 'OnHoverOverColorWheel2' );
		inkWidgetRef.RegisterToCallback( m_mouseHitLightsRef, 'OnHoverOver', this, 'OnHoverOverColorWheelLights' );
		inkWidgetRef.RegisterToCallback( m_mouseHitColor1Ref, 'OnHoverOut', this, 'OnHoverOutColorWheel1' );
		inkWidgetRef.RegisterToCallback( m_mouseHitColor2Ref, 'OnHoverOut', this, 'OnHoverOutColorWheel2' );
		inkWidgetRef.RegisterToCallback( m_mouseHitLightsRef, 'OnHoverOut', this, 'OnHoverOutColorWheelLights' );
		SetTimeDilatation( true );
		UpdateVehicleManufacturer();
		PlayAnimation( m_introAnimation );
		m_animProxy.RegisterToCallback( inkanimEventType.OnFinish, this, 'OnIntroFinished' );
		GameInstance.GetAudioSystem( m_gameInstance ).Play( 'ui_menu_open' );
		initEvent = new VehicleColorSelectionInitFinishedEvent;
		lightsEvent = new VehicleLightQuestToggleEvent;
		lightsEvent.toggle = true;
		m_vehicle.QueueEvent( lightsEvent );
		ProcessFakeUpdate( true );
		QueueEvent( initEvent );
	}

	protected event OnUninitialize()
	{
		UnregisterFromGlobalInputCallback( 'OnPostOnRelease', this, 'OnGlobalInputReleased' );
		UnregisterFromGlobalInputCallback( 'OnPostOnPress', this, 'OnGlobalPress' );
		UnregisterFromGlobalInputCallback( 'OnPostOnRelative', this, 'OnMouseInput' );
		UnregisterFromGlobalInputCallback( 'OnPostOnAxis', this, 'OnGlobalAxisInput' );
		ProcessFakeUpdate( false );
		SetTimeDilatation( false );
	}

	protected event OnVehicleColorSelectionInitFinishedEvent( e : VehicleColorSelectionInitFinishedEvent )
	{
		if( m_player.PlayerLastUsedKBM() )
		{
			SetCursorVisibility( true );
		}
		else
		{
			SetCursorVisibility( false );
		}
	}

	private function UpdateActiveModeBasedOnCursorPosition()
	{
		var hoverWidget : inkWidget;
		hoverWidget = GameInstance.GetUISystem( m_player.GetGame() ).GetInteractableWidgetUnderCursor();
		if( hoverWidget == inkWidgetRef.Get( m_mouseHitLightsRef ) )
		{
			SwitchActiveMode( 0, vehicleColorSelectorActiveMode.Lights );
			m_hoveredOver = true;
			m_mouseInputEnabled = true;
			return;
		}
		if( hoverWidget == inkWidgetRef.Get( m_mouseHitColor1Ref ) )
		{
			SwitchActiveMode( 0, vehicleColorSelectorActiveMode.Primary );
			m_hoveredOver = true;
			m_mouseInputEnabled = true;
			return;
		}
		if( hoverWidget == inkWidgetRef.Get( m_mouseHitColor2Ref ) )
		{
			SwitchActiveMode( 0, vehicleColorSelectorActiveMode.Secondary );
			m_hoveredOver = true;
			m_mouseInputEnabled = true;
			return;
		}
		SwitchActiveMode( 0, vehicleColorSelectorActiveMode.Primary );
		m_hoveredOver = false;
		m_mouseInputEnabled = false;
	}

	protected event OnIntroFinished( proxy : inkAnimProxy )
	{
		m_inputEnabled = true;
		ProcessPreviousCustomizationState();
		if( VerifyVehicleValidity() == true )
		{
			UpdateActiveModeBasedOnCursorPosition();
		}
	}

	protected event OnHoverOverColorWheel1( evt : inkPointerEvent )
	{
		if( !( m_inputEnabled ) )
		{
			return false;
		}
		SwitchActiveMode( 0, vehicleColorSelectorActiveMode.Primary );
		m_hoveredOver = true;
		m_mouseInputEnabled = true;
		GameInstance.GetAudioSystem( m_gameInstance ).Play( 'ui_menu_hover' );
	}

	protected event OnHoverOverColorWheel2( evt : inkPointerEvent )
	{
		if( !( m_inputEnabled ) )
		{
			return false;
		}
		SwitchActiveMode( 0, vehicleColorSelectorActiveMode.Secondary );
		m_hoveredOver = true;
		m_mouseInputEnabled = true;
		GameInstance.GetAudioSystem( m_gameInstance ).Play( 'ui_menu_hover' );
	}

	protected event OnHoverOverColorWheelLights( evt : inkPointerEvent )
	{
		if( !( m_inputEnabled ) )
		{
			return false;
		}
		SwitchActiveMode( 0, vehicleColorSelectorActiveMode.Lights );
		m_hoveredOver = true;
		m_mouseInputEnabled = true;
		GameInstance.GetAudioSystem( m_gameInstance ).Play( 'ui_menu_hover' );
	}

	protected event OnHoverOutColorWheel1( evt : inkPointerEvent )
	{
		if( !( m_inputEnabled ) )
		{
			return false;
		}
		m_hoveredOver = false;
		m_mouseInputEnabled = false;
	}

	protected event OnHoverOutColorWheel2( evt : inkPointerEvent )
	{
		if( !( m_inputEnabled ) )
		{
			return false;
		}
		SwitchActiveMode( 0, vehicleColorSelectorActiveMode.Primary );
		m_hoveredOver = true;
		m_mouseInputEnabled = true;
	}

	protected event OnHoverOutColorWheelLights( evt : inkPointerEvent )
	{
		if( !( m_inputEnabled ) )
		{
			return false;
		}
		m_hoveredOver = false;
		m_mouseInputEnabled = false;
	}

	private function Apply()
	{
		if( !( m_inputEnabled ) )
		{
			return;
		}
		m_inputEnabled = false;
		m_CloseReason = vehicleColorSelectorMenuCloseReason.Apply;
		if( m_activeMode == vehicleColorSelectorActiveMode.Lights )
		{
			PlayLightsFocusAnimation( false );
		}
		PlayAnimation( m_applyAnimation );
		m_animProxy.RegisterToCallback( inkanimEventType.OnFinish, this, 'OnFinalAnimationFinished' );
	}

	private function Cancel()
	{
		if( !( m_inputEnabled ) )
		{
			return;
		}
		m_inputEnabled = false;
		m_CloseReason = vehicleColorSelectorMenuCloseReason.Cancel;
		PlayAnimation( m_cancelAnimation );
		m_animProxy.RegisterToCallback( inkanimEventType.OnFinish, this, 'OnFinalAnimationFinished' );
		StatusEffectHelper.ApplyStatusEffect( m_player, T"BaseStatusEffect.VehicleVisualModCooldownInstant" );
	}

	private function Reset()
	{
		if( !( m_inputEnabled ) )
		{
			return;
		}
		m_inputEnabled = false;
		if( ( !( m_colorADefined ) && !( m_colorBDefined ) ) && !( m_lightsDefined ) )
		{
			m_inputEnabled = true;
			return;
		}
		UpdateLightsPreviewWidgets( true );
		m_CloseReason = vehicleColorSelectorMenuCloseReason.Reset;
		PlayAnimation( m_applyAnimation );
		PlayLibraryAnimation( 'Reset' );
		if( m_activeMode == vehicleColorSelectorActiveMode.Lights )
		{
			PlayLightsFocusAnimation( false );
		}
		m_animProxy.RegisterToCallback( inkanimEventType.OnFinish, this, 'OnFinalAnimationFinished' );
	}

	private function Update()
	{
		var angle : Float;
		var angleReadout : weak< inkText >;
		var sektorReadout : weak< inkText >;
		var root : weak< inkCompoundWidget >;
		if( !( m_inputEnabled ) )
		{
			return;
		}
		else
		{
			if( ( AbsF( m_axisInputCache.Y ) > m_axisInputThreshold ) || ( AbsF( m_axisInputCache.X ) > m_axisInputThreshold ) )
			{
				angle = AtanF( m_axisInputCache.X, m_axisInputCache.Y ) - ( Pi() / 2.0 );
				ProcessPointerMovement( angle, GetColorPickerForActiveColor() );
				root = ( ( inkCompoundWidget )( GetRootWidget() ) );
				angleReadout = ( ( inkText )( root.GetWidgetByPath( inkWidgetPath.Build( 'AngleTest' ) ) ) );
				sektorReadout = ( ( inkText )( root.GetWidgetByPath( inkWidgetPath.Build( 'SectionTest' ) ) ) );
				m_currentAngle = CalculateNewColorAngle( angle );
				sektorReadout.SetText( FloatToString( m_axisInputCache.X ) );
				angleReadout.SetText( FloatToString( m_axisInputCache.Y ) );
				m_axisInputCache.X = 0.0;
				m_axisInputCache.Y = 0.0;
			}
		}
	}

	private function ProcessMouseInput( mousePos : Vector2 )
	{
		var angle : Float;
		var rootWidget : weak< inkWidget >;
		var rootSize : Vector2;
		var localPos : Vector2;
		var offsetMargins : inkMargin;
		var offsetX, offsetY : Float;
		var angleReadoutX : weak< inkText >;
		var angleReadoutY : weak< inkText >;
		var root : weak< inkCompoundWidget >;
		root = ( ( inkCompoundWidget )( GetRootWidget() ) );
		angleReadoutX = ( ( inkText )( root.GetWidgetByPath( inkWidgetPath.Build( 'AngleTestX' ) ) ) );
		angleReadoutY = ( ( inkText )( root.GetWidgetByPath( inkWidgetPath.Build( 'AngleTestY' ) ) ) );
		if( m_inputEnabled )
		{
			rootWidget = GetRootWidget();
			offsetMargins = inkWidgetRef.GetMargin( m_CursorRootOffsetPoint );
			if( m_activeMode == vehicleColorSelectorActiveMode.Lights )
			{
				offsetX = ( offsetMargins.left - ( rootSize.X / 2.0 ) ) * -1.0;
				offsetY = ( offsetMargins.top - ( rootSize.Y / 2.0 ) ) * -1.0;
			}
			localPos = WidgetUtils.GlobalToLocal( inkWidgetRef.Get( m_CursorRootContainerRef ), mousePos );
			rootSize = rootWidget.GetSize();
			angle = AtanF( ( localPos.Y + offsetY ) - ( rootSize.Y / 2.0 ), ( localPos.X + offsetX ) - ( rootSize.X / 2.0 ) );
			angleReadoutX.SetText( FloatToString( localPos.X ) );
			angleReadoutY.SetText( FloatToString( offsetX ) );
			ProcessPointerMovement( angle, GetColorPickerForActiveColor() );
		}
	}

	private function ProcessPointerMovement( angle : Float, pointer : vehicleColorSelectorPointerDef )
	{
		var selectedColorID : Int32;
		m_currentAngle = CalculateNewColorAngle( angle );
		selectedColorID = FloorF( m_currentAngle ) + 1;
		if( selectedColorID != m_storedSelectedColorID )
		{
			m_storedSelectedColorID = selectedColorID;
			PlayRumble( RumbleStrength.SuperLight, RumbleType.Pulse, RumblePosition.Left );
		}
		UpdatePointerPosition( m_currentAngle, pointer, true );
	}

	private function ProcessPointerClick()
	{
		if( !( m_inputEnabled ) )
		{
			return;
		}
		switch( m_activeMode )
		{
			case vehicleColorSelectorActiveMode.Primary:
			{
				m_colorADefined = true;
				m_targetColorAngleA = CalculateNewColorAngle( m_currentAngle );
				UpdateSaturationAndBrightnessSlider( 0 );
				UpdateColor( m_targetColorAngleA, m_activeMode );
				UpdatePointerPosition( m_targetColorAngleA, m_selectedColorPointerA, false );
				UpdateSelectedColorDisplay( m_activeMode );
				ProcessApplyHintVisiblity();
			}
			break;
			case vehicleColorSelectorActiveMode.Secondary:
			{
				m_colorBDefined = true;
				m_targetColorAngleB = CalculateNewColorAngle( m_currentAngle );
				UpdateSaturationAndBrightnessSlider( 0 );
				UpdateColor( m_targetColorAngleB, m_activeMode );
				UpdatePointerPosition( m_targetColorAngleB, m_selectedColorPointerB, false );
				UpdateSelectedColorDisplay( m_activeMode );
				ProcessApplyHintVisiblity();
			}
			break;
			case vehicleColorSelectorActiveMode.Lights:
			{
				m_lightsDefined = true;
				m_targetColorAngleLights = CalculateNewColorAngle( m_currentAngle );
				UpdateColor( m_targetColorAngleLights, m_activeMode );
				UpdatePointerPosition( m_targetColorAngleLights, m_selectedColorPointerLights, false );
				UpdateSelectedColorDisplay( m_activeMode );
				ProcessApplyHintVisiblity();
				UpdateLightsPreviewWidgets();
			}
			break;
		}
	}

	private function ResetSBSlider()
	{
		m_sliderHold = false;
		m_sliderHoldDamp = 0;
		m_sliderPadHoldAccelerationTreshhold = 50;
	}

	private function ProcessSBSliderChange( change : Int32 )
	{
		if( !( m_inputEnabled ) )
		{
			return;
		}
		if( m_sliderHoldDamp < 0 )
		{
			m_sliderHoldDamp = 0;
		}
		if( ( m_sliderHoldDamp >= m_sliderPadHoldAccelerationTreshhold ) || ( m_sliderHoldDamp == 0 ) )
		{
			switch( m_activeMode )
			{
				case vehicleColorSelectorActiveMode.Primary:
				{
					if( !( m_colorADefined ) )
					{
						return;
					}
					UpdateSaturationAndBrightnessSlider( change );
					UpdateColor( m_targetColorAngleA, m_activeMode );
					UpdateSelectedColorDisplay( m_activeMode );
				}
				break;
				case vehicleColorSelectorActiveMode.Secondary:
				{
					if( !( m_colorBDefined ) )
					{
						return;
					}
					UpdateSaturationAndBrightnessSlider( change );
					UpdateColor( m_targetColorAngleB, m_activeMode );
					UpdateSelectedColorDisplay( m_activeMode );
				}
				break;
				case vehicleColorSelectorActiveMode.Lights:
				{
					return;
				}
				break;
			}
			if( m_sliderHoldDamp > m_sliderPadHoldAccelerationTreshhold )
			{
				m_sliderHoldDamp -= 5;
				if( m_sliderPadHoldAccelerationTreshhold > 0 )
				{
					m_sliderPadHoldAccelerationTreshhold -= 1;
				}
			}
		}
		m_sliderHoldDamp += 1;
	}

	private function UpdatePointerPosition( colorAngle : Float, pointer : vehicleColorSelectorPointerDef, rotate : Bool )
	{
		var dx, dy : Float;
		if( pointer.m_pointerCircleRadius == 0.0 )
		{
			return;
		}
		dx = CosF( colorAngle ) * pointer.m_pointerCircleRadius;
		dy = SinF( colorAngle ) * pointer.m_pointerCircleRadius;
		inkWidgetRef.SetMargin( pointer.m_pointerRoot, dx, dy, 0.0, 0.0 );
		if( rotate )
		{
			inkWidgetRef.SetRotation( pointer.m_pointerRoot, NormalizeAngle( colorAngle ) * 60.0 );
		}
		UpdatePointerVisiblity( pointer, true );
	}

	private function UpdatePointerVisiblity( pointer : vehicleColorSelectorPointerDef, set : Bool )
	{
		var widget : weak< inkWidget >;
		widget = inkWidgetRef.Get( pointer.m_pointerRoot );
		widget.SetVisible( set );
	}

	private function CalculateNewColorAngle( angle : Float ) : Float
	{
		var value : Float;
		value = ( angle + ( 2.0 * Pi() ) ) % ( 2.0 * Pi() );
		return value;
	}

	private function UpdateColor( colorAngle : Float, selectedMode : vehicleColorSelectorActiveMode ) : Color
	{
		var color : Color;
		switch( selectedMode )
		{
			case vehicleColorSelectorActiveMode.Primary:
			{
				color = m_vvcComponent.VehicleVisualCustomizationColorParamsToColor( colorAngle, false, m_targetColorASaturation, m_targetColorABrightness );
				m_cachedNewColorA = color;
			}
			break;
			case vehicleColorSelectorActiveMode.Secondary:
			{
				color = m_vvcComponent.VehicleVisualCustomizationColorParamsToColor( colorAngle, false, m_targetColorBSaturation, m_targetColorBBrightness );
				m_cachedNewColorB = color;
			}
			break;
			case vehicleColorSelectorActiveMode.Lights:
			{
				color = m_vvcComponent.VehicleVisualCustomizationColorParamsToColor( colorAngle, true );
				m_cachedNewColorLights = color;
			}
			break;
		}
		return color;
	}

	private function PlayAnimation( animationName : CName, optional playbackOptions : inkAnimOptions )
	{
		if( m_animProxy && m_animProxy.IsPlaying() )
		{
			m_animProxy.Stop( true );
		}
		m_animProxy = PlayLibraryAnimation( animationName, playbackOptions );
	}

	protected event OnIsInMenuChanged( param : Bool )
	{
		if( param )
		{
			Cancel();
		}
	}

	protected event OnAction( action : ListenerAction, consumer : ListenerActionConsumer )
	{
		if( ListenerAction.IsAction( action, '__DEVICE_CHANGED__' ) )
		{
			if( m_player.PlayerLastUsedKBM() )
			{
				SetCursorVisibility( true );
			}
			else
			{
				SetCursorVisibility( false );
			}
		}
	}

	protected event OnMouseInput( e : inkPointerEvent )
	{
		m_sliderHold = false;
		if( m_mouseInputEnabled && ( e.IsAction( 'mouse_x' ) || e.IsAction( 'mouse_y' ) ) )
		{
			ProcessMouseInput( e.GetScreenSpacePosition() );
		}
	}

	protected event OnGlobalAxisInput( e : inkPointerEvent )
	{
		var value : Float;
		value = e.GetAxisData();
		if( e.IsAction( 'popup_axisX' ) )
		{
			m_axisInputCache.X = value;
		}
		else if( e.IsAction( 'popup_axisY' ) )
		{
			m_axisInputCache.Y = value;
		}
	}

	protected event OnGlobalPressInput( e : inkPointerEvent )
	{
		var holdEvent : VehicleColorSelectionSliderHoldEvent;
		if( e.IsHandled() )
		{
			return false;
		}
		else if( e.IsAction( 'UI_vehicle_customization_slider_left' ) )
		{
			e.Handle();
			ProcessSBSliderChange( -1 );
			holdEvent = new VehicleColorSelectionSliderHoldEvent;
			holdEvent.direction = -1;
			m_sliderHold = true;
		}
		else if( e.IsAction( 'UI_vehicle_customization_slider_right' ) )
		{
			e.Handle();
			ProcessSBSliderChange( 1 );
			holdEvent = new VehicleColorSelectionSliderHoldEvent;
			holdEvent.direction = 1;
			m_sliderHold = true;
		}
		QueueEvent( holdEvent );
	}

	protected event OnVehicleColorSelectionSliderHoldEvent( evt : VehicleColorSelectionSliderHoldEvent )
	{
		if( m_sliderHold )
		{
			if( evt.direction > 0 )
			{
				ProcessSBSliderChange( 1 );
			}
			else
			{
				ProcessSBSliderChange( -1 );
			}
			QueueEvent( evt );
		}
	}

	protected event OnGlobalInputReleased( e : inkPointerEvent )
	{
		if( e.IsHandled() )
		{
			return false;
		}
		ResetSBSlider();
		if( e.IsAction( 'UI_vehicle_customization_select' ) )
		{
			e.Handle();
			ProcessPointerClick();
			GameInstance.GetAudioSystem( m_gameInstance ).Play( 'ui_menu_onpress' );
			PlayRumble( RumbleStrength.SuperLight, RumbleType.Pulse, RumblePosition.Both );
		}
		else if( e.IsAction( 'UI_vehicle_customization_confirm' ) )
		{
			e.Handle();
			if( ( m_colorADefined || m_colorBDefined ) || m_lightsDefined )
			{
				Apply();
				GameInstance.GetAudioSystem( m_gameInstance ).Play( 'ui_menu_close' );
				PlayRumble( RumbleStrength.Light, RumbleType.Pulse, RumblePosition.Both );
			}
		}
		else if( e.IsAction( 'UI_vehicle_customization_cancel' ) )
		{
			e.Handle();
			Cancel();
			GameInstance.GetAudioSystem( m_gameInstance ).Play( 'ui_menu_close' );
		}
		else if( e.IsAction( 'UI_vehicle_customization_mode_next' ) )
		{
			e.Handle();
			if( !( m_unsupportedVehicle ) )
			{
				SwitchActiveMode( 1 );
				GameInstance.GetAudioSystem( m_gameInstance ).Play( 'ui_menu_onpress' );
			}
		}
		else if( e.IsAction( 'UI_vehicle_customization_mode_prev' ) )
		{
			e.Handle();
			if( !( m_unsupportedVehicle ) )
			{
				SwitchActiveMode( -1 );
				GameInstance.GetAudioSystem( m_gameInstance ).Play( 'ui_menu_onpress' );
			}
		}
		else if( e.IsAction( 'UI_vehicle_customization_slider_left' ) )
		{
			e.Handle();
			if( !( m_player.PlayerLastUsedKBM() ) )
			{
				GameInstance.GetAudioSystem( m_gameInstance ).Play( 'ui_menu_value_up' );
			}
		}
		else if( e.IsAction( 'UI_vehicle_customization_slider_right' ) )
		{
			e.Handle();
			if( !( m_player.PlayerLastUsedKBM() ) )
			{
				GameInstance.GetAudioSystem( m_gameInstance ).Play( 'ui_menu_value_down' );
			}
		}
		else if( e.IsAction( 'UI_vehicle_customization_reset' ) )
		{
			if( ( ( m_colorADefined || m_colorBDefined ) || m_lightsDefined ) && m_vehicle.GetVehicleComponent().GetIsVehicleVisualCustomizationEnabled() )
			{
				e.Handle();
				GameInstance.GetAudioSystem( m_gameInstance ).Play( 'ui_menu_close' );
				Reset();
			}
		}
	}

	private function NormalizeAngle( angle : Float ) : Float
	{
		return ( angle / ( 2.0 * Pi() ) ) * 6.0;
	}

	private function SetCursorVisibility( visible : Bool )
	{
		var evt : inkGameNotificationLayer_SetCursorVisibility;
		evt = new inkGameNotificationLayer_SetCursorVisibility;
		evt.Init( visible );
		QueueEvent( evt );
	}

	private function UpdateSelectedColorDisplay( mode : vehicleColorSelectorActiveMode, optional isRestore : Bool )
	{
		switch( mode )
		{
			case vehicleColorSelectorActiveMode.Primary:
			{
				inkWidgetRef.SetTintColor( m_targetColorPrintA, m_cachedNewColorA );
				inkWidgetRef.SetVisible( m_targetColorPrintA, true );
				SetSBBarTint( m_targetColorAngleA );
				inkWidgetRef.SetTintColor( m_selectedColorPointerA.m_partToPaint, m_cachedNewColorA );
			}
			break;
			case vehicleColorSelectorActiveMode.Secondary:
			{
				inkWidgetRef.SetTintColor( m_targetColorPrintB, m_cachedNewColorB );
				inkWidgetRef.SetVisible( m_targetColorPrintB, true );
				if( !( isRestore ) )
				{
					SetSBBarTint( m_targetColorAngleB );
				}
				inkWidgetRef.SetTintColor( m_selectedColorPointerB.m_partToPaint, m_cachedNewColorB );
			}
			break;
			case vehicleColorSelectorActiveMode.Lights:
			{
				inkWidgetRef.SetTintColor( m_selectedColorPointerLights.m_partToPaint, m_cachedNewColorLights );
			}
			break;
		}
	}

	private function SendCustomizationToVehicle()
	{
		var evt : NewVehicleVisualCustomizationEvent;
		var defSet : vehicleVisualModdingDefinition;
		if( m_colorADefined == true )
		{
			defSet.primaryColorDefined = true;
			defSet.primaryColorH = m_targetColorAngleA;
			defSet.primaryColorS = m_targetColorASaturation;
			defSet.primaryColorB = m_targetColorABrightness;
		}
		else
		{
			defSet.primaryColorDefined = false;
			defSet.primaryColorH = 0.0;
			defSet.primaryColorS = 0.0;
			defSet.primaryColorB = 1.0;
		}
		if( m_colorBDefined == true )
		{
			defSet.secondaryColorDefined = true;
			defSet.secondaryColorH = m_targetColorAngleB;
			defSet.secondaryColorS = m_targetColorBSaturation;
			defSet.secondaryColorB = m_targetColorBBrightness;
		}
		else
		{
			defSet.secondaryColorDefined = false;
			defSet.secondaryColorH = m_targetColorAngleA;
			defSet.secondaryColorS = m_targetColorASaturation;
			defSet.secondaryColorB = m_targetColorABrightness;
		}
		if( m_lightsDefined == true )
		{
			defSet.lightsColorDefined = true;
			defSet.lightsColorH = m_targetColorAngleLights;
		}
		evt = new NewVehicleVisualCustomizationEvent;
		evt.modSet = defSet;
		m_vehicle.QueueEvent( evt );
	}

	private function ResetCustomizationToVehicle()
	{
		var evt : NewVehicleVisualCustomizationEvent;
		var defSet : vehicleVisualModdingDefinition;
		defSet.primaryColorDefined = false;
		defSet.primaryColorH = 0.0;
		defSet.primaryColorS = 0.0;
		defSet.primaryColorB = 0.0;
		defSet.secondaryColorDefined = false;
		defSet.secondaryColorH = 0.0;
		defSet.secondaryColorS = 0.0;
		defSet.secondaryColorB = 0.0;
		defSet.lightsColorDefined = false;
		defSet.lightsColorH = 0.0;
		evt = new NewVehicleVisualCustomizationEvent;
		evt.modSet = defSet;
		evt.reset = true;
		m_vehicle.QueueEvent( evt );
	}

	private function SwitchActiveMode( optional direction : Int32, optional switchTo : vehicleColorSelectorActiveMode )
	{
		m_previousMode = m_activeMode;
		if( m_unsupportedVehicle )
		{
			return;
		}
		switch( switchTo )
		{
			case vehicleColorSelectorActiveMode.Primary:
			{
				m_activeMode = vehicleColorSelectorActiveMode.Primary;
			}
			break;
			case vehicleColorSelectorActiveMode.Secondary:
			{
				m_activeMode = vehicleColorSelectorActiveMode.Secondary;
			}
			break;
			case vehicleColorSelectorActiveMode.Lights:
			{
				m_activeMode = vehicleColorSelectorActiveMode.Lights;
			}
			break;
			default:
			{
				m_activeMode = GetNextValidMode( m_activeMode, direction );
			}
		}
		m_stickersPage.SetVisible( false );
		inkWidgetRef.SetVisible( m_colorPaletteRef, true );
		if( m_activeMode == vehicleColorSelectorActiveMode.Lights )
		{
			inkTextRef.SetOpacity( m_titleTextMain, 1.0 );
			inkTextRef.SetText( m_titleTextMain, GetLocalizedText( "LocKey#96054" ) );
			inkTextRef.SetOpacity( m_titleTextNumber, 0.0 );
		}
		else
		{
			inkTextRef.SetOpacity( m_titleTextMain, 1.0 );
			inkTextRef.SetText( m_titleTextMain, GetLocalizedText( "LocKey#95816" ) );
			inkTextRef.SetText( m_titleTextNumber, IntToString( ( ( Int32 )( m_activeMode ) ) ) );
			inkTextRef.SetOpacity( m_titleTextNumber, 1.0 );
		}
		UpdateSaturationAndBrightnessSlider( 0 );
		ProcessColorHighlight( m_activeMode, m_previousMode );
	}

	private function GetNextValidMode( currentMode : vehicleColorSelectorActiveMode, optional direction : Int32 ) : vehicleColorSelectorActiveMode
	{
		var i : Int32;
		var enumMax : Int32;
		var newEnumValue : vehicleColorSelectorActiveMode;
		enumMax = ( ( Int32 )( EnumGetMax( 'vehicleColorSelectorActiveMode' ) ) );
		i = ( ( Int32 )( currentMode ) );
		i += direction;
		if( i <= 0 )
		{
			i = enumMax;
		}
		if( i > enumMax )
		{
			i = 1;
		}
		newEnumValue = ( ( vehicleColorSelectorActiveMode )( i ) );
		return newEnumValue;
	}

	private function UpdateLightsPreviewWidgets( optional reset : Bool )
	{
		var i : Int32;
		var size : Int32;
		var widget : inkWidget;
		var color : Color;
		size = m_targetColorPrintLights.Size();
		if( reset )
		{
			color = Color( 255, 255, 255, 255 );
		}
		else
		{
			color = m_cachedNewColorLights;
		}
		for( i = 0; i < size; i += 1 )
		{
			widget = inkWidgetRef.Get( m_targetColorPrintLights[ i ] );
			widget.SetTintColor( color );
		}
	}

	private function PlayLightsFocusAnimation( val : Bool )
	{
		var animOptions : inkAnimOptions;
		if( val )
		{
			m_LightsFocusProxy = PlayLibraryAnimation( 'ZoomOnLights' );
		}
		else
		{
			animOptions.playReversed = true;
			m_LightsFocusProxy = PlayLibraryAnimation( 'ZoomOnLights', animOptions );
		}
	}

	private function ProcessColorHighlight( currentMode : vehicleColorSelectorActiveMode, previousMode : vehicleColorSelectorActiveMode )
	{
		switch( currentMode )
		{
			case vehicleColorSelectorActiveMode.Primary:
			{
				inkWidgetRef.SetOpacity( m_colorWheelColorA, 1.0 );
				inkWidgetRef.SetOpacity( m_colorWheelColorB, 0.30000001 );
				inkWidgetRef.SetOpacity( m_colorWheelColorLights, 0.30000001 );
				SetSBBarTint( m_targetColorAngleA );
				UpdatePointerPosition( m_targetColorAngleA, m_colorPickerA, true );
				UpdatePointerVisiblity( m_colorPickerB, false );
				UpdatePointerVisiblity( m_colorPickerLights, false );
				if( previousMode == vehicleColorSelectorActiveMode.Lights )
				{
					PlayLightsFocusAnimation( false );
				}
			}
			break;
			case vehicleColorSelectorActiveMode.Secondary:
			{
				inkWidgetRef.SetOpacity( m_colorWheelColorA, 0.30000001 );
				inkWidgetRef.SetOpacity( m_colorWheelColorB, 1.0 );
				inkWidgetRef.SetOpacity( m_colorWheelColorLights, 0.30000001 );
				SetSBBarTint( m_targetColorAngleB );
				UpdatePointerPosition( m_targetColorAngleB, m_colorPickerB, true );
				UpdatePointerVisiblity( m_colorPickerA, false );
				UpdatePointerVisiblity( m_colorPickerLights, false );
				if( previousMode == vehicleColorSelectorActiveMode.Lights )
				{
					PlayLightsFocusAnimation( false );
				}
			}
			break;
			case vehicleColorSelectorActiveMode.Lights:
			{
				inkWidgetRef.SetOpacity( m_colorWheelColorA, 0.15000001 );
				inkWidgetRef.SetOpacity( m_colorWheelColorB, 0.15000001 );
				inkWidgetRef.SetOpacity( m_colorWheelColorLights, 1.0 );
				UpdatePointerPosition( m_targetColorAngleLights, m_colorPickerLights, true );
				UpdatePointerVisiblity( m_colorPickerA, false );
				UpdatePointerVisiblity( m_colorPickerB, false );
				PlayLightsFocusAnimation( true );
			}
			break;
		}
	}

	private function GetColorPickerForActiveColor() : vehicleColorSelectorPointerDef
	{
		switch( m_activeMode )
		{
			case vehicleColorSelectorActiveMode.Primary:
			{
				return m_colorPickerA;
			}
			break;
			case vehicleColorSelectorActiveMode.Secondary:
			{
				return m_colorPickerB;
			}
			break;
			case vehicleColorSelectorActiveMode.Lights:
			{
				return m_colorPickerLights;
			}
			break;
		}
		return m_colorPickerA;
	}

	protected event OnFinalAnimationFinished( proxy : inkAnimProxy )
	{
		switch( m_CloseReason )
		{
			case vehicleColorSelectorMenuCloseReason.Apply:
			{
				SendCustomizationToVehicle();
			}
			break;
			case vehicleColorSelectorMenuCloseReason.Reset:
			{
				ResetCustomizationToVehicle();
			}
			break;
		}
		SignalUICallBack();
	}

	private function SignalUICallBack()
	{
		m_popupData.token.TriggerCallback( m_popupData );
	}

	protected event OnFakeUpdate( proxy : inkAnimProxy )
	{
		Update();
	}

	private function ProcessPreviousCustomizationState()
	{
		var dataSet : vehicleVisualModdingDefinition;
		dataSet = m_vehicle.GetVehiclePS().GetVehicleVisualCustomizationDefinition();
		m_colorADefined = dataSet.primaryColorDefined;
		m_colorBDefined = dataSet.secondaryColorDefined;
		m_lightsDefined = dataSet.lightsColorDefined;
		if( m_vehicle.GetVehicleComponent().GetIsVehicleVisualCustomizationEnabled() )
		{
			if( ( !( m_colorADefined ) && !( m_colorBDefined ) ) && !( m_lightsDefined ) )
			{
				dataSet = m_player.GetVehicleVisualCustomizationComponent().RetriveVisualCustomizationDefinitionForID( m_vehicle.GetRecordID() );
				m_colorADefined = dataSet.primaryColorDefined;
				m_colorBDefined = dataSet.secondaryColorDefined;
				m_lightsDefined = dataSet.lightsColorDefined;
			}
			if( m_colorADefined )
			{
				m_targetColorAngleA = dataSet.primaryColorH;
				m_targetColorASaturation = dataSet.primaryColorS;
				m_targetColorABrightness = dataSet.primaryColorB;
				m_currentSBSliderPositionA = GetSBSliderPositionFromEndValues( m_targetColorASaturation, m_targetColorABrightness );
				UpdateSaturationAndBrightnessSlider( 0 );
				UpdateColor( m_targetColorAngleA, vehicleColorSelectorActiveMode.Primary );
				UpdatePointerPosition( m_targetColorAngleA, m_selectedColorPointerA, false );
				UpdateSelectedColorDisplay( vehicleColorSelectorActiveMode.Primary );
			}
			else
			{
				m_activeMode = vehicleColorSelectorActiveMode.Secondary;
			}
			if( m_colorBDefined )
			{
				m_targetColorAngleB = dataSet.secondaryColorH;
				m_targetColorBSaturation = dataSet.secondaryColorS;
				m_targetColorBBrightness = dataSet.secondaryColorB;
				m_currentSBSliderPositionB = GetSBSliderPositionFromEndValues( m_targetColorBSaturation, m_targetColorBBrightness );
				if( !( m_colorADefined ) )
				{
					UpdateSaturationAndBrightnessSlider( 0 );
				}
				UpdateColor( m_targetColorAngleB, vehicleColorSelectorActiveMode.Secondary );
				UpdatePointerPosition( m_targetColorAngleB, m_selectedColorPointerB, false );
				UpdateSelectedColorDisplay( vehicleColorSelectorActiveMode.Secondary, true );
			}
			if( m_lightsDefined )
			{
				m_targetColorAngleLights = dataSet.lightsColorH;
				UpdateColor( m_targetColorAngleLights, vehicleColorSelectorActiveMode.Lights );
				UpdatePointerPosition( m_targetColorAngleLights, m_selectedColorPointerLights, false );
				UpdateSelectedColorDisplay( vehicleColorSelectorActiveMode.Lights );
				UpdateLightsPreviewWidgets();
			}
		}
		ProcessApplyHintVisiblity();
		ProcessResetHintVisiblity();
	}

	private function SetSBBarTint( colorAngle : Float )
	{
		if( ( m_activeMode == vehicleColorSelectorActiveMode.Primary && m_colorADefined ) || ( m_activeMode == vehicleColorSelectorActiveMode.Secondary && m_colorBDefined ) )
		{
			inkWidgetRef.SetTintColor( m_brightnessBarFill, m_vvcComponent.VehicleVisualCustomizationColorParamsToColor( colorAngle, true ) );
		}
		else
		{
			inkWidgetRef.SetTintColor( m_brightnessBarFill, Color( 255, 255, 255, 255 ) );
		}
	}

	private function ShowSBBar( val : Bool )
	{
		var animOptions : inkAnimOptions;
		if( m_sbBarShown == val )
		{
			return;
		}
		if( !( m_sbBarShown ) && !( val ) )
		{
			return;
		}
		m_inputEnabled = false;
		m_sbBarShown = val;
		if( !( val ) )
		{
			animOptions.playReversed = true;
		}
		m_SBBarProxy = PlayLibraryAnimation( 'ShowBrightnessBar', animOptions );
		m_SBBarProxy.RegisterToCallback( inkanimEventType.OnFinish, this, 'OnShowSBBarAnimFinished' );
	}

	protected event OnShowSBBarAnimFinished( proxy : inkAnimProxy )
	{
		inkWidgetRef.SetVisible( m_sliderInputHintUp, true );
		inkWidgetRef.SetVisible( m_sliderInputHintDown, true );
		inkWidgetRef.SetVisible( m_brightnessPointer, true );
		m_SBBarProxy.UnregisterFromAllCallbacks( inkanimEventType.OnFinish );
		m_inputEnabled = true;
	}

	private function UpdateSaturationAndBrightnessSlider( direction : Int32 )
	{
		if( ( m_activeMode == vehicleColorSelectorActiveMode.Primary && m_colorADefined ) || ( m_activeMode == vehicleColorSelectorActiveMode.Secondary && m_colorBDefined ) )
		{
			UpdateSBSliderPosition( direction, m_activeMode );
			ProcessSBValues();
			ShowSBBar( true );
		}
		else
		{
			inkWidgetRef.SetVisible( m_sliderInputHintUp, false );
			inkWidgetRef.SetVisible( m_sliderInputHintDown, false );
			inkWidgetRef.SetVisible( m_brightnessPointer, false );
			ShowSBBar( false );
		}
	}

	private function GetSliderStepForControlDevice() : Float
	{
		if( m_player.PlayerLastUsedKBM() )
		{
			return m_SBSliderStepMouse;
		}
		else
		{
			return m_SBSliderStepPad;
		}
	}

	private function GetSBSliderPositionFromEndValues( saturation : Float, brightness : Float ) : Float
	{
		var position : Float;
		var sliderStep : Float;
		sliderStep = GetSliderStepForControlDevice();
		position = ( saturation * 0.5 ) + ( 0.5 - ( brightness * 0.5 ) );
		position = ( ( position - 0.5 ) * ( m_sbSliderLenght / sliderStep ) ) * sliderStep;
		return position;
	}

	private function ProcessApplyHintVisiblity()
	{
		if( ( m_colorADefined || m_colorBDefined ) || m_lightsDefined )
		{
			inkWidgetRef.SetVisible( m_applyContainerWidget, true );
		}
		else
		{
			inkWidgetRef.SetVisible( m_applyContainerWidget, false );
		}
	}

	private function ProcessResetHintVisiblity()
	{
		if( ( ( m_colorADefined || m_colorBDefined ) || m_lightsDefined ) && m_vehicle.GetVehicleComponent().GetIsVehicleVisualCustomizationEnabled() )
		{
			inkWidgetRef.SetVisible( m_resetContainerWidget, true );
		}
		else
		{
			inkWidgetRef.SetVisible( m_resetContainerWidget, false );
		}
	}

	private function ProcessSBValues()
	{
		var brightnessValue : Float;
		var saturationValue : Float;
		var currentPosition : Float;
		switch( m_activeMode )
		{
			case vehicleColorSelectorActiveMode.Primary:
			{
				currentPosition = ( ( ( Float )( m_currentSBSliderPositionA ) ) + ( ( Float )( ( m_sbSliderLenght / 2.0 ) ) ) ) / ( ( Float )( ( m_sbSliderLenght / 2.0 ) ) );
			}
			break;
			case vehicleColorSelectorActiveMode.Secondary:
			{
				currentPosition = ( ( ( Float )( m_currentSBSliderPositionB ) ) + ( ( Float )( ( m_sbSliderLenght / 2.0 ) ) ) ) / ( ( Float )( ( m_sbSliderLenght / 2.0 ) ) );
			}
			break;
		}
		saturationValue = 1.0 - ( 1.0 + ( currentPosition * -1.0 ) );
		if( saturationValue > 1.0 )
		{
			saturationValue = 1.0;
		}
		brightnessValue = 1.0 + ( 1.0 + ( currentPosition * -1.0 ) );
		if( brightnessValue > 1.0 )
		{
			brightnessValue = 1.0;
		}
		switch( m_activeMode )
		{
			case vehicleColorSelectorActiveMode.Primary:
			{
				m_targetColorASaturation = saturationValue;
				m_targetColorABrightness = brightnessValue;
			}
			break;
			case vehicleColorSelectorActiveMode.Secondary:
			{
				m_targetColorBSaturation = saturationValue;
				m_targetColorBBrightness = brightnessValue;
			}
			break;
		}
	}

	private function UpdateSBSliderPosition( direction : Int32, activeColor : vehicleColorSelectorActiveMode )
	{
		var sliderStep : Float;
		sliderStep = GetSliderStepForControlDevice();
		switch( activeColor )
		{
			case vehicleColorSelectorActiveMode.Primary:
			{
				if( AbsF( m_currentSBSliderPositionA + ( sliderStep * ( ( Float )( direction ) ) ) ) > ( m_sbSliderLenght / 2.0 ) )
				{
					return;
				}
				m_currentSBSliderPositionA = m_currentSBSliderPositionA + ( sliderStep * ( ( Float )( direction ) ) );
				if( m_currentSBSliderPositionA > ( m_sbSliderLenght / 2.0 ) )
				{
					m_currentSBSliderPositionA = m_sbSliderLenght / 2.0;
				}
				inkWidgetRef.SetMargin( m_brightnessPointer, m_currentSBSliderPositionA, 0.0, 0.0, 0.0 );
			}
			break;
			case vehicleColorSelectorActiveMode.Secondary:
			{
				if( AbsF( m_currentSBSliderPositionB + ( sliderStep * ( ( Float )( direction ) ) ) ) > ( m_sbSliderLenght / 2.0 ) )
				{
					return;
				}
				m_currentSBSliderPositionB = m_currentSBSliderPositionB + ( sliderStep * ( ( Float )( direction ) ) );
				if( m_currentSBSliderPositionB > ( m_sbSliderLenght / 2.0 ) )
				{
					m_currentSBSliderPositionB = m_sbSliderLenght / 2.0;
				}
				inkWidgetRef.SetMargin( m_brightnessPointer, m_currentSBSliderPositionB, 0.0, 0.0, 0.0 );
			}
			break;
		}
		inkWidgetRef.SetVisible( m_brightnessPointer, true );
	}

	protected function SetTimeDilatation( enable : Bool )
	{
		var uiSystem : UISystem;
		uiSystem = GameInstance.GetUISystem( m_player.GetGame() );
		if( enable )
		{
			TimeDilationHelper.SetTimeDilationWithProfile( GetPlayerControlledObject(), m_timeDilationProfile, true, false );
			uiSystem.PushGameContext( UIGameContext.ModalPopup );
			uiSystem.RequestNewVisualState( 'inkModalPopupState' );
			PopupStateUtils.SetBackgroundBlur( this, true );
		}
		else
		{
			TimeDilationHelper.SetTimeDilationWithProfile( GetPlayerControlledObject(), m_timeDilationProfile, false, false );
			uiSystem.PopGameContext( UIGameContext.ModalPopup );
			uiSystem.RestorePreviousVisualState( 'inkModalPopupState' );
			PopupStateUtils.SetBackgroundBlur( this, false );
		}
	}

	private function ProcessFakeUpdate( on : Bool )
	{
		var anim : inkAnimDef;
		var alphaInterpolator : inkAnimTransparency;
		var animOptions : inkAnimOptions;
		if( on )
		{
			anim = new inkAnimDef;
			alphaInterpolator = new inkAnimTransparency;
			alphaInterpolator.SetDuration( 0.0001 );
			alphaInterpolator.SetStartTransparency( 1.0 );
			alphaInterpolator.SetEndTransparency( 1.0 );
			alphaInterpolator.SetType( inkanimInterpolationType.Linear );
			alphaInterpolator.SetMode( inkanimInterpolationMode.EasyIn );
			anim.AddInterpolator( alphaInterpolator );
			animOptions.playReversed = false;
			animOptions.executionDelay = 0.0;
			animOptions.loopType = inkanimLoopType.Cycle;
			animOptions.loopInfinite = true;
			m_fakeUpdateProxy = inkWidgetRef.PlayAnimationWithOptions( m_CursorRootContainerRef, anim, animOptions );
			m_fakeUpdateProxy.RegisterToCallback( inkanimEventType.OnEndLoop, this, 'OnFakeUpdate' );
		}
		else
		{
			if( m_fakeUpdateProxy.IsPlaying() )
			{
				m_fakeUpdateProxy.Stop();
				m_fakeUpdateProxy.UnregisterFromCallback( inkanimEventType.OnEndLoop, this, 'OnFakeUpdate' );
			}
		}
	}

	private function VerifyVehicleValidity() : Bool
	{
		if( !( m_vehicle.GetVehicleComponent().GetIsVehicleVisualCustomizationEnabled() ) )
		{
			SwitchActiveMode( 0, vehicleColorSelectorActiveMode.Lights );
			inkWidgetRef.SetVisible( m_mouseHitColor1Ref, false );
			inkWidgetRef.SetVisible( m_mouseHitColor2Ref, false );
			inkWidgetRef.SetVisible( m_modeChangeNext, false );
			inkWidgetRef.SetVisible( m_modeChangeBack, false );
			inkWidgetRef.SetOpacity( m_colorWheelColorA, 0.0 );
			inkWidgetRef.SetOpacity( m_colorWheelColorB, 0.0 );
			m_unsupportedVehicle = true;
			inkWidgetRef.SetOpacity( m_vehicleUnknownPane, 1.0 );
			PlayLibraryAnimation( 'GlitchBrand' );
			return false;
		}
		return true;
	}

	private function UpdateVehicleManufacturer()
	{
		var vehicleManufacturer : VehicleManufacturer_Record;
		var recordID : TweakDBID;
		var record : Vehicle_Record;
		recordID = m_vehicle.GetRecordID();
		record = TweakDBInterface.GetVehicleRecord( recordID );
		vehicleManufacturer = record.Manufacturer();
		if( vehicleManufacturer )
		{
			if( vehicleManufacturer.Type() != gamedataVehicleManufacturer.Rayfield )
			{
				inkImageRef.SetOpacity( m_vehicleBrandIcon, 0.80000001 );
				InkImageUtils.RequestSetImage( this, m_vehicleBrandIcon, "UIIcon." + vehicleManufacturer.EnumName() );
				inkImageRef.SetScale( m_vehicleBrandIcon, Vector2( 1.0, 1.0 ) );
			}
		}
		else
		{
			inkImageRef.SetOpacity( m_vehicleBrandIcon, 0.0 );
		}
	}

}

