--
-- Copyright (c) 2021-2022 Zeping Lee
-- Released under the MIT license.
-- Repository: https://github.com/zepinglee/citeproc-lua
--

local number_module = {}

local element = require("citeproc-element")
local util = require("citeproc-util")


local Number = element.Element:new()

function Number:render (item, context)
  self:debug_info(context)
  context = self:process_context(context)
  local variable = context.options["variable"]
  local content = self:get_variable(item, variable, context)

  table.insert(context.variable_attempt, content ~= nil)

  if not content then
    return nil
  end

  local numbers = {}
  local punct_list = {}
  local last_position = 1
  for number, punct, pos in string.gmatch(content, "(.-)%s*([-,&])%s*()") do
    table.insert(numbers, number)
    table.insert(punct_list, punct)
    last_position = pos
  end
  table.insert(numbers, string.sub(content, last_position))

  local res = ""
  for i, number in ipairs(numbers) do
    local punct = punct_list[i]
    number = self:_format_single_number(number, context)
    res = res .. number

    if punct == "-" then
      res = res .. punct
    elseif punct == "," then
      res = res .. punct .. " "
    elseif punct == "&" then
      res = res .. " " .. punct .. " "
    end
  end

  res = self:case(res, context)
  res = self:wrap(res, context)
  res = self:display(res, context)

  return res
end

function Number:_format_single_number(number, context)
  local form = context.options["form"] or "numeric"
  if form  == "numeric" or not string.match(number, "^%d+$") then
    return number
  end
  number = tonumber(number)
  if form == "ordinal" or form == "long-ordinal" then
    return self:_format_oridinal(number, form, context)
  elseif form == "roman" then
    return util.convert_roman(number)
  end
end

function Number:_format_oridinal(number, form, context)
  assert(type(number) == "number")
  local variable = context.options["variable"]

  if form == "long-ordinal" then
    if number < 1 or number > 10 then
      form = "ordinal"
    end
  end

  local gender = nil
  local term = self:get_term(variable)
  if term then
    gender = term:get_attribute("gender")
  end

  term = self:get_term(form, nil, number, gender)
  local res = term:render(context)
  if form == "ordinal" then
    if res then
      return tostring(number) .. res
    else
      res = tostring(number)
    end
  else
    return res
  end
  return res
end


number_module.Number = Number

return number_module
