-- ================================================================================
-- LOCAL FUNCTIONS
-- ================================================================================
local function setupCheckpoints(args)
	if not (activePlayer) then return end
		
	local numLaps = 1
	if #args >= 1 then
		numLaps = args[1]
	end

	-- Player is in race
	inRace = true
	
	-- Set the number of laps in the race and use it to calc the total number
	-- of checkpoints
	if (numLaps and _numLaps == 0) then
		_numLaps = numLaps
		numCheckpoints = numCheckpoints * _numLaps
	end
	
	-- Set up checkpoints (color as not hit)
	for _, checkpoint in ipairs(checkpointList) do
		local checkpointCollisionBody = checkpoint:FindFirstChild("Checkpoint")
		
		-- Set color of checkpoint
		checkpointCollisionBody.Color = NOT_HIT_COLOR
		
		-- Set color of checkpoint ring if one exists
		local ring = checkpoint:FindFirstChild("Ring")
		if ring then
			ring.Color = NOT_HIT_COLOR
		end
	end
	
	if not ArrowGuide then
		ArrowGuide = require(script:WaitForChild("ArrowGuide"))
	end
	arrow = ArrowGuide.new(checkpointList)
end -- setupCheckpoints()

local function checkpointHit(args)	
	if not (activePlayer and inRace) then return end
	
	local checkpointCollisionBody = false
	if #args >= 1 then
		checkpointCollisionBody = args[1]
	else
		return
	end
	
	local parent = checkpointCollisionBody.Parent
	
	-- Mark checkpoint as hit
	local hit = parent:FindFirstChild("Hit")
	if not (hit) then
		hit = Instance.new("BoolValue")
		hit.Name = "Hit"
		hit.Parent = parent
		hit.Value = true
	else
		-- Checkpoint already hit
		return
	end
	
	-- Set color of checkpoint
	checkpointCollisionBody.Color = HIT_COLOR
		
	-- Set color of checkpoint ring if one exists
	local ring = checkpointCollisionBody.Parent:FindFirstChild("Ring")
	if ring then
		ring.Color = HIT_COLOR
	end
	
	-- Create particle effect
	local particle = checkpointParticle:Clone()
	local character = player.Character or player.CharacterAdded:wait()
	particle.CFrame = character.PrimaryPart.CFrame
	particle.Parent = character.PrimaryPart

	--particle.CFrame = checkpointCollisionBody.CFrame
	--particle.Parent = checkpointCollisionBody

	local emitterChildren = particle:GetChildren()
	
	for _, child in pairs(emitterChildren) do 
		-- If the child is a particle, then cause it to emit
		if child:IsA("ParticleEmitter") then
			child:Emit(10) 
		end
	end

	-- Destroy particle after PARTICLE_DURATION seconds
	spawn(function() wait(PARTICLE_DURATION) particle:Destroy() end)
	
	-- Play checkpoint sound
	checkpointSound.Parent = checkpointCollisionBody
	checkpointSound:Play()
	
	-- Increment checkpoints hit count
	numCheckpointsHit = numCheckpointsHit + 1
	
	-- Display checkpoint count
	CheckpointCount.Text = tostring(numCheckpointsHit).."/"..tostring(numCheckpoints)
end -- checkpointHit()

local function newLap()
	if not (activePlayer and inRace) then return end
	
	-- Set up checkpoints (color as not hit)
	for _, checkpoint in ipairs(checkpointList) do
		local checkpointCollisionBody = checkpoint:FindFirstChild("Checkpoint")
		
		-- Delete hit BoolValue
		local hit = checkpoint:FindFirstChild("Hit")
		if hit then
			hit:Destroy()
		end
		
		-- Set color of checkpoint
		checkpointCollisionBody.Color = NOT_HIT_COLOR
		
		-- Set color of checkpoint ring if one exists
		local ring = checkpoint:FindFirstChild("Ring")
		if ring then
			ring.Color = NOT_HIT_COLOR
		end
	end
end -- newLap()

local function resetCheckpoints()
	inRace = false
	numCheckpointsHit = 0
	
		-- Set up checkpoints (color as not hit)
	for _, checkpoint in ipairs(checkpointList) do
		local checkpointCollisionBody = checkpoint:FindFirstChild("Checkpoint")
		
		-- Delete hit BoolValue
		local hit = checkpoint:FindFirstChild("Hit")
		if hit then
			hit:Destroy()
		end
		
		-- Set color of checkpoint
		checkpointCollisionBody.Color = HIT_COLOR
		
		-- Set color of checkpoint ring if one exists
		local ring = checkpoint:FindFirstChild("Ring")
		if ring then
			ring.Color = HIT_COLOR
		end
	end
	
	arrow:Destroy()
	
	-- Display checkpoint count
	CheckpointCount.Text = tostring(numCheckpointsHit).."/"..tostring(numCheckpoints)
end -- resetCheckpoints()

local function setActive(args)
	local active = false
	if #args >= 1 then
		active = args[1]
	else
		return
	end

	activePlayer = active
	
	-- No longer in current race if no longer active
	if (not active and inRace) then
		inRace = false
		resetCheckpoints()
	end

	if not active then
		-- Hide racing GUIs
		local PlayerGui = player.PlayerGui
		local TopBar = PlayerGui:FindFirstChild("TopBar")
		TopBar.Enabled = false
	end
end -- setActive()

local function raceFinished()
	RaceFinishedSound:Play()
end

local function checkpointEvent(args)
	for _, arg in pairs(args) do
		if arg[1] == "setup" then
			table.remove(arg, 1)
			setupCheckpoints(arg)
		elseif arg[1] == "checkpointHit" then
			table.remove(arg, 1)
			checkpointHit(arg)
		elseif arg[1] == "newLap" then
			newLap()
		elseif arg[1] == "reset" then
			resetCheckpoints()
		elseif arg[1] == "setActive" then
			table.remove(arg, 1)
			setActive(arg)
		elseif arg[1] == "raceFinished" then
			table.remove(arg, 1)
			raceFinished()
		end
	end
end -- checkpointEvent()