local LD = require("design.LevelDesignLibrary")
local timer = require("level.timer")
local thisObj, thisLevel, isEnabled, isExposed, rotSpeed, pillar
local isRaising = false
local isNozzlesOn = false
local isLocked = false
local spinRing
local nozzles = {}
local nozzleFacings = {}
local exposedFrame, baseJointIndex, childCounter, callbacks_EmergeComplete, callbacks_SubmergeComplete
function GetPillar()
  return pillar or thisObj:FindSingleGOByName("Turret_Sprayer_Base_Pillar").Child
end
function GetRing()
  return spinRing or thisObj:FindSingleGOByName("Turret_Sprayer_Base_Ring")
end
function IsEnabled()
  return isEnabled
end
function IsExposed()
  return isExposed
end
function OnScriptLoaded(level, obj)
  thisObj = obj
  thisLevel = level
  spinRing = thisObj:FindSingleGOByName("Turret_Sprayer_Base_Ring")
  pillar = thisObj:FindSingleGOByName("Turret_Sprayer_Base_Pillar").Child
  pillar:SetInhibitSave()
  isEnabled = thisObj:GetLuaTableAttribute("startEnabled")
  isExposed = thisObj:GetLuaTableAttribute("startExposed")
  isLocked = thisObj:GetLuaTableAttribute("startLocked")
  rotSpeed = thisObj:GetLuaTableAttribute("roationSpeed")
  exposedFrame = thisObj:GetLuaTableAttribute("exposedFrame")
  baseJointIndex = pillar:GetJointIndex("JOTrapBase1")
  callbacks_EmergeComplete = thisObj:GetLuaTableAttribute("OnEmergeComplete")
  callbacks_SubmergeComplete = thisObj:GetLuaTableAttribute("OnSubmergeComplete")
  callbacks_EmergeComplete = LD.ExtractCallbacksForEvent(level, obj, callbacks_EmergeComplete)
  callbacks_SubmergeComplete = LD.ExtractCallbacksForEvent(level, obj, callbacks_SubmergeComplete)
  local nozzleList = thisObj:GetLuaTableAttribute("nozzleFacingAngles")
  if nozzleList ~= nil and nozzleList ~= "" then
    nozzleList = LD.ConvertStringListToTable(nozzleList)
    for _, nozzle in ipairs(nozzleList) do
      table.insert(nozzleFacings, tonumber(nozzle))
    end
  end
  childCounter = #pillar.Children
  SoundInit()
end
function OnPreStart()
  local nozzleList = thisObj:GetLuaTableAttribute("nozzleObjects")
  if nozzleList ~= nil and nozzleList ~= "" then
    nozzleList = LD.ConvertStringListToTable(nozzleList)
    for i = 1, #nozzleList do
      AttachNozzle(thisLevel:GetGameObject(nozzleList[i]), nozzleFacings[i])
    end
  end
end
function OnStart(level, obj)
  AttachObject(spinRing)
  AttachObject(thisObj:FindSingleGOByName("Collision_Bottom"))
  AttachObject(thisObj:FindSingleGOByName("Collision_Top"), "JOTop1")
end
function AttachNozzle(newNozzle, newFacing)
  if newNozzle == nil or newFacing == nil then
    return
  end
  local jntPos = spinRing:GetWorldPosition(baseJointIndex)
  local jntForward = spinRing:GetWorldForward(baseJointIndex)
  newFacing = jntForward:RotateXZ(newFacing)
  newNozzle:SetWorldFacing(newFacing)
  newNozzle:SetWorldPosition(jntPos + newFacing:Normalized() * 1.09)
  newNozzle.LuaObjectScript.SetController(thisObj, isEnabled and isExposed)
  if newNozzle.Parent ~= spinRing then
    if newNozzle.Parent then
      newNozzle:Unparent()
    end
    spinRing:AddChild(newNozzle)
    table.insert(nozzles, newNozzle)
  end
end
function AttachObject(attachedObj, joint)
  if attachedObj.Parent ~= nil then
    attachedObj:Unparent()
  end
  if joint ~= nil then
    pillar:AddChild(attachedObj, pillar:GetJointIndex(joint))
  else
    pillar:AddChild(attachedObj, baseJointIndex)
  end
  childCounter = childCounter + 1
