#include "helpers/table.lua"

MainMenu = {}

MainMenu.nonserializable = true
MainMenu.transitionTime = 0.5

-------- State Transition ---------

MainMenu.State =
{
    Main = "main",
    Avatar = "avatar",
    Undefined = "undef"
}


MainMenu.transitToState = function(state)
    local curState = MainMenu.getState()

    if curState == state then
        return
    end

    MainMenu.setState(state)
    MainMenu.setLeavingState(curState)
    MainMenu.beginTransit()
end


MainMenu.getState = function()
    if not HasKey("game.menu.state") then
        MainMenu.setState(MainMenu.State.Main)
    end

    return GetString("game.menu.state")
end


MainMenu.getLeavingState = function()
    return GetString("game.menu.leavingstate")
end


MainMenu.setLeavingState = function(state)
    SetString("game.menu.leavingstate", state)
end


MainMenu.setState = function(state)
    SetString("game.menu.state", state)
end


MainMenu.beginTransit = function()
    TriggerEvent("OnMainMenuStateTransitStarted")
    SetFloat("game.menu.fade", 0.0)
end


MainMenu.getFadeFactor = function(state)
    if state ~= MainMenu.getLeavingState() and state ~= MainMenu.getState() then
        return 0
    end

    -- normalize fade factor half of time is taken for fading out leaving state
    -- half of time is for fading in entering state
    if state == MainMenu.getLeavingState() then
        return math.clamp(1 - 2 * GetFloat("game.menu.fade"), 0, 1)
    elseif state == MainMenu.getState() then
        return math.clamp(2 * GetFloat("game.menu.fade"), 0, 1)
    end

    return 0
end


MainMenu.canDrawInState = function(state)
    return MainMenu.getFadeFactor(state) ~= 0 
end


MainMenu.updateStates = function()
    if not HasKey("game.menu.fade") then
        SetFloat("game.menu.fade", 1.0)
    end

    local fBefore = MainMenu.getFadeFactor(MainMenu.getState())

    local fadeTime = GetFloat("game.menu.fade") * MainMenu.transitionTime
    fadeTime = fadeTime + GetTimeStep()

    local fade = math.clamp(fadeTime / MainMenu.transitionTime, 0, 1)
    SetFloat("game.menu.fade", fade)

    local fAfter = MainMenu.getFadeFactor(MainMenu.getState())

    if fAfter == 1 and fAfter > fBefore then
        TriggerEvent("OnMainMenuStateTransitFinished")
    end
end

-------- Events ---------

MainMenu.Events = {}
MainMenu.Events._handlers = {}

MainMenu.Events.subscribe = function(eventKey, handler)
    local handlers = MainMenu.Events._handlers[eventKey] or {}
    table.insert(handlers, handler)
    MainMenu.Events._handlers[eventKey] = handlers
end

MainMenu.Events.unsubscribe = function(eventKey, handler)
    local handlers = MainMenu.Events._handlers[eventKey] or {}
    local _, idx = tableFirst(handlers, function(h) return h == handler end)
    if idx ~= 0 then
        table.remove(handlers, idx)
    end
    MainMenu.Events._handlers[eventKey] = handlers
end

MainMenu.Events.trigger = function(eventKey)
    local handlers = MainMenu.Events._handlers[eventKey] or {}
    tableForEach(handlers, function(h) h() end)
end

RegisterListenerTo("OnMainMenuStateTransitStarted", "_EventsMainMenuStateTransitStarted")
RegisterListenerTo("OnMainMenuStateTransitFinished", "_EventsMainMenuStateTransitFinished")
RegisterListenerTo("DlcAdded", "_EventsDlcAdded")

function _EventsMainMenuStateTransitStarted()
    MainMenu.Events.trigger("OnMainMenuStateTransitStarted")
end


function _EventsMainMenuStateTransitFinished()
    MainMenu.Events.trigger("OnMainMenuStateTransitFinished")
end


function _EventsDlcAdded()
    MainMenu.Events.trigger("DlcAdded")
end