class QuickHackCallElevator extends ActionBool
{

	public override function GetTweakDBChoiceRecord() : String
	{
		if( TDBID.IsValid( m_objectActionID ) )
		{
			return super.GetTweakDBChoiceRecord();
		}
		else
		{
			return "QuickHackCallElevator";
		}
	}

}

class CallElevator extends ActionBool
{
	var m_destination : Int32;

	public function SetProperties( destination : Int32 )
	{
		actionName = 'CallElevator';
		prop = DeviceActionPropertyFunctions.SetUpProperty_Bool( 'CallElevator', true, 'LocKey#293', 'LocKey#293' );
		m_destination = destination;
	}

	public static function IsDefaultConditionMet( device : ScriptableDeviceComponentPS, const context : ref< GetActionsContext > ) : Bool
	{
		if( IsAvailable( device ) && IsClearanceValid( context.clearance ) )
		{
			return true;
		}
		return false;
	}

	public static function IsAvailable( device : ScriptableDeviceComponentPS ) : Bool
	{
		if( device.IsDisabled() )
		{
			return false;
		}
		if( device.IsUnpowered() )
		{
			return false;
		}
		if( !( device.IsON() ) )
		{
			return false;
		}
		return true;
	}

	public static function IsClearanceValid( clearance : Clearance ) : Bool
	{
		if( Clearance.IsInRange( clearance, DefaultActionsParametersHolder.GetInteractiveClearance() ) )
		{
			return true;
		}
		return false;
	}

	public override function GetTweakDBChoiceRecord() : String
	{
		if( TDBID.IsValid( m_objectActionID ) )
		{
			return super.GetTweakDBChoiceRecord();
		}
		else
		{
			return "CallElevator";
		}
	}

	public function CreateActionWidgetPackage( isElevatorAtThisFloor : Bool )
	{
		m_actionWidgetPackage.wasInitalized = true;
		m_actionWidgetPackage.widgetTweakDBID = GetInkWidgetTweakDBID( isElevatorAtThisFloor );
		m_actionWidgetPackage.widgetName = "Call Elevator";
		m_actionWidgetPackage.displayName = "Call Elevator";
		m_actionWidgetPackage.libraryPath = GetInkWidgetLibraryPath();
		m_actionWidgetPackage.libraryID = GetInkWidgetLibraryID();
		ResolveActionWidgetTweakDBData();
	}

	public function GetInkWidgetTweakDBID( isElevatorAtThisFloor : Bool ) : TweakDBID
	{
		if( isElevatorAtThisFloor )
		{
			return T"DevicesUIDefinitions.EnterElevatorActionWidget";
		}
		else
		{
			return T"DevicesUIDefinitions.CallElevatorActionWidget";
		}
	}

}

class LiftFloorSyncDataEvent extends Event
{
	var isHidden : Bool;
	var isInactive : Bool;
}

struct ElevatorFloorSetup
{
	instanceeditable persistent var m_isHidden : Bool;
	instanceeditable persistent var m_isInactive : Bool;
	[ unsavable = "true" ]
	instanceeditable persistent var m_floorMarker : NodeRef;
	editable var m_floorName : String;
	[ category = "Localization" ][ unsavable = "true" ]
	instanceeditable persistent var m_floorDisplayName : CName;
	instanceeditable var m_authorizationTextOverride : String;
	[ unsavable = "true" ]
	const instanceeditable persistent var doorShouldOpenFrontLeftRight : array< Bool >;

	public static function GetFloorName( const self : ref< ElevatorFloorSetup > ) : String
	{
		var floorName : String;
		if( IsNameValid( self.m_floorDisplayName ) )
		{
			floorName = NameToString( self.m_floorDisplayName );
		}
		else
		{
			floorName = self.m_floorName;
		}
		return floorName;
	}

}

class ElevatorFloorTerminalController extends TerminalController
{

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

}

