local LD = require("design.LevelDesignLibrary")
local color = require("core.color")
local thisObj, startGearsActive, animationSpeed, zoomAngle, strafeAngle, maxZoomRadius, maxStrafeRadius, toolboxEmbedCallbacks, toolboxUnembedCallbacks, toolboxUnembedStartCallbacks, toolboxLockedOnCallbacks, toolboxOnHitCallbacks, animationOnEmbed, animationOnUnembed
local iceFrozen = {}
local iceEmbedFX = {rate = 1}
local iceUnembedFX = {rate = 1}
local enabled
local isGearStuck = false
local axeEmbedded = false
local embedCallbacks, unembedCallbacks, unembedStartCallbacks, onHitCallbacks, passThrough, assistTarget
function OnScriptLoaded(level, obj)
  thisObj = obj
  iceFrozen.embed = thisObj:FindSingleGOByName("IceFX_Embed")
  iceFrozen.unembed = thisObj:FindSingleGOByName("IceFX_Unembed")
  if iceFrozen.embed and iceFrozen.embed.IsRefNode then
    iceFrozen.embed = iceFrozen.embed.Child
  end
  if iceFrozen.unembed and iceFrozen.unembed.IsRefNode then
    iceFrozen.unembed = iceFrozen.unembed.Child
  end
  startGearsActive = obj:GetLuaTableAttribute("GearsActive")
  enabled = obj:GetLuaTableAttribute("TargetingEnabled")
  zoomAngle = obj:GetLuaTableAttribute("ZoomAngle")
  strafeAngle = obj:GetLuaTableAttribute("StrafeAngle")
  maxZoomRadius = obj:GetLuaTableAttribute("MaxZoomRadius")
  maxStrafeRadius = obj:GetLuaTableAttribute("MaxStrafeRadius")
  animationSpeed = obj:GetLuaTableAttribute("AnimSpeed")
  passThrough = obj:GetLuaTableAttribute("PassThrough")
  animationOnEmbed = obj:GetLuaTableAttribute("AnimationOnEmbed")
  animationOnUnembed = obj:GetLuaTableAttribute("AnimationOnUnembed")
  toolboxEmbedCallbacks = LD.ExtractCallbacksForEvent(level, obj, obj:FindLuaTableAttribute("OnWeaponEmbed"))
  toolboxUnembedCallbacks = LD.ExtractCallbacksForEvent(level, obj, obj:FindLuaTableAttribute("OnWeaponUnembed"))
  toolboxUnembedStartCallbacks = LD.ExtractCallbacksForEvent(level, obj, obj:FindLuaTableAttribute("OnWeaponUnembedStart"))
  toolboxLockedOnCallbacks = LD.ExtractCallbacksForEvent(level, obj, obj:FindLuaTableAttribute("OnWeaponLockedOn"))
  toolboxOnHitCallbacks = LD.ExtractCallbacksForEvent(level, obj, obj:FindLuaTableAttribute("OnWeaponHit"))
  SoundInit()
  game.SubObject.Sleep(obj)
end
function OnFirstPreStart(level, obj)
  if iceFrozen.embed then
    HideIceFX(iceFrozen.embed)
  end
  if iceFrozen.unembed then
    HideIceFX(iceFrozen.unembed)
  end
end
function OnFirstStart(level, obj)
  if startGearsActive then
    TriggerUnembedBehavior()
  else
    thisObj:PauseAnim()
  end
end
function OnStart(level, obj)
  if axeEmbedded and obj:IsAxeEmbedded() == false then
    OnWeaponUnembedStart(level, obj, nil, nil)
    OnWeaponUnembed(level, obj, nil, nil)
    HideIceFX(iceFrozen.embed, true)
    HideIceFX(iceFrozen.unembed, true)
    iceFrozen.unembed:ClearAllAnimCallbacks()
  end
  if enabled then
    Enable()
  else
    Disable()
  end
