class KeypadButtonSpawnData extends IScriptable
{
	var m_widgetName : CName;
	var m_locKey : String;
	var m_isActionButton : Bool;
	var m_widgetData : SDeviceWidgetPackage;

	public function Initialize( widgetName : CName, const locKey : ref< String >, isActionButton : Bool, const widgetData : ref< SDeviceWidgetPackage > )
	{
		m_widgetName = widgetName;
		m_locKey = locKey;
		m_isActionButton = isActionButton;
		m_widgetData = widgetData;
		m_widgetData.displayName = "OK";
	}

}

class KeypadDeviceController extends DeviceWidgetControllerBase
{
	private editable var m_hasButtonAuthorization : Bool;
	private var m_enteredPasswordWidget : weak< inkText >;
	private var m_passwordStatusWidget : weak< inkText >;
	private var m_actionButton : weak< inkWidget >;
	private var m_ActionText : weak< inkText >;
	private var m_passwordsList : array< CName >;
	private var m_cardName : String;
	private var m_isPasswordKnown : Bool;
	private var m_maxDigitsCount : Int32;
	private var m_row1 : weak< inkHorizontalPanel >;
	private var m_row2 : weak< inkHorizontalPanel >;
	private var m_row3 : weak< inkHorizontalPanel >;
	private var m_row4 : weak< inkHorizontalPanel >;
	private var m_arePasswordsInitialized : Bool;
	private var m_blackboard : weak< IBlackboard >;

	protected event OnInitialize()
	{
		m_enteredPasswordWidget = ( ( inkText )( GetWidget( 'safeArea/enteredPassword' ) ) );
		m_passwordStatusWidget = ( ( inkText )( GetWidget( 'safeArea/passwordStatus' ) ) );
		m_row1 = ( ( inkHorizontalPanel )( GetWidget( 'safeArea/keypadButtonsVert/row1' ) ) );
		m_row2 = ( ( inkHorizontalPanel )( GetWidget( 'safeArea/keypadButtonsVert/row2' ) ) );
		m_row3 = ( ( inkHorizontalPanel )( GetWidget( 'safeArea/keypadButtonsVert/row3' ) ) );
		m_row4 = ( ( inkHorizontalPanel )( GetWidget( 'safeArea/keypadButtonsVert/row4' ) ) );
		m_enteredPasswordWidget.SetText( "" );
		m_passwordStatusWidget.SetLocalizedTextScript( "LocKey#42212" );
	}

	public override function Initialize( gameController : DeviceInkGameControllerBase, widgetData : SDeviceWidgetPackage )
	{
		DetermineMaxDigitsCount( gameController );
		inkTextRef.SetLocalizedTextScript( m_statusNameWidget, widgetData.deviceStatus, widgetData.textData );
		inkTextRef.SetLocalizedTextScript( m_displayNameWidget, widgetData.displayName );
		m_cardName = ( ( String )( ( ( DoorWidgetCustomData )( widgetData.customData ) ).GetCardName() ) );
		m_isPasswordKnown = ( ( DoorWidgetCustomData )( widgetData.customData ) ).IsPasswordKnown();
		TryInitializePasswords( gameController, widgetData );
		if( !( m_isInitialized ) )
		{
			AddKeypadButtons( m_row1, 1, widgetData, gameController );
			AddKeypadButtons( m_row2, 2, widgetData, gameController );
			AddKeypadButtons( m_row3, 3, widgetData, gameController );
			AddKeypadButtons( m_row4, 4, widgetData, gameController );
		}
		if( m_actionButton && !( CheckPassword() ) )
		{
			SetWidgetsLocked();
		}
		else if( widgetData.widgetState == EWidgetState.ALLOWED )
		{
			SetWidgetsAllowed();
		}
		else if( widgetData.widgetState == EWidgetState.LOCKED )
		{
			SetWidgetsLocked();
		}
		else if( widgetData.widgetState == EWidgetState.SEALED )
		{
			SetWidgetsState( 'Sealed' );
		}
		else
		{
			SetWidgetsAllowed();
		}
		m_isInitialized = true;
		if( gameController != NULL )
		{
			gameController.SetUICameraZoomState( true );
			TrySaveBlackboard( gameController );
		}
	}