class ElevatorFloorTerminalControllerPS extends TerminalControllerPS
{
	default m_deviceName = "LocKey#88";
	default m_tweakDBRecord = T"Devices.ElevatorFloorTerminal";
	default m_tweakDBDescriptionRecord = T"device_descriptions.ElevatorFloorTerminal";
	private instanceeditable persistent var m_elevatorFloorSetup : ElevatorFloorSetup;
	private editable var m_hasDirectInteration : Bool;
	protected var m_isElevatorAtThisFloor : Bool;

	protected override function GameAttached()
	{
		EvaluateFloor();
	}

	public const function GetElevatorFloorSetup() : ElevatorFloorSetup
	{
		return m_elevatorFloorSetup;
	}

	public const function GetAuthorizationTextOverride() : String
	{
		return m_elevatorFloorSetup.m_authorizationTextOverride;
	}

	public quest const function IsElevatorAtThisFloor() : Bool
	{
		return m_isElevatorAtThisFloor;
	}

	public function EvaluateThisFloor()
	{
		var i : Int32;
		var devices : array< DeviceComponentPS >;
		var liftControllerPS : LiftControllerPS;
		GetParents( devices );
		for( i = 0; i < devices.Size(); i += 1 )
		{
			if( ( ( LiftControllerPS )( devices[ i ] ) ) )
			{
				liftControllerPS = ( ( LiftControllerPS )( devices[ i ] ) );
				if( liftControllerPS.GetFloorPSID( liftControllerPS.GetActiveFloor() ) == GetID() )
				{
					m_isElevatorAtThisFloor = true;
				}
			}
		}
	}

	private function EvaluateFloor()
	{
		if( !( IsNameValid( m_elevatorFloorSetup.m_floorDisplayName ) ) )
		{
			m_elevatorFloorSetup.m_floorDisplayName = StringToName( m_elevatorFloorSetup.m_floorName );
		}
	}

	protected override function Initialize()
	{
		super.Initialize();
		if( !( IsStringValid( m_deviceName ) ) )
		{
			m_deviceName = "LocKey#88";
		}
	}

	protected override function GetInkWidgetTweakDBID( const context : ref< GetActionsContext > ) : TweakDBID
	{
		return T"DevicesUIDefinitions.ElevatorFloorDeviceWidget";
	}

	public override function GetThumbnailWidgets() : array< SThumbnailWidgetPackage >
	{
		var devices : array< DeviceComponentPS >;
		var widgetsData : array< SThumbnailWidgetPackage >;
		GetParents( devices );
		widgetsData.PushBack( devices[ 0 ].GetThumbnailWidget() );
		return widgetsData;
	}

	public override function GetActions( out outActions : array< DeviceAction >, context : GetActionsContext ) : Bool
	{
		var scriptableAction : ScriptableDeviceAction;
		if( !( IsPlayerAuthorized() ) && !( context.ignoresAuthorization ) )
		{
			outActions.PushBack( ActionSetExposeQuickHacks() );
			scriptableAction = ActionAuthorizeUser( ShouldForceAuthorizeUser( context ) );
			scriptableAction.SetDurationValue( 0.69999999 );
			outActions.PushBack( scriptableAction );
			return false;
		}
		if( m_hasDirectInteration )
		{
			outActions.PushBack( ActionCallElevator() );
		}
		return super.GetActions( outActions, context );
	}

	protected const override function CanCreateAnyQuickHackActions() : Bool
	{
		return true;
	}

	protected override function GetQuickHackActions( out actions : array< DeviceAction >, const context : ref< GetActionsContext > )
	{
		var currentAction : ScriptableDeviceAction;
		if( !( m_isElevatorAtThisFloor ) )
		{
			currentAction = ActionQuickHackCallElevator();
			currentAction.SetObjectActionID( T"DeviceAction.ToggleStateClassHack" );
			currentAction.SetInactiveWithReason( QuickHackCallElevator.IsDefaultConditionMet( ( ( ElevatorFloorTerminalControllerPS )( this ) ), context ), "LocKey#7003" );
			actions.PushBack( currentAction );
		}
		if( !( IsPlayerAuthorized() ) )
		{
			currentAction = ActionQuickHackAuthorization();
			currentAction.SetObjectActionID( T"DeviceAction.OverrideAttitudeClassHack" );
			currentAction.SetInactiveWithReason( QuickHackAuthorization.IsDefaultConditionMet( ( ( ElevatorFloorTerminalControllerPS )( this ) ), context ), "LocKey#7003" );
			actions.PushBack( currentAction );
		}
		FinalizeGetQuickHackActions( actions, context );
	}

