-- see copyright notice in grldc.h

-- This module follows approximately the same interface as the lua socket module, but implements only the subset needed by GRLD for easier port on platforms that lua socket does not support

local socket = require( "socket" )

local setmetatable = setmetatable
local ipairs = ipairs
local table = table
local assert = assert
local print = print
local error = error
local type = type

module( "grldc.socket" )

local listenerMeta = { __index = {} }
local connectionMeta = { __index = {} }

function sleep( time )
	socket.sleep( time )
end

-- Wait until one of the sockets in the recvt list is receiving data, or the timeout has expired (if timeout is nil, wait forever)
function select( recvt, timeout )
	local sockets = {}
	for _, s in ipairs( recvt ) do
		table.insert( sockets, s )
	end
	socket.select( sockets, nil, timeout )
end

-- Start listening for connections. See listener:accept
function bind( address, port )
	local listener = assert( socket.bind( address, port ) )
	listener:settimeout( 0 )
	local self = { listener_ = listener }
	setmetatable( self, listenerMeta )
	return self
end

-- Connects to a listening server. Throws an error with message "connection refused" if the connection is refused by the server.
function connect( address, port )
	print( "Connecting to "..address..":"..port.."..." )
	local con, msg = socket.connect( address, port )
	if not con and msg == "connection refused" then error( msg, 0 ) end
	assert( con, msg )
	con:setoption( "tcp-nodelay", true )
	local res = { connection = con }
	setmetatable( res, connectionMeta )
	return res
end

-- If a client is connecting, returns a connection with it, otherwise returns nil (no waiting)
function listenerMeta.__index:accept()
	local con, msg = self.listener_:accept()
	if con == nil and msg ~= "timeout" then
		error( msg )
	end
	if con == nil then return nil end
	con:setoption( "tcp-nodelay", true )
	--con:setoption( "keepalive", true )
	local res = { connection = con }
	setmetatable( res, connectionMeta )
	return res
end

function connectionMeta.__index:getpeername()
	return self.connection:getpeername()
end

function connectionMeta.__index:send( data )
	return self.connection:send( data )
end

-- Receives a string until first "\n" character if what is nil, or the specified number of bytes if what is a number. The result is returned as a string. If the connection is closed, throws an error "closed"
function connectionMeta.__index:receive( what )
	assert( what == nil or type( what ) == "number" )
	return self.connection:receive( what )
end

-- Sets the timeout for the next receive operations
function connectionMeta.__index:settimeout( timeout )
	self.connection:settimeout( timeout )
end
