struct ComputerPersistentData
{
	var mails : array< GenericDataContent >;
	var files : array< GenericDataContent >;
	var newsFeedElements : array< SNewsFeedElementData >;
	var internetData : SInternetData;
	var initialUIPosition : String;
	var m_openedFileIDX : Int32;
	var m_openedFolderIDX : Int32;
}

class SetDocumentStateEvent extends Event
{
	var documentType : EDocumentType;
	var documentAdress : SDocumentAdress;
	var isOpened : Bool;
}

class EnableDocumentEvent extends Event
{
	editable var documentType : EDocumentType;
	editable var documentName : CName;
	editable var documentAdress : SDocumentAdress;
	editable var enable : Bool;
	default enable = true;
	editable var entireFolder : Bool;
	default entireFolder = false;

	public constexpr export function GetFriendlyDescription() : String
	{
		return "Enable Document";
	}

}

class OpenDocumentEvent extends Event
{
	editable var documentType : EDocumentType;
	editable var documentName : CName;
	editable var documentAdress : SDocumentAdress;
	editable var wakeUp : Bool;
	default wakeUp = true;
	var ownerID : EntityID;

	public constexpr function GetFriendlyDescription() : String
	{
		return "Open Document";
	}

}

class GoToMenuEvent extends Event
{
	editable var menuType : EComputerMenuType;
	editable var wakeUp : Bool;
	default wakeUp = true;
	var ownerID : EntityID;

	public constexpr export function GetFriendlyDescription() : String
	{
		return "Go to Menu";
	}

}

importonly struct QuestInfo
{
	import var factName : CName;
	import var isHighlighted : Bool;
}

importonly struct DataElement
{
	import var journalPath : gameJournalPath;
	import var documentName : CName;
	import var owner : String;
	import var date : String;
	import var title : String;
	import var content : String;
	import var videoPath : ResRef;
	import var questInfo : QuestInfo;
	import persistent var isEncrypted : Bool;
	import persistent var wasRead : Bool;
	import persistent var isEnabled : Bool;
}

importonly struct GenericDataContent
{
	import var name : String;
	import persistent var content : array< DataElement >;
}

importonly struct ComputerUIData
{
	import persistent var mails : array< GenericDataContent >;
	import persistent var files : array< GenericDataContent >;
}

import struct UIScreenDefinition
{
	import var screenType : TweakDBID;
}

struct SNewsFeedData
{
	instanceeditable var interval : Float;
	default interval = 5.0;
	const instanceeditable var elements : array< SNewsFeedElementData >;
}

struct SInternetData
{
	instanceeditable var startingPage : String;
}

struct SNewsFeedElementData
{
	const instanceeditable var banners : array< SsimpleBanerData >;
	var currentBanner : Int32;
}

struct SsimpleBanerData
{
	instanceeditable var title : String;
	instanceeditable var description : String;
	instanceeditable var content : ResRef;
}

class Computer extends Terminal
{
	default m_controllerTypeName = 'ComputerController';
	private var m_bannerUpdateActive : Bool;
	private var m_bannerUpdateID : DelayID;
	private var m_transformX : IPlacedComponent;
	private var m_transformY : IPlacedComponent;
	private var m_playerControlData : PlayerControlDeviceData;
	private var m_currentAnimationState : EComputerAnimationState;

	protected event OnRequestComponents( ri : EntityRequestComponentsInterface )
	{
		super.OnRequestComponents( ri );
		EntityRequestComponentsInterface.RequestComponent( ri, 'takeOverX', 'IPlacedComponent', false );
		EntityRequestComponentsInterface.RequestComponent( ri, 'takeOverY', 'IPlacedComponent', false );
	}

	protected event OnTakeControl( ri : EntityResolveComponentsInterface )
	{
		super.OnTakeControl( ri );
		m_transformX = ( ( IPlacedComponent )( EntityResolveComponentsInterface.GetComponent( ri, 'takeOverX' ) ) );
		m_transformY = ( ( IPlacedComponent )( EntityResolveComponentsInterface.GetComponent( ri, 'takeOverY' ) ) );
		m_controller = ( ( ComputerController )( EntityResolveComponentsInterface.GetComponent( ri, 'controller' ) ) );
	}

