--[[

	The OpenAreaChecker finds an open area around a given position.
	It checks in a grid around the supplied position.
	For any positive matches (open areas) it will perform a downward scan to ensure the open area isn't a gap.
	
--]]



local scanGrid = {
	Vector3.new(1,0,0),
	Vector3.new(.707,0,.707),
	Vector3.new(0,0,1),
	Vector3.new(-.707,0,.707),
	Vector3.new(-1,0,0),
	Vector3.new(-.707,0,-.707),
	Vector3.new(0,0,-1),
	Vector3.new(.707,0,-.707),
}

local scanRadius = 4
local scanHeight = 12
local scanDepth = 20
local scanMaxDiff = 5

local function findPosition(owner, previousPosition, ignoreInstance)
	
	assert(typeof(owner) == "Instance" and owner:IsA("Player"), "Must feed a Player to find position at")
	assert(previousPosition == nil or typeof(previousPosition) == "Vector3", "Must feed the previous position to find closest match to")
	assert(ignoreInstance == nil or typeof(ignoreInstance) == "Instance", "Must feed an Instance as ignore instance if given")
	
	if not owner.Character then return end
	local root = owner.Character:FindFirstChild("HumanoidRootPart")
	local hum = owner.Character:FindFirstChildOfClass("Humanoid")
	if not (root and hum) then return end
	
	local origin = root.Position - Vector3.new(0, hum.HipHeight, 0)
	
	local finalGrid = {}
	for i = 1, #scanGrid do
		table.insert(finalGrid, origin + scanGrid[i]*scanRadius)
	end
	if previousPosition then
		local offset = Vector3.new(previousPosition.X, origin.Y, previousPosition.Z)
		table.sort(finalGrid, function(a,b) return (a - offset).Magnitude < (b - offset).magnitude end)
	end
	
	for i = 1, #finalGrid do
		
		local blocked = workspace:FindPartOnRayWithIgnoreList(Ray.new(origin, finalGrid[i] - origin), {owner.Character, ignoreInstance})
		
		if not blocked then
			
			local ray = Ray.new(
				finalGrid[i] + Vector3.new(0, scanHeight, 0),
				Vector3.new(0, -scanDepth, 0)
			)
			
			local part, position, normal, material = workspace:FindPartOnRay(ray, ignoreInstance)
			
			if part and math.abs(position.Y - origin.Y) <= scanMaxDiff then
				return position
			end
			
		end
		
	end
	
end

return findPosition