	protected override function PushInactiveInteractionChoice( const context : ref< GetActionsContext >, choices : ref< array< InteractionChoice > > )
	{
		var baseAction : CallElevator;
		var inactiveChoice : InteractionChoice;
		if( m_hasDirectInteration )
		{
			baseAction = ActionCallElevator();
			inactiveChoice.choiceMetaData.tweakDBName = baseAction.GetTweakDBChoiceRecord();
			inactiveChoice.caption = "DEBUG: Reason Unhandled";
			ChoiceTypeWrapper.SetType( inactiveChoice.choiceMetaData.type, gameinteractionsChoiceType.Inactive );
			if( !( IsPlayerAuthorized() ) )
			{
				inactiveChoice.caption = "[UNAUTHORIZED]";
				choices.PushBack( inactiveChoice );
				return;
			}
		}
	}

	protected virtual function ActionQuickHackCallElevator() : QuickHackCallElevator
	{
		var action : QuickHackCallElevator;
		action = new QuickHackCallElevator;
		action.clearanceLevel = 1;
		action.SetUp( this );
		action.AddDeviceName( GetDeviceName() );
		action.CreateInteraction();
		return action;
	}

	public function ActionQuickHackAuthorization() : QuickHackAuthorization
	{
		var action : QuickHackAuthorization;
		action = new QuickHackAuthorization;
		action.clearanceLevel = DefaultActionsParametersHolder.GetInteractiveClearance();
		action.SetUp( this );
		action.AddDeviceName( m_deviceName );
		action.CreateInteraction();
		return action;
	}

	protected override function ActionAuthorizeUser( optional isForced : Bool ) : AuthorizeUser
	{
		var action : AuthorizeUser;
		action = new AuthorizeUser;
		action.clearanceLevel = DefaultActionsParametersHolder.GetAuthorizeUserClearance();
		action.SetUp( this );
		action.SetProperties( GetPasswords(), isForced );
		action.AddDeviceName( GetDeviceName() );
		action.CreateActionWidgetPackage( 'elevator', GetAuthorizationTextOverride() );
		return action;
	}

	private function ActionCallElevator() : CallElevator
	{
		var action : CallElevator;
		action = new CallElevator;
		action.clearanceLevel = DefaultActionsParametersHolder.GetInteractiveClearance();
		action.SetUp( this );
		action.SetProperties( 0 );
		action.AddDeviceName( m_deviceName );
		action.CreateInteraction();
		return action;
	}

	public function OnQuickHackCallElevator( evt : QuickHackCallElevator ) : EntityNotificationType
	{
		m_authorizationProperties.m_isAuthorizationModuleOn = false;
		HackCallElevator();
		UseNotifier( evt );
		return EntityNotificationType.DoNotNotifyEntity;
	}

	public function OnCallElevator( evt : CallElevator ) : EntityNotificationType
	{
		if( IsPlayerAuthorized() )
		{
			CallElevator();
			UseNotifier( evt );
		}
		return EntityNotificationType.DoNotNotifyEntity;
	}

	public override function OnQuickHackAuthorization( evt : QuickHackAuthorization ) : EntityNotificationType
	{
		var notifier : ActionNotifier;
		notifier = new ActionNotifier;
		notifier.SetNone();
		m_authorizationProperties.m_isAuthorizationModuleOn = false;
		SendQuickHackAuthorizationToParents();
		RefreshUI( GetBlackboard() );
		if( IsElevatorAtThisFloor() )
		{
			UnlockConnectedDoors();
		}
		if( !( IsFinal() ) )
		{
		}
		Notify( notifier, evt );
		return EntityNotificationType.SendThisEventToEntity;
	}

