--[[

  @package   eg4-crank-ui-2
  @file      create-translations-file.lua
  @brief     Functionality for writing the strings from the model to a file.
             The current language facility does not properly determine all
             the strings that require translation from the model. Ay start-up,
             this module will scan the model and pickup all the strings and
             write them to a file.
             Note: This only works when the model is run on the computer. This
             is intention behaviour.
]]

---
--- @brief  Check if value represents a image
--- @param  value - item to check
---
local function check_value_is_image(value)
  value = tostring(value)
  if value:starts_with("images/") then
    if value:ends_with(".svg") or value:ends_with(".png") or value:ends_with(".jpg") or value:ends_with(".gif") then
          return true
    end
  end
  return false
end

---
--- @brief  Check if value represents a function callback
--- @param  value - item to check
---
local function check_value_is_function(value)
  if type(value) == "function" or _G[value] ~= nil then
    return true
  elseif tostring(value):starts_with("cb_") then
    return true
  end
end

---
--- @brief  Check if value represents a reserved string
--- @param  value - item to check
--- @return true if reserved string
local function check_reserved_string(value)
  local reserved_strings = {
    "%s",
    "%d",
    "%d%%",
    "%d - %d%%",
    "%1.0f",
    "%.1f",
    "%.1fs",
    "UDP",
    "TCP",
    "HTC",
    "IBIS1",
    "STFT1",
    "OBC1",
    "keypad",
    "keyboard",
    "IMEI",
    "%d°C",
    "%dms",
  }

  for i = 1, #reserved_strings do
    if value == reserved_strings[i] then
      return true
    end
  end
end

---
--- @brief  Check if value represents a non numerical string
--- @param  value - item to check
--- @return true if a valid string requiring translation
local function check_value_is_string(value)
  if type(value) ~= "string" then return end
  if check_value_is_function(value) then return end
  if check_value_is_image(value) then return end
  if check_reserved_string(value) then return end
  if gredom.get_object(value) ~= nil then return end
  if value:starts_with("fonts/") then return end
  if value:match('[A-Za-z]+') == nil then return end
  if value:match('[_]+') ~= nil then return end
  return true
end

---
--- @brief  Checks for valid string and if valid creates a data item to be written to the csv file.
--- @param  var - variable to parse
--- @param  value - value of variable
---
local function populate_string_item(var, value)
  if var:ends_with(".short_name") then return end
  if var:ends_with(".overflow") then return end
  if var:ends_with(".start_key_group") then return end
  if not check_value_is_string(value) then return end
  local text_name = var:sub(var:match(".*%.()") or 1)

  var = var:sub(1, (var:match(".*%.()") or 1) - 2)
  local data = {}
  local base = var:sub(1, (var:match("%.()") or 1) - 2)
  data.text_width = gre.get_value(var.."."..text_name.."_width") or gre.get_value(var..".width") or gre.get_value(base.."."..text_name.."_width") or gre.get_value(var..".grd_width")  or gre.get_value(text_name.."_width") or -1
  data.font_size = gre.get_value(var..".font_size") or 24
  data.font_style = 'Noto Sans SC Regular'
  data.text = value
  return data
end

---
--- @brief  Scans var item for individual string or list and adds item(s) to list
---         string list with all items.
--- @param  string_list - list to populate
--- @param  var - variable to parse
---
local function parse_string_to_file(string_list, var)
  local status = false
  local row = 1
  repeat
    local value
    local col = 1
    local item = string.format("%s.%u.%u", tostring(var), row, col)
    value = gre.get_value(item)
    if value ~= nil then
      status = true
      repeat
        string_list[item] = populate_string_item(var, value)
        col = col + 1
        item = string.format("%s.%u.%u", tostring(var), row, col)
        value = gre.get_value(item)
      until value == nil
      value = ""
    end
    row = row + 1
  until value == nil

  if status == false then
    local value = gre.get_value(var)
    string_list[var] = populate_string_item(var, value)
  end
end

---
--- @brief  Search the object for strings that require translation.
--- @param  string_list - list to populate
--- @param  dom_object - parent object
---
local function search_variables_for_strings(string_list, dom_object)
  if dom_object == nil then return end
  for _,item in ipairs(dom_object:get_variables() or {}) do
    parse_string_to_file(string_list, tostring(item))
  end
end

---
--- @brief  Nested search of all objects for translations
--- @param  string_list - list to populate
--- @param  dom_object - parent object
---
local function search_object_children_for_strings(string_list, dom_object)
  search_variables_for_strings(string_list, dom_object)
  for _,object in ipairs(dom_object:get_children() or {}) do
    search_object_children_for_strings(string_list, object)
  end
end

---
--- @brief  Callback to collect all the strings from the model and write them to a file.
--- @param  gre#context mapargs
---
function cb_collect_strings_for_translation(mapargs)

  if gre.APP_ROOT:starts_with("/usr/share") then return end

  file = io.open(gre.APP_ROOT.."/../docs/translations.csv", "w")
  if file == nil then return end

  local string_list = {}
  search_object_children_for_strings(string_list, gredom.get_application())

  -- Remove this item as it is not a string
  string_list["Translations for"] = nil

  -- Create a table of keys and sort
  local keys = {}
  for k, v in pairs(string_list) do
    table.insert(keys, k)
  end
  table.sort(keys)

  -- Write to file
  for _,k in pairs(keys) do
    local v = string_list[k]
    if v.text:find('[,"]') then
      v.text = '"'..v.text:gsub('"', '""')..'"'
    end
    -- file:write(string.format('%s,%d,%d,%s,%s\n', k, v.text_width, v.font_size, v.font_style, v.text:gsub('"', '""')))
    file:write(string.format('%s,%s\n', k, v.text))
  end
  file:close()
end
