local Class = require "luanode.class"
local Transport = require "socket-io-client.transport"
local Data = require "socket-io-client.data"
local url_encode = require "luanode.querystring".url_encode

local XHR = Class.InheritsFrom(Transport)

---
--
function XHR:__init (...)
	local new = Class.construct(XHR, ...)
	new._sendBuffer = {}
	new._disconnecting = false
	return new
end

---
--
function XHR:connect ()
	--console.log("XHR:connect")

	self:_get()
	return self
end

---
--
function XHR:_checkSend ()
	--console.log("XHR:_checkSend")

	if not self.posting and #self._sendBuffer > 0 then
		local encoded = Data.encode(self._sendBuffer)
		self._sendBuffer = {}
		self:_send(encoded)
	end
end

---
--
function XHR:write (kind, data)
	--console.log("XHR:write", kind, data)

	if type(kind) == "table" then
		table.insert(self._sendBuffer, kind)
	else
		table.insert(self._sendBuffer, { kind, data })
	end
	self:_checkSend()
	return self
end

---
--
function XHR:_send (data)
	--console.log("XHR:_send", data)
	
	local prepared_path
	
	self._posting = true
	self._sendXhr, prepared_path = self:_request("send", "post")
	
	self._sendXhr:on("response", function(_, res)

		res:on("data", function(_, chunk)
			res._body = res._body or {}
			table.insert(res._body, chunk)
		end)

		res:on("end", function()
			self._posting = false;
			res._body = table.concat(res._body, "")
			if res.statusCode ~= 200 then
				local msg = console.warn("request for url '%s' failed with status %s => Body: '%s'", 
					prepared_path, res.statusCode, res._body)
				self:_onDisconnect()
			else
				self:_checkSend()
			end
			if self._disconnecting then
				self:_onDisconnect()
			end
		end)
	end)
	
	local encoded_data = "data=" .. url_encode(data)
	self._sendXhr:setHeader("content-length", #encoded_data)
	self._sendXhr:finish(encoded_data)
end

---
--
function XHR:disconnect ()
	--console.log("XHR:disconnect")
	self:write("0")
	self._disconnecting = true
	return self
end

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

	if self._xhr then
		-- Leave listeners on. We need the error handler to stay
		--self._xhr:removeAllListeners()
		self._xhr:destroy()
		self._xhr = nil
	end

	if self._sendXhr then
		-- Leave listeners on. We need the error handler to stay
		--self._sendXhr:removeAllListeners()
		self._sendXhr:destroy()
		self._sendXhr = nil
	end
	self._sendBuffer = {}
	Transport._onDisconnect(self)
end

---
--
function XHR:_request (url, method, multipart)
	--console.log("XHR:_request", url, method, multipart)

	method = method or "get"

	local headers = {}

	if method:lower() == "post" then
		headers["Content-type"] = "application/x-www-form-urlencoded; charset=utf-8"
	end

	local prepared_path = self:_prepareUrl()
	if url then
		prepared_path = prepared_path .. "/" .. url
	end
	
	local req = luanode.http.request({
		hostname = self.base.host,
		port = self.base.port,
		method = method,
		path = prepared_path,
		headers = headers
	}, function()
	end)

	req:on("error", function(...)
		console.error("client error", ...)
		self:_onDisconnect()
	end)

	return req, prepared_path
end

return XHR