	protected override function ResolveGameplayState()
	{
		super.ResolveGameplayState();
		DetermineActivationState();
	}

	protected override function RestoreDeviceState()
	{
		super.RestoreDeviceState();
		ResolveAnimationState( ( ( ComputerControllerPS )( GetDevicePS() ) ).GetAnimationState() );
	}

	public export override function ResavePersistentData( ps : PersistentState ) : Bool
	{
		return true;
	}

	protected override function ShouldAlwasyRefreshUIInLogicAra() : Bool
	{
		return false;
	}

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

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

	public const function IsInSleepMode() : Bool
	{
		return GetDevicePS().IsInSleepMode();
	}

	protected override function ShouldExitZoomOnAuthorization() : Bool
	{
		return false;
	}

	private function InitializeBanners()
	{
		if( GetDevicePS().HasNewsfeed() )
		{
			RequestBannerWidgetsUpdate( GetBlackboard() );
		}
	}

	private function ReadFile( fileAdress : SDocumentAdress )
	{
		GetDevicePS().SetOpenedFileAdress( fileAdress );
	}

	private function ReadMail( fileAdress : SDocumentAdress )
	{
		GetDevicePS().SetOpenedMailAdress( fileAdress );
	}

	private function ClearOpenedFileAdress()
	{
		GetDevicePS().ClearOpenedFileAdress();
	}

	private function ClearOpenedMailAdress()
	{
		GetDevicePS().ClearOpenedMailAdress();
	}

	private function DecryptFile( fileAdress : SDocumentAdress )
	{
		GetDevicePS().DecryptFile( fileAdress );
	}

	private function DecryptMail( fileAdress : SDocumentAdress )
	{
		GetDevicePS().DecryptMail( fileAdress );
	}

	protected event OnSetDocumentState( evt : SetDocumentStateEvent )
	{
		if( evt.documentType == EDocumentType.MAIL )
		{
			if( evt.isOpened )
			{
				ReadMail( evt.documentAdress );
			}
			else
			{
				ClearOpenedMailAdress();
			}
		}
		else if( evt.documentType == EDocumentType.FILE )
		{
			if( evt.isOpened )
			{
				ReadFile( evt.documentAdress );
			}
			else
			{
				ClearOpenedFileAdress();
			}
		}
	}

	protected override function TurnOffDevice()
	{
		super.TurnOffDevice();
	}

	protected override function TurnOnDevice()
	{
		super.TurnOnDevice();
	}

	protected override function CreateBlackboard()
	{
		m_blackboard = IBlackboard.Create( GetAllBlackboardDefs().ComputerDeviceBlackboard );
	}

	public const override function GetBlackboardDef() : ComputerDeviceBlackboardDef
	{
		return GetDevicePS().GetBlackboardDef();
	}

	protected function StopBannerWidgetsUpdate()
	{
		GameInstance.GetDelaySystem( GetGame() ).CancelDelay( m_bannerUpdateID );
		m_bannerUpdateActive = false;
	}

	private function RequestBannerWidgetsUpdate( blackboard : IBlackboard )
	{
		var evt : RequestBannerWidgetUpdateEvent;
		if( m_bannerUpdateActive )
		{
			StopBannerWidgetsUpdate();
		}
		GetDevicePS().RequestBannerWidgetsUpdate( blackboard );
		evt = new RequestBannerWidgetUpdateEvent;
		if( !( m_bannerUpdateActive ) )
		{
			m_bannerUpdateID = GameInstance.GetDelaySystem( GetGame() ).DelayEvent( this, evt, GetDevicePS().GetNewsfeedInterval() );
			m_bannerUpdateActive = true;
		}
	}

	protected event OnToggleOpen( evt : ToggleOpenComputer )
	{
		ResolveAnimationState( GetDevicePS().GetAnimationState() );
	}

	protected event OnCreateFactQuickHack( evt : FactQuickHack )
	{
		var properties : ComputerQuickHackData;
		properties = evt.GetFactProperties();
		if( properties.operationType == EMathOperationType.Set )
		{
			SetFactValue( GetGame(), properties.factName, properties.factValue );
		}
		else
		{
			AddFact( GetGame(), properties.factName, properties.factValue );
		}
	}

