class MessageMenuAttachmentData extends IScriptable
{
	var m_entryHash : Int32;
}

class PhoneMessagePopupGameController extends gameuiNewPhoneRelatedGameController
{
	private editable var m_content : inkWidgetRef;
	private editable var m_title : inkTextRef;
	private editable var m_avatarImage : inkImageRef;
	private editable var m_menuBackgrouns : inkWidgetRef;
	[ category = "Hints" ]
	private editable var m_hintsContainer : inkWidgetRef;
	[ category = "Hints" ]
	private editable var m_hintTrack : inkWidgetRef;
	[ category = "Hints" ]
	private editable var m_hintClose : inkWidgetRef;
	[ category = "Hints" ]
	private editable var m_hintReply : inkWidgetRef;
	[ category = "Hints" ]
	private editable var m_scrollReply : inkWidgetRef;
	[ category = "Hints" ]
	private editable var m_hintMessenger : inkWidgetRef;
	[ category = "Hints" ]
	private editable var m_hintCall : inkWidgetRef;
	private editable var m_scrollSlider : inkWidgetRef;
	private editable var m_contactsPath : inkWidgetRef;
	private editable var m_messagesPath : inkWidgetRef;
	private var m_blackboard : weak< IBlackboard >;
	private var m_blackboardDef : UI_ComDeviceDef;
	private var m_uiSystem : UISystem;
	private var m_player : weak< GameObject >;
	private var m_journalMgr : weak< JournalManager >;
	private var m_phoneSystem : weak< PhoneSystem >;
	private var m_data : JournalNotificationData;
	private var m_entry : weak< JournalPhoneMessage >;
	private var m_contactEntry : weak< JournalContact >;
	private var m_attachment : weak< JournalEntry >;
	private var m_attachmentState : gameJournalEntryState;
	private var m_attachmentHash : Uint32;
	private var m_activeEntry : weak< JournalEntry >;
	private var m_dialogViewController : weak< MessengerDialogViewController >;
	private var m_journalEntryHash : Int32;
	private var m_proxy : inkAnimProxy;
	private var m_isFocused : Bool;
	default m_isFocused = false;
	private var m_isHubVisiale : Bool;
	default m_isHubVisiale = false;

	protected event OnInitialize()
	{
		m_player = GetPlayerControlledObject();
		m_journalMgr = GameInstance.GetJournalManager( m_player.GetGame() );
		m_uiSystem = GameInstance.GetUISystem( m_player.GetGame() );
		m_phoneSystem = ( ( PhoneSystem )( GameInstance.GetScriptableSystemsContainer( m_player.GetGame() ).Get( 'PhoneSystem' ) ) );
		m_blackboardDef = GetAllBlackboardDefs().UI_ComDevice;
		m_blackboard = GetBlackboardSystem().Get( m_blackboardDef );
		m_blackboard.SetBool( m_blackboardDef.isDisplayingMessage, true, true );
		GetRootWidget().SetOpacity( 0.0 );
		m_dialogViewController = ( ( MessengerDialogViewController )( inkWidgetRef.GetController( m_content ) ) );
		m_dialogViewController.AttachJournalManager( m_journalMgr );
		m_dialogViewController.InitDelaySystem( GetPlayerControlledObject() );
		m_data = ( ( JournalNotificationData )( GetRootWidget().GetUserData( 'JournalNotificationData' ) ) );
		SetupData();
		QueueEvent( new SmsMessangerInitalizedEvent );
		m_journalMgr.RegisterScriptCallback( this, 'OnChoiceEntryStateChanged', gameJournalListenerType.ChoiceEntry );
	}

	protected event OnChoiceEntryStateChanged( entryHash : Uint32, className : CName, notifyOption : JournalNotifyOption, changeType : JournalChangeType )
	{
		m_dialogViewController.UpdateData( false, false );
		m_dialogViewController.SetFocus( true );
	}

