-- Note: does not handle the options menu itself (see battleGeneral for that),
-- this instead handles the internals of handling options and rulesets.

local battleGeneral,battleItems,battleTimer,battleMenu
local onlinePlay

local battleOptions = {}


local rulesUpdateCommand
local rulesJoinPacket


local function cloneValue(v)
    if type(v) == "table" then
        return table.deepclone(v)
    else
        return v
    end
end


function battleOptions.onInitAPI()
    battleGeneral = require("scripts/battleGeneral")
    battleItems = require("scripts/battleItems")
    battleTimer = require("scripts/battleTimer")
    battleMenu = require("scripts/battleMenu")
    onlinePlay = require("scripts/onlinePlay")

    -- Rules setup
    battleOptions.rulesetTypeList = {
        "general",
        battleGeneral.gameMode.CLASSIC,
        battleGeneral.gameMode.STARS,
        battleGeneral.gameMode.STONE,
        battleGeneral.gameMode.PHANTO,
        battleGeneral.gameMode.BOMBS,
    }

    battleOptions.rulesetOptions = {
        general = {
            {name = "physicsPatchEnabled",default = true,selection = {battleMenu.SELECTION_CHECKBOX}},
            {name = "reserveBoxEnabled",default = true,selection = {battleMenu.SELECTION_CHECKBOX}},
            {name = "startWithMushroom",default = false,selection = {battleMenu.SELECTION_CHECKBOX}},
            {name = "killFeedEnabled",default = false,selection = {battleMenu.SELECTION_CHECKBOX}},
            {name = "splitScreenStyle",default = 1,selection = {battleMenu.SELECTION_NUMBERS,1,2}},
        },
        [battleGeneral.gameMode.CLASSIC] = {
            {name = "lives",default = 3,selection = {battleMenu.SELECTION_NUMBERS,1,5}},
            {name = "itemsType",default = battleItems.ITEMS_TYPE.NORMAL,selection = {battleMenu.SELECTION_NUMBERS,0,2}},
            {name = "coinsForItem",default = 6,selection = {battleMenu.SELECTION_NUMBERS,3,10}},
            {name = "timeLimit",default = battleTimer.TIME_OPTIONS.FIVE_MINUTES,selection = {battleMenu.SELECTION_NUMBERS,0,5}},
            {name = "bannedCharacters",default = {false,false,false,false,false}},
        },
        [battleGeneral.gameMode.STARS] = {
            {name = "lives",default = 0,selection = {battleMenu.SELECTION_NUMBERS,0,5}},
            {name = "starsToWin",default = 5,selection = {battleMenu.SELECTION_NUMBERS,3,10}},
            {name = "itemsType",default = battleItems.ITEMS_TYPE.NORMAL,selection = {battleMenu.SELECTION_NUMBERS,0,2}},
            {name = "coinsForItem",default = 6,selection = {battleMenu.SELECTION_NUMBERS,3,10}},
            {name = "timeLimit",default = battleTimer.TIME_OPTIONS.FIVE_MINUTES,selection = {battleMenu.SELECTION_NUMBERS,0,5}},
            {name = "bannedCharacters",default = {false,false,false,false,false}},
        },
        [battleGeneral.gameMode.STONE] = {
            {name = "lives",default = 0,selection = {battleMenu.SELECTION_NUMBERS,0,5}},
            {name = "itemsType",default = battleItems.ITEMS_TYPE.NORMAL,selection = {battleMenu.SELECTION_NUMBERS,0,2}},
            {name = "coinsForItem",default = 6,selection = {battleMenu.SELECTION_NUMBERS,3,10}},
            {name = "timeLimit",default = battleTimer.TIME_OPTIONS.THREE_MINUTES,selection = {battleMenu.SELECTION_NUMBERS,1,5}},
            {name = "bannedCharacters",default = {false,false,false,false,true}},
        },
        [battleGeneral.gameMode.PHANTO] = {
            {name = "lives",default = 0,selection = {battleMenu.SELECTION_NUMBERS,0,5}},
            {name = "itemsType",default = battleItems.ITEMS_TYPE.NORMAL,selection = {battleMenu.SELECTION_NUMBERS,0,2}},
            {name = "coinsForItem",default = 6,selection = {battleMenu.SELECTION_NUMBERS,3,10}},
            {name = "timeLimit",default = battleTimer.TIME_OPTIONS.THREE_MINUTES,selection = {battleMenu.SELECTION_NUMBERS,1,5}},
            {name = "bannedCharacters",default = {false,false,false,false,false}},
        },
        [battleGeneral.gameMode.BOMBS] = {
            {name = "lives",default = 0,selection = {battleMenu.SELECTION_NUMBERS,0,5}},
            {name = "itemsType",default = battleItems.ITEMS_TYPE.NORMAL,selection = {battleMenu.SELECTION_NUMBERS,0,2}},
            {name = "coinsForItem",default = 6,selection = {battleMenu.SELECTION_NUMBERS,3,10}},
            {name = "timeLimit",default = battleTimer.TIME_OPTIONS.THREE_MINUTES,selection = {battleMenu.SELECTION_NUMBERS,1,5}},
            {name = "bannedCharacters",default = {false,false,false,false,false}},
        },
    }

    battleOptions.alwaysBannedCharacters = {
        [battleGeneral.gameMode.CLASSIC] = {false,false,false,false,false},
        [battleGeneral.gameMode.STARS] = {false,false,false,false,false},
        [battleGeneral.gameMode.STONE] = {false,false,false,false,true},
        [battleGeneral.gameMode.PHANTO] = {false,false,false,false,false},
        [battleGeneral.gameMode.BOMBS] = {false,false,false,false,false},
        [battleGeneral.gameMode.SPECIAL] = {false,false,false,false,false},
    }


    -- Online commands setup
    rulesUpdateCommand = onlinePlay.createCommand("battle_options_update",onlinePlay.IMPORTANCE_MAJOR)

    rulesJoinPacket = onlinePlay.createJoinPacket("battle_options")


    function rulesUpdateCommand.onReceive(sourcePlayerIdx, newRuleset,hostAllowsClientRuleChange)
        if onlinePlay.currentMode == onlinePlay.MODE_HOST then
            if not battleOptions.hostAllowsClientRuleChange() then
                return
            end
        else
            if sourcePlayerIdx ~= onlinePlay.hostPlayerIdx then
                return
            end

            battleGeneral.gameData.hostAllowsClientRuleChange = hostAllowsClientRuleChange
        end

        battleGeneral.gameData.onlineRuleset = newRuleset

        if onlinePlay.currentMode == onlinePlay.MODE_HOST then
            battleOptions.sendRulesUpdate()
        end
    end


    function rulesJoinPacket.encodeData(targetPlayerIdx)
        return battleOptions.getFullRuleset(),battleOptions.hostAllowsClientRuleChange()
    end

    function rulesJoinPacket.onReceive(newRuleset,hostAllowsClientRuleChange)
        battleGeneral.gameData.onlineRuleset = newRuleset
        battleGeneral.gameData.hostAllowsClientRuleChange = hostAllowsClientRuleChange
    end


    function battleOptions.sendRulesUpdate()
        local targetPlayerIdx = 0

        if onlinePlay.currentMode == onlinePlay.MODE_CLIENT then
            if not battleOptions.hostAllowsClientRuleChange() then
                return
            end

            targetPlayerIdx = onlinePlay.hostPlayerIdx
        end

        rulesUpdateCommand:send(targetPlayerIdx, battleOptions.getFullRuleset(),battleOptions.hostAllowsClientRuleChange())
    end


    --[[function onlinePlay.onConnect(playerIdx)
        if onlinePlay.currentMode == onlinePlay.MODE_HOST then
            if playerIdx == onlinePlay.playerIdx then
                battleGeneral.gameData.onlineRuleset = battleGeneral.saveData.mainRuleset
            else
                rulesUpdateCommand:send(playerIdx, battleOptions.getFullRuleset(),battleOptions.hostAllowsClientRuleChange())
            end
        else
            battleGeneral.gameData.onlineRuleset = nil
            battleGeneral.gameData.hostAllowsClientRuleChange = nil
        end
    end]]

    function onlinePlay.onDisconnect(playerIdx)
        if playerIdx == onlinePlay.playerIdx then
            battleGeneral.gameData.onlineRuleset = nil
            battleGeneral.gameData.hostAllowsClientRuleChange = nil
        end
    end
