class TeleportToLinkedPortalEvent extends Event
{
}

class ToggleStreamOnLinkedPortalEvent extends Event
{
	var m_activate : Bool;
}

class Portal extends InteractiveDevice
{
	default m_controllerTypeName = 'PortalController';
	[ category = "Portal Setup" ]
	private instanceeditable var m_exitNode : NodeRef;
	[ category = "Portal Setup" ]
	private instanceeditable var m_LinkedPortal : NodeRef;
	protected var m_renderToTextureComponent : weak< IPlacedComponent >;
	protected var m_virtualCameraComponent : weak< IPlacedComponent >;
	protected var m_isInStreamRange : Bool;
	protected var m_isInTeleportRange : Bool;
	protected var m_isOnOtherSide : Bool;
	protected var m_playerBlocker : weak< IPlacedComponent >;
	protected var m_screen : weak< MeshComponent >;

	protected event OnRequestComponents( ri : EntityRequestComponentsInterface )
	{
		EntityRequestComponentsInterface.RequestComponent( ri, 'stream_view_ui', 'worlduiWidgetComponent', true );
		EntityRequestComponentsInterface.RequestComponent( ri, 'render_to_texture_component', 'entRenderToTextureCameraComponent', true );
		EntityRequestComponentsInterface.RequestComponent( ri, 'virtual_camera_portal', 'entVirtualCameraComponent', true );
		EntityRequestComponentsInterface.RequestComponent( ri, 'player_blocker', 'SimpleColliderComponent', true );
		EntityRequestComponentsInterface.RequestComponent( ri, 'stream_video_screen', 'MeshComponent', true );
		super.OnRequestComponents( ri );
	}

	protected event OnTakeControl( ri : EntityResolveComponentsInterface )
	{
		m_uiComponent = ( ( worlduiWidgetComponent )( EntityResolveComponentsInterface.GetComponent( ri, 'stream_view_ui' ) ) );
		m_renderToTextureComponent = ( ( IPlacedComponent )( EntityResolveComponentsInterface.GetComponent( ri, 'render_to_texture_component' ) ) );
		m_virtualCameraComponent = ( ( IPlacedComponent )( EntityResolveComponentsInterface.GetComponent( ri, 'virtual_camera_portal' ) ) );
		m_playerBlocker = ( ( IPlacedComponent )( EntityResolveComponentsInterface.GetComponent( ri, 'player_blocker' ) ) );
		m_screen = ( ( MeshComponent )( EntityResolveComponentsInterface.GetComponent( ri, 'stream_video_screen' ) ) );
		m_playerBlocker.Toggle( false );
		super.OnTakeControl( ri );
		m_controller = ( ( PortalController )( EntityResolveComponentsInterface.GetComponent( ri, 'controller' ) ) );
	}

	protected event OnAreaEnter( evt : AreaEnteredEvent )
	{
		if( evt.componentName == 'other_side' )
		{
			m_isOnOtherSide = true;
		}
		else if( evt.componentName == 'activate_stream' )
		{
			m_isInStreamRange = true;
			if( !( m_isInTeleportRange ) )
			{
				m_isOnOtherSide = false;
			}
			if( GetDevicePS().IsON() )
			{
				TurnOnScreen();
			}
		}
		else if( evt.componentName == 'teleport' )
		{
			m_isInTeleportRange = true;
			if( !( m_isOnOtherSide ) && GetDevicePS().IsON() )
			{
				TeleportPlayerToLinkedPortal();
			}
		}
	}

	protected event OnAreaExit( evt : AreaExitedEvent )
	{
		if( evt.componentName == 'activate_stream' )
		{
			if( GetDevicePS().IsON() )
			{
				TurnOffScreen();
			}
			m_isInStreamRange = false;
		}
		else if( evt.componentName == 'teleport' )
		{
			m_isInTeleportRange = false;
			m_isOnOtherSide = false;
		}
	}

	private function ToggleStream( activate : Bool )
	{
		m_virtualCameraComponent.Toggle( activate );
		m_renderToTextureComponent.Toggle( activate );
		TurnOffScreen();
	}