	protected event OnRefresh( evt : RefreshSmsMessagerEvent )
	{
		m_data = evt.m_data;
		SetupData();
	}

	private function SetupData()
	{
		var messageState : gameJournalEntryState;
		var messageHash : Uint32;
		var conversationEntry : weak< JournalEntry >;
		m_contactEntry = ( ( JournalContact )( m_data.journalEntry ) );
		if( m_contactEntry == NULL )
		{
			conversationEntry = ( ( JournalPhoneConversation )( m_data.journalEntry ) );
			m_contactEntry = ( ( JournalContact )( m_journalMgr.GetParentEntry( conversationEntry ) ) );
			m_entry = FindFirstMessageWithAttachment( ( ( JournalContainerEntry )( m_data.journalEntry ) ) );
			m_journalEntryHash = m_journalMgr.GetEntryHash( conversationEntry );
		}
		else
		{
			m_journalEntryHash = m_journalMgr.GetEntryHash( m_contactEntry );
		}
		m_attachmentHash = m_entry.GetAttachmentPathHash();
		m_attachment = m_journalMgr.GetEntry( m_attachmentHash );
		inkWidgetRef.SetVisible( m_menuBackgrouns, m_data.mode == JournalNotificationMode.Menu );
		messageState = m_journalMgr.GetEntryState( m_entry );
		if( messageState != gameJournalEntryState.Active )
		{
			messageHash = ( ( Uint32 )( m_journalMgr.GetEntryHash( m_entry ) ) );
			m_journalMgr.ChangeEntryStateByHash( messageHash, gameJournalEntryState.Active, JournalNotifyOption.Notify );
		}
		m_attachmentState = m_journalMgr.GetEntryState( m_attachment );
		if( ( m_attachmentState != gameJournalEntryState.Active && m_attachmentState != gameJournalEntryState.Succeeded ) && m_attachmentState != gameJournalEntryState.Failed )
		{
			m_journalMgr.ChangeEntryStateByHash( m_attachmentHash, gameJournalEntryState.Active, JournalNotifyOption.DoNotNotify );
		}
		inkWidgetRef.SetVisible( m_hintTrack, m_attachment && ( m_attachmentState != gameJournalEntryState.Succeeded && m_attachmentState != gameJournalEntryState.Failed ) );
		inkWidgetRef.SetVisible( m_contactsPath, m_data.source == PhoneScreenType.Contacts );
		inkWidgetRef.SetVisible( m_messagesPath, m_data.source == PhoneScreenType.Unread );
		inkWidgetRef.SetVisible( m_hintCall, m_contactEntry.IsCallable( m_journalMgr ) );
		inkWidgetRef.SetOpacity( m_hintCall, ( ( m_phoneSystem.IsCallingEnabled() ) ? ( 1.0 ) : ( 0.1 ) ) );
		InkImageUtils.RequestAvatarOrUnknown( this, m_avatarImage, m_contactEntry.GetAvatarID( m_journalMgr ) );
		if( m_data.openedFromPhone )
		{
			switch( m_data.type )
			{
				case MessengerContactType.SingleThread:
					m_activeEntry = m_contactEntry;
				m_dialogViewController.ShowDialog( m_data.journalEntry, m_isFocused );
				break;
				case MessengerContactType.MultiThread:
					m_activeEntry = m_contactEntry;
				m_dialogViewController.ShowThread( m_data.journalEntry, m_isFocused );
				break;
				default:
					break;
			}
		}
		else
		{
			if( conversationEntry )
			{
				m_activeEntry = conversationEntry;
				m_dialogViewController.ShowThread( m_activeEntry );
			}
			else
			{
				m_activeEntry = m_contactEntry;
				m_dialogViewController.ShowDialog( m_activeEntry );
			}
		}
		if( IsStringValid( m_contactEntry.GetLocalizedName( m_journalMgr ) ) )
		{
			inkTextRef.SetText( m_title, m_contactEntry.GetLocalizedName( m_journalMgr ) );
		}
		else
		{
			inkTextRef.SetText( m_title, GetLocalizedText( NameToString( m_data.contactNameLocKey ) ) );
		}
		inkWidgetRef.SetVisible( m_hintReply, false );
		inkWidgetRef.SetVisible( m_scrollReply, ( m_player.PlayerLastUsedKBM() && m_dialogViewController.HasReplyOptions() ) && inkWidgetRef.IsVisible( m_scrollSlider ) );
		if( m_data.mode == JournalNotificationMode.Menu )
		{
			RegisterToGlobalInputCallback( 'OnPostOnRelease', this, 'OnHandleMenuInput' );
			inkWidgetRef.SetVisible( m_hintMessenger, false );
		}
		else
		{
			if( !( m_data.openedFromPhone ) )
			{
				PopupStateUtils.SetBackgroundBlurBlendTime( this, 0.1 );
				PopupStateUtils.SetBackgroundBlur( this, true );
				m_uiSystem.PushGameContext( UIGameContext.ModalPopup );
				m_uiSystem.RequestNewVisualState( 'inkModalPopupState' );
				SetTimeDilatation( true );
			}
			inkWidgetRef.SetVisible( m_hintMessenger, true );
		}
		SetFocus( !( m_data.openedFromPhone ) );
		if( !( m_data.openedFromPhone ) )
		{
			OnGotFocus( NULL );
		}
	}