end
function OnWeaponEmbed(level, go, attacker, weapon)
  if weapon:GetName() == "axe00" then
    axeEmbedded = true
    if enabled then
      TriggerEmbedBehavior()
      LD.ExecuteCallbacksForEvent(level, thisObj, toolboxEmbedCallbacks, "WeaponEmbeddedEvents")
      FireEmbedCallbacks()
    end
    if iceFrozen.embed then
      iceFrozen.unembed:ClearAllAnimCallbacks()
      LD.ShowFX(iceFrozen.embed)
      HideIceFX(iceFrozen.unembed)
      PlayGearFreezeSound()
    end
  end
end
function OnWeaponUnembed(level, go, attacker, weapon)
  if weapon == nil or weapon:GetName() == "axe00" then
    axeEmbedded = false
    if enabled == true then
      LD.ExecuteCallbacksForEvent(level, thisObj, toolboxUnembedCallbacks, "WeaponUnembededEvents")
      FireUnembedCallbacks()
    end
  end
end
function OnWeaponUnembedStart(level, go, attacker, weapon)
  if weapon == nil or weapon:GetName() == "axe00" then
    if enabled == true then
      TriggerUnembedBehavior()
      FireUnembedStartCallbacks()
      LD.ExecuteCallbacksForEvent(level, thisObj, toolboxUnembedStartCallbacks, "WeaponUnembedStartEvents")
    end
    if iceFrozen.embed then
      HideIceFX(iceFrozen.embed)
      StopGearFreezeSound()
    end
    if iceFrozen.unembed then
      LD.ShowFX(iceFrozen.unembed)
      iceFrozen.unembed:OnAnimDone(thisObj, "OnIceUnembedDone")
    end
  end
end
function OnWeaponLockedOn(level, go, attacker, weapon)
  if weapon:GetName() == "axe00" and enabled then
    LD.ExecuteCallbacksForEvent(level, thisObj, toolboxLockedOnCallbacks, "WeaponLockedOnEvents")
  end
end
function OnHitByWeapon(level, obj, weapon, weaponOwnerCreature)
  if weapon:GetName() == "axe00" then
    OnHit(level, obj, weaponOwnerCreature, weapon)
  end
end
function OnHit(level, go, attacker, weapon)
  if weapon:GetName() == "axe00" and enabled then
    LD.ExecuteCallbacksForEvent(level, thisObj, toolboxOnHitCallbacks, "WeaponHitEvents")
    FireHitCallbacks()
  end
end
function OnSaveCheckpoint(level, obj)
  return {
    enabled = enabled,
    animationSpeed = animationSpeed,
    axeEmbedded = axeEmbedded
  }
end
function OnRestoreCheckpoint(level, obj, savedInfo)
  enabled = savedInfo.enabled
  animationSpeed = savedInfo.animationSpeed
  axeEmbedded = savedInfo.axeEmbedded
end
function Enable()
  enabled = true
  if assistTarget ~= nil then
    return
  end
  local passThroughJoint
  if passThrough == false then
    passThroughJoint = 0
  else
    passThroughJoint = 1
  end
  assistTarget = LD.AddAxeTarget(thisObj, "AxeJoint", zoomAngle, maxZoomRadius, strafeAngle, maxStrafeRadius, passThroughJoint)
end
function Disable()
  enabled = false
  if assistTarget == nil then
    return
  end
  local passThroughJoint
  if passThrough == false then
    passThroughJoint = 0
  else
    passThroughJoint = 1
  end
  LD.RemoveAxeTarget(thisObj, "AxeJoint", zoomAngle, maxZoomRadius, strafeAngle, maxStrafeRadius, passThroughJoint)
  assistTarget = nil
end
function IsEnabled()
  return enabled
end
function IsGearStuck()
  return isGearStuck
end
function IsEmbedAnim()
  return animationOnEmbed
end
function IsUnembedAnim()
  return animationOnUnembed
end
function IsAxePinned()
  return axeEmbedded and thisObj:IsAxeEmbedded()
end
function ShowGear()
  thisObj:FindSingleGOByName("GearGeo"):Show()
  thisObj:ShowCollision()
  thisObj:ShowAudio()
  if thisObj:IsAxeEmbedded() == false then
    if iceFrozen.embed then
      HideIceFX(iceFrozen.embed)
    end
    if iceFrozen.unembed then
      HideIceFX(iceFrozen.unembed)
    end
  end