	protected function SendQuickHackAuthorizationToParents()
	{
		var parents : array< DeviceComponentPS >;
		var i : Int32;
		var evt : QuickHackAuthorization;
		evt = new QuickHackAuthorization;
		GetParents( parents );
		for( i = 0; i < parents.Size(); i += 1 )
		{
			if( ( ( LiftControllerPS )( parents[ i ] ) ) )
			{
				GetPersistencySystem().QueuePSEvent( parents[ i ].GetID(), parents[ i ].GetClassName(), evt );
			}
		}
	}

	public export override function OnAuthorizeUser( evt : AuthorizeUser ) : EntityNotificationType
	{
		if( evt.IsStarted() )
		{
			ExecutePSActionWithDelay( evt, this, evt.GetDurationValue() );
			return EntityNotificationType.DoNotNotifyEntity;
		}
		else
		{
			UseNotifier( evt );
			if( IsPlayerAuthorized() )
			{
				return EntityNotificationType.SendPSChangedEventToEntity;
			}
			else
			{
				return EntityNotificationType.DoNotNotifyEntity;
			}
		}
	}

	public override function GetDeviceWidgets() : array< SDeviceWidgetPackage >
	{
		var devices : array< DeviceComponentPS >;
		var widgetsData : array< SDeviceWidgetPackage >;
		var widgetData : SDeviceWidgetPackage;
		var i : Int32;
		GetParents( devices );
		for( i = 0; i < devices.Size(); i += 1 )
		{
			if( ( ( LiftControllerPS )( devices[ i ] ) ) )
			{
				widgetData = devices[ i ].GetDeviceWidget( GenerateContext( gamedeviceRequestType.External, GetClearance() ) );
				widgetsData.PushBack( widgetData );
			}
		}
		return widgetsData;
	}

	public override function GetSlaveDeviceWidget( deviceID : PersistentID ) : SDeviceWidgetPackage
	{
		var i : Int32;
		var devices : array< DeviceComponentPS >;
		var widgetData : SDeviceWidgetPackage;
		GetParents( devices );
		for( i = 0; i < devices.Size(); i += 1 )
		{
			if( ( ( LiftControllerPS )( devices[ i ] ) ) )
			{
				widgetData = devices[ i ].GetDeviceWidget( GenerateContext( gamedeviceRequestType.External, GetClearance() ) );
				break;
			}
		}
		return widgetData;
	}

	public override function GetDeviceWidget( const context : ref< GetActionsContext > ) : SDeviceWidgetPackage
	{
		var widgetData : SDeviceWidgetPackage;
		widgetData = super.GetDeviceWidget( context );
		widgetData.displayName = ElevatorFloorSetup.GetFloorName( m_elevatorFloorSetup );
		return widgetData;
	}

	public export function OnLiftArrived( evt : LiftArrivedEvent ) : EntityNotificationType
	{
		UnlockConnectedDoors();
		m_isElevatorAtThisFloor = true;
		return EntityNotificationType.DoNotNotifyEntity;
	}

	public export function OnLiftDeparted( evt : LiftDepartedEvent ) : EntityNotificationType
	{
		LockConnectedDoors();
		m_isElevatorAtThisFloor = false;
		return EntityNotificationType.DoNotNotifyEntity;
	}

	public export function OnLiftFloorSyncDataEvent( evt : LiftFloorSyncDataEvent ) : EntityNotificationType
	{
		m_elevatorFloorSetup.m_isHidden = evt.isHidden;
		m_elevatorFloorSetup.m_isInactive = evt.isInactive;
		return EntityNotificationType.DoNotNotifyEntity;
	}

	private function UnlockConnectedDoors()
	{
		var i : Int32;
		var LockAction : ForceUnlockAndOpenElevator;
		var devices : array< DeviceComponentPS >;
		devices = GetImmediateSlaves();
		for( i = 0; i < devices.Size(); i += 1 )
		{
			if( ( ( DoorControllerPS )( devices[ i ] ) ) && IsPlayerAuthorized() )
			{
				LockAction = ActionForceUnlockAndOpenElevator( ( ( DoorControllerPS )( devices[ i ] ) ) );
				if( LockAction && ( ( ( DoorControllerPS )( devices[ i ] ) ).IsLocked() || ( ( DoorControllerPS )( devices[ i ] ) ).IsClosed() ) )
				{
					GetPersistencySystem().QueuePSDeviceEvent( LockAction );
				}
			}
		}
	}