	private function SetFocus( isFocused : Bool )
	{
		m_isFocused = isFocused;
		inkWidgetRef.SetVisible( m_hintsContainer, isFocused );
		m_dialogViewController.SetFocus( m_phoneSystem.IsTextingEnabled() );
	}

	protected event OnGotFocus( evt : FocusSmsMessagerEvent )
	{
		SetFocus( true );
		GameInstance.GetAudioSystem( m_player.GetGame() ).Play( 'ui_menu_hover' );
		m_dialogViewController.SetCurrentMessagesAsVisited();
		EnableInput();
	}

	public function EnableInput()
	{
		m_player.RegisterInputListener( this, 'OpenPauseMenu' );
		m_player.RegisterInputListener( this, 'cancel' );
		m_player.RegisterInputListener( this, 'phone_open_journal' );
		m_player.RegisterInputListener( this, 'click' );
		m_player.RegisterInputListener( this, 'call' );
		m_player.RegisterInputListener( this, 'popup_moveDown' );
		m_player.RegisterInputListener( this, 'popup_moveUp' );
		m_player.RegisterInputListener( this, 'popup_moveUp_left_stick_up' );
		m_player.RegisterInputListener( this, 'popup_moveUp_left_stick_down' );
		m_player.RegisterInputListener( this, 'sms_view_scroll_km' );
		m_player.RegisterInputListener( this, 'mouse_wheel' );
		m_player.RegisterInputListener( this, 'right_stick_y' );
	}

	public function DisableInput()
	{
		m_player.UnregisterInputListener( this, 'OpenPauseMenu' );
		m_player.UnregisterInputListener( this, 'cancel' );
		m_player.UnregisterInputListener( this, 'phone_open_journal' );
		m_player.UnregisterInputListener( this, 'click' );
		m_player.UnregisterInputListener( this, 'call' );
		m_player.UnregisterInputListener( this, 'popup_moveUp_left_stick_up' );
		m_player.UnregisterInputListener( this, 'popup_moveUp_left_stick_down' );
		m_player.UnregisterInputListener( this, 'popup_moveDown' );
		m_player.UnregisterInputListener( this, 'popup_moveUp' );
		m_player.UnregisterInputListener( this, 'sms_view_scroll_km' );
		m_player.UnregisterInputListener( this, 'mouse_wheel' );
		m_player.UnregisterInputListener( this, 'right_stick_y' );
	}

	protected event OnLostFocus( evt : UnfocusSmsMessagerEvent )
	{
		SetFocus( false );
	}

