local rotation, translation, myCrt
local rotationDriverName = "WarpRotation"
local translationDriverName = "WarpTranslation"
local DL = require("design.DesignerLibrary")
local CreateDrivers = function(crt)
  myCrt = crt
  if not rotation or not translation then
    rotation = crt:GetAnimDriver(rotationDriverName)
    translation = crt:GetAnimDriver(translationDriverName)
  end
end
local SetDrivers = function(values)
  if not myCrt then
    return values
  end
  local rotationAnimDriver = myCrt:GetAnimDriver(rotationDriverName)
  local translationAnimDriver = myCrt:GetAnimDriver(translationDriverName)
  if rotationAnimDriver == nil or translationAnimDriver == nil then
    return nil
  end
  if values.Rotation then
    rotationAnimDriver.ValueVec = values.Rotation
  end
  if values.Translation then
    translationAnimDriver.ValueVec = values.Translation
  end
  return values
end
local SetWarp = function(r, t)
  SetDrivers({Rotation = r, Translation = t})
end
local DisableWarp = function(crt)
  SetDrivers({
    Rotation = crt:GetWorldForward(),
    Translation = crt:GetWorldPosition()
  })
end
local LuaHook_SyncWarp = function(crt)
  local info = crt:GetSyncInfo()
  local values = {
    Rotation = info.Forward,
    Translation = info.Position
  }
  return SetDrivers(values)
end
local LuaHook_TraverseLinkWarp = function(crt)
  local traverseLink = crt:GetTraverseLink()
  local values = {
    Rotation = traverseLink.WarpDirection,
    Translation = traverseLink.WarpLocation
  }
  return SetDrivers(values)
end
local LuaHook_PathWarp = function(crt)
  local info = crt:GetLocomotionInfo()
  local values = {
    Rotation = info.PathDirection,
    Translation = info.Destination
  }
  return SetDrivers(values)
end
local LuaHook_ApproachPOIWarp = function(crt)
  local info = crt:GetLocomotionInfo()
  local values = {
    Rotation = info.PathDirection,
    Translation = info.Destination
  }
  if crt.OwnedPOI ~= nil then
    values.Rotation = (crt.OwnedPOI:GetWorldPosition() - crt:GetWorldPosition()):Normalized()
  end
  return SetDrivers(values)
end
local LuaHook_ApproachEnvironmentEventWarp = function(crt)
  local info = crt:GetLocomotionInfo()
  local values = {
    Rotation = info.PathDirection,
    Translation = info.Destination
  }
  if _G._EnvironmentEventWarpTarget ~= nil then
    values.Rotation = (_G._EnvironmentEventWarpTarget - crt:GetWorldPosition()):Normalized()
  end
  return SetDrivers(values)
end
local LuaHook_FocusWarp = function(crt)
  local info = crt:GetLocomotionInfo()
  local values = {
    Rotation = info.FocusDirection,
    Translation = info.PathDestination
  }
  return SetDrivers(values)
end
local LuaHook_TargetWarp = function(crt)
  local target = crt:GetTargetCreature()
  local rot = engine.Vector.New(1, 0, 0)
  local targetPosition = crt.WorldPosition
  if crt.OwnedPOI ~= nil then
    rot = DL.ReturnFacing(crt.OwnedPOI)
    targetPosition = DL.ReturnPosition(crt.OwnedPOI)
  elseif target ~= nil then
    rot = (target:GetWorldPosition() - crt:GetWorldPosition()):Normalized()
    targetPosition = target:GetWorldPosition()
  end
  if not target and not crt.OwnedPOI then
    DisableWarp(crt)
    return
  end
  local values = {Rotation = rot, Translation = targetPosition}
  return SetDrivers(values)
end
local LuaHook_PredictiveTargetWarp = function(crt)
  local target = crt:GetTargetCreature()
  if not target or crt.OwnedPOI ~= nil then
    return LuaHook_FocusWarp(crt)
  end
  local locInfo = crt:GetAI():GetLocomotionInfo()
  local locPathDir = locInfo.PathDirection or engine.Vector.New(0, 0, 0)
  local locTargetSpeed = locInfo.TargetSpeed or 0
  local crtPosition = crt:GetWorldPosition() + locPathDir * locTargetSpeed
  local targetPosition = target:GetWorldPosition()
  local values = {
    Rotation = (targetPosition - crtPosition):Normalized(),
    Translation = targetPosition
  }
  return SetDrivers(values)
end
local LuaHook_PlayerWarp = function(crt)
  local player = game.Player.FindPlayer()
  if not player then
    DisableWarp(crt)
    return
  end
  local crtPosition = crt:GetWorldPosition()
  local playerPosition = player:GetWorldPosition()
  local values = {
    Rotation = (playerPosition - crtPosition):Normalized(),
    Translation = playerPosition
  }
  return SetDrivers(values)
end
local Install = function()
  _G.LuaHook_SyncWarp = LuaHook_SyncWarp
  _G.LuaHook_TraverseLinkWarp = LuaHook_TraverseLinkWarp
  _G.LuaHook_PathWarp = LuaHook_PathWarp
  _G.LuaHook_ApproachPOIWarp = LuaHook_ApproachPOIWarp
  _G.LuaHook_ApproachEnvironmentEventWarp = LuaHook_ApproachEnvironmentEventWarp
  _G.LuaHook_FocusWarp = LuaHook_FocusWarp
  _G.LuaHook_TargetWarp = LuaHook_TargetWarp
  _G.LuaHook_PlayerWarp = LuaHook_PlayerWarp
  _G.LuaHook_PredictiveTargetWarp = LuaHook_PredictiveTargetWarp
end
return {
  Install = Install,
  CreateDrivers = CreateDrivers,
  SetWarp = SetWarp,
  DisableWarp = DisableWarp
}