	protected event OnRequestBannerWidgetUpdate( evt : RequestBannerWidgetUpdateEvent )
	{
		StopBannerWidgetsUpdate();
		RequestBannerWidgetsUpdate( GetBlackboard() );
		GetDevicePS().UpdateBanners();
	}

	protected event OnRequestDocumentWidgetUpdate( evt : RequestDocumentWidgetUpdateEvent )
	{
		if( evt.documentType == EDocumentType.FILE )
		{
			GetDevicePS().RequestFileWidgetUpdate( GetBlackboard(), evt.documentAdress );
		}
		else if( evt.documentType == EDocumentType.MAIL )
		{
			GetDevicePS().RequestMailWidgetUpdate( GetBlackboard(), evt.documentAdress );
		}
	}

	protected event OnRequestDocumentThumbnailWidgetsUpdate( evt : RequestDocumentThumbnailWidgetsUpdateEvent )
	{
		if( evt.documentType == EDocumentType.FILE )
		{
			GetDevicePS().RequestFileThumbnailWidgetsUpdate( GetBlackboard() );
		}
		else if( evt.documentType == EDocumentType.MAIL )
		{
			GetDevicePS().RequestMailThumbnailWidgetsUpdate( GetBlackboard() );
		}
	}

	protected event OnRequestMenuWidgetsUpdate( evt : RequestComputerMenuWidgetsUpdateEvent )
	{
		GetDevicePS().RequestMenuButtonWidgetsUpdate( GetBlackboard() );
	}

	protected event OnRequestMainMenuWidgetsUpdate( evt : RequestComputerMainMenuWidgetsUpdateEvent )
	{
		GetDevicePS().RequestMainMenuButtonWidgetsUpdate( GetBlackboard() );
	}

	public const function GetInitialMenuType() : EComputerMenuType
	{
		return GetDevicePS().GetInitialMenuType();
	}

	public const function GetHideTopNavigationBar() : Bool
	{
		return GetDevicePS().GetHideTopNavigationBar();
	}

	public const override function DeterminGameplayRole() : EGameplayRole
	{
		if( GetDevicePS().HasAnySlave() )
		{
			return EGameplayRole.ControlOtherDevice;
		}
		else
		{
			return EGameplayRole.GrantInformation;
		}
	}

	private function DetermineActivationState()
	{
		if( GetDevicePS().GetActivationState() == EActivationState.ACTIVATED )
		{
			if( GetDevicePS().GetActivatorType() == EToggleActivationTypeComputer.Raise )
			{
				TransformAnimActivate( false );
			}
		}
		else if( GetDevicePS().GetActivationState() == EActivationState.DEACTIVATED )
		{
			if( GetDevicePS().GetActivatorType() == EToggleActivationTypeComputer.Raise )
			{
				TransformAnimActivate( true );
			}
		}
	}

	protected event OnActivateDevice( evt : ActivateDevice )
	{
		if( GetDevicePS().GetActivatorType() == EToggleActivationTypeComputer.Raise )
		{
			TransformAnimActivate( false );
		}
	}

	protected event OnDeactivateDevice( evt : DeactivateDevice )
	{
		if( GetDevicePS().GetActivatorType() == EToggleActivationTypeComputer.Raise )
		{
			TransformAnimActivate( true );
		}
	}

	private function TransformAnimActivate( activate : Bool )
	{
		var playEvent : gameTransformAnimationPlayEvent;
		playEvent = new gameTransformAnimationPlayEvent;
		playEvent.looping = false;
		playEvent.timesPlayed = 1;
		playEvent.timeScale = 1.0;
		if( activate )
		{
			playEvent.animationName = 'deactivate';
		}
		else
		{
			playEvent.animationName = 'activate';
		}
		QueueEvent( playEvent );
	}

