local classlib = require("core.class")
local PriorityList = classlib.Class("PriorityList")
local STATES = {
  ON = true,
  OFF = false,
  UNSET = nil
}
function PriorityList:init(defaultState, items)
  if items == nil then
    items = {}
  end
  self._default = defaultState
  self._items = items
end
function PriorityList:Inherit(otherList)
  for _, item in ipairs(otherList._items) do
    table.insert(self._items, item)
  end
end
function PriorityList:GetIndexFromName(name)
  for index, item in ipairs(self._items) do
    if item.Name == name then
      return index
    end
  end
end
function PriorityList:SetItem(index, newState)
  if self._items[index].Set ~= nil then
    self._items[index].Set(newState)
  end
end
function PriorityList:SetItemByName(name, newState)
  for index, item in ipairs(self._items) do
    if item.Name == name then
      self:SetItem(index, newState)
      return
    end
  end
end
function PriorityList:Clear()
  for _, item in ipairs(self._items) do
    if item.Set then
      item.Set(STATES.UNSET)
    end
  end
end
function PriorityList:GetAvailable()
  for _, item in ipairs(self._items) do
    local value = item.Get()
    if value ~= STATES.UNSET then
      return value
    end
  end
  return self._default
end
function CreateSimpleItem(name)
  assert(type(name) == "string", "Name must be a string")
  local value = STATES.UNSET
  return {
    Name = name,
    Get = function()
      return value
    end,
    Set = function(newVal)
      value = newVal
    end
  }
end
function CreateComplexItem(name, getter, setter)
  assert(type(name) == "string", "Name must be a string")
  assert(type(getter) == "function", "Getter must be a function")
  return {
    Name = name,
    Get = getter,
    Set = setter
  }
end
function GenerateItem(name, getter, setter)
  local t
  if getter == nil and setter == nil then
    t = CreateSimpleItem(name)
  else
    t = CreateComplexItem(name, getter, setter)
  end
  return t
end
function PriorityList:AddItem(name, getter, setter)
  table.insert(self._items, GenerateItem(name, getter, setter))
end
function PriorityList:AddItemAtIndex(index, name, getter, setter)
  table.insert(self._items, index, GenerateItem(name, getter, setter))
end
function sign(x)
  return x < 0 and -1 or 1
end
function PriorityList:AddCounter(name)
  local count = 0
  local get = function()
    if count == 0 then
      return STATES.UNSET
    elseif 0 < count then
      return STATES.ON
    else
      return STATES.OFF
    end
  end
  local set = function(newState)
    if newState == STATES.ON then
      count = count + 1
    elseif newState == STATES.OFF then
      count = count - 1
    elseif count ~= 0 then
      count = count - sign(count)
    end
  end
  self:AddItem(name, get, set)
end
function nameForState(state)
  if state == STATES.ON then
    return "On"
  elseif state == STATES.OFF then
    return "Off"
  elseif state == STATES.UNSET then
    return "Unset"
  else
    return "Unknown State, this is probably a bug"
  end
end
function PriorityList:DrawDebugTable()
  local dbgTable = {}
  local preventingItem
  dbgTable[#dbgTable + 1] = {"Name", "Value"}
  for _, item in ipairs(self._items) do
    local value = item.Get()
    if value ~= STATES.UNSET and preventingItem == nil then
      preventingItem = item
    end
    dbgTable[#dbgTable + 1] = {
      item.Name,
      nameForState(item.Get())
    }
  end
  dbgTable[#dbgTable + 1] = {"", ""}
  dbgTable[#dbgTable + 1] = {
    "Deciding Item:",
    ""
  }
  if preventingItem ~= nil then
    dbgTable[#dbgTable + 1] = {
      preventingItem.Name,
      nameForState(preventingItem.Get())
    }
  else
    dbgTable[#dbgTable + 1] = {
      "Default",
      nameForState(self._default)
    }
  end
  dbgTable.Title = "Priority List Table"
  engine.DrawDebugTable(dbgTable)
end
return {
  PriorityList = PriorityList,
  STATES = STATES,
  CreateSimpleItem = CreateSimpleItem,
  CreateComplexItem = CreateComplexItem
}