	private function ToggleStreamOnLinkedPortal( activate : Bool )
	{
		var evt : ToggleStreamOnLinkedPortalEvent;
		var gNodeRef : GlobalNodeRef;
		gNodeRef = ResolveNodeRefWithEntityID( m_LinkedPortal, GetEntityID() );
		if( GlobalNodeRef.IsDefined( gNodeRef ) )
		{
			m_virtualCameraComponent.Toggle( false );
			evt = new ToggleStreamOnLinkedPortalEvent;
			evt.m_activate = activate;
			QueueEventForNodeID( gNodeRef, evt );
		}
	}

	protected event OnToggleStreamOnLinkedPortal( evt : ToggleStreamOnLinkedPortalEvent )
	{
		ToggleStream( evt.m_activate );
	}

	private function TeleportToExitNode()
	{
		var globalRef : GlobalNodeRef;
		var position : Vector4;
		var nodeTransform : Transform;
		var rotation : EulerAngles;
		globalRef = ResolveNodeRefWithEntityID( m_exitNode, GetEntityID() );
		if( GlobalNodeRef.IsDefined( globalRef ) )
		{
			GameInstance.GetNodeTransform( GetGame(), globalRef, nodeTransform );
			position = Transform.GetPosition( nodeTransform );
			rotation = Quaternion.ToEulerAngles( Transform.GetOrientation( nodeTransform ) );
			GameInstance.GetTeleportationFacility( GetGame() ).Teleport( GetPlayer( GetGame() ), position, rotation );
		}
	}

	private function TeleportPlayerToLinkedPortal()
	{
		var evt : TeleportToLinkedPortalEvent;
		var gNodeRef : GlobalNodeRef;
		gNodeRef = ResolveNodeRefWithEntityID( m_LinkedPortal, GetEntityID() );
		if( GlobalNodeRef.IsDefined( gNodeRef ) )
		{
			evt = new TeleportToLinkedPortalEvent;
			QueueEventForNodeID( gNodeRef, evt );
		}
	}

	protected event OnTeleportToLinkedPortalEvent( evt : TeleportToLinkedPortalEvent )
	{
		TeleportToExitNode();
	}

	protected const override function GetController() : ScriptableDeviceComponent
	{
		return m_controller;
	}

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

	protected event OnLogicReady( evt : SetLogicReadyEvent )
	{
		super.OnLogicReady( evt );
		if( IsUIdirty() && m_isInsideLogicArea )
		{
			RefreshUI();
		}
	}

	protected override function CutPower()
	{
		super.CutPower();
		TurnOffScreen();
	}

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

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

	protected override function DeactivateDevice()
	{
		super.DeactivateDevice();
		ToggleLogicLayer( false );
	}

	protected override function ActivateDevice()
	{
		super.ActivateDevice();
		ToggleLogicLayer( true );
	}

	protected function TurnOffScreen()
	{
		m_screen.Toggle( false );
		if( m_uiComponent )
		{
			m_uiComponent.Toggle( false );
		}
		if( m_isInStreamRange )
		{
			ToggleStreamOnLinkedPortal( false );
		}
		m_playerBlocker.Toggle( false );
	}

	protected function TurnOnScreen()
	{
		var gNodeRef : GlobalNodeRef;
		if( !( m_isInStreamRange ) )
		{
			m_screen.Toggle( false );
			m_uiComponent.Toggle( false );
			return;
		}
		else
		{
			gNodeRef = ResolveNodeRefWithEntityID( m_LinkedPortal, GetEntityID() );
			if( !( GlobalNodeRef.IsDefined( gNodeRef ) ) )
			{
				m_screen.Toggle( false );
				m_uiComponent.Toggle( false );
				return;
			}
		}
		if( m_uiComponent )
		{
			m_screen.Toggle( true );
			m_uiComponent.Toggle( true );
		}
		ToggleStreamOnLinkedPortal( true );
		m_playerBlocker.Toggle( true );
		if( m_isInTeleportRange && !( m_isOnOtherSide ) )
		{
			TeleportPlayerToLinkedPortal();
		}
	}

}

