function create()
	return {
		["components"] = {}
	}
end

function add(compound, provider, offsetX, offsetY, offsetZ, materialMap)
	if provider.startX == nil then provider.startX = 0 end
	if provider.startY == nil then provider.startY = 0 end
	if provider.startZ == nil then provider.startZ = 0 end
	local component = {
		["provider"] = provider,
		["offsetX"] = offsetX,
		["offsetY"] = offsetY,
		["offsetZ"] = offsetZ,
		["materialMap"] = materialMap
	}
	table.insert(compound.components, component)
end

function getDimensions(compound)
	local maxX, maxY, maxZ = nil, nil, nil
	local minX, minY, minZ = nil, nil, nil
	local compIdx, comp
	for compIdx, comp in ipairs(compound.components) do
		local xLow = comp.offsetX + comp.provider.startX
		local yLow = comp.offsetY + comp.provider.startY
		local zLow = comp.offsetZ + comp.provider.startZ
		local xHigh = xLow + comp.provider.sizeX - 1
		local yHigh = yLow + comp.provider.sizeY - 1
		local zHigh = zLow + comp.provider.sizeZ - 1
		if minX == nil or xLow < minX then minX = xLow end
		if minY == nil or yLow < minY then minY = yLow end
		if minZ == nil or zLow < minZ then minZ = zLow end
		if maxX == nil or xHigh > maxX then maxX = xHigh end
		if maxY == nil or yHigh > maxY then maxY = yHigh end
		if maxZ == nil or zHigh > maxZ then maxZ = zHigh end
	end
	if maxX == nil then return nil, nil, nil end
	local sizeX = maxX - minX + 1
	local sizeY = maxY - minY + 1
	local sizeZ = maxZ - minZ + 1
	return sizeX, sizeY, sizeZ, minX, minY, minZ
end

function getNumMaterials(compound)
	local curNum = 1
	local compIdx, comp
	for compIdx, comp in ipairs(compound.components) do
		local maxMaterialNum
		if comp.materialMap == nil then
			maxMaterialNum = comp.provider.numMaterials
		else
			local i
			maxMaterialNum = 0
			for i = 1,comp.provider.numMaterials do
				local cMatNum = i
				if comp.materialMap[i] ~= nil then cMatNum = comp.materialMap[i] end
				if cMatNum > maxMaterialNum then maxMaterialNum = cMatNum end
			end
		end
		if maxMaterialNum > curNum then curNum = maxMaterialNum end
	end
	return curNum
end

function compoundGetBlockAt(compound, x, y, z, compoundStartX, compoundStartY, compoundStartZ)
	local compIdx, comp
	for compIdx, comp in ipairs(compound.components) do
		local compX = x - comp.offsetX
		local compY = y - comp.offsetY
		local compZ = z - comp.offsetZ
		if compX >= comp.provider.startX and compX < comp.provider.startX + comp.provider.sizeX
			and compY >= comp.provider.startY and compY < comp.provider.startY + comp.provider.sizeY
			and compZ >= comp.provider.startZ and compZ < comp.provider.startZ + comp.provider.sizeZ
		then
			local compMat = comp.provider.getBlockAt(compX, compY, compZ)
			if compMat ~= nil and compMat ~= 0 then
				if comp.materialMap ~= nil and comp.materialMap[compMat] ~= nil and comp.materialMap[compMap] ~= 0 then
					return comp.materialMap[compMat]
				else
					return compMat
				end
			end
		end
	end
	return nil
end

function prov(compound)
	local sizeX, sizeY, sizeZ, startX, startY, startZ = getDimensions(compound)
	local numMaterials = getNumMaterials(compound)
	local provGetBlockAt = function(x, y, z)
		return compoundGetBlockAt(compound, x, y, z, startX, startY, startZ)
	end
	return pcons.makeProvider(provGetBlockAt, sizeX, sizeY, sizeZ, numMaterials, startX, startY, startZ)
end