	private function LockConnectedDoors()
	{
		var i : Int32;
		var LockAction : ForceLockElevator;
		var devices : array< DeviceComponentPS >;
		devices = GetImmediateSlaves();
		for( i = 0; i < devices.Size(); i += 1 )
		{
			if( ( ( DoorControllerPS )( devices[ i ] ) ) )
			{
				LockAction = ActionForceLockElevator( ( ( DoorControllerPS )( devices[ i ] ) ) );
				if( LockAction && !( ( ( DoorControllerPS )( devices[ i ] ) ).IsLocked() ) )
				{
					GetPersistencySystem().QueuePSDeviceEvent( LockAction );
				}
			}
		}
	}

	private function CallElevator()
	{
		var i : Int32;
		var callElevator : CallElevator;
		var devices : array< DeviceComponentPS >;
		var context : GetActionsContext;
		context.requestType = gamedeviceRequestType.External;
		context.requestorID = GetMyEntityID();
		GetParents( devices );
		for( i = 0; i < devices.Size(); i += 1 )
		{
			if( ( ( LiftControllerPS )( devices[ i ] ) ) )
			{
				callElevator = ( ( CallElevator )( ( ( LiftControllerPS )( devices[ i ] ) ).GetActionByName( 'CallElevator', context ) ) );
				if( callElevator )
				{
					GetPersistencySystem().QueuePSDeviceEvent( callElevator );
				}
			}
		}
	}

	public const function IsLiftMoving() : Bool
	{
		var i : Int32;
		var devices : array< DeviceComponentPS >;
		GetParents( devices );
		for( i = 0; i < devices.Size(); i += 1 )
		{
			if( ( ( LiftControllerPS )( devices[ i ] ) ) )
			{
				return ( ( LiftControllerPS )( devices[ i ] ) ).IsMoving();
			}
		}
		return false;
	}

	private function HackCallElevator()
	{
		var i : Int32;
		var callElevator : CallElevator;
		var devices : array< DeviceComponentPS >;
		var context : GetActionsContext;
		context.clearance = Clearance.CreateClearance( 0, 100 );
		context.requestType = gamedeviceRequestType.External;
		context.requestorID = GetMyEntityID();
		context.ignoresAuthorization = true;
		GetParents( devices );
		for( i = 0; i < devices.Size(); i += 1 )
		{
			if( ( ( LiftControllerPS )( devices[ i ] ) ) )
			{
				callElevator = ( ( CallElevator )( ( ( LiftControllerPS )( devices[ i ] ) ).GetActionByName( 'CallElevator', context ) ) );
				if( callElevator )
				{
					GetPersistencySystem().QueuePSDeviceEvent( callElevator );
				}
			}
		}
	}

	protected function ActionForceLockElevator( targetDevicePS : PersistentState ) : ForceLockElevator
	{
		var action : ForceLockElevator;
		action = new ForceLockElevator;
		action.clearanceLevel = DefaultActionsParametersHolder.GetToggleLockClearance();
		action.SetUp( targetDevicePS );
		action.SetProperties();
		action.AddDeviceName( "ElevatorDoor" );
		return action;
	}

	protected function ActionForceUnlockAndOpenElevator( targetDevicePS : PersistentState ) : ForceUnlockAndOpenElevator
	{
		var action : ForceUnlockAndOpenElevator;
		action = new ForceUnlockAndOpenElevator;
		action.clearanceLevel = DefaultActionsParametersHolder.GetToggleLockClearance();
		action.SetUp( targetDevicePS );
		action.SetProperties();
		action.AddDeviceName( "ElevatorDoor" );
		return action;
	}

	public override function TurnAuthorizationModuleOFF()
	{
		m_authorizationProperties.m_isAuthorizationModuleOn = false;
	}

}

