LD = require("design.LevelDesignLibrary")
local thisObj, son, caughtUpZones, waitZones, bailOutZones
local currentSpeed = "normal"
local sonLeashingSuppressed = false
local disabled = false
function OnScriptLoaded(level, obj)
  thisObj = obj
  son = game.AI.FindSon()
  caughtUpZones = thisObj.Parent.Parent:FindSingleGOByName("CaughtUpZones")
  waitZones = thisObj.Parent.Parent:FindSingleGOByName("WaitZones")
  bailOutZones = thisObj.Parent.Parent:FindSingleGOByName("BailOutZones")
  local missingObjNames = ""
  if caughtUpZones == nil then
    missingObjNames = missingObjNames .. "'CaughtUpZones', "
  end
  if waitZones == nil then
    missingObjNames = missingObjNames .. "'WaitZones', "
  end
  if bailOutZones == nil then
    missingObjNames = missingObjNames .. "'BailOutZones', "
  end
  if caughtUpZones == nil or waitZones == nil or bailOutZones == nil then
    engine.Error("Wait gate setup is missing the following children objects, each of which should contain one or more entity zones: " .. tostring(missingObjNames) .. " Were they accidentally renamed? Speak to tech design for more info. (" .. LD.GetParentTrace(thisObj.Parent.Parent) .. ")")
  end
  game.SubObject.SetEntityZoneHandler(thisObj, caughtUpZones)
  game.SubObject.SetEntityZoneHandler(thisObj, waitZones)
  game.SubObject.SetEntityZoneHandler(thisObj, bailOutZones)
  game.SubObject.Sleep(thisObj)
end
function OnStart(level, obj)
  local player = game.Player.FindPlayer()
  if player:IsInsideEntityZone(bailOutZones) then
    RestoreSonLeashing()
    EndSonIdle()
  elseif son:IsInsideEntityZone(caughtUpZones) then
    SonEnteredCaughtUpZone()
    if son:IsInsideEntityZone(waitZones) then
      son:SetMaxSpeedOverride(0)
      SonEnteredWaitZone()
    end
  elseif son:IsInsideEntityZone(waitZones) then
    son:SetMaxSpeedOverride(0)
    SonEnteredWaitZone()
    engine.Warning("'CaughtUpZones' in this wait gate setup do not physically overlap 'WaitZones'. This can cause checkpointing bugs. Fix this by resizing 'CaughtUpZones' to physically overlap or encompass 'WaitZones' (" .. LD.GetParentTrace(thisObj.Parent.Parent) .. ")")
  end
end
function OnMarkerEnterZone(level, obj, zoneObject, markerObject, markerId)
  local playerMarker = 3
  local sonMarker = 5
  if tostring(markerId) == tostring(playerMarker) then
    if zoneObject == caughtUpZones or zoneObject == waitZones then
      PlayerCaughtUp()
    elseif zoneObject == bailOutZones then
      PlayerLeftArea()
    end
  elseif tostring(markerId) == tostring(sonMarker) then
    if zoneObject == caughtUpZones then
      SonEnteredCaughtUpZone()
    elseif zoneObject == waitZones then
      SonEnteredWaitZone()
    end
  end
end
function SonEnteredCaughtUpZone()
  if IsDisabled() then
    return
  end
  SuppressSonLeashing()
end
function SonEnteredWaitZone()
  if IsDisabled() then
    return
  end
  if not IsSonLeashingSuppressed() then
    SuppressSonLeashing()
  end
  StartSonIdle()
end
function PlayerCaughtUp()
  if IsDisabled() then
    return
  end
  DisableAllZones()
  if IsSonLeashingSuppressed() then
    RestoreSonLeashing()
  end
  if IsSonIdled() then
    EndSonIdle()
  end
end
function PlayerLeftArea()
  if IsDisabled() then
    return
  end
  if IsSonLeashingSuppressed() then
    RestoreSonLeashing()
  end
  if IsSonIdled() then
    EndSonIdle()
  end
end
function DisableAllZones()
  caughtUpZones:HideEntityVolume()
  waitZones:HideEntityVolume()
  bailOutZones:HideEntityVolume()
  disabled = true
end
function SuppressSonLeashing()
  son:CallScript("DisableLeashing")
  sonLeashingSuppressed = true
end
function RestoreSonLeashing()
  son:CallScript("EnableLeashing")
  sonLeashingSuppressed = false
end
function StartSonIdle()
  son:CallScript("WaitGateEnter")
  currentSpeed = "idle"
end
function EndSonIdle()
  son:CallScript("WaitGateExit")
  currentSpeed = "normal"
end
function IsSonLeashingSuppressed()
  return sonLeashingSuppressed == true
end
function IsSonIdled()
  return currentSpeed == "idle"
end
function IsDisabled()
  return disabled == true
end
function OnSaveCheckpoint(level, obj)
  return {
    sonLeashingSuppressed = sonLeashingSuppressed,
    currentSpeed = currentSpeed,
    disabled = disabled
  }
end
function OnRestoreCheckpoint(level, obj, savedInfo)
  sonLeashingSuppressed = savedInfo.sonLeashingSuppressed
  currentSpeed = savedInfo.currentSpeed
  disabled = savedInfo.disabled
end