	protected event OnDelayedDotsAnimation( evt : TypingDelayEvent )
	{
		if( ( m_journalEntryHash == evt.m_conversationHash ) || ( evt.m_contactHash == m_journalEntryHash ) )
		{
			m_dialogViewController.PlayDotsAnimation();
		}
	}

	protected event OnUninitialize()
	{
		m_blackboard.SetBool( m_blackboardDef.isDisplayingMessage, false, true );
		m_journalMgr.SetEntryVisited( m_entry, true );
		if( m_data.mode == JournalNotificationMode.Menu )
		{
			UnregisterFromGlobalInputCallback( 'OnPostOnRelease', this, 'OnHandleMenuInput' );
		}
		else
		{
			if( !( m_data.openedFromPhone ) )
			{
				PopupStateUtils.SetBackgroundBlur( this, false );
				m_uiSystem.PopGameContext( UIGameContext.ModalPopup );
				m_uiSystem.RestorePreviousVisualState( 'inkModalPopupState' );
				SetTimeDilatation( false );
			}
		}
		m_journalMgr.UnregisterScriptCallback( this, 'OnChoiceEntryStateChanged' );
	}

	protected event OnShow( evt : ShowSmsMessagerEvent )
	{
		var animOptions : inkAnimOptions;
		if( ( m_proxy != NULL ) && m_proxy.IsPlaying() )
		{
			m_proxy.Stop();
		}
		animOptions.customTimeDilation = 2.0;
		animOptions.applyCustomTimeDilation = true;
		m_proxy = PlayLibraryAnimation( 'Intro', animOptions );
	}

	protected event OnHide( evt : HideSmsMessagerEvent )
	{
		var animOptions : inkAnimOptions;
		if( ( m_proxy != NULL ) && m_proxy.IsPlaying() )
		{
			m_proxy.Stop();
		}
		m_proxy = PlayLibraryAnimation( 'Outro', animOptions );
	}

	protected event OnPopupHidden( evt : inkAnimProxy )
	{
		var closeEvent : CloseSmsMessengerEvent;
		if( m_data.mode != JournalNotificationMode.HUD )
		{
			m_data.token.TriggerCallback( m_data );
		}
		else
		{
			closeEvent = new CloseSmsMessengerEvent;
			QueueEvent( closeEvent );
		}
	}

	protected event OnHandleMenuInput( evt : inkPointerEvent )
	{
		var inputHandled : Bool;
		if( evt.IsAction( 'cancel' ) )
		{
			inputHandled = HandleCommonInputActions( 'cancel' );
		}
		else if( evt.IsAction( 'phone_open_journal' ) )
		{
			inputHandled = HandleCommonInputActions( 'phone_open_journal' );
		}
		else if( evt.IsAction( 'up_button' ) )
		{
			NavigateChoices( true );
		}
		else if( evt.IsAction( 'down_button' ) )
		{
			NavigateChoices( false );
		}
		else if( evt.IsAction( 'click' ) )
		{
			TryActivateChoice();
		}
		if( !( inputHandled ) )
		{
		}
	}

