local LD = require("design.LevelDesignLibrary")
local timers = require("level.timer")
local monitors = require("level.MonitorLibrary")
local thisObj, flipperModule, thisObjAnim, thisObjAnim_Rope, thisObjectAnim_Wobble, LiftWrench, LiftSwitch, ZipLift_LineManager_01, ZipLift_LineManager_02, ZipLift_LineManager_03, ZipLift_LineManager_04
local lineManagers = {}
local MaxLevel = 3
local MinLevel = 1
local CurrentLevel = 1
local Level0_TargetFrame = 0
local Level1_TargetFrame = 30
local Level2_TargetFrame = 75
local Level3_TargetFrame = 120
local isMoving = false
local CA_01 = {}
local CA_02 = {}
local CA_03 = {}
local CA_04 = {}
function OnScriptLoaded(level, obj)
  thisObj = obj
  thisObjAnim = thisObj:FindSingleGOByName("ZipLift_Anim")
  thisObjAnim_Rope = thisObj:FindSingleGOByName("ZipLift_Anim_Rope")
  thisObjectAnim_Wobble = thisObj:FindSingleGOByName("ZipLift_Anim_Wobble")
  if obj:GetLuaTableAttribute("ZipLift_LineManager_01") ~= "" then
    ZipLift_LineManager_01 = level:GetGameObject(obj:GetLuaTableAttribute("ZipLift_LineManager_01"))
    table.insert(lineManagers, ZipLift_LineManager_01)
  end
  if obj:GetLuaTableAttribute("ZipLift_LineManager_02") ~= "" then
    ZipLift_LineManager_02 = level:GetGameObject(obj:GetLuaTableAttribute("ZipLift_LineManager_02"))
    table.insert(lineManagers, ZipLift_LineManager_02)
  end
  if obj:GetLuaTableAttribute("ZipLift_LineManager_03") ~= "" then
    ZipLift_LineManager_03 = level:GetGameObject(obj:GetLuaTableAttribute("ZipLift_LineManager_03"))
    table.insert(lineManagers, ZipLift_LineManager_03)
  end
  if obj:GetLuaTableAttribute("ZipLift_LineManager_04") ~= "" then
    ZipLift_LineManager_04 = level:GetGameObject(obj:GetLuaTableAttribute("ZipLift_LineManager_04"))
    table.insert(lineManagers, ZipLift_LineManager_04)
  end
  LiftSwitch = obj:FindSingleGOByName("Lift_Switch")
  if obj:GetLuaTableAttribute("HideSwitch") == true then
    LiftSwitch:Hide()
    LiftSwitch.LuaObjectScript.Disable()
  else
    LiftSwitch.LuaObjectScript.AddSwitchOnOffCallback(function()
      setLevel(MaxLevel, false)
    end)
  end
  LiftWrench = thisObj:FindSingleGOByName("Lift_Wrench")
  flipperModule = LiftWrench:FindSingleGOByName("FlipperModule")
  flipperModule.LuaObjectScript.RegisterOnRotateCWCallback(OnRotateClockwise)
  flipperModule.LuaObjectScript.RegisterOnRotateCCWCallback(OnRotateCounterclockwise)
  CA_01 = {
    thisObj:FindSingleGOByName("CA_01_01"),
    thisObj:FindSingleGOByName("CA_01_02"),
    thisObj:FindSingleGOByName("CA_01_03")
  }
  CA_02 = {
    thisObj:FindSingleGOByName("CA_02_01"),
    thisObj:FindSingleGOByName("CA_02_02"),
    thisObj:FindSingleGOByName("CA_02_03")
  }
  CA_03 = {
    thisObj:FindSingleGOByName("CA_03_01"),
    thisObj:FindSingleGOByName("CA_03_02"),
    thisObj:FindSingleGOByName("CA_03_03")
  }
  CA_04 = {
    thisObj:FindSingleGOByName("CA_04_01"),
    thisObj:FindSingleGOByName("CA_04_02"),
    thisObj:FindSingleGOByName("CA_04_03")
  }
  SoundInit()
