--[[
  @package    eg4-crank-ui-2
  @file       code-page.lua
  @brief      Converts code page text to unicode
]]

-- Other code pages can be found here:
--   https://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/

local CODE_PAGES_FOLDER = gre.APP_ROOT.."/code-pages"
local DEFAULT = "UTF-8"
local code_page = "CP1252" --DEFAULT
local encoder
local code_pages = {
  [DEFAULT] = {
    parse = function(text) return text end,
  }
}

---
--- @brief  Parse the code page source and create the data set.
--- @param  source  The source text to parse.
--- @return table of character to unicode mappings.
local function parse_encoding_text(source)
  local data = {}
  for w, u in source:gmatch('0x(%x%x)%s+0x(%x+)') do
    local c, t, h = tonumber(u, 16), {}, 128
    while c >= h do
        t[#t + 1] = 128 + c % 64
        c = math.floor(c / 64)
        h = h > 32 and 32 or h / 2
    end
    t[#t + 1] = 256 - 2 * h + c
    if #t > 1 or tonumber(w, 16) ~= table.unpack(t) then
      data[w.char(tonumber(w, 16))] = w.char(table.unpack(t)):reverse()
    end
  end
  return data
end

---
--- @brief  Fetch the currently selected code page encoder
--- @return encoder table.
local function get_encoder()
  if code_page ~= DEFAULT then
    local file = io.open(CODE_PAGES_FOLDER.."/"..code_page..".TXT", "r")
    if file then
      code_pages[code_page] = {
        data = parse_encoding_text(file:read("*all")),
        parse = function(text) return text:gsub('.', encoder.data) end
      }
    end
  end
  return code_pages[code_page] or code_pages[DEFAULT]
end

---
--- @brief  Parse the driver text for currently selected code page
--- @param  text  The text to parse.
--- @return parsed text.
function string:parse_text_for_code_page()
  local value = get_driver_message_text_encoding()
  if code_page ~= value then
    code_page = value
    encoder = get_encoder()
  end
  return encoder.parse(self)
end

---
--- @brief  Fetch list of available code pages
--- @return list of code pages
function get_character_encodings()
  local list = { DEFAULT }
  local files = fileinfo:scandir(CODE_PAGES_FOLDER)
  if files == nil then return list end
  for k,v in ipairs(files) do
    v = v:upper()
    if v:ends_with(".TXT") then
      table.insert(list, v:remove_trailing(".TXT"))
    end
  end
  return list
end