end
function OnUpdate()
  if #pillar.Children >= childCounter then
    pillar:StartAnim("envCalSpawn")
    if isExposed then
      pillar:JumpAnimToFrame(exposedFrame)
    else
      pillar:JumpAnimToPercent(0)
    end
    pillar:PauseAnim()
    if isEnabled then
      Enable()
    else
      Disable()
    end
    game.SubObject.Sleep(thisObj)
  end
end
function OnSaveCheckpoint(level, obj)
  return {
    isEnabled = isEnabled,
    isExposed = isRaising or isExposed
  }
end
function OnRestoreCheckpoint(level, obj, savedInfo)
  isEnabled = savedInfo.isEnabled
  isExposed = savedInfo.isExposed
end
function Enable()
  if isExposed then
    NozzlesOn()
    if not isLocked then
      Unlock()
    end
  end
  isEnabled = true
end
function Disable()
  if isEnabled then
    PlaySoundOnDisable()
  end
  isEnabled = false
  NozzlesOff()
end
function Lock()
  isLocked = true
  StopSpin()
end
function Unlock()
  isLocked = false
  StartSpin()
end
function StartSpin()
  if rotSpeed ~= 0 and not isLocked then
    spinRing:PlayAnimCycle(rotSpeed)
    PlaySoundOnSpin()
  end
end
function StopSpin()
  spinRing:PauseAnim()
  StopSoundOnSpinStop()
end
function Expose()
  if isRaising or isExposed then
    return
  end
  isRaising = true
  pillar:PlayAnimToFrame(exposedFrame, 1)
  PlaySoundOnExpose()
  pillar:OnAnimDone(thisObj, "OnExposeDone")
end
function OnExposeDone()
  isExposed = true
  isRaising = false
  pillar:ClearAllAnimCallbacks()
  LD.ExecuteCallbacksForEvent(thisLevel, thisObj, callbacks_EmergeComplete)
  if isEnabled then
    NozzlesOn()
  end
  if not isLocked then
    StartSpin()
  end
end
function Submerge()
  if not isExposed then
    return
  end
  isRaising = false
  isExposed = false
  pillar:ClearAllAnimCallbacks()
  pillar:PlayAnimToEnd(-1)
  pillar:OnAnimDone(thisObj, "OnSubmergeDone")
  spinRing:PauseAnim()
  NozzlesOff()
  StopSpin()
end
function OnSubmergeDone()
  LD.ExecuteCallbacksForEvent(thisLevel, thisObj, callbacks_SubmergeComplete)
end
function NozzlesOn()
  if isNozzlesOn then
    return
  end
  isNozzlesOn = true
  for _, nozzle in ipairs(nozzles) do
    nozzle.LuaObjectScript.Enable()
  end
end
function NozzlesOff()
  if not isNozzlesOn then
    return
  end
  isNozzlesOn = false
  for _, nozzle in ipairs(nozzles) do
    nozzle.LuaObjectScript.Disable()
  end
end
function ChangeSpeed(newSpeed, startSpin)
  rotSpeed = newSpeed
  if startSpin == nil or startSpin == true then
    StartSpin()
  end
end
function GetRotationSpeed()
  return rotSpeed
end
local soundEmitter
local soundEvents = {
  OnExpose = "SND_TRAP_Fire_Trap_Drain_Pillar_Emerge",
  OnSpin = "SND_TRAP_Fire_Trap_Rotate_LP",
  OnDisable = "SND_TRAP_Fire_Trap_Off"
}
function SoundInit()
  soundEmitter = thisObj:FindSingleSoundEmitterByName("SNDSprayer")
end
function SoundSetup(sounds)
  if sounds ~= nil then
    if sounds.SoundEmitter ~= nil then
      soundEmitter = thisObj:FindSingleSoundEmitterByName(sounds.SoundEmitter)
    end
    for key in pairs(soundEvents) do
      for newKey, newValue in pairs(sounds) do
        if newKey == key and newValue ~= nil and newValue ~= "" then
          soundEvents[key] = newValue
        end
      end
      LD.SoundDebug(tostring(key) .. ": " .. tostring(soundEvents[key]))
    end
  end
end
function PlaySoundOnExpose()
  LD.PlaySound(soundEmitter, soundEvents.OnExpose)
end
function PlaySoundOnSpin()
  LD.PlaySound(soundEmitter, soundEvents.OnSpin)
end
function StopSoundOnSpinStop()
  LD.StopSound(soundEmitter, soundEvents.OnSpin)
end
function PlaySoundOnDisable()
  LD.PlaySound(soundEmitter, soundEvents.OnDisable)
end
