curSeqnum = nil

function openall()
	rednet.open("left")
	rednet.open("right")
	rednet.open("back")
	rednet.open("front")
	rednet.open("bottom")
	rednet.open("top")
end

seqnumTable = {}
recvBuffer = {}

function processRecv(senderID, recvSeqnum, recvMsg)
	local lastSeqnum = seqnumTable[senderID]
	if lastSeqnum == nil then
		-- First message from sender
		rednet.send(senderID, "rrpr " .. recvSeqnum)
		seqnumTable[senderID] = recvSeqnum
		return true
	elseif lastSeqnum == recvSeqnum then
		-- Duplicate message from sender
		rednet.send(senderID, "rrpr " .. recvSeqnum)
		return false
	else
		-- New message from sender
		rednet.send(senderID, "rrpr " .. recvSeqnum)
		seqnumTable[senderID] = recvSeqnum
		return true
	end
end

function receive(timeout)
	if #recvBuffer > 0 then
		local bufMsg = recvBuffer[0]
		table.remove(recvBuffer, 0)
		return bufMsg[1], bufMsg[2], bufMsg[3]
	end
	if timeout == nil then timeout = 10000000 end
	local startTime = os.clock()
	local timeoutTime = startTime + timeout
	while true do
		local recvTimeout = timeoutTime - os.clock()
		if recvTimeout <= 0 then return nil end
		local senderID, message, dist = rednet.receive(recvTimeout)
		if senderID == nil then
			return nil
		else
			local recvSeqnum, recvMsg = message:match("^rrps ([0-9]+) (.*)$")
			if recvSeqnum ~= nil then recvSeqnum = tonumber(recvSeqnum) end
			if recvSeqnum ~= nil then
				if processRecv(senderID, recvSeqnum, recvMsg) then
					return senderID, recvMsg, dist
				end
			else
				return senderID, message, dist
			end
		end
	end
end


function send(receiverID, message, timeout)
	if curSeqnum == nil then curSeqnum = math.floor(os.time() * 1000) end
	if timeout == nil then timeout = 10000000 end
	curSeqnum = curSeqnum + 1
	local startTime = os.clock()
	local timeoutTime = startTime + timeout
	-- RRP Send
	local encMsg = "rrps " .. curSeqnum .. " " .. message
	while true do
		local recvTimeout = timeoutTime - os.clock()
		if recvTimeout <= 0 then return false end
		if rednet.send(receiverID, encMsg, true) then
			local recvId, recvMsg, dist = rednet.receive(1)
			if recvId ~= nil and recvId == receiverID then
				-- RRP sent message
				local recvSeqnum, recvSndMsg = recvMsg:match("^rrps ([0-9]+) (.*)$")
				if recvSeqnum ~= nil then recvSeqnum = tonumber(recvSeqnum) end
				if recvSeqnum ~= nil then
					if processRecv(recvId, recvSeqnum, recvSndMsg) then
						table.insert(recvBuffer, { recvId, recvSndMsg, dist })
					end
				end
				-- RRP Response
				recvSeqnum = recvMsg:match("^rrpr ([0-9]+)$")
				if recvSeqnum ~= nil then recvSeqnum = tonumber(recvSeqnum) end
				if recvSeqnum ~= nil and recvSeqnum == curSeqnum then
					return true
				end
				-- RRP Cancellation
				recvSeqnum = recvMsg:match("^rrpc ([0-9]+)$")
				if recvSeqnum ~= nil then recvSeqnum = tonumber(recvSeqnum) end
				if recvSeqnum ~= nil and recvSeqnum == curSeqnum then
					return false
				end
			end
		else
			os.sleep(1)
		end
	end
end


