local class = require("core.class")
local levelmonitor = require("level.levelmonitor")
local savelib = require("core.save")
local EntityZoneMonitor = class.Class("EntityZoneMonitor", levelmonitor.LevelMonitor)
local callEnterOrExitCallback
function EntityZoneMonitor:OnEnter(fn, ...)
  self:OnValue(true, callEnterOrExitCallback, self, fn, ...)
end
function EntityZoneMonitor:OnExit(fn, ...)
  self:OnValue(false, callEnterOrExitCallback, self, fn, ...)
end
local AddEntityZoneMonitor = function(go, zoneNameOrGameObject)
  return EntityZoneMonitor.New(go, zoneNameOrGameObject)
end
local OnMonitorSaveCallback = function(saveKey, zoneMonitor)
  local saveState = savelib.GetSaveState(saveKey, "__entityZoneMonitorState", zoneMonitor.go)
  saveState[zoneMonitor.zoneNameOrGameObject] = {
    zoneMonitor.value,
    zoneMonitor.triggerCount
  }
end
local OnMonitorLoadCallback = function(saveKey, zoneMonitor)
  local saveInfo = savelib.GetSaveState(saveKey, "__entityZoneMonitorState", zoneMonitor.go)
  local value = saveInfo and saveInfo[zoneMonitor.zoneNameOrGameObject]
  if value ~= nil then
    zoneMonitor.value, zoneMonitor.triggerCount = value[1], value[2]
    if zoneMonitor.triggerCountLimit and zoneMonitor.triggerCount >= zoneMonitor.triggerCountLimit then
      zoneMonitor:Stop()
    end
  end
end
function EntityZoneMonitor:MarkForSave()
  savelib.AddSaveObjectCallback(self.saveKey, self, OnMonitorSaveCallback)
  savelib.AddLoadObjectCallback(self.saveKey, self, OnMonitorLoadCallback)
  savelib.CreateSaveState(self.saveKey, "__entityZoneMonitorState", self.go)
end
function EntityZoneMonitor:ManualLoadFromCheckpoint()
  OnMonitorLoadCallback(nil, self)
end
function callEnterOrExitCallback(value, self, fn, ...)
  self:dprint("Entity Zone Monitor triggered: '" .. tostring(self.go) .. "' in zone '" .. tostring(self.zoneNameOrGameObject) .. "': " .. tostring(value))
  fn(self, self.go, self.zoneNameOrGameObject, ...)
  return true
end
function EntityZoneMonitor:init(go, zoneNameOrGameObject)
  self.go = go
  self.zoneNameOrGameObject = zoneNameOrGameObject
  self.value = false
  self.saveKey = engine.CurrentlyExecutingSubObject() or engine.CurrentlyExecutingObject()
  self:Watch(self.watch_callback, self)
  self:Start()
end
function EntityZoneMonitor:watch_callback()
  if self.go == nil then
    return self.value
  end
  return self.go:InsideZone(self.zoneNameOrGameObject) or false
end
_G.AddEntityZoneMonitor = AddEntityZoneMonitor
return {EntityZoneMonitor = EntityZoneMonitor, Add = AddEntityZoneMonitor}