	private function ResolveAnimationState( state : EComputerAnimationState )
	{
		var playEvent : gameTransformAnimationPlayEvent;
		var animSetFactName : CName;
		animSetFactName = ( ( ComputerControllerPS )( GetDevicePS() ) ).GetAnimationStateFactName();
		if( state != m_currentAnimationState )
		{
			playEvent = new gameTransformAnimationPlayEvent;
			if( state == EComputerAnimationState.Opened )
			{
				playEvent.animationName = 'open';
				if( IsNameValid( animSetFactName ) )
				{
					SetFactValue( GetGame(), animSetFactName, 1 );
				}
			}
			else if( state == EComputerAnimationState.Closed )
			{
				playEvent.animationName = 'close';
				if( IsNameValid( animSetFactName ) )
				{
					SetFactValue( GetGame(), animSetFactName, 0 );
				}
			}
			if( IsNameValid( playEvent.animationName ) )
			{
				playEvent.looping = false;
				playEvent.timesPlayed = 1;
				playEvent.timeScale = 1.0;
				QueueEvent( playEvent );
			}
			m_currentAnimationState = state;
		}
	}

	private override function InitializeScreenDefinition()
	{
		if( !( TDBID.IsValid( m_screenDefinition.screenDefinition ) ) )
		{
			m_screenDefinition.screenDefinition = T"DevicesUIDefinitions.Computer_21x9";
		}
		if( !( TDBID.IsValid( m_screenDefinition.style ) ) )
		{
			m_screenDefinition.style = T"DevicesUIStyles.None";
		}
	}

	protected event OnGoToMenuEvent( evt : GoToMenuEvent )
	{
		evt.ownerID = GetEntityID();
		if( evt.wakeUp )
		{
			GetDevicePS().SetIsInSleepMode( false );
		}
		GameInstance.GetUISystem( GetGame() ).QueueEvent( evt );
	}

	protected event OnOpenDocumentEvent( evt : OpenDocumentEvent )
	{
		evt.ownerID = GetEntityID();
		if( IsNameValid( evt.documentName ) )
		{
			evt.documentAdress = GetDevicePS().GetDocumentAdressByName( evt.documentType, evt.documentName );
		}
		if( evt.wakeUp )
		{
			GetDevicePS().SetIsInSleepMode( false );
		}
		GameInstance.GetUISystem( GetGame() ).QueueEvent( evt );
	}

	protected event OnEnableDocumentEvent( evt : EnableDocumentEvent )
	{
		if( IsNameValid( evt.documentName ) )
		{
			GetDevicePS().EnableDocumentsByName( evt.documentType, evt.documentName, evt.enable );
		}
		else if( evt.entireFolder )
		{
			GetDevicePS().EnableDocumentsInFolder( evt.documentType, evt.documentAdress.folderID, evt.enable );
		}
		else
		{
			GetDevicePS().EnableDocument( evt.documentType, evt.documentAdress, evt.enable );
		}
	}

	protected event OnTCSInputXAxisEvent( evt : TCSInputXAxisEvent )
	{
		var currentRotation : Quaternion;
		var normalizedFloat : Float;
		super.OnTCSInputXAxisEvent( evt );
		m_playerControlData.m_currentYawModifier -= evt.value;
		m_playerControlData.m_currentYawModifier = ClampF( m_playerControlData.m_currentYawModifier, -90.0, 90.0 );
		normalizedFloat = m_playerControlData.m_currentYawModifier / 180.0;
		Quaternion.SetZRot( currentRotation, normalizedFloat );
		m_transformX.SetLocalOrientation( currentRotation );
	}

	protected event OnTCSInputYAxisEvent( evt : TCSInputYAxisEvent )
	{
		var currentRotation : Quaternion;
		var normalizedFloat : Float;
		super.OnTCSInputYAxisEvent( evt );
		m_playerControlData.m_currentPitchModifier -= evt.value;
		m_playerControlData.m_currentPitchModifier = ClampF( m_playerControlData.m_currentPitchModifier, -90.0, 90.0 );
		normalizedFloat = m_playerControlData.m_currentPitchModifier / 180.0;
		Quaternion.SetXRot( currentRotation, normalizedFloat );
		m_transformY.SetLocalOrientation( currentRotation );
	}

}