end
function HideGear()
  thisObj:FindSingleGOByName("GearGeo"):Hide()
  thisObj:HideCollision()
  thisObj:HideAudio()
  if iceFrozen.embed then
    HideIceFX(iceFrozen.embed)
  end
  if iceFrozen.unembed then
    HideIceFX(iceFrozen.unembed)
  end
end
function SetIceEmbedFx(embedFX, playRate)
  iceFrozen.embed = embedFX
  if iceFrozen.embed and iceFrozen.embed.IsRefNode then
    iceFrozen.embed = iceFrozen.embed.Child
  end
  iceEmbedFX.rate = playRate or iceEmbedFX.rate
end
function SetIceUnembedFx(unembedFx, playRate)
  iceFrozen.unembed = unembedFx
  if iceFrozen.unembed and iceFrozen.unembed.IsRefNode then
    iceFrozen.unembed = iceFrozen.unembed.Child
  end
  iceUnembedFX.rate = playRate or iceUnembedFX.rate
end
function OnIceUnembedDone()
  HideIceFX(iceFrozen.unembed)
end
function HideIceFX(obj, immediate)
  LD.HideFX(obj, {immediate = immediate})
  obj:HideModel()
end
function SetGearStuck(value)
  isGearStuck = value
end
function SetAnimationSpeed(animName, speed)
  animationSpeed = speed or animationSpeed
  if enabled == false or animName == "PauseAnim" then
    thisObj:PauseAnim()
  elseif animName == "" then
    thisObj:PlayAnimToEnd(animationSpeed)
  elseif animName == "PlayAnimToBeginning" then
    thisObj:PlayAnimToEnd(-animationSpeed)
  elseif animName == "PlayAnimCycle" then
    thisObj:PlayAnimCycle(animationSpeed)
  elseif animName == "PlayAnimCycleReverse" then
    thisObj:PlayAnimCycle(-animationSpeed)
  elseif tonumber(animName) then
    thisObj:PlayAnimToFrame(tonumber(animName), animationSpeed)
  end
end
function TriggerUnembedBehavior()
  if enabled == false or isGearStuck == true or animationOnUnembed == "PauseAnim" then
    thisObj:PauseAnim()
  elseif animationOnUnembed == "PlayAnimToEnd" then
    thisObj:PlayAnimToEnd()
    thisObj:SetAnimRate(animationSpeed)
  elseif animationOnUnembed == "PlayAnimToBeginning" then
    thisObj:PlayAnimToEnd()
    thisObj:SetAnimRate(-animationSpeed)
  elseif animationOnUnembed == "PlayAnimCycle" then
    thisObj:PlayAnimCycle()
    thisObj:SetAnimRate(animationSpeed)
  elseif animationOnUnembed == "PlayAnimCycleReverse" then
    thisObj:PlayAnimCycle()
    thisObj:SetAnimRate(-animationSpeed)
  end
end
function TriggerEmbedBehavior()
  if enabled == false or isGearStuck == true or animationOnEmbed == "PauseAnim" then
    thisObj:PauseAnim()
  elseif animationOnEmbed == "PlayAnimToEnd" then
    thisObj:PlayAnimToEnd()
    thisObj:SetAnimRate(animationSpeed)
  elseif animationOnEmbed == "PlayAnimToBeginning" then
    thisObj:PlayAnimToEnd()
    thisObj:SetAnimRate(-animationSpeed)
  elseif animationOnEmbed == "PlayAnimCycle" then
    thisObj:PlayAnimCycle()
    thisObj:SetAnimRate(animationSpeed)
  elseif animationOnEmbed == "PlayAnimCycleReverse" then
    thisObj:PlayAnimCycle()
    thisObj:SetAnimRate(-animationSpeed)
  end
end
function RegisterEmbedCallback(fn)
  if embedCallbacks == nil then
    embedCallbacks = {}
  end
  table.insert(embedCallbacks, fn)
