local version = { major = 0, minor = 0, revison = 2 }
local MT = minetest
local fsbuilder = { version = version }

local modname = MT.get_current_modname()
local fs_esc = MT.formspec_escape
local theme = {
  bgcolor = "#000000BB",
  boxcolor = "#87CEFA17",
  lists = {
    normal = "#172d3a75",
    hover = "#1E90FF15",
    border = "#1E90FF40",
    tt_background = "#2F2F2F",
    tt_font = "#c1c1c1"
  },
  buttons = {
    normal = "#0E1A21",
    hover = "green",
    pressed = "#DAA520",
    alpha = "true"
  },
  color = "#c1c1c1"
}
fsbuilder.theme = theme
fsbuilder.esc = fs_esc
fsbuilder.concat = function(t)
  if t == nil then
    return ""
  else
    if type(t) == "string" then
      return t
    end
  end
  return table.concat(t, "")
end

function fsbuilder:new(def)
  def = def or {}
  local o = {
    name = "fsbuilder",
    valid = true,
    form = {},
    id = 0,
    height = def.height or 0,
    width = def.width or 0,
    spacing = 0.25,
    padding = 0.125,
    background = def.background or modname .. "_background",
    theme = theme
  }
  setmetatable(o, self)
  self.__index = self
  return o
end

function fsbuilder:set_size(height, width)
  self:set_height(height)
  self:set_width(width)
end

function fsbuilder:set_height(height)
  self.height = height
end

function fsbuilder:set_width(width)
  self.width = width
end

function fsbuilder:set_background(background)
  self.background = background
end

function fsbuilder:set_theme(key, value, force)
  value = value == nil and "" or value
  if not key then
    return false
  end
  if not force then
    if not self.theme[key] then
      self.theme[key] = value
      return true
    end
  else
    self.theme[key] = value
    return true
  end
  return false
end

function fsbuilder:get_theme(key)
  return self.theme[key]
end

function fsbuilder:new_id()
  self.id = self.id + 1
  return self.id
end

function fsbuilder:add_form_element(data)
  self.form[self:new_id()] = self.concat(data)
  return self.id
end

function fsbuilder:get_form_element(key)
  if self.form[key] ~= nil then
    return self.form[key]
  end
  return false
end

function fsbuilder:is_valid()
  return self.valid and true or false
end

function fsbuilder:set_invalid()
  self.valid = false
end

function fsbuilder:set_valid()
  self.valid = true
end

function fsbuilder:del_form_element(key)
  if self.form[key] ~= nil then
    self.form[key] = nil
  end
end

function fsbuilder:get_form_string(add_header)
  add_header = add_header or true
  return (add_header and self:add_header() or "") .. self.concat(self.form)
end

function fsbuilder:add_header()
  return string.format(
    [[
		formspec_version[4]
		size[%f,%f]
		background9[0,0;0,0;%s.png;true;4]
		bgcolor[%s;true]
		listcolors[%s;%s;%s;%s;%s]
		style_type[image_button,button,item_image_button;bgcolor=%s;bgcolor_hovered=%s;bgcolor_pressed=%s;alpha=%s,border=false,padding=1]
	]],
    self.width,
    self.height,
    self.background,
    self.theme.bgcolor,
    self.theme.lists.normal,
    self.theme.lists.hover,
    self.theme.lists.border,
    self.theme.lists.tt_background,
    self.theme.lists.tt_font,
    self.theme.buttons.normal,
    self.theme.buttons.hover,
    self.theme.buttons.pressed,
    self.theme.buttons.alpha
  )
end

-- listring[<inventory location>;<list name>]
function fsbuilder:listring(location, listname)
  self:add_form_element("listring[" .. location .. ";" .. listname .. "]")
end

function fsbuilder:add_footer()
end

-- helper functions
function fsbuilder:slot(slot)
  return slot + (self.spacing * (slot + 1))
end

