ZO_INTERACTIVE_CHAT_LOG_GAMEPAD_LOG_MAX_SIZE = 200
ZO_INTERACTIVE_CHAT_LOG_GAMEPAD_LOG_LINE_WIDTH = ZO_GAMEPAD_QUADRANT_1_2_3_CONTAINER_WIDTH - (ZO_GAMEPAD_INTERACTIVE_FILTER_HIGHLIGHT_PADDING * 2) --We squeeze in for the highlighting

ZO_InteractiveChatLog_Gamepad = ZO_Object.MultiSubclass(ZO_Gamepad_ParametricList_Screen, ZO_SocialOptionsDialogGamepad, ZO_GamepadMultiFocusArea_Manager)

function ZO_InteractiveChatLog_Gamepad:Initialize(control, scene)
    local ACTIVATE_ON_SHOW = true
    ZO_Gamepad_ParametricList_Screen.Initialize(self, control, ZO_GAMEPAD_HEADER_TABBAR_DONT_CREATE, ACTIVATE_ON_SHOW, scene)
    ZO_SocialOptionsDialogGamepad.Initialize(self)
    ZO_GamepadMultiFocusArea_Manager.Initialize(self)

    local logFragment = ZO_FadeSceneFragment:New(control)
    scene:AddFragment(logFragment)

    self:InitializeHeader()
    self:InitializeControls()
    self:InitializeTextInputSection()
    self:InitializePassiveFocus()
    self:RegisterForEvents()

    --This screen needs to manage the narration a bit differently, so unregister ourselves upon creation
    SCREEN_NARRATION_MANAGER:UnregisterParametricList(self.list)
end

function ZO_InteractiveChatLog_Gamepad:InitializeHeader()
    -- Optional override
end

function ZO_InteractiveChatLog_Gamepad:InitializeControls()
    self.messageEntries = {}
    self.nextMessageId = 1
    self.mask = self.control:GetNamedChild("Mask")
    self.textInputControl = self.mask:GetNamedChild("TextInput")

    self.textControl = self.textInputControl:GetNamedChild("Text")
    self.textEdit = self.textControl:GetNamedChild("EditBox")
    self.textControlHighlight = self.textControl:GetNamedChild("Highlight")

    --Log List--
    local list = self:GetMainList()
    list:SetSelectedItemOffsets(0, 0)
    list:SetAnchorOppositeSide(true)
    list:SetHandleDynamicViewProperties(true)
    list:AddDataTemplate("ZO_InteractiveChatLog_Gamepad_LogLine", function(...) self:SetupLogMessage(...) end, ZO_GamepadMenuEntryTemplateParametricListFunction, function(a, b) return a.data.id == b.data.id end)

    local function HandleListDirectionalInput(result)
        if result == MOVEMENT_CONTROLLER_MOVE_NEXT then
            if list:GetSelectedIndex() == list:GetNumEntries() then
                self:FocusTextInput()
            end
        end
    end

    list:SetCustomDirectionInputHandler(HandleListDirectionalInput)
    list:SetDirectionalInputEnabled(false)
    list:SetSoundEnabled(false)
    self.list = list

    self.moreBelowTimeline = ANIMATION_MANAGER:CreateTimelineFromVirtual("ZO_InteractiveChatLog_Gamepad_MoreBelowAnimation", self.mask:GetNamedChild("MoreBelow"))
end

function ZO_InteractiveChatLog_Gamepad:InitializeTextInputSection()
    --For passive focus switching between text input area and chat entry list
    self.textInputVerticalMovementController = ZO_MovementController:New(MOVEMENT_CONTROLLER_DIRECTION_VERTICAL)

    self:InitializeTextEdit()
end