end
function FireEmbedCallbacks()
  if embedCallbacks ~= nil then
    for i = 1, #embedCallbacks do
      embedCallbacks[i]()
    end
  end
end
function RegisterUnembedCallback(fn)
  if unembedCallbacks == nil then
    unembedCallbacks = {}
  end
  table.insert(unembedCallbacks, fn)
end
function FireUnembedCallbacks()
  if unembedCallbacks ~= nil then
    for i = 1, #unembedCallbacks do
      unembedCallbacks[i]()
    end
  end
end
function RegisterUnembedStartCallback(fn)
  if unembedStartCallbacks == nil then
    unembedStartCallbacks = {}
  end
  table.insert(unembedStartCallbacks, fn)
end
function FireUnembedStartCallbacks()
  if unembedStartCallbacks ~= nil then
    for i = 1, #unembedStartCallbacks do
      unembedStartCallbacks[i]()
    end
  end
end
function RegisterHitCallback(fn)
  if onHitCallbacks == nil then
    onHitCallbacks = {}
  end
  table.insert(onHitCallbacks, fn)
end
function FireHitCallbacks()
  if onHitCallbacks ~= nil then
    for i = 1, #onHitCallbacks do
      onHitCallbacks[i]()
    end
  end
end
function BuildInterface(interfaceObject)
  local interfaceScript = interfaceObject.LuaObjectScript
  interfaceScript.Enable = Enable
  interfaceScript.Disable = Disable
  interfaceScript.IsGearStuck = IsGearStuck
  interfaceScript.SetAnimationSpeed = SetAnimationSpeed
  interfaceScript.RegisterEmbedCallback = RegisterEmbedCallback
  interfaceScript.RegisterUnembedCallback = RegisterUnembedCallback
  interfaceScript.FireEmbedCallbacks = FireEmbedCallbacks
  interfaceScript.FireUnembedCallbacks = FireUnembedCallbacks
end
function ShowDebugTable(x, y)
  local debugTable = {}
  debugTable.Title = "AnimatedAxeTarget Info"
  debugTable.X = x or 120
  debugTable.Y = y or 10
  debugTable.TitleColor = engine.Vector.New(255, 0, 128)
  debugTable[#debugTable + 1] = {
    "AnimFrame: ",
    thisObj.AnimFrame
  }
  if iceFrozen ~= nil then
    debugTable[#debugTable + 1] = {
      "AnimFrame: ",
      iceFrozen
    }
    debugTable[#debugTable + 1] = {
      "AnimFrame: ",
      iceFrozen.AnimFrame
    }
    if iceFrozen.embed then
      debugTable[#debugTable + 1] = {
        "Ice-Embed Frame: ",
        iceFrozen.embed.AnimFrame
      }
    end
    if iceFrozen.unembed then
      debugTable[#debugTable + 1] = {
        "Ice-Unembed Frame: ",
        iceFrozen.unembed.AnimFrame
      }
    end
  end
  engine.DrawDebugTable(debugTable)
end
function ShowDebugText()
  local debugText = thisObj.Parent:GetName() .. "\n"
  debugText = debugText .. " AnimFrame " .. thisObj.AnimFrame
  if iceFrozen.embed then
    debugText = debugText .. " Ice-Embed Frame " .. tostring(iceFrozen.embed.AnimFrame)
  end
  if iceFrozen.unembed then
    debugText = debugText .. " Ice-Unembed Frame " .. tostring(iceFrozen.unembed.AnimFrame)
  end
  engine.DrawTextInWorld(thisObj:GetWorldPosition(), debugText, color.green)
end
local soundEmitter
function SoundInit()
  soundEmitter = thisObj:FindSingleSoundEmitterByName("SNDWallGears")
end
function PlayGearFreezeSound()
  LD.PlaySound(soundEmitter, "SND_WPN_Axe_Hit_Freeze_Object_LP")
end
function StopGearFreezeSound()
  LD.StopSound(soundEmitter, "SND_WPN_Axe_Hit_Freeze_Object_LP")
end
