local class = require("core.class")
local Monitor = class.Class("Monitor")
local NIL = {}
function Monitor:init(runList)
  self.runList = assert(runList)
  self.valueCallbacks = {}
  self.triggerCount = 0
  self.triggerCountLimit = nil
  self.bPrintsEnabled = true
end
local assignCallback = function(fn, ...)
  assert(fn)
  local args
  if (...) then
    args = {
      ...
    }
  end
  return fn, args
end
function Monitor:Start()
  self.watching = true
  self.runList:add(self)
end
function Monitor:Stop()
  self.watching = false
  self.runList:remove(self)
end
function Monitor:Watch(watchFn, ...)
  self.watchFn, self.watchFnArgs = assignCallback(watchFn, ...)
end
function Monitor:OnChanged(changedFn, ...)
  self.changedFn, self.changedFnArgs = assignCallback(changedFn, ...)
end
function Monitor:OnValue(value, fn, ...)
  if type(value) == "nil" then
    value = NIL
  end
  self.valueCallbacks[value] = {
    fn = fn,
    ...
  }
end
function Monitor:UpdateWithoutCallbacks()
  assert(self.watchFn, "Monitor is missing a Watch function!")
  self.value = self.watchFn(unpack(self.watchFnArgs or NIL))
end
function Monitor:Update()
  if not self.watching then
    return
  end
  assert(self.watchFn, "Monitor is missing a Watch function!")
  local value = self.watchFn(unpack(self.watchFnArgs or NIL))
  if self.value ~= value then
    if self.changedFn and self.changedFn(self.value, value, unpack(self.changedFnArgs or NIL)) then
      self.dprint("Incrementing Monitor")
      self.triggerCount = self.triggerCount + 1
    end
    local lookupValue = type(value) == "nil" and NIL or value
    local valueCallback = self.valueCallbacks[lookupValue]
    if valueCallback and valueCallback.fn(value, unpack(valueCallback)) then
      self.dprint("Incrementing Monitor")
      self.triggerCount = self.triggerCount + 1
    end
    self.value = value
    if self.triggerCountLimit and self.triggerCount >= self.triggerCountLimit then
      self:Stop()
    end
  end
end
function Monitor:SetTriggerCountLimit(max)
  if max then
    self.triggerCountLimit = max
  end
end
function Monitor:SetPrintsEnabled(bEnabled)
  self.bPrintsEnabled = bEnabled
end
function Monitor:dprint(str)
  if self.bPrintsEnabled then
    print(str)
  end
end
return {Monitor = Monitor}