	private function TrySaveBlackboard( gameController : DeviceInkGameControllerBase )
	{
		var device : Device;
		device = ( ( Device )( gameController.GetOwnerEntity() ) );
		if( device )
		{
			m_blackboard = device.GetBlackboard();
		}
	}

	private function TryInitializePasswords( gameController : DeviceInkGameControllerBase, widgetData : SDeviceWidgetPackage )
	{
		var i : Int32;
		if( !( m_arePasswordsInitialized ) )
		{
			for( i = 0; i < widgetData.actionWidgets.Size(); i += 1 )
			{
				if( widgetData.actionWidgets[ i ].widgetName == "AuthorizeUser" )
				{
					m_passwordsList = ( ( AuthorizeUser )( widgetData.actionWidgets[ i ].action ) ).GetValidPasswords();
					break;
				}
			}
			m_arePasswordsInitialized = true;
		}
	}

	private function DetermineMaxDigitsCount( gameController : DeviceInkGameControllerBase )
	{
		m_maxDigitsCount = ( ( gameController.IsOwnerFactInvoker() ) ? ( 10 ) : ( 6 ) );
	}

	private function AddKeypadButtons( parentWidget : weak< inkWidget >, rowNumber : Int32, const widgetData : ref< SDeviceWidgetPackage >, gameController : DeviceInkGameControllerBase )
	{
		var i : Int32;
		var asyncSpawnData : AsyncSpawnData;
		var buttonSpawnData : KeypadButtonSpawnData;
		for( i = ( ( rowNumber - 1 ) * 3 ) + 1; i < ( ( ( rowNumber - 1 ) * 3 ) + 4 ); i += 1 )
		{
			if( TryGetButtonSpawnedDataForIndex( i, widgetData, buttonSpawnData ) )
			{
				asyncSpawnData = new AsyncSpawnData;
				asyncSpawnData.Initialize( this, 'OnKeypadButtonWidgetSpawned', buttonSpawnData, gameController );
				CreateWidgetAsync( parentWidget, 'keypad_button', , asyncSpawnData );
			}
		}
	}

	private function TryGetButtonSpawnedDataForIndex( index : Int32, const widgetData : ref< SDeviceWidgetPackage >, out keypadButtonSpawnData : KeypadButtonSpawnData ) : Bool
	{
		keypadButtonSpawnData = new KeypadButtonSpawnData;
		switch( index )
		{
			case 1:
			{
				keypadButtonSpawnData.Initialize( '1', "LocKey#910", false, widgetData );
				return true;
			}
			case 2:
			{
				keypadButtonSpawnData.Initialize( '2', "LocKey#911", false, widgetData );
				return true;
			}
			case 3:
			{
				keypadButtonSpawnData.Initialize( '3', "LocKey#912", false, widgetData );
				return true;
			}
			case 4:
			{
				keypadButtonSpawnData.Initialize( '4', "LocKey#913", false, widgetData );
				return true;
			}
			case 5:
			{
				keypadButtonSpawnData.Initialize( '5', "LocKey#914", false, widgetData );
				return true;
			}
			case 6:
			{
				keypadButtonSpawnData.Initialize( '6', "LocKey#915", false, widgetData );
				return true;
			}
			case 7:
			{
				keypadButtonSpawnData.Initialize( '7', "LocKey#916", false, widgetData );
				return true;
			}
			case 8:
			{
				keypadButtonSpawnData.Initialize( '8', "LocKey#917", false, widgetData );
				return true;
			}
			case 9:
			{
				keypadButtonSpawnData.Initialize( '9', "LocKey#918", false, widgetData );
				return true;
			}
			case 10:
			{
				keypadButtonSpawnData.Initialize( 'Cancel', "LocKey#920", false, widgetData );
				return true;
			}
			case 11:
			{
				keypadButtonSpawnData.Initialize( '0', "LocKey#890", false, widgetData );
				return true;
			}
			case 12:
			{
				keypadButtonSpawnData.Initialize( 'AuthorizeUser', "OK", true, widgetData );
				return true;
			}
		}
		return false;
	}