-- Minetest formspec elements
--### `list[<inventory location>;<list name>;<X>,<Y>;<W>,<H>;<starting item index>]`
function fsbuilder:list(loc, inv_name, x, y, w, h, start, x_offset, y_offset)
  y_offset = y_offset or 0 --hotbar padding
  x_offset = x_offset or 0
  start = start or ""
  self:add_form_element(
    {
      string.format(
        [[
					list[%s;%s;%f,%f;%f,%f;%s]
				]],
        fs_esc(loc),
        fs_esc(inv_name),
        x + x_offset,
        y + y_offset,
        w,
        h,
        start
      )
    }
  )
end

--### `label[<X>,<Y>;<label>]`
function fsbuilder:label(x, y, str)
  self:add_form_element(
    {
      string.format("label[%f,%f;%s]", x, y, fs_esc(str))
    }
  )
end

--### `tooltip[<X>,<Y>;<W>,<H>;<tooltip_text>;<bgcolor>;<fontcolor>]`
function fsbuilder:tooltip(x, y, w, h, tooltip_text, bgcolor, fontcolor)
  self:add_form_element(
    {
      string.format(
        [[ tooltip[%f,%f;%f,%f;%s;%s;%s] ]],
        x,
        y,
        w,
        h,
        fs_esc(tooltip_text),
        fs_esc(bgcolor and bgcolor or self:get_theme("lists").tt_background),
        fs_esc(fontcolor and fontcolor or self:get_theme("lists").tt_font)
      )
    }
  )
end

--### `tooltip[<gui_element_name>;<tooltip_text>;<bgcolor>;<fontcolor>]`
function fsbuilder:tooltip_element(gui_element_name, tooltip_text, bgcolor, fontcolor)
  self:add_form_element(
    {
      string.format(
        [[ tooltip[%s;%s;%s;%s] ]],
        fs_esc(gui_element_name),
        fs_esc(tooltip_text),
        fs_esc(bgcolor and bgcolor or self:get_theme("lists").tt_background),
        fs_esc(fontcolor and fontcolor or self:get_theme("lists").tt_font)
      )
    }
  )
end

-- ### `button[<X>,<Y>;<W>,<H>;<name>;<label>]`
function fsbuilder:button(x, y, w, h, name, label)
  self:add_form_element(
    {
      string.format("button[%f,%f;%f,%f;%s;%s]", x, y, w, h, fs_esc(name), fs_esc(label))
    }
  )
end

-- ### `image[<X>,<Y>;<W>,<H>;<texture name>]`
function fsbuilder:image(x, y, w, h, image)
  self:add_form_element(
    {
      string.format("image[%f,%f;%f,%f;%s]", x, y, w, h, fs_esc(image))
    }
  )
end

-- ### `image_button[<X>,<Y>;<W>,<H>;<texture name>;<name>;<label>]`
--### `image_button[<X>,<Y>;<W>,<H>;<texture name>;<name>;<label>;<noclip>;<drawborder>;<pressed texture name>]`
function fsbuilder:image_button(x, y, w, h, image, name, label)
  label = label or ""
  self:add_form_element(
    {
      string.format("image_button[%f,%f;%f,%f;%s;%s;%s]", x, y, w, h, fs_esc(image), fs_esc(name), fs_esc(label))
    }
  )
end

--### `item_image_button[<X>,<Y>;<W>,<H>;<item name>;<name>;<label>]`
function fsbuilder:item_image_button(x, y, w, h, item, name, label)
  self:add_form_element(
    {
      string.format(
        "item_image_button[%f,%f;%f,%f;%s;%s;%s]",
        x,
        y,
        w,
        h,
        fs_esc(item),
        fs_esc(name),
        fs_esc(label or "")
      )
    }
  )
end

function fsbuilder:get_player_list(x, y)
  self:list("current_player", "main", self:slot(x), self:slot(y), 8, 1)
  self:list("current_player", "main", self:slot(x), self:slot(y), 8, 3, 8, 0, 1.5)
end

return fsbuilder
