local script = script.Parent.Pieces.PieceScript

if not script.Parent:FindFirstChild("Roots") then game.ServerStorage.Roots.Parent = script.Parent end
local roots = {}
for _,root in pairs(script.Parent.Roots:GetChildren()) do
	if root.Name == "Root" then
		root.Anchored = true
		root.Transparency = 1
		root.CanCollide = false
		table.insert(roots,root)
	end
end
-- piece: {"X,Y,Z,NX,NY,NZ,A,B...} marking each property it has
local pieces = {}
for _,piece in pairs(script.Parent:GetChildren()) do
	if piece:IsA("Model") then
		-- Set of 'characteristics' this has, equivalent to (unary?) branches in lhmes14c
		local characteristics = {}

		local position = piece:GetPivot().Position
		local closest_root
		local closest = 32
		for _,root in pairs(roots) do
			local distance = (root.Position - position).Magnitude 
			if distance < closest then 
				closest = distance
				closest_root = root
			end
		end

		if closest_root then
			closest_root.Parent = piece
			piece.PrimaryPart = closest_root
		end

		-- Make sure there is a PrimaryPart
		if not piece.PrimaryPart then 
			piece.PrimaryPart = piece:FindFirstChildWhichIsA("BasePart")
		end
		if not piece.PrimaryPart then
			warn(string.format("Piece: '%s' has no viable PrimaryPart (empty), please provide one.",piece.Name)) 
			continue 
		end

		-- Weld all Parts together
		piece.PrimaryPart.Anchored = true
		local template_weld = Instance.new("WeldConstraint")
		template_weld.Part0 = piece.PrimaryPart
		for _,item in pairs(piece:GetChildren()) do
			if item:IsA("BasePart") and item ~= piece.PrimaryPart then
				local weld = template_weld:Clone()
				weld.Parent = piece
				weld.Part1 = item
			end
		end

		-- Populate characteristics
		for literal in string.gmatch(piece.Name,"[^%.]+") do
			local value,class = string.match(literal,"^(!?)(.*)")
			characteristics[class] = #value == 0
		end

		piece.Parent = game.ServerStorage
		--piece:ScaleTo()
		table.insert(pieces,{characteristics = characteristics,piece = piece})
	end
end
-- Compute whether variants are viable and actually copy/rotate them as options
local rotator = {
	["X"] = "Z",
	["Z"] = "NX",
	["NX"] = "NZ",
	["NZ"] = "X"
}
local function alreadyExists(match)
	for _,piece in pairs(pieces) do
		local success = true
		for class,value in pairs(match) do
			if piece.characteristics[class] ~= value then success = false break end 
		end
		if success then return true end
	end
end
local function rotateClass(class)
	return rotator[class] or class
end
local new_pieces = {}
for _,piece in pairs(pieces) do -- This isn't very optimised, but it runs at the start of the program, this is ok.
	local r90 = {}
	local r180 = {}
	local r270 = {}
	for class,value in pairs(piece.characteristics) do
		local c90 = rotateClass(class)
		local c180 = rotateClass(c90)
		local c270 = rotateClass(c180)
		r90[c90] = value
		r180[c180] = value
		r270[c270] = value
	end
	local function pieceFactory(angle,characteristics)
		if not alreadyExists(characteristics) then 
			local new_piece = piece.piece:Clone()
			new_piece.Name = "V."..new_piece.Name
			new_piece:PivotTo(new_piece:GetPivot() * CFrame.Angles(0,math.rad(angle),0))
			table.insert(new_pieces,{piece = new_piece,characteristics = characteristics})
		end
	end
	pieceFactory(270,r90)
	pieceFactory(180,r180)
	pieceFactory(90,r270)
end
for _,piece in pairs(pieces) do table.insert(new_pieces,piece) end
pieces = new_pieces

--[[local city = function(x,y,z)
	return (math.noise(x*0.16,y*0.16,z*0.16) - (y * 0.05) + 0.2) > 0
end]]

local scale = 4
local template_part = Instance.new("Part")
template_part.Anchored = true
template_part.Name = "PieceTemplate"
template_part.CanCollide = false
template_part.Transparency = 0.5
template_part.Size = Vector3.one * scale

local function block(x,y,z,f,city)
	local X = city(x+f,y,z)
	local Y = city(x,y+f,z)
	local Z = city(x,y,z+f)
	local NX = city(x-f,y,z)
	local NY = city(x,y-f,z)
	local NZ = city(x,y,z-f)
	local match = { -- The matching characteristics table for the hypothetical piece in this place
		X = X,
		Y = Y,
		Z = Z,
		NX = NX,
		NY = NY,
		NZ = NZ
	}
	if X and Y and Z and NX and NY and NZ then return false end
	local greatest_rank = 0 -- The amount of matching characteristics for the best matching piece
	local greatest = template_part -- The physical piece
	for _,piece in pairs(pieces) do -- Look through every known piece
		local rank = 0
		for class,value in pairs(match) do -- Assimilate a rank of the characteristics it shares with this hypothetical one
			local this = piece.characteristics[class] 
			if value == this then rank = rank + 1 elseif this ~= nil then rank = rank - 1 end -- If it's greatest, make it so
		end
		if rank > greatest_rank or (rank == greatest_rank and (math.random(1,10) > 3)) then
			greatest = piece.piece
			greatest_rank = rank
		end
	end
	greatest = greatest:Clone()
	greatest.Parent = game.Workspace -- Position it
	greatest:PivotTo(greatest:GetPivot().Rotation + Vector3.new(x,y,z))
	return true
end

--[[local function gen()
	for x = 1,20 do
		for y = 1,15 do
			for z = 1,20 do
				if city(x,y,z) then

				end
			end
		end
	end
end]]

return {block=block}
