local makeSane = function(availableItems) -- output from meController.getAvailableItems()
	if type(availableItems) ~= "table" then error("Expected table, got "..type(availableItems)) end
	
	local sanified = {}
	for _, stack in pairs(availableItems) do
		local rawName = stack.rawName
		if stack.beeInfo then rawName = stack.beeInfo.ident end
		
		if sanified[rawName] then
			sanified[rawName].qty = sanified[rawName].qty + stack.qty
		else
			sanified[rawName] = {}
			sanified[rawName].qty = stack.qty
			
			if stack.beeInfo then
   	sanified[rawName].name = stack.beeInfo.displayName
			else
				sanified[rawName].name = stack.name
			end
		end
	end
	
	return sanified
end

clearAll = function(outputs) -- table of wrapped monitors or term
	if type(outputs) ~= "table" then error("Expected table, got "..type(outputs)) end
	
	for _, output in pairs(outputs) do
		output.clear()
		output.setCursorPos(1, 1)
	end
end

writeToAll = function(outputs, linesToWrite) -- table of wrapped monitors or term, table of lines with one line being { backgroundColor, textColor, text }
	if type(linesToWrite) ~= "table" then error("Expected table, got "..type(linesToWrite)) end
	
	for _, output in pairs(outputs) do
		for __, line in pairs(linesToWrite) do
			if output.isColor() then
				output.setBackgroundColor(line.backgroundColor)
				output.setTextColor(line.textColor)
			end
			
			if output ~= term then
				term.redirect(output)
				print(line.text)
    term.restore()
			else
				print(line.text)
			end
		end
	end
end

local Args = {...} -- <interval> [monitor names ... (for all connected one: all)]
if #Args < 1 then
	error("Interval argument needs to be specified. Usage: "..shell.getRunningProgram().." <interval> [monitorNames ...]")
end

local interval = 0
local interval = tonumber(Args[1])
if interval < 1 then
	error("Invalid interval! It needs to be greater than 0.")
end

local outputs = { term }
if #Args == 2 then
	if string.lower(Args[2]) == "all" then
		for _, name in pairs(peripheral.getNames()) do
			if peripheral.getType(name) == "monitor" then
				outputs[#outputs + 1] = peripheral.wrap(name)
			end
		end
	end
else
	for _, name in pairs(Args) do
		if peripheral.getType(name) == "monitor" then
			outputs[#outputs + 1] = peripheral.wrap(name)
		end
	end
end

local meController = ""
for _, name in pairs(peripheral.getNames()) do	
	if peripheral.getType(name) == "appeng_me_tilecontroller" then
		meController = peripheral.wrap(name)
		break
	end
end
if type(meController) ~= "table" then error("No ME Controller found.") end

local previousStock = makeSane(meController.getAvailableItems())
os.startTimer(interval)
clearAll(outputs)
while true do
	os.pullEvent("timer")
	
	local newStock = makeSane(meController.getAvailableItems())
	
	local differences = {}
	for rawName, stack in pairs(newStock) do
		local change = stack.qty
		if previousStock[rawName] then
			change = stack.qty - previousStock[rawName].qty
		end
		
		if change ~= 0 then
			differences[rawName] = {}
			differences[rawName].change = change
			differences[rawName].name = stack.name
			
			if change > 0 then
				differences[rawName].percentage = math.floor(((change / stack.qty) * 10000) + 0.5) / 100
			else
				differences[rawName].percentage = math.floor(((math.abs(change) / previousStock[rawName].qty) * 10000) + 0.5) / 100
			end
		end
	end
	
	for rawName, stack in pairs(previousStock) do
		if not newStock[rawName] then
			local change = stack.qty * -1
			
			differences[rawName] = {}
			differences[rawName].change = change
			differences[rawName].name = stack.name
			differences[rawName].percentage = 100
		end
	end
	
	local linesToWrite = {}
	
	for _, changes in pairs(differences) do
		linesToWrite[#linesToWrite + 1] = {}
		linesToWrite[#linesToWrite].backgroundColor = colors.black
		
		if changes.change > 0 then
			linesToWrite[#linesToWrite].text = "+"..changes.change.." ("..changes.percentage.."%) "
			linesToWrite[#linesToWrite].textColor = colors.green
		else
			linesToWrite[#linesToWrite].text = changes.change.." ("..changes.percentage.."%) "
			linesToWrite[#linesToWrite].textColor = colors.red
		end
		
		linesToWrite[#linesToWrite].text = linesToWrite[#linesToWrite].text..changes.name
		
		writeToAll(outputs, linesToWrite)
	end
	
	previousStock = newStock
	
	os.startTimer(interval)
end
