--[[
=========================

settings module
Game research by: nesa24 // pesweb
Requires: sider.dll 5.1.0

=========================
--]]

local m = {}
m.version = "2.2"
local hex = memory.hex
local settings

local RESTORE_KEY = 0x38
local PREV_PROP_KEY = 0x39
local NEXT_PROP_KEY = 0x30
local PREV_VALUE_KEY = 0xbd
local NEXT_VALUE_KEY = 0xbb

local overlay_curr = 1
local overlay_states = {
    { ui = "Replay: %s", prop = "replays", def = "On",
        nextf = function(v)
            return (v == "On") and "Off" or "On"
        end,
        prevf = function(v)
            return (v == "On") and "Off" or "On"
        end,
    },
    { ui = "Ball Cursor: %s", prop = "ball_cursor", def = "On",
        nextf = function(v)
            return (v == "On") and "Off" or "On"
        end,
        prevf = function(v)
            return (v == "On") and "Off" or "On"
        end,
    },
    { ui = "Blackbar   : %s", prop = "blackbar", def = "On",
        nextf = function(v)
            return (v == "On") and "Off" or "On"
        end,
        prevf = function(v)
            return (v == "On") and "Off" or "On"
        end,
    },
}
local ui_lines = {}

local bases = {
    replays = nil,
    ball_cursor = nil,
    blackbar = nil,
}
local game_info = {
    replays = { "replays", 0x04, "", 1, {On='\x04', Off='\x06'}},
    ball_cursor = { "ball", 0x00, "", 7, {On='\x0f\x29\x8d\xc0\xff\xff\xff', Off='\x90\x90\x90\x90\x90\x90\x90'}},
    blackbar = { "blackbar", 0x03, "", 1, {On='\x01', Off='\x00'}},            
}

local function load_ini(ctx, filename)
    local t = {}
    for line in io.lines(ctx.sider_dir .. "\\" .. filename) do
        local name, value = string.match(line, "^([%w_]+)%s*=%s*([-%w%d.]+)")
        if name and value then
            value = tonumber(value) or value
            t[name] = value
            --log(string.format("Using setting: %s = %s", name, value))
        end
    end
    return t
end

local function save_ini(ctx, filename)
    local f,err = io.open(ctx.sider_dir .. "\\" .. filename, "wt")
    if not f then
        log(string.format("PROBLEM saving settings: %s", tostring(err)))
        return
    end
    f:write(string.format("[EvoSettings]\n\n"))
    f:write(string.format("evokit = %s\n", settings.evokit))
    f:write(string.format("replays = %s\n", settings.replays))
    f:write(string.format("ball_cursor = %s\n", settings.ball_cursor))
    f:write(string.format("blackbar = %s\n", settings.blackbar))
    f:write("\n")
    f:close()
end

local function apply_settings(ctx, log_it, save_it)
    for name,value in pairs(settings) do
        local entry = game_info[name]
        if entry then
            local base_name, offset, format, len, value_mapping = unpack(entry)
            local base = bases[base_name]
            if base then
                if value_mapping then
                    value = value_mapping[value]
                end
                local addr = base + offset
                local old_value, new_value
                if format ~= "" then
                    old_value = memory.unpack(format, memory.read(addr, len))
                    memory.write(addr, memory.pack(format, value))
                    new_value = memory.unpack(format, memory.read(addr, len))
                    if log_it then
                        --log(string.format("%s: changed at %s: %s --> %s",
                            --name, hex(addr), old_value, new_value))
                    end
                else
                    old_value = memory.read(addr, len)
                    memory.write(addr, value)
                    new_value = memory.read(addr, len)
                    if log_it then
                        --log(string.format("%s: changed at %s: %s --> %s",
                            --name, hex(addr), hex(old_value), hex(new_value)))
                    end
                end
            end
        end
    end
    if (save_it) then
        save_ini(ctx, "modules\\EvoSwitcher\\EvoSetting.ini")
    end
end

function m.set_teams(ctx, home, away)
    apply_settings(ctx, true)
end

function m.overlay_on(ctx)
    for i,v in ipairs(overlay_states) do
        local s = overlay_states[i]
        local setting = string.format(s.ui, settings[s.prop])
        if i == overlay_curr then
            ui_lines[i] = string.format("\n---> %s <---", setting)
        else
            ui_lines[i] = string.format("\n     %s", setting)
        end
    end
    return string.format("version %s\nKeys: [9][0] - choose setting, [-][+] - modify value, [8] - restore defaults%s",
        m.version, table.concat(ui_lines))
end

function m.key_down(ctx, vkey)
    if vkey == NEXT_PROP_KEY then
        if overlay_curr < #overlay_states then
            overlay_curr = overlay_curr + 1
        end
    elseif vkey == PREV_PROP_KEY then
        if overlay_curr > 1 then
            overlay_curr = overlay_curr - 1
        end
    elseif vkey == NEXT_VALUE_KEY then
        local s = overlay_states[overlay_curr]
        if s.incr ~= nil then
            settings[s.prop] = settings[s.prop] + s.incr
        elseif s.nextf ~= nil then
            settings[s.prop] = s.nextf(settings[s.prop])
        end
        apply_settings(ctx, false, true)
    elseif vkey == PREV_VALUE_KEY then
        local s = overlay_states[overlay_curr]
        if s.decr ~= nil then
            settings[s.prop] = settings[s.prop] + s.decr
        elseif s.prevf ~= nil then
            settings[s.prop] = s.prevf(settings[s.prop])
        end
        apply_settings(ctx, false, true)
    elseif vkey == RESTORE_KEY then
        for i,s in ipairs(overlay_states) do
            settings[s.prop] = s.def
        end
        apply_settings(ctx, false, true)
    end
end

function m.init(ctx)
    -- find replays opcode
    local pattern = "\x41\xc6\x45\x08\x04"
    local loc = memory.search_process(pattern)
    if loc then
        bases.replays = loc
        --log(string.format("Replays op-code address: %s", hex(bases.replays)))
    else
        log("problem: unable to find code pattern for replays switch")
    end

    -- find ball cursor place
    --[[
00000001515ED611 | 89 B5 BC FF FF FF                    | mov dword ptr ss:[rbp-44],esi          |
00000001515ED617 | 0F 28 B5 B0 FF FF FF                 | movaps xmm6,xmmword ptr ss:[rbp-50]    |
00000001515ED61E | 0F 29 8D C0 FF FF FF                 | movaps xmmword ptr ss:[rbp-40],xmm1    | store ball cursor coordinates
    --]]
    local pattern = "\x89\xb5\xbc\xff\xff\xff\x0f\x28\xb5\xb0\xff\xff\xff"
    local loc = memory.search_process(pattern)
    if loc then
        loc = loc + #pattern
        bases.ball = loc
        --log(string.format("Ball cursor op-code address: %s", hex(bases.ball)))
    else
        log("problem: unable to find code pattern for ball cursor read")
    end

	-- find blackbackbar
    local pattern = "\x28\xce\xe8\x0f\xdb\x19\xf6"
    local loc = memory.search_process(pattern)
    if loc then
    	loc = loc + #pattern
    	bases.blackbar = loc       
    	--log(string.format("blackbar op-code address: %s", hex(bases.blackbar)))
    else
        log("problem: unable to find code pattern for blackbar switch")
    end

    settings = load_ini(ctx, "modules\\EvoSwitcher\\EvoSetting.ini")

    -- register for events
    ctx.register("set_teams", m.set_teams)
    ctx.register("overlay_on", m.overlay_on)
    ctx.register("key_down", m.key_down)
end

return m