	protected event OnAction( action : ListenerAction, consumer : ListenerActionConsumer )
	{
		var actionName : CName;
		var isPressed, isAxis, isRelative : Bool;
		isPressed = ListenerAction.GetType( action ) == gameinputActionType.BUTTON_PRESSED;
		isAxis = ListenerAction.GetType( action ) == gameinputActionType.AXIS_CHANGE;
		isRelative = ListenerAction.GetType( action ) == gameinputActionType.RELATIVE_CHANGE;
		inkWidgetRef.SetVisible( m_scrollReply, ( m_player.PlayerLastUsedKBM() && m_dialogViewController.HasReplyOptions() ) && inkWidgetRef.IsVisible( m_scrollSlider ) );
		if( m_isHubVisiale )
		{
			return false;
		}
		if( ( isPressed || isAxis ) || isRelative )
		{
			actionName = ListenerAction.GetName( action );
			if( actionName == 'OpenPauseMenu' )
			{
				ListenerActionConsumer.DontSendReleaseEvent( consumer );
			}
			else
			{
				if( !( HandleCommonInputActions( actionName ) ) )
				{
					switch( actionName )
					{
						case 'call':
							TryCallContact();
						break;
						case 'click':
							TryActivateChoice();
						break;
						case 'sms_view_scroll_km':
							ScrollMessages( ListenerAction.GetValue( action ), true );
						break;
						case 'popup_moveUp':
							NavigateChoices( true );
						break;
						case 'popup_moveDown':
							NavigateChoices( false );
						break;
						case 'popup_moveUp_left_stick_up':
							NavigateChoices( true );
						break;
						case 'popup_moveUp_left_stick_down':
							NavigateChoices( false );
						break;
						case 'mouse_wheel':
							if( !( m_dialogViewController.HasReplyOptions() ) )
							{
								ScrollMessages( ListenerAction.GetValue( action ), true );
							}
						break;
						case 'right_stick_y':
							ScrollMessages( ListenerAction.GetValue( action ), false );
						break;
					}
				}
			}
		}
	}

	private function TryCallContact()
	{
		if( !( m_contactEntry.IsCallable( m_journalMgr ) ) )
		{
			return;
		}
		if( !( m_phoneSystem.IsCallingEnabled() ) )
		{
			ShowActionBlockedNotification();
			return;
		}
		PlayRumble( RumbleStrength.SuperLight, RumbleType.Pulse, RumblePosition.Right );
		CallContact();
	}

	private function ShowActionBlockedNotification()
	{
		var notificationEvent : UIInGameNotificationEvent;
		notificationEvent = new UIInGameNotificationEvent;
		m_uiSystem.QueueEvent( new UIInGameNotificationRemoveEvent );
		notificationEvent.m_notificationType = UIInGameNotificationType.CombatRestriction;
		m_uiSystem.QueueEvent( notificationEvent );
	}

	private function CallContact()
	{
		var callRequest : questTriggerCallRequest;
		callRequest = new questTriggerCallRequest;
		callRequest.addressee = StringToName( m_contactEntry.GetId() );
		callRequest.caller = 'Player';
		callRequest.callPhase = questPhoneCallPhase.IncomingCall;
		callRequest.callMode = questPhoneCallMode.Video;
		m_phoneSystem.QueueRequest( callRequest );
	}

	private function TryActivateChoice()
	{
		if( !( m_dialogViewController.HasReplyOptions() ) )
		{
			return;
		}
		if( !( m_phoneSystem.IsTextingEnabled() ) )
		{
			ShowActionBlockedNotification();
			return;
		}
		m_dialogViewController.ActivateSelectedReplyOption();
	}

	private function HandleCommonInputActions( actionName : CName ) : Bool
	{
		var res : Bool;
		res = true;
		switch( actionName )
		{
			case 'cancel':
				RequestUnfocus();
			break;
			case 'phone_open_journal':
				if( m_attachment && ( m_attachmentState != gameJournalEntryState.Succeeded && m_attachmentState != gameJournalEntryState.Failed ) )
				{
					GotoJournalMenu();
				}
			break;
			default:
				res = false;
			break;
		}
		return res;
	}

	private function RequestUnfocus()
	{
		DisableInput();
		QueueEvent( new UnfocusSmsMessagerEvent );
	}

	protected event OnCloseRequest( evt : RequestSmsMessagerCloseEvent )
	{
		ClosePopup();
	}

	private function ClosePopup()
	{
		var animOptions : inkAnimOptions;
		if( ( m_proxy == NULL ) || !( m_proxy.IsPlaying() ) )
		{
			m_proxy = PlayLibraryAnimation( 'Outro', animOptions );
			m_proxy.RegisterToCallback( inkanimEventType.OnFinish, this, 'OnPopupHidden' );
		}
	}

