--[[
  @package   eg4-crank-ui-2
  @file      string-utils.lua
  @brief     Various string utilities
]]

---
-- @brief Split string using delimiter with a parameter to limit the number of splits
-- @param delimiter - The delimiter to use (default is ',')
-- @param limit - The maximum number of splits (nil for no limit)
--
function string:split(delimiter, limit)
  if self:len() == 0 then return {} end
  delimiter = delimiter or ","
  local result = {}
  local from = 1
  local delim_from, delim_to = self:find(delimiter, from, true)
  while delim_from and (not limit or limit > 0) do
    table.insert(result, self:sub(from, delim_from - 1))
    from = delim_to + 1
    delim_from, delim_to = self:find(delimiter, from, true)
    if limit then limit = limit - 1 end
  end
  table.insert(result, self:sub(from))
  return result
end

---
-- @brief  Checks if a string starts with a string
-- @param  start  The string to check for
-- @return True if the string starts with the given string
function string:starts_with(start)
  return self:sub(1, #start) == start
end

---
-- @brief  Checks if a string end with a string
-- @param  ending  The string to check for
-- @return True if the string ends with the given string
function string:ends_with(ending)
  return ending == "" or self:sub(-#ending) == ending
end

---
-- @brief  Fetchs all text after the last full stop for the ui object
-- @return The text after the last full stop
function string:object_name()
  local match = self:match("%.([^%.]*)$")
  return match or self
end

---
-- @brief  Fetchs all text before the last full stop for the ui object
-- @return The text before the last full stop
function string:object_parent()
  local match = self:match("^(.*)%.[^%.]*$")
  return match or ""
end

---
-- @brief  If matched, remove the trailing string from a string
-- @param  text - string to remove
-- @return string with trailing string removed
function string:remove_trailing(text)
  return self:sub(-#text) == text and self:sub(1, #self - #text) or self
end

---
-- @brief  Splits string and returns as an array of lines
-- @param  text - string to remove
-- @return array of lines
function string:lines()
  local lines = {}
  local function helper(line) table.insert(lines, line) return "" end
  helper((self:gsub("(.-)\r?\n", helper)))
  if lines[#lines] == "" then table.remove(lines) end
  return lines
end

---
--- @brief  Removes leading and trailing whitespace from a string
--- @param  self - string to remove
--- @return string with leading and trailing whitespace removed
function string:trim()
  return self:match( "^%s*(.-)%s*$" )
end

-- Convert value to text
function map(item, indent)
  function string:encode(text)
    -- Encode and replace special characters in string.
    return '\''..self:gsub('[%c\'\\]', function(c)
      if c == '\\' then return '\\\\' end
      if c == '\n' then return '\\n' end
      if c == '\r' then return '\\r' end
      if c == '\t' then return '\\t' end
      if c == '\b' then return '\\b' end
      if c == '\f' then return '\\f' end
      if c == '\'' then return '\\\'' end
      return string.format('\\%03d', c:byte())
    end)..'\''
  end

  indent = indent or ""

  if type(item) ~= 'table' then
    return type(item) == "string" and item:encode() or tostring(item)
  end

  -- Create list for the numerical array part of table
  local text = "{"
  local sep = "\n"
  for i=1,#item do
    text = text..sep..indent.."  "..map(item[i], indent.."  ")
    sep = ",\n"
  end

  for key,value in sorted_pairs(item) do
    if type(key) == 'number' then
      if key < 1 or key > #item then
        text = text..sep..indent.."  ["..tostring(key).."] = "..map(value, indent.."  ")
        sep = ",\n"
      end
    else
      text = text..sep..indent.."  ["..tostring(key):encode().."] = "..map(value, indent.."  ")
      sep = ",\n"
    end
  end
  text = text.."\n"..indent.."}"
  return text
end

function print_map(value)
  print(map(value))
end