function ZO_InteractiveChatLog_Gamepad:InitializeTextEdit()
    local function TextEditFocusGained()
        self.textInputAreaFocalArea:Deactivate()
        ZO_GamepadEditBox_FocusGained(self.textEdit)
    end

    local function TextEditFocusLost()
        ZO_GamepadEditBox_FocusLost(self.textEdit)
        self:FocusTextInput()
    end

    local function TextEditTextChanged()
        if self.textInputAreaFocalArea:IsFocused() then
            self.textInputAreaFocalArea:UpdateKeybinds()
        end
    end

    self.textEdit:SetHandler("OnFocusGained", TextEditFocusGained)
    self.textEdit:SetHandler("OnFocusLost", TextEditFocusLost)
    self.textEdit:SetHandler("OnTextChanged", TextEditTextChanged)
end

function ZO_InteractiveChatLog_Gamepad:InitializePassiveFocus()
    --Passive Area Focus--
    local function TextInputAreaActivateCallback()
        self:OnTextInputAreaActivated()
    end

    local function TextInputAreaDeactivateCallback()
        self:OnTextInputAreaDeactivated()
    end

    self.textInputAreaFocalArea = ZO_GamepadMultiFocusArea_Base:New(self, TextInputAreaActivateCallback, TextInputAreaDeactivateCallback)

    local function ChatEntryPanelActivateCallback()
        self:OnChatEntryPanelActivated()
    end

    local function ChatEntryPanelDeactivateCallback()
        self:OnChatEntryPanelDeactivated()
    end
    self.chatEntryPanelFocalArea = ZO_GamepadMultiFocusArea_Base:New(self, ChatEntryPanelActivateCallback, ChatEntryPanelDeactivateCallback)

    self:AddNextFocusArea(self.chatEntryPanelFocalArea)
    self:AddNextFocusArea(self.textInputAreaFocalArea)
end

function ZO_InteractiveChatLog_Gamepad:RegisterForEvents()
    local function OnScreenResized()
        self:OnScreenResized()
    end

    self.control:RegisterForEvent(EVENT_SCREEN_RESIZED, OnScreenResized)
end

function ZO_InteractiveChatLog_Gamepad:InitializeFocusKeybinds()
    -- Optional override
end

-- ZO_Gamepad_ParametricList_Screen Overrides

function ZO_InteractiveChatLog_Gamepad:OnDeferredInitialize()
    self:ReadjustFixedCenterOffset()
    self:InitializeFocusKeybinds()
end

function ZO_InteractiveChatLog_Gamepad:PerformUpdate()
    self.dirty = false
end

function ZO_InteractiveChatLog_Gamepad:OnShow()
    self.list:RefreshVisible()
    self:FocusTextInput()
end

function ZO_InteractiveChatLog_Gamepad:OnHiding()
    if self.currentFocalArea then
        self.currentFocalArea:Deactivate()
    end
end

function ZO_InteractiveChatLog_Gamepad:OnTargetChanged(list, targetData, oldTargetData, reachedTarget, targetSelectedIndex)
    self:RefreshMoreBelow(targetSelectedIndex)
    self:SetupOptions(targetData)
    if self.chatEntryPanelFocalArea:IsFocused() then
        self.chatEntryPanelFocalArea:UpdateKeybinds()
    end
end

-- End ZO_Gamepad_ParametricList_Screen Overrides

-- ZO_GamepadMultiFocusArea_Manager Overrides

function ZO_InteractiveChatLog_Gamepad:UpdateDirectionalInput()
    --We don't want to change focus to the chat entry area if there are no entries to scroll through
    if self.list:GetNumEntries() > 0 then
        local result = self.textInputVerticalMovementController:CheckMovement()
        if result == MOVEMENT_CONTROLLER_MOVE_PREVIOUS then
            self.textInputAreaFocalArea:HandleMovePrevious()
        end
    end
end

-- End ZO_GamepadMultiFocusArea_Manager Overrides

-- ZO_SocialOptionsDialogGamepad Overrides

-- We expect child classes to override these functions, but this class doesn't alter their behavior
-- Leaving these here as comments to make it easier to find the source of these functions
--function ZO_InteractiveChatLog_Gamepad:SetupOptions(socialData)
--function ZO_InteractiveChatLog_Gamepad:BuildOptionsList()