	protected event OnKeypadButtonWidgetSpawned( widget : inkWidget, userData : IScriptable )
	{
		var textWidget : inkText;
		var actionWidget : inkWidget;
		var asyncSpawnData : AsyncSpawnData;
		var buttonSpawnData : KeypadButtonSpawnData;
		var i : Int32;
		var actionWidgetName : String;
		var gameController : DeviceInkGameControllerBase;
		asyncSpawnData = ( ( AsyncSpawnData )( userData ) );
		if( !( asyncSpawnData ) )
		{
			return false;
		}
		buttonSpawnData = ( ( KeypadButtonSpawnData )asyncSpawnData.m_widgetData );
		if( !( buttonSpawnData ) )
		{
			return false;
		}
		widget.SetSizeRule( inkESizeRule.Stretch );
		widget.RegisterToCallback( 'OnRelease', this, 'OnMouseButtonReleased' );
		widget.SetName( buttonSpawnData.m_widgetName );
		textWidget = ( ( inkText )( widget.GetController().GetWidget( 'displayName' ) ) );
		textWidget.SetLocalizedTextScript( buttonSpawnData.m_locKey );
		gameController = ( ( DeviceInkGameControllerBase )( asyncSpawnData.m_controller ) );
		if( buttonSpawnData.m_isActionButton )
		{
			if( gameController )
			{
				m_actionButton = widget;
				for( i = 0; i < buttonSpawnData.m_widgetData.actionWidgets.Size(); i += 1 )
				{
					actionWidgetName = buttonSpawnData.m_widgetData.actionWidgets[ i ].widgetName;
					if( actionWidgetName != "AuthorizeUser" )
					{
						continue;
					}
					buttonSpawnData.m_widgetData.actionWidgets[ i ].displayName = buttonSpawnData.m_locKey;
					actionWidget = GetActionWidget( buttonSpawnData.m_widgetData.actionWidgets[ i ], gameController );
					if( actionWidget == NULL )
					{
						actionWidget = m_actionButton;
						AddActionWidget( actionWidget, buttonSpawnData.m_widgetData.actionWidgets[ i ], gameController );
					}
					ResolveAction( buttonSpawnData.m_widgetData.actionWidgets[ i ] );
					InitializeActionWidget( gameController, actionWidget, buttonSpawnData.m_widgetData.actionWidgets[ i ] );
					widget.SetVisible( m_hasButtonAuthorization );
					break;
				}
			}
		}
		else
		{
			RegisterButtonWidgetToAudioCallbacks( gameController, widget );
		}
	}

	protected event OnMouseButtonReleased( e : inkPointerEvent )
	{
		var button : weak< inkWidget >;
		if( e.IsAction( 'click' ) && CanHandleClickAction() )
		{
			button = e.GetTarget();
			HandleButtonClicked( button );
		}
	}

	private function CanHandleClickAction() : Bool
	{
		return !( m_blackboard ) || !( m_blackboard.GetBool( GetAllBlackboardDefs().DeviceBaseBlackboard.UI_InteractivityBlocked ) );
	}