end
function OnStart(level, obj)
  local ChildrenToParent = obj:GetLuaTableAttribute("ObjectsToParent")
  if ChildrenToParent ~= "" then
    AddChildren(ChildrenToParent)
  end
  if CurrentLevel ~= 0 then
    setLevel(CurrentLevel, true)
    thisObj:Show()
  else
    flipperModule.LuaObjectScript.DisableCWRotation()
    flipperModule.LuaObjectScript.DisableCCWRotation()
    thisObj:Hide()
  end
  flipperModule.LuaObjectScript.EnableReaction()
end
function OnSaveCheckpoint(level, obj)
  return {CurrentLevel = CurrentLevel}
end
function OnRestoreCheckpoint(level, obj, savedInfo)
  CurrentLevel = savedInfo.CurrentLevel
end
function setLevel_toInitial()
  local initialLevel = thisObj:GetLuaTableAttribute("InitialLevel")
  setLevel(initialLevel, true)
  thisObj:Show()
end
function setLevel(num, jump)
  if num == 1 then
    flipperModule.LuaObjectScript.DisableCCWRotation()
    flipperModule.LuaObjectScript.EnableCWRotation()
    thisObjectAnim_Wobble:ClearAllAnimationCallbacks()
    GoTo_Level1(jump)
  elseif num == 2 then
    flipperModule.LuaObjectScript.EnableCCWRotation()
    flipperModule.LuaObjectScript.EnableCWRotation()
    thisObjectAnim_Wobble:ClearAllAnimationCallbacks()
    GoTo_Level2(jump)
  elseif num == 3 then
    flipperModule.LuaObjectScript.DisableCWRotation()
    flipperModule.LuaObjectScript.EnableCCWRotation()
    thisObjectAnim_Wobble:ClearAllAnimationCallbacks()
    GoTo_Level3(jump)
  elseif num == 0 then
    flipperModule.LuaObjectScript.DisableCWRotation()
    flipperModule.LuaObjectScript.DisableCCWRotation()
    thisObjectAnim_Wobble:ClearAllAnimationCallbacks()
    GoTo_LevelHidden(jump)
  end
  for Managers in pairs(lineManagers) do
    lineManagers[Managers].LuaObjectScript.UpdateLines()
  end
end
function getLevel()
  return CurrentLevel
end
function setLiftMoving()
  isMoving = true
  for Managers in pairs(lineManagers) do
    lineManagers[Managers].LuaObjectScript.LiftMoving()
  end
  LiftSwitch.LuaObjectScript.Disable()
end
function setLiftStopped()
  isMoving = false
  for Managers in pairs(lineManagers) do
    lineManagers[Managers].LuaObjectScript.LiftStopped()
  end
  LiftSwitch.LuaObjectScript.Enable()
end
function OnRotateClockwise()
  if CurrentLevel < MaxLevel then
    CurrentLevel = CurrentLevel + 1
    setLevel(CurrentLevel, false)
  end
end
function OnRotateCounterclockwise()
  if CurrentLevel > MinLevel then
    CurrentLevel = CurrentLevel - 1
    setLevel(CurrentLevel, false)
  end
end
function OnFlipperReaction()
  PlaySoundOnReaction()
end
function PlayWobble()
  thisObjectAnim_Wobble:JumpAnimToFrame(0)
  thisObjectAnim_Wobble:PlayAnimToEnd(1)
  thisObjectAnim_Wobble:OnAnimDone(thisObj, "setLiftStopped")
end
function GoTo_Level1(jump)
  CurrentLevel = 1
  LiftSwitch.LuaObjectScript.Unlock()
  if jump == false then
    if thisObjAnim.AnimFrame > Level1_TargetFrame then
      thisObjAnim:PlayAnimToFrame(Level1_TargetFrame, -1)
      thisObjAnim_Rope:PlayAnimToFrame(Level1_TargetFrame, -1)
      PlaySoundMovingDownLoop(Level1_TargetFrame)
    elseif thisObjAnim.AnimFrame < Level1_TargetFrame then
      thisObjAnim:PlayAnimToFrame(Level1_TargetFrame, 1)
      thisObjAnim_Rope:PlayAnimToFrame(Level1_TargetFrame, 1)
      PlaySoundMovingUpLoop(Level1_TargetFrame)
    end
    setLiftMoving()
    thisObjAnim_Rope:OnAnimDone(thisObj, "PlayWobble")
  else
    thisObjAnim:JumpAnimToFrame(Level1_TargetFrame)
    thisObjAnim_Rope:JumpAnimToFrame(Level1_TargetFrame)
    thisObjAnim:PauseAnim()
    thisObjAnim_Rope:PauseAnim()
    setLiftMoving()
    PlayWobble()
  end
