-- Existance in this list signifies that it is an emote, the value indicates if it is a looping emote
local emoteNames = { wave = false, point = false, dance = true, dance2 = true, dance3 = true, laugh = false, cheer = false}

math.randomseed(tick())

function findExistingAnimationInSet(set, anim)
	if set == nil or anim == nil then
		return 0
	end

	for idx = 1, set.count, 1 do
		if set[idx].anim.AnimationId == anim.AnimationId then
			return idx
		end
	end

	return 0
end

local function destroyWalkAnimations()
	for _,v in pairs(strafingLocomotionMap) do
		if v.track then
			v.track:Stop()
			v.track:Destroy()
			v.track = nil
		end
	end
	for _,v in pairs(fallbackLocomotionMap) do
		if v.track then
			v.track:Stop()
			v.track:Destroy()
			v.track = nil
		end
	end
	cachedRunningSpeed = 0
end


local maxVeloX, minVeloX, maxVeloY, minVeloY

local function resetVelocityBounds(velo)
	minVeloX = 0
	maxVeloX = 0
	minVeloY = 0
	maxVeloY = 0
end

local function updateVelocityBounds(velo)
	if velo then
		if velo.x > maxVeloX then maxVeloX = velo.x end
		if velo.y > maxVeloY then maxVeloY = velo.y end
		if velo.x < minVeloX then minVeloX = velo.x end
		if velo.y < minVeloY then minVeloY = velo.y end
	end
end

local function checkStrafingEnabled(velo)
	if maxVeloX == 0 or minVeloX == 0 or maxVeloY == 0 or minVeloY == 0  then
		if locomotionMap == strafingLocomotionMap then
			warn("Strafe blending disabled.  Not all quadrants of motion represented.")
		end
		locomotionMap = fallbackLocomotionMap
	elseif not strafingLocomotionMap["run"] or not strafingLocomotionMap["walk"] then
		if locomotionMap == strafingLocomotionMap then
			warn("Strafe blending disabled.  Run and walk must be strafing-friendly.")
		end
		locomotionMap = fallbackLocomotionMap
	else
		if locomotionMap ~= strafingLocomotionMap then
			locomotionMap = strafingLocomotionMap
			warn("Strafing reenabled")
		end
	end
end

local function setupWalkAnimations()
	resetVelocityBounds()
	-- check to see if we need to blend a walk/run animation
	for n,v in pairs(strafingLocomotionMap) do
		updateVelocityBounds(v.lv)
	end
	checkStrafingEnabled()
	for n,v in pairs(locomotionMap) do
		v.track = Humanoid:LoadAnimation(animTable[n][1].anim)
		v.track.Priority = Enum.AnimationPriority.Core
	end
end

local function replaceLocomotionTrack(name, lv)
	local restartWalks = false
	if currentAnim == "walk" and locomotionMap[name] then
		-- Need to tear down and startup locomotion
		destroyWalkAnimations()
		restartWalks = true
	end

	if lv then
		strafingLocomotionMap[name] = {lv=lv, speed = lv.Magnitude}
	else
		strafingLocomotionMap[name] = nil
	end
	if  name == "run"  or name == "walk" then
		if lv then
			fallbackLocomotionMap[name] = strafingLocomotionMap[name]
		else
			local speed = name == "run" and RUN_SPEED or WALK_SPEED
			fallbackLocomotionMap[name] = {lv=Vector2.new(0.0, speed), speed = speed}
			strafingLocomotionMap[name] = nil
		end
	end
	if restartWalks then
		setupWalkAnimations()
		lastBlendTime = 0
	end
end

function configureAnimationSet(name, fileList)
	if (animTable[name] ~= nil) then
		for _, connection in pairs(animTable[name].connections) do
			connection:disconnect()
		end
	end
	animTable[name] = {}
	animTable[name].count = 0
	animTable[name].totalWeight = 0
	animTable[name].connections = {}

	-- check for config values
	local config = script:FindFirstChild(name)
	if (config ~= nil) then
		table.insert(animTable[name].connections, config.ChildAdded:connect(function(child) configureAnimationSet(name, fileList) end))
		table.insert(animTable[name].connections, config.ChildRemoved:connect(function(child) configureAnimationSet(name, fileList) end))

		local idx = 0

		for _, childPart in pairs(config:GetChildren()) do
			if (childPart:IsA("Animation")) then
				local newWeight = 1
				local weightObject = childPart:FindFirstChild("Weight")
				if (weightObject ~= nil) then
					newWeight = weightObject.Value
				end
				animTable[name].count = animTable[name].count + 1
				idx = animTable[name].count
				animTable[name][idx] = {}
				animTable[name][idx].anim = childPart
				animTable[name][idx].weight = newWeight
				animTable[name].totalWeight = animTable[name].totalWeight + animTable[name][idx].weight
				table.insert(animTable[name].connections, childPart.Changed:connect(function(property) configureAnimationSet(name, fileList) end))
				table.insert(animTable[name].connections, childPart.ChildAdded:connect(function(property) configureAnimationSet(name, fileList) end))
				table.insert(animTable[name].connections, childPart.ChildRemoved:connect(function(property) configureAnimationSet(name, fileList) end))
				local lv = childPart:GetAttribute("LinearVelocity")
				replaceLocomotionTrack(name, lv)

			end
		end
	end

	-- fallback to defaults
	if (animTable[name].count <= 0) then
		for idx, anim in pairs(fileList) do
			animTable[name][idx] = {}
			animTable[name][idx].anim = Instance.new("Animation")
			animTable[name][idx].anim.Name = name
			animTable[name][idx].anim.AnimationId = anim.id
			animTable[name][idx].weight = anim.weight
			animTable[name].count = animTable[name].count + 1
			animTable[name].totalWeight = animTable[name].totalWeight + anim.weight
		end
	end

	-- preload anims
	for i, animType in pairs(animTable) do
		for idx = 1, animType.count, 1 do
			if PreloadedAnims[animType[idx].anim.AnimationId] == nil then
				Humanoid:LoadAnimation(animType[idx].anim)
				PreloadedAnims[animType[idx].anim.AnimationId] = true
			end
		end
	end
end