class PerkTraining extends InteractiveDevice
{
	default m_controllerTypeName = 'PerkTrainingController';
	[ category = "Progress Bar config" ]
	private editable var m_progressBarHeaderText : String;
	[ category = "Progress Bar config" ]
	private editable var m_progressBarBottomText : String;
	[ category = "Pulsing FX" ][ customEditor = "AudioEvent" ]
	private editable var m_pulsingEndSoundName : CName;
	private var m_animFeature : AnimFeature_PerkDeviceData;
	private var m_uiSlots : SlotComponent;

	protected event OnGameAttached()
	{
		super.OnGameAttached();
		TryShowMappin();
		UpdatePulsingEffects();
		SetInitialAnimationState();
	}

	private function SetInitialAnimationState()
	{
		m_animFeature.isUsed = GetDevicePS().IsPerkGranted();
		AnimationControllerComponent.ApplyFeature( this, AnimFeature_PerkDeviceData.GetFeatureName(), m_animFeature );
	}

	protected event OnDetach()
	{
		super.OnDetach();
		GameObjectEffectHelper.StopEffectEvent( this, GetLightsEffectName() );
	}

	protected event OnRequestComponents( ri : EntityRequestComponentsInterface )
	{
		EntityRequestComponentsInterface.RequestComponent( ri, 'SlotComponent', 'UI_Slots', false );
		super.OnRequestComponents( ri );
	}

	protected event OnTakeControl( ri : EntityResolveComponentsInterface )
	{
		super.OnTakeControl( ri );
		m_uiSlots = ( ( SlotComponent )( EntityResolveComponentsInterface.GetComponent( ri, 'UI_Slots' ) ) );
		m_controller = ( ( PerkTrainingController )( EntityResolveComponentsInterface.GetComponent( ri, 'controller' ) ) );
		m_animFeature = new AnimFeature_PerkDeviceData;
	}

	protected event OnAreaEnter( evt : AreaEnteredEvent )
	{
		if( IsTriggeredByPlayer( evt ) )
		{
			GetDevicePS().SetDeviceAsDetected();
			TryShowMappin();
		}
	}

	private function UpdatePulsingEffects()
	{
		if( !( GetDevicePS().IsPerkGranted() ) )
		{
			GameObjectEffectHelper.StartEffectEvent( this, GetLightsEffectName() );
		}
		else
		{
			GameObjectEffectHelper.StopEffectEvent( this, GetLightsEffectName() );
		}
	}

	private constexpr function GetLightsEffectName() : CName
	{
		return 'animated_lights';
	}

	private function TryShowMappin()
	{
		if( GetDevicePS().WasDetected() && !( GetDevicePS().IsPerkGranted() ) )
		{
			ShowMappin();
		}
	}

	private function IsTriggeredByPlayer( evt : TriggerEvent ) : Bool
	{
		var obj : GameObject;
		obj = ( ( GameObject )( EntityGameInterface.GetEntity( evt.activator ) ) );
		return obj.IsPlayer();
	}

	private function ShowMappin()
	{
		var request : RegisterPerkDeviceMappinRequest;
		request = new RegisterPerkDeviceMappinRequest;
		request.m_ownerID = GetEntityID();
		request.m_position = GetSlotPosition();
		GetPerkSystem().QueueRequest( request );
	}

	private function GetSlotPosition() : Vector4
	{
		var worldTransform : WorldTransform;
		m_uiSlots.GetSlotTransform( 'roleMappin', worldTransform );
		return WorldPosition.ToVector4( WorldTransform.GetWorldPosition( worldTransform ) );
	}

	private const function GetPerkSystem() : RelicPerkSystem
	{
		return ( ( RelicPerkSystem )( GameInstance.GetScriptableSystemsContainer( GetGame() ).Get( 'RelicPerkSystem' ) ) );
	}

	protected event OnConnectionEnded( evt : ConnectionEndedEvent )
	{
		if( GetDevicePS().IsPerkGranted() )
		{
			HideMappin();
		}
	}

	private function HideMappin()
	{
		var request : SetPerkDeviceAsUsedRequest;
		request = new SetPerkDeviceAsUsedRequest;
		request.m_ownerID = GetEntityID();
		GetPerkSystem().QueueRequest( request );
	}

	public const override function GetDevicePS() : PerkTrainingControllerPS
	{
		return GetController().GetPS();
	}

	private const override function GetController() : PerkTrainingController
	{
		return ( ( PerkTrainingController )( m_controller ) );
	}

	public const override function DeterminGameplayRole() : EGameplayRole
	{
		return EGameplayRole.GenericRole;
	}

	protected event OnTogglePersonalLink( evt : TogglePersonalLink )
	{
		super.OnTogglePersonalLink( evt );
		if( GetDevicePS().IsPersonalLinkConnected() )
		{
			PlaySound( this, m_pulsingEndSoundName );
			GameObjectEffectHelper.BreakEffectLoopEvent( this, GetLightsEffectName() );
			StartProgressBar();
		}
		else if( GetDevicePS().IsPersonalLinkDisconnecting() )
		{
			SetProgressBarActiveState( false );
		}
	}

	protected override function InitiatePersonalLinkWorkspot( puppet : GameObject )
	{
		EnterWorkspot( ( ( GameObject )( puppet ) ), false, 'personalLinkPlayerWorkspot', 'deviceWorkspot' );
	}

	private function StartProgressBar()
	{
		StartTickEvent();
		SetProgressBarTexts();
		SetProgressBarActiveState( true );
	}

	private function StartTickEvent()
	{
		var tickEvent : PerkDeviceTickEvent;
		tickEvent = new PerkDeviceTickEvent;
		GameInstance.GetDelaySystem( GetGame() ).TickOnEvent( this, tickEvent, GetDevicePS().GetLoopTime() );
	}

	protected event OnTick( evt : PerkDeviceTickEvent )
	{
		GetProgressBarBlackboard().SetFloat( GetAllBlackboardDefs().UI_HUDProgressBar.Progress, evt.GetProgress() );
	}

	private function SetProgressBarActiveState( isActive : Bool )
	{
		GetProgressBarBlackboard().SetBool( GetAllBlackboardDefs().UI_HUDProgressBar.Active, isActive );
	}

	private function SetProgressBarTexts()
	{
		GetProgressBarBlackboard().SetString( GetAllBlackboardDefs().UI_HUDProgressBar.Header, m_progressBarHeaderText );
		GetProgressBarBlackboard().SetString( GetAllBlackboardDefs().UI_HUDProgressBar.BottomText, m_progressBarBottomText );
	}

	private function GetProgressBarBlackboard() : IBlackboard
	{
		return GameInstance.GetBlackboardSystem( GetGame() ).Get( GetAllBlackboardDefs().UI_HUDProgressBar );
	}

	protected override function EnterWorkspot( activator : GameObject, optional freeCamera : Bool, optional componentName : CName, optional deviceData : CName )
	{
		var workspotSystem : WorkspotGameSystem;
		workspotSystem = GameInstance.GetWorkspotSystem( activator.GetGame() );
		if( activator.IsPlayer() )
		{
			m_workspotActivator = activator;
			workspotSystem.PlayInDeviceSimple( this, activator, freeCamera, componentName, deviceData, 'plugin_start', 0.5, WorkspotSlidingBehaviour.PlayAtResourcePosition, this );
		}
	}

}

class PerkDeviceTickEvent extends TickableEvent
{
}

class PerkTrainingController extends ScriptableDeviceComponent
{

	public const override function GetPS() : PerkTrainingControllerPS
	{
		return ( ( PerkTrainingControllerPS )( GetBasePS() ) );
	}

}