end
function GoTo_Level2(jump)
  CurrentLevel = 2
  LiftSwitch.LuaObjectScript.Unlock()
  if jump == false then
    if thisObjAnim.AnimFrame > Level2_TargetFrame then
      thisObjAnim:PlayAnimToFrame(Level2_TargetFrame, -1)
      thisObjAnim_Rope:PlayAnimToFrame(Level2_TargetFrame, -1)
      PlaySoundMovingDownLoop(Level2_TargetFrame)
    elseif thisObjAnim.AnimFrame < Level2_TargetFrame then
      thisObjAnim:PlayAnimToFrame(Level2_TargetFrame, 1)
      thisObjAnim_Rope:PlayAnimToFrame(Level2_TargetFrame, 1)
      PlaySoundMovingUpLoop(Level2_TargetFrame)
    end
    setLiftMoving()
    thisObjAnim_Rope:OnAnimDone(thisObj, "PlayWobble")
  else
    thisObjAnim:JumpAnimToFrame(Level2_TargetFrame)
    thisObjAnim_Rope:JumpAnimToFrame(Level2_TargetFrame)
    thisObjAnim:PauseAnim()
    thisObjAnim_Rope:PauseAnim()
    setLiftMoving()
    PlayWobble()
  end
end
function GoTo_Level3(jump)
  CurrentLevel = 3
  LiftSwitch.LuaObjectScript.Lock()
  if jump == false then
    if thisObjAnim.AnimFrame > Level3_TargetFrame then
      thisObjAnim:PlayAnimToFrame(Level3_TargetFrame, -1)
      thisObjAnim_Rope:PlayAnimToFrame(Level3_TargetFrame, -1)
      PlaySoundMovingDownLoop(Level3_TargetFrame)
    elseif thisObjAnim.AnimFrame < Level3_TargetFrame then
      thisObjAnim:PlayAnimToFrame(Level3_TargetFrame, 1)
      thisObjAnim_Rope:PlayAnimToFrame(Level3_TargetFrame, 1)
      PlaySoundMovingUpLoop(Level3_TargetFrame)
    end
    setLiftMoving()
    thisObjAnim_Rope:OnAnimDone(thisObj, "PlayWobble")
  else
    thisObjAnim:JumpAnimToFrame(Level3_TargetFrame)
    thisObjAnim_Rope:JumpAnimToFrame(Level3_TargetFrame)
    thisObjAnim:PauseAnim()
    thisObjAnim_Rope:PauseAnim()
    setLiftMoving()
    PlayWobble()
  end
end
function GoTo_LevelHidden()
  CurrentLevel = 0
  LiftSwitch.LuaObjectScript.Lock()
  setLiftMoving()
  thisObjAnim:JumpAnimToFrame(Level0_TargetFrame)
  thisObjAnim_Rope:JumpAnimToFrame(Level0_TargetFrame)
  thisObjAnim:PauseAnim()
  thisObjAnim_Rope:PauseAnim()
  PlayWobble()
end
function AddChildren(ObjectsToParent)
  if ObjectsToParent ~= nil then
    local objNameTable = LD.ConvertStringListToTable(ObjectsToParent)
    local thisObjectGeo = thisObjectAnim_Wobble:FindSingleGOByName("Geo")
    for _, objName in ipairs(objNameTable) do
      local obj = GameObjects[objName]
      if obj ~= nil then
        thisObjectGeo:AddChild(obj)
      end
    end
  end