	private function HandleButtonClicked( button : weak< inkWidget > )
	{
		var buttonName : CName;
		buttonName = button.GetName();
		m_passwordStatusWidget.SetLocalizedTextString( "LocKey#42212" );
		if( buttonName == 'AuthorizeUser' )
		{
			if( m_hasButtonAuthorization )
			{
				if( CheckPassword() )
				{
					GrantAccess();
				}
				else
				{
					DenyAccess();
				}
			}
		}
		else if( buttonName == 'Cancel' )
		{
			if( m_enteredPasswordWidget.GetText() != "" )
			{
				ClearPassword();
				SetWidgetsLocked();
				PlayTerminalSound( GetDeleteInputSoundEventName() );
			}
		}
		else if( IsDigit( buttonName ) && CanAddDigit() )
		{
			m_enteredPasswordWidget.SetText( m_enteredPasswordWidget.GetText() + ( ( String )( buttonName ) ) );
			if( !( m_hasButtonAuthorization ) && CheckPassword() )
			{
				GrantAccess();
			}
			else
			{
				SetWidgetsLocked();
			}
		}
		RefreshActionButtons();
	}

	private function SetWidgetsLocked()
	{
		SetWidgetsState( 'Locked' );
	}

	private function SetWidgetsAllowed()
	{
		SetWidgetsState( 'Allowed' );
	}

	private function SetWidgetsState( stateName : CName )
	{
		m_passwordStatusWidget.SetState( stateName );
		inkTextRef.SetState( m_statusNameWidget, stateName );
	}

	private function CanAddDigit() : Bool
	{
		return StrLen( m_enteredPasswordWidget.GetText() ) < m_maxDigitsCount;
	}

	private function IsDigit( buttonName : CName ) : Bool
	{
		return StringToInt( NameToString( buttonName ), -1 ) != -1;
	}

	private function DenyAccess()
	{
		m_passwordStatusWidget.SetLocalizedTextScript( "LocKey#42213" );
		SetWidgetsLocked();
		ClearPassword();
		PlayTerminalSound( GetAccessDeniedSoundEventName() );
	}

	public function ClearPassword()
	{
		m_enteredPasswordWidget.SetText( "" );
	}

	private function CheckPassword() : Bool
	{
		var i : Int32;
		for( i = 0; i < m_passwordsList.Size(); i += 1 )
		{
			if( StringToName( m_enteredPasswordWidget.GetText() ) == m_passwordsList[ i ] )
			{
				return true;
			}
		}
		return false;
	}

	private function RefreshActionButtons()
	{
		m_actionButton.SetState( 'Default' );
	}

	private function GrantAccess()
	{
		var i : Int32;
		for( i = 0; i < m_actionWidgetsData.Size(); i += 1 )
		{
			ResolveAction( m_actionWidgetsData[ i ] );
			m_actionButton.CallCustomCallback( 'OnExecuteButtonAction' );
		}
		m_passwordStatusWidget.SetLocalizedTextScript( "LocKey#42214" );
		SetWidgetsAllowed();
		m_actionButton.SetState( 'Press' );
		PlayTerminalSound( GetAccessGrantedSoundEventName() );
	}

	private constexpr function GetAccessGrantedSoundEventName() : CName
	{
		return 'OnAccessGranted';
	}

	private constexpr function GetAccessDeniedSoundEventName() : CName
	{
		return 'OnAccessDenied';
	}

	private constexpr function GetDeleteInputSoundEventName() : CName
	{
		return 'OnDeleteInput';
	}

	private function PlayTerminalSound( soundEventName : CName )
	{
		PlaySound( GetTerminalAudioName(), soundEventName );
	}

	private constexpr function GetTerminalAudioName() : CName
	{
		return 'Terminal';
	}

	protected override function ResolveAction( const widgetData : ref< SActionWidgetPackage > )
	{
		var data : ResolveActionData;
		var actions : array< weak< DeviceAction > >;
		var action : ScriptableDeviceAction;
		data = new ResolveActionData;
		data.m_password = m_enteredPasswordWidget.GetText();
		actions = ( ( DeviceActionWidgetControllerBase )( widgetData.widget.GetController() ) ).GetActions();
		action = ( ( ScriptableDeviceAction )( actions[ 0 ] ) );
		action.ResolveAction( data );
	}

}