	private function TrackQuest()
	{
		var objective : weak< JournalQuestObjective >;
		objective = ( ( JournalQuestObjective )( m_attachment ) );
		if( objective )
		{
			m_journalMgr.TrackEntry( objective );
		}
		else
		{
			objective = GetFirstObjectiveFromQuest( ( ( JournalQuest )( m_attachment ) ) );
			m_journalMgr.TrackEntry( objective );
		}
	}

	private function FindFirstMessageWithAttachment( entry : weak< JournalContainerEntry > ) : weak< JournalPhoneMessage >
	{
		var i : Int32;
		var unpackedData : array< weak< JournalEntry > >;
		var msg : weak< JournalPhoneMessage >;
		QuestLogUtils.UnpackRecursive( m_journalMgr, entry, unpackedData );
		for( i = 0; i < unpackedData.Size(); i += 1 )
		{
			msg = ( ( JournalPhoneMessage )( unpackedData[ i ] ) );
			if( ( msg != NULL ) && ( msg.GetAttachmentPathHash() != 0 ) )
			{
				return msg;
			}
		}
		return NULL;
	}

	private function GetFirstObjectiveFromQuest( journalQuest : weak< JournalQuest > ) : weak< JournalQuestObjective >
	{
		var i : Int32;
		var unpackedData : array< weak< JournalEntry > >;
		QuestLogUtils.UnpackRecursive( m_journalMgr, journalQuest, unpackedData );
		for( i = 0; i < unpackedData.Size(); i += 1 )
		{
			if( ( ( JournalQuestObjective )( unpackedData[ i ] ) ) )
			{
				return ( ( JournalQuestObjective )( unpackedData[ i ] ) );
			}
		}
		return NULL;
	}

	private function GotoJournalMenu()
	{
		var userData : MessageMenuAttachmentData;
		QueueEvent( new KeepPhoneOpenWhenInHubMenuEvent );
		userData = new MessageMenuAttachmentData;
		userData.m_entryHash = ( ( Int32 )( m_attachmentHash ) );
		GotoHubMenu( 'quest_log', userData );
	}

	protected event OnHUBMenuChanged( evt : inkMenuLayer_SetMenuModeEvent )
	{
		var mode : inkMenuMode;
		var state : inkMenuState;
		mode = evt.GetMenuMode();
		state = evt.GetMenuState();
		m_isHubVisiale = state == inkMenuState.Enabled && mode == inkMenuMode.HubMenu;
	}

	private function GotoMessengerMenu()
	{
		var userData : MessageMenuAttachmentData;
		userData = new MessageMenuAttachmentData;
		userData.m_entryHash = m_journalMgr.GetEntryHash( m_activeEntry );
		GotoHubMenu( 'phone', userData );
	}

	private function GotoHubMenu( menuName : CName, optional userData : IScriptable )
	{
		var evt : StartHubMenuEvent;
		evt = new StartHubMenuEvent;
		evt.SetStartMenu( menuName, , userData );
		QueueBroadcastEvent( evt );
	}

	private function ScrollMessages( value : Float, isMouseWheel : Bool )
	{
		m_dialogViewController.ScrollMessages( value, isMouseWheel );
	}

	private function NavigateChoices( isUp : Bool )
	{
		m_dialogViewController.NavigateReplyOptions( isUp );
		if( m_dialogViewController.HasReplyOptions() )
		{
			GameInstance.GetAudioSystem( m_player.GetGame() ).Play( 'ui_menu_hover' );
		}
	}

	protected function SetTimeDilatation( enable : Bool )
	{
		if( enable )
		{
			TimeDilationHelper.SetTimeDilationWithProfile( m_player, "radialMenu", true, true );
			PopupStateUtils.SetBackgroundBlur( this, true );
		}
		else
		{
			TimeDilationHelper.SetTimeDilationWithProfile( m_player, "radialMenu", false, false );
			PopupStateUtils.SetBackgroundBlur( this, false );
		}
	}

}