end


function battleOptions.defaultEmptyRulesetOptions(ruleset)
    for _,rulesetType in ipairs(battleOptions.rulesetTypeList) do
        ruleset[rulesetType] = ruleset[rulesetType] or {}

        for _,option in ipairs(battleOptions.rulesetOptions[rulesetType]) do
            if ruleset[rulesetType][option.name] == nil then
                ruleset[rulesetType][option.name] = cloneValue(option.default)
            end
        end
    end
end

function battleOptions.resetRulesetTypeToDefault(rulesetType)
    local fullRuleset = battleOptions.getFullRuleset()

    for _,option in ipairs(battleOptions.rulesetOptions[rulesetType]) do
        fullRuleset[rulesetType][option.name] = cloneValue(option.default)
    end
end


function battleOptions.getFullRuleset()
    if onlinePlay.currentMode ~= onlinePlay.MODE_OFFLINE and battleGeneral.gameData.onlineRuleset ~= nil then
        return battleGeneral.gameData.onlineRuleset
    end

    return battleGeneral.saveData.mainRuleset
end

function battleOptions.getModeRuleset(mode)
    mode = mode or battleGeneral.mode

    local fullRuleset = battleOptions.getFullRuleset()

    if fullRuleset[mode] ~= nil then
        return fullRuleset[mode]
    else
        return {}
    end
end


function battleOptions.characterIsBanned(character,mode)
    mode = mode or battleGeneral.mode

    if battleOptions.alwaysBannedCharacters[mode][character] then
        return true
    end

    local modeRuleset = battleOptions.getModeRuleset(mode)

    if modeRuleset.bannedCharacters ~= nil then
        return modeRuleset.bannedCharacters[character]
    end

    return false
end

function battleOptions.hostAllowsClientRuleChange()
    if onlinePlay.currentMode == onlinePlay.MODE_HOST then
        return battleGeneral.saveData.options.allowClientRuleChange
    else
        return battleGeneral.gameData.hostAllowsClientRuleChange
    end
end

function battleOptions.canChangeRules()
    if onlinePlay.currentMode == onlinePlay.MODE_CLIENT then
        return battleOptions.hostAllowsClientRuleChange()
    else
        return true
    end
end


return battleOptions