--[[
ARC: AR Client
Uses Plethora overlay glasses and modems to display 3D signage transmitted from local "beacons"
]]

local m = peripheral.find "modem"
local mods = peripheral.wrap "back"

if not m then error "Modem required." end
if not mods then error "Is this even on a neural interface?" end
if not mods.canvas3d then error "Overlay glasses required." end

local canv = mods.canvas3d()

local object_channel = 666

m.open(object_channel)

local x, y, z

-- convert position to string for use as table key
local function serialize_position(p)
	return string.format("%f,%f,%f", p[1], p[2], p[3])
end

-- Generate a string representation of a table, for easy comparison. Not really hashing, I guess.
local function hash_table(x)
	if type(x) == "table" then
		local out = ""
		for k, v in pairs(x) do
			if type(k) ~= "string" or not k:match "^_" then -- ignore keys beginning with _
				out = out .. hash_table(k) .. ":" .. hash_table(v) .. ";"
			end
		end
		return out
	else
		return tostring(x)
	end
end

-- honestly not that elegant, but it works
-- TODO: do this more efficiently/nicely somehow?
local function tables_match(x, y)
	return hash_table(x) == hash_table(y)
end

local objects = {}
local timers = {}

local function redraw(object)
	local frame = object._frame
	frame.clear()
end

local function process_object(object)
	local pos = serialize_position(object.position)
	if objects[pos] then
		if not tables_match(object, objects[pos]) then
			print("redrawing", pos)
			objects[pos] = object
			redraw(objects[pos])
		end
		local t = os.startTimer(20)
		timers[t] = pos
	else
		print("new object at", pos)
		if x then
			local frame = 
		else
			print("GPS error, cannot create object")
		end
	end
end

local function main_loop()
	while true do
		local event, timer, channel, reply_channel, message, distance = os.pullEvent()
		if event == "modem_message" and channel == object_channel and distance and type(message) == "table" then -- ensure message is from this dimension and otherwise valid
			for _, object in pairs(msg) do
				local ok, err = pcall(process_object, object)
				if not ok then printError(err) end
			end
		elseif event == "timer" then
			local objpos = timers[timer]
			if objpos then
				local obj = objects[objpos]
				if obj then
					print(objpos, "timed out")
					obj._frame.remove()
					objects[objpos] = nil
				end
			end
		end
	end
end

-- Request location every second
local function GPS_loop()
	while true do
		x, y, z = gps.locate()
		sleep(1)
	end
end

parallel.waitForAll(GPS_loop, main_loop)