-- This module can be required and used by other scripts to get information about where the mouse is in the 3D world
local module = {}

module.tags = _G.Tags
-- table of parts in game by index, each index is the object's id, each object has an ID tag associated to it
--[[module.objects = {} -- this should only be regarded for the server

function module.getId(object) -- CLIENT/SERVER
	for _,tag in pairs(module.tags:GetTags(object)) do -- remove object from the objects table by its ID
		if string.sub(tag,1,3) == "ID_" then
			local id = tonumber(string.sub(tag,4,#tag))
			return id
		end
	end
	return false
end

function module.removeId(object) -- SERVER ONLY
	module.objects[module.getId(object)] = nil
end

function module.newId(object) -- SERVER ONLY
	local currentIdIndex = 1
	for i=1,#module.objects do
		if not module.objects[i] then
			module.objects[i] = object
			return i
		end
	end
	module.objects[#module.objects+1] = object
	return #module.objects+1
end]]

local function getConnectedParts(part)
	local connected = part:GetConnectedParts(false)
	for _,joint in pairs(part:GetJoints()) do
		if joint:IsA("Constraint") then
			if joint.Attachment0 and joint.Attachment1 then 
				if joint.Attachment0.Parent == part then 
					table.insert(connected,joint.Attachment1.Parent)	
				else
					table.insert(connected,joint.Attachment0.Parent)	
				end
			end
		end
	end
	return connected
end

function module.forEachConnectedObject(start,callback,show,parent,ignore)
	if not start then return end
	if start:IsA("Model") then start = start.PrimaryPart end
	
	if not parent then parent = game.Workspace.Objects end
	
	local parts = {}
	local objects = {}
	
	local function checkPart(part)
		local object
		if part.Parent:IsA("Model") and part.Parent.Parent == parent then
			object = part.Parent
		elseif part.Parent == parent then
			object = part
		end
		if not object or objects[object] then return end
		objects[object] = object
		callback(object)
	end
	
	local function tryConnected(part)
		if parts[part] then return else parts[part] = part checkPart(part) end
		local connected = getConnectedParts(part)
		for _,part in pairs(connected) do
			tryConnected(part)
		end
	end
	
	tryConnected(start)
	
	return objects
end

--[[function module.forEachConnectedObjectOld2(start,callback,show,parent,ignore)
	if not start then return end
	if start:IsA("Model") then start = start.PrimaryPart end
	
	if not parent then parent = game.Workspace.Objects end
	local checkedTag = "checked"..tostring(tick())
	
	local objects = {}

	local function checkPart(part)
		local object
		if part.Parent:IsA("Model") and part.Parent.Parent == parent then
			object = part.Parent
		elseif part.Parent == parent then
			object = part
		end
		if object and not object:HasTag(checkedTag) then
			object:AddTag(checkedTag)
			table.insert(objects,object) 
		end
		return object
	end
	
	local function getConnected(part)
		if not part:HasTag(checkedTag) then 
			checkPart(part)
			part:AddTag(checkedTag)
			for _,part in pairs(getConnectedParts(part)) do
				if part.Name ~= "Separator" or not ignore then getConnected(part) end
			end
		end 
	end
	
	for _,part in pairs(start:GetConnectedParts(false)) do
		getConnected(part)
	end
	
	for _,object in pairs(objects) do
		callback(object)
	end
	
	for _,part in pairs(module.tags:GetTagged(checkedTag)) do
		module.tags:RemoveTag(part,checkedTag)
	end
end

function module.forEachConnectedObjectOld(start,callback,debugShow,parent)
	local tagId = "checked"..tostring(tick())
	if start:IsA("Model") then start = start.PrimaryPart end
	local parts = start:GetConnectedParts(true)
	module.tags:AddTag(start,tagId)
	module.tags:AddTag(start.Parent,tagId)
	local function checkPart(part,depth)
		local count = 0
		if not module.tags:HasTag(part,tagId) then
			if depth < 2 then
				for _,joint in pairs(part:GetJoints()) do
					if joint:IsA("Constraint") then
						if joint.Attachment1 and not module.tags:HasTag(joint.Attachment1.Parent,tagId) then
							for _,part in pairs(joint.Attachment1.Parent:GetConnectedParts(true)) do
								checkPart(part,depth+1)
							end
						end
						if joint.Attachment0 and not module.tags:HasTag(joint.Attachment0.Parent,tagId) then
							for _,part in pairs(joint.Attachment0.Parent:GetConnectedParts(true)) do
								checkPart(part,depth+1)
							end
						end
					end
				end
			end
			local newObject -- Note, we are walking over the newObject function. this is ok, we're not gonna use it. a neat feature of lua's scope
			if part.Parent == game.Workspace.Objects then -- we found a part! lets add it
				newObject = part
			elseif part.Parent:IsA("Model") and part.Parent.Parent == game.Workspace.Objects then -- we found a model instead from this part (its a child of the model)
				newObject = part.Parent
			end
			print(part,depth)
			if newObject and not module.tags:HasTag(newObject,tagId) then
				module.tags:AddTag(newObject,tagId)
				callback(newObject)
				if debugShow then
					local previousTransparency = part.Transparency -- fancy bits here show for debug
					part.LocalTransparencyModifier = 0.9 - (depth * 0.2)
					if count == 6 then count = 0 wait() else count = count + 1 end
					task.delay(0.25,function() part.LocalTransparencyModifier = previousTransparency end) -- fancy bits here show for debug
				end
			end
		end
	end
	for key,part in pairs(parts) do
		checkPart(part,0)
	end
	for _,part in pairs(module.tags:GetTagged(tagId)) do
		module.tags:RemoveTag(part,tagId)
	end
end]]

return module
