---
-- Formatting functions for script output
--

local stdnse = require "stdnse"
local table = require "table"
local string = require "string"
local debug = require "debug"
local _R = debug.getregistry()
_ENV = stdnse.module("format", stdnse.seeall)

---Indent a multiline string
--@param str The string to indent
--@param ind The string to indent by. Usually a number of spaces, i.e. "  "
--@return The string, indented by that number of spaces.
indent = function(str, ind)
  local i = "\n" .. ind
  return ind .. string.gsub(str, "\n", i)
end

---Set a function as the tostring-handler for a table.
-- This is especially useful for instructing Nmap how to display a table that is
-- returned from a script.
--
-- @param  tab   The table to set the __tostring metamethod for.
-- @param  func  The function to set. It should take the table as its first
--               parameter, and return a string.
-- @return None.
set_tostring = function(tab, func)
  local mt = getmetatable(tab)
  mt = mt or {}
  mt["__tostring"] = func
  setmetatable(tab, mt)
end

---Set a string as the output representation of a table.
-- Instead of specifying a function to convert a table to a string, the
-- string is returned directly when tostring(table) is called
--
-- @param  tab    The table to set string representation for.
-- @param  str  The string to use.
-- @return None.
as_string = function(tab, str)
  local mt = getmetatable(tab)
  mt = mt or {}
  mt["__tostring"] = function(this) return str end
  setmetatable(tab, mt)
end

---Treat a table as a horizontal list when formatting
--@param tab   The table to apply the formatting function to
--@param sep The separator to place between list items. Default: ", "
as_horizontal = function(tab, sep)
  sep = sep or ", "
  set_tostring(tab, function(this)
    local lines = {}
    for _, v in ipairs(this) do
      lines[#lines + 1] = tostring(v)
    end
    return table.concat(lines, sep);
  end)
end

---Indent the string resulting from formatting a table
--@param tab   The table whose output should be indented
--@param ind The string to indent by.
add_indent = function(tab, ind)
  local mt = getmetatable(tab)
  mt = mt or {}
  local prev = mt["__tostring"] or _R["NSE_FORMAT_TABLE"]
  mt["__tostring"] = function(this)
    local str = prev(this)
    return indent(str, ind)
  end
  setmetatable(tab, mt)
end

---Prepend a string to the output of a table
--@param tab   The table whose output should be prepended
--@param str The string to prepend
prepend = function(tab, str)
  local mt = getmetatable(tab)
  mt = mt or {}
  local prev = mt["__tostring"] or _R["NSE_FORMAT_TABLE"]
  mt["__tostring"] = function(this)
    local repr = prev(this)
    return str .. repr
  end
  setmetatable(tab, mt)
end

return _ENV