-- End ZO_SocialOptionsDialogGamepad Overrides

function ZO_InteractiveChatLog_Gamepad:FocusTextInput()
    if self.scene:IsShowing() then
        if self.currentFocalArea ~= self.textInputAreaFocalArea then
            if self.currentFocalArea then
                self.currentFocalArea:Deactivate()
            end
            self.currentFocalArea = self.textInputAreaFocalArea
        end
        self.currentFocalArea:Activate()
    end
end

do
    local FIXED_CENTER_OFFSET_PADDING = 37

    function ZO_InteractiveChatLog_Gamepad:ReadjustFixedCenterOffset()
        local scrollHeight = self.list.control:GetHeight()
        local fixedCenterOffset = scrollHeight / 2 - FIXED_CENTER_OFFSET_PADDING
        self.list:SetFixedCenterOffset(fixedCenterOffset)
    end
end

function ZO_InteractiveChatLog_Gamepad:SetupLogMessage(control, data, selected, reselectingDuringRebuild, enabled, active)
    ZO_SharedGamepadEntry_OnSetup(control, data, selected, reselectingDuringRebuild, enabled, active)
    
    -- Optional override
end

function ZO_InteractiveChatLog_Gamepad:RefreshMoreBelow(targetSelectedIndex)
    local isMoreBelow = targetSelectedIndex < self.list:GetNumItems()
    if isMoreBelow then
        self.moreBelowTimeline:PlayForward()
    else
        self.moreBelowTimeline:PlayBackward()
    end
end

function ZO_InteractiveChatLog_Gamepad:BuildChatList()
    self.list:Clear()

    for i, entry in ipairs(self.messageEntries) do
        self.list:AddEntry("ZO_InteractiveChatLog_Gamepad_LogLine", entry)
    end

    self.list:Commit()
end

function ZO_InteractiveChatLog_Gamepad:OnScreenResized()
    self:ReadjustFixedCenterOffset()
end

function ZO_InteractiveChatLog_Gamepad:OnTextInputAreaActivated()
    DIRECTIONAL_INPUT:Activate(self, self.textInputControl)
end

function ZO_InteractiveChatLog_Gamepad:OnTextInputAreaDeactivated()
    DIRECTIONAL_INPUT:Deactivate(self)
end

function ZO_InteractiveChatLog_Gamepad:OnChatEntryPanelActivated()
    local function EnableChatDirectionalInputLater()
        if self.chatEntryPanelFocalArea:IsFocused() then
            self.list:SetDirectionalInputEnabled(true)
        end
    end

    --Wait until we are actually navigating the chat panel before we start caring about narrating it
    SCREEN_NARRATION_MANAGER:RegisterParametricListScreen(self.list, self)
    SCREEN_NARRATION_MANAGER:QueueParametricListEntry(self.list)

    --We want the chat entry list to wait a moment before it starts processing the input
    --Otherwise it will move immediately on the next frame after gaining focus
    zo_callLater(EnableChatDirectionalInputLater, 200)
    self.list:RefreshVisible()
    self.list:SetSoundEnabled(true)
end

function ZO_InteractiveChatLog_Gamepad:OnChatEntryPanelDeactivated()
    --Once we leave the chat panel we no longer want to narrate anything in it, so unregister ourselves again
    SCREEN_NARRATION_MANAGER:UnregisterParametricList(self.list)
    self.list:SetDirectionalInputEnabled(false)
    self.list:RefreshVisible()
    self.list:SetSoundEnabled(false)
end

--------------
--Global XML--
--------------

do
    local function GetHeight(self)
        return self.label:GetTextHeight()
    end

    function ZO_InteractiveChatLog_Gamepad_LogLine_OnInitialized(self)
        ZO_SharedGamepadEntry_OnInitialized(self)
        self.GetHeight = GetHeight
        self.label = self:GetNamedChild("Label")
        self.marker = self:GetNamedChild("Marker")
    end
end