end
function CA_01_Enable()
  CA_01[math.random(1, #CA_01)].LuaObjectScript.Enable()
end
function CA_02_Enable()
  CA_02[math.random(1, #CA_02)].LuaObjectScript.Enable()
end
function CA_03_Enable()
  CA_03[math.random(1, #CA_03)].LuaObjectScript.Enable()
end
function CA_04_Enable()
  CA_04[math.random(1, #CA_04)].LuaObjectScript.Enable()
end
function CA_01_EnableIdle()
  CA_01[1].LuaObjectScript.Enable()
end
function CA_02_EnableIdle()
  CA_02[1].LuaObjectScript.Enable()
end
function CA_03_EnableIdle()
  CA_03[1].LuaObjectScript.Enable()
end
function CA_04_EnableIdle()
  CA_04[1].LuaObjectScript.Enable()
end
function LiftSwitch_Disable()
  LiftSwitch.LuaObjectScript.Disable()
end
function LiftSwitch_Enable()
  LiftSwitch.LuaObjectScript.Enable()
end
local ziplineLiftSoundTable = {
  SoundEmitter = nil,
  MovingUpLoop = "SND_MECH_Gondola_Lift_Raise_LP",
  MovingDownLoop = "SND_MECH_Gondola_Lift_Lower_LP",
  OnStuck = "SND_MECH_Gondola_Lift_Stuck"
}
local emitterAnimMonitor
local sound_liftMovementState = "rest"
function SoundInit()
  ziplineLiftSoundTable.SoundEmitter = thisObjectAnim_Wobble:FindSingleSoundEmitterByName("SNDZipLift")
end
function PlaySoundMovingUpLoop(endFrame)
  if emitterAnimMonitor ~= nil then
    emitterAnimMonitor:Stop()
    emitterAnimMonitor:Terminate()
    emitterAnimMonitor = nil
  end
  if sound_liftMovementState == "down" then
    LD.StopSound(ziplineLiftSoundTable.SoundEmitter, ziplineLiftSoundTable.MovingDownLoop)
    LD.PlaySound(ziplineLiftSoundTable.SoundEmitter, ziplineLiftSoundTable.MovingUpLoop, true)
  elseif sound_liftMovementState == "rest" then
    LD.PlaySound(ziplineLiftSoundTable.SoundEmitter, ziplineLiftSoundTable.MovingUpLoop, true)
  end
  emitterAnimMonitor = monitors.CreateAnimFrameMonitor(thisObjAnim)
  emitterAnimMonitor:OnFrameForward(endFrame, function()
    LD.StopSound(ziplineLiftSoundTable.SoundEmitter, ziplineLiftSoundTable.MovingUpLoop)
    emitterAnimMonitor:Stop()
    emitterAnimMonitor:Terminate()
    emitterAnimMonitor = nil
    sound_liftMovementState = "rest"
  end)
  sound_liftMovementState = "up"
end
function PlaySoundMovingDownLoop(endFrame)
  if emitterAnimMonitor ~= nil then
    emitterAnimMonitor:Stop()
    emitterAnimMonitor:Terminate()
    emitterAnimMonitor = nil
  end
  if sound_liftMovementState == "up" then
    LD.StopSound(ziplineLiftSoundTable.SoundEmitter, ziplineLiftSoundTable.MovingUpLoop)
    LD.PlaySound(ziplineLiftSoundTable.SoundEmitter, ziplineLiftSoundTable.MovingDownLoop, true)
  elseif sound_liftMovementState == "rest" then
    LD.PlaySound(ziplineLiftSoundTable.SoundEmitter, ziplineLiftSoundTable.MovingDownLoop, true)
  end
  emitterAnimMonitor = monitors.CreateAnimFrameMonitor(thisObjAnim)
  emitterAnimMonitor:OnFrameBackward(endFrame, function()
    LD.StopSound(ziplineLiftSoundTable.SoundEmitter, ziplineLiftSoundTable.MovingDownLoop)
    emitterAnimMonitor:Stop()
    emitterAnimMonitor:Terminate()
    emitterAnimMonitor = nil
    sound_liftMovementState = "rest"
  end)
  sound_liftMovementState = "down"
end
function PlaySoundOnReaction()
  if CurrentLevel == MinLevel and not flipperModule.LuaObjectScript.GetCCWRotationEnabled() and thisObjAnim.AnimFrame == Level1_TargetFrame then
    LD.PlaySound(ziplineLiftSoundTable.SoundEmitter, ziplineLiftSoundTable.OnStuck)
  elseif CurrentLevel == MaxLevel and not flipperModule.LuaObjectScript.GetCWRotationEnabled() and thisObjAnim.AnimFrame == Level3_TargetFrame then
    LD.PlaySound(ziplineLiftSoundTable.SoundEmitter, ziplineLiftSoundTable.OnStuck)
  end
end
function IsMoving()
  return isMoving
end
