#include "data.h"
#include <time.h>

Socket::Socket(SOCKET s) : m_socket(s), m_bufferSize(0), m_bufferPos(0)
{
	u_long nonBlock = 1;
	ioctlsocket(s, FIONBIO, &nonBlock);
}

Socket::~Socket()
{
	closesocket(m_socket);
}

uint8 Socket::ReadByte()
{
	if (m_bufferPos == m_bufferSize)
		Fetch();
	return m_buffer[m_bufferPos++];
}

void Socket::Fetch()
{
	time_t start = time(NULL);

	while (true)
	{
		if (start+30 < time(NULL))
			throw std::runtime_error("Timeout on socket");

		fd_set fds;
		FD_ZERO(&fds);
		FD_SET(m_socket, &fds);
		timeval timeout;
		timeout.tv_sec = 300;
		timeout.tv_usec = 0;
		// not portable to *nix
		int n = select(SOCKET(0), &fds, NULL, NULL, &timeout);
		switch (n)
		{
		case 0:
			throw std::runtime_error("Timeout on socket");
		case SOCKET_ERROR:
			throw std::runtime_error("Error waiting for read on socket");
		}
		int r = recv( m_socket, (char*) m_buffer, BUFFER_SIZE, 0 );
		if (r == SOCKET_ERROR)
		{
			if (WSAGetLastError() != WSAEWOULDBLOCK)
			{
				Sleep(1000);
				continue;
			}
			throw std::runtime_error("Error in WSARecv");
		}
		else if (r)
		{
			m_bufferSize = r;
			m_bufferPos = 0;
			break;
		}
		else
		{
			if (WSAGetLastError() != WSAEWOULDBLOCK)
			{
				Sleep(1000);
				continue;
			}
			throw std::runtime_error("No bytes received by recv");
		}
	}
}

void ReadSock( Socket& sock, std::string& value )
{
	uint32 length;
	ReadSock( sock, length );
	if (length > 1024)
		throw std::runtime_error("size too big");
	value.resize(0);
	for (uint32 i=0; i<length; i++)
	{
		uint8 ch;
		ReadSock( sock, ch );
		value += char(ch);
	}
}

void ReadSock( Socket& sock, SAnnotation& annot )
{
	ReadSock(sock, annot.index);
	ReadSock(sock, annot.annotation);
}

void ReadSock( Socket& sock, SPacket& pkt )
{
	ReadSock(sock, pkt.uniqueId);
	ReadSock(sock, pkt.isEncoding);
	ReadSock(sock, pkt.channel);
	ReadSock(sock, pkt.coding);
	ReadSock(sock, pkt.annotations);
}

void ReadSock( Socket& sock, uint8& value )
{
	value = sock.ReadByte();
}
