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

LiveBroadcastCamera module DATAPACK_2.0
Game research by: nesa24
Requires: sider.dll 5.1.1

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

local m = {}
m.version = "2.0"
local hex = memory.hex
local settings
local iniFile = ".\\modules\\EvoSwitcher\\EvoLiveBroadcastCamera.ini"
local section = "st029"
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 = "camera zoom range: %0.2f", prop = "camera_range_zoom", decr = -0.1, incr = 0.1, def = 14.40999985 },
    { ui = "camera height range: %0.2f", prop = "camera_range_height", decr = -0.01, incr = 0.01, def = 0.2300000042 },
    { ui = "camera angle range: %0.2f", prop = "camera_range_angle", decr = -0.01, incr = 0.01, def = 0.4099999964 },
    { ui = "camera up down range: %0.2f", prop = "camera_range_up_down", decr = -0.05, incr = 0.05, def = 0.5 },
    { ui = "camera tracking delay range: %0.2f", prop = "camera_range_tracking_delay", decr = -0.05, incr = 0.05, def = 1.00999999 },
}


local ui_lines = {}
local bases = {
    camera = nil,
}

local game_info = {
    camera_range_zoom           = { "camera", 0xD16F24, "f", 4},   --> default: 14.40999985
    camera_range_height         = { "camera", 0xD16F28, "f", 4},   --> default: 0.2300000042
    camera_range_angle          = { "camera", 0xD16F40, "f", 4},   --> default: 0.4099999964
    camera_range_up_down        = { "camera", 0xD16F2C, "f", 4},   --> default: 0.5
    camera_range_tracking_delay = { "camera", 0xD16F20, "f", 4},   --> default: 1.00999999
}

function read_config(filename)
  assert(type(filename) == 'string')
  local t,u,name,value,temp = {}
  for line in io.lines(filename) do
    temp = line:match('^%[(.+)%]$')
    if temp ~= nil and u ~= temp then u = temp end
    name,value = line:match('^([%w_]+)%s*=%s*([-%w%d.]+)')
    if u ~= nil then
      t[u] = t[u] or {}
      if name ~= nil then
      if u == section then
         value = tonumber(value) or value
           t[name] = value
       --log(string.format("Using setting: %s = %s", name, value))
    end
      end
    end
  end
  return t
end


function read_exists(filename)
  assert(type(filename) == 'string')
  local t,u,k,v,temp = {}
  for line in io.lines(filename) do
    temp = line:match('^%[(.+)%]$')
    if temp ~= nil and u ~= temp then u = temp end
    k,v = line:match('^([%w_]+)%s*=%s*([-%w%d.]+)')
    if u ~= nil then
      t[u] = t[u] or {}
      if k ~= nil then
      v = tonumber(v) or v
        t[u][k] = v
      end
    end
  end
  return t
end

function write_config(filename,section,key,value)
  assert(type(filename) == 'string')
  if section == nil and key == nil and value == nil then return end
  local t = read_exists(filename)
  if section ~= nil and value == nil then
    if key == nil then
      t[section] = nil
    else
      t[section][key] = nil
    end
    goto WriteFile
  end

  if key:match '=' then
    error('An equals sign is not expected inside key')
  end

  t[section] = t[section] or {}
  t[section][key] = value

  ::WriteFile::
  local f = io.open(filename,'w')
  f:write('# Module created by juce, modified by MjTs-140914.\n')
  f:write('# DATAPACK_2.0_COMPATIBLE by_PESWEB.\n')
  f:write('# Camera settings. Written by EvoLiveBroadcastCamera.lua ' .. m.version .. '(do not modified).\n\n')
  for k,v in pairs(t) do
    f:write('['..k..']\n')
    for k,v in pairs(v) do
      f:write(k..' = '..v..'\n')
    end
    f:write('\n')
  end
  f:close()
  return t
end
local function save_ini(ctx, filename)
    f = filename  
    if not f then
        log(string.format("PROBLEM saving settings: %s", tostring(err)))
        return
    end
    write_config(f, section,'camera_range_zoom',settings.camera_range_zoom)
    write_config(f, section,'camera_range_height',settings.camera_range_height)
    write_config(f, section,'camera_range_angle',settings.camera_range_angle)
    write_config(f, section,'camera_range_up_down',settings.camera_range_up_down)
    write_config(f, section,'camera_range_tracking_delay',settings.camera_range_tracking_delay)
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, iniFile)
    end
end

local function stadium_id(ctx)
    stadium = ctx.stadium
  if string.len(stadium) == 1 then
     stid = "st00" .. stadium
  elseif string.len(stadium) == 2 then
     stid = "st0" .. stadium
  elseif string.len(stadium) == 3 then
     stid = "st" .. stadium
  end
  section = stid
    settings = read_config(iniFile)
    apply_settings(ctx, true)
    --log(string.format("Camera assign to: %s", section))
end

local function trophy_rewrite(ctx, tournament_id)
     log("- Camera: " .. section)
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, [1] - switch module.\n     Current Stadium: %s%s", m.version, section, 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)
    if iniFile:sub(1,1)=='.' then
        iniFile = ctx.sider_dir .. iniFile
    end

	local pattern = "\x42\x61\x6c\x6c\x20\x41\x6e\x67"
    local loc = memory.search_process(pattern)
    if loc then
        local rel_offset = loc
        bases.camera = rel_offset
    else
        log("problem: unable to find code pattern for camera block")
    end
    settings = read_config(iniFile)
    
    ctx.register("after_set_conditions", stadium_id)
  ctx.register("overlay_on", m.overlay_on)
    ctx.register("key_down", m.key_down)
    
end

return m
