local bxor = bit32.bxor
local angles = CFrame.Angles
local rad = math.rad
local handlers = {}
local function get(folder,...)
	local items = {}
	for _,item in pairs({...}) do
		table.insert(items,folder:WaitForChild(item))
	end
	return table.unpack(items)
end
local function update(folder,tab,match)
	for _,item in pairs(folder:GetChildren()) do
		if string.match(item.Name,match) then table.insert(tab,item) end
	end
	folder.ChildAdded:Connect(function(item)
		if string.match(item.Name,match) then table.insert(tab,item) end
	end)
end
local function single_handler_factory(folder)
	local item = folder:FindFirstChild("Block")
	table.insert(handlers,function(x,y,z,f,city,val)
		local item = item:Clone()
		item.Position = Vector3.new(x,y,z)
		item.Parent = game.Workspace
	end)
end
local function generic_handler_factory(folder)
	local roof,support = get(folder,"Surface","Support")
	local plain = get(folder,"WallPlain")
	local walls = {}
	update(folder,walls,"Wall")
	table.insert(handlers,function(x,y,z,f,city,val)
		local by = city(x,y+f,z)
		local bny = city(x,y-f,z)
		if not by then
			local item = roof:Clone()
			item.Position = Vector3.new(x,y+16.5,z)
			item.Parent = game.Workspace
		end
		if not bny then
			local item = support:Clone()
			item:PivotTo(CFrame.new(x,y-2,z))
			item.Parent = game.Workspace
			local function wall(mod)
				local item = plain:Clone()
				item:PivotTo(CFrame.new(x,y,z) * mod)
				item.Parent = game.Workspace
			end
			if city(x+f,y,z) and city(x+f,y-f,z) then wall(angles(0,rad(-90),0)) end
			if city(x-f,y,z) and city(x-f,y-f,z) then wall(angles(0,rad(90),0)) end
			if city(x,y,z+f) and city(x,y-f,z+f) then wall(angles(0,rad(180),0)) end
			if city(x,y,z-f) and city(x,y-f,z-f) then wall(angles(0,rad(0),0)) end
		else
			local bz = city(x,y,z+f)
			local bnz = city(x,y,z-f)
			local bx = city(x+f,y,z)
			local bnx = city(x-f,y,z)
			local function wall(mod)
				local item = walls[bxor(y*z%3,y*x%5) % #walls + 1]:Clone()
				item:PivotTo(CFrame.new(x,y,z) * mod)
				item.Parent = game.Workspace
			end
			if not bx then wall(angles(0,rad(-90),0)) end
			if not bnx then wall(angles(0,rad(90),0)) end
			if not bz then wall(angles(0,rad(180),0)) end
			if not bnz then wall(angles(0,rad(0),0)) end
		end
	end)
end
local function fancy_handler_factory(folder)
	local roof,support = get(folder,"Surface","Support")
	local plain = get(folder,"WallPlain")
	local fancy_support = get(folder,"FancyPlain")
	local walls = {}
	local fancy = {}
	update(folder,walls,"Wall")
	update(folder,fancy,"Fancy")
	table.insert(handlers,function(x,y,z,f,city,val)
		local by = city(x,y+f,z)
		local bny = city(x,y-f,z)
		if not by then
			local item = roof:Clone()
			item.Position = Vector3.new(x,y+16.5,z)
			item.Parent = game.Workspace
		end
		local bz = city(x,y,z+f)
		local bnz = city(x,y,z-f)
		local bx = city(x+f,y,z)
		local bnx = city(x-f,y,z)
		if not bny then
			local item = support:Clone()
			item:PivotTo(CFrame.new(x,y-2,z))
			item.Parent = game.Workspace
			local function wall(mod)
				local item = plain:Clone()
				item:PivotTo(CFrame.new(x,y,z) * mod)
				item.Parent = game.Workspace
			end
			if bx and city(x+f,y-f,z) then wall(angles(0,rad(-90),0)) end
			if bnx and city(x-f,y-f,z) then wall(angles(0,rad(90),0)) end
			if bz and city(x,y-f,z+f) then wall(angles(0,rad(180),0)) end
			if bnz and city(x,y-f,z-f) then wall(angles(0,rad(0),0)) end
		else
			local function wall(mod)
				local item = walls[bxor(y*z%3,y*x%5) % #walls + 1]:Clone()
				item:PivotTo(CFrame.new(x,y,z) * mod)
				item.Parent = game.Workspace
			end
			if not bx then wall(angles(0,rad(-90),0)) end
			if not bnx then wall(angles(0,rad(90),0)) end
			if not bz then wall(angles(0,rad(180),0)) end
			if not bnz then wall(angles(0,rad(0),0)) end
			
			if bx ~= bnx and bz ~= bnz then
				local mod
				if bx then
					if bz then
						mod = angles(0,rad(0),0)
					else
						mod = angles(0,rad(90),0)
					end
				else
					if bz then
						mod = angles(0,rad(-90),0)
					else
						mod = angles(0,rad(180),0)
					end
				end
				local fancy = fancy[bxor(y*z%3,y*x%5) % #fancy + 1]:Clone()
				fancy:PivotTo(CFrame.new(x,y,z) * mod)
				fancy.Parent = game.Workspace
			end
		end
	end)
end
generic_handler_factory(game.Workspace.Piece.Posh)
generic_handler_factory(game.Workspace.Piece.Poor)
generic_handler_factory(game.Workspace.Piece.Plain)
fancy_handler_factory(game.Workspace.Piece.Castle)
generic_handler_factory(game.Workspace.Piece.Stone)
local opts = #handlers
local function block(x,y,z,f,city,cx,cy,cz)
	local val = bxor(cx*cz,cy+cz)
	handlers[val % #handlers + 1](x,y,z,f,city,val)
end

return {block=block}
