local Class = require "luanode.class"
local EventEmitter = require "luanode.event_emitter"
local Decoder = require "socket-io-client.data".Decoder
local decodeMessage = require "socket-io-client.data".decodeMessage

local merge = require "socket-io-client.utils".merge
local json = require "json"


local Transport = Class.InheritsFrom(EventEmitter)

---
-- base es una instancia de Io
function Transport:__init (base, options)
	local new = Class.construct(Transport)

	new.base = base
	new.options = {
		timeout = 15000
	}
	merge(new.options, options)
	new.decoder = Decoder()
	new.decoder:on("data", function(self, ...)
		new:_onMessage(...)
	end)
	
	return new
end

function Transport:write ()
	error("Missing write() implementation")
end

function Transport:connect ()
	error("Missing connect() implementation")
end

function Transport:disconnect ()
	error("Missing disconnect() implementation")
end

---
--
function Transport:_onData (data)
	--console.log("Transport:_onData", data)
	
	self:_setTimeout()
	self.decoder:add(data)
end

---
--
function Transport:_setTimeout ()
	--console.log("Transport:_setTimeout")

	if self._timeout then
		clearTimeout(self._timeout)
	end
	self._timeout = setTimeout(function()
		self:_onTimeout()
	end, self.options.timeout)
end

---
--
function Transport:_onTimeout ()
	--console.log("Transport:_onTimeout")

	self:_onDisconnect()
end

---
--
function Transport:_onMessage (type, data)
	--console.log("Transport:_onMessage", type, data)

	if type == "0" then
		self:_onDisconnect()

	elseif type == "1" then
		local msg, anns = decodeMessage(data)
		-- handle json decoding
		if anns.j then
			msg = json.decode(msg)
		end
		self.base:_onMessage(msg, anns)
	
	elseif type == "2" then
		self:_onHeartbeat(data)
	
	elseif type == "3" then
		self.sessionid = data
		self:_onConnect()
	end
end

---
--
function Transport:_onHeartbeat (heartbeat)
	--console.log("Transport:_onHeartbeat", heartbeat)

	self:write("2", heartbeat) --echo
end

---
--
function Transport:_onConnect ()
	--console.log("Transport:_onConnect")

	self.connected = true
	self.connecting = false
	self.base:_onConnect()
	self:_setTimeout()
end

---
--
function Transport:_onDisconnect ()
	--console.log("Transport:_onDisconnect")

	self.connecting = false
	self.connected = false
	self.sessionid = nil
	if self._timeout then
		clearTimeout(self._timeout)
		self._timeout = nil
	end
	self.base:_onDisconnect()
end

---
--
function Transport:_prepareUrl ()
	
	local path = "/" .. self.base.options.resource .. "/" .. self.type .. 
				(self.sessionid and ("/" .. self.sessionid) or "/")
	return path
end

return Transport
