/*
Copyright (C) 1996-1997 Id Software, Inc.

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  

See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

*/
// net_adhoc.c

#include "quakedef.h"
#include "net_adhoc.h"

#include "ds.h"

//#define USE_ADHOC

#ifdef USE_ADHOC

#include "libwifi/include/lobby.h"
#include "libwifi/include/safe_malloc.h"

qsocket_t	*adhoc_client = NULL;
qsocket_t	*adhoc_server = NULL;

char *msg = 0 ;

int recved = 0, sent = 0 ;

int myDriverLevel;

void receiveText(unsigned char *data, int length, LPLOBBY_USER from)
{
	if (msg) free(msg) ;
	msg = (char *)safe_malloc(length) ; // strdup((char *)data) ;
	strcpy(msg, (const char *)data);
	recved ++ ;
}

int adhoc_Init (void)
{
	if (cls.state == ca_dedicated)
		return -1;

	printf("Initialising ad-hoc lobby system\n");
	LOBBY_Init() ;
	LOBBY_SetStreamHandler(0x0001,&receiveText) ;
	
	myDriverLevel = net_driverlevel;
	
	return 0;
}


void adhoc_Shutdown (void)
{
	printf("Trying to shut down ad-hoc system (doing nothing)\n");
}


void adhoc_Listen (qboolean state)
{
	printf("Setting ad-hoc to listen (doing nothing)\n");
}


void adhoc_SearchForHosts (qboolean xmit)
{
	printf("Ad-hoc is searching for active hosts\n");
	
	if (!sv.active)
		return;

	hostCacheCount = LOBBY_GetNumberOfKnownUsers() ;
	
	for (int count = 0; count < hostCacheCount; count++)
	{
		Q_strcpy(hostcache[count].name, (char *)LOBBY_GetUserName(LOBBY_GetUserByID(count)));
		Q_strcpy(hostcache[count].cname, (char *)LOBBY_GetUserName(LOBBY_GetUserByID(count)));
		
		hostcache[count].users = 0;
		hostcache[count].maxusers = 2;
		hostcache[count].driver = myDriverLevel;
	}
}

static qsocket_t *_adhoc_Connect (char *host)
{
	int		ret;
	double	start_time;
	double	last_time;
	
	qsocket_t *sock;

	sock = NET_NewQSocket ();
	sock->driver = myDriverLevel;
	if (sock == NULL)
	{
		Con_Printf("No sockets available\n");
		return NULL;
	}

	// send the connection request
	start_time = SetNetTime();
	last_time = 0.0;

	SZ_Clear(&net_message);
	MSG_WriteByte(&net_message, CCREQ_CONNECT);
	MSG_WriteString(&net_message, "QUAKE");
	do
	{
		SetNetTime();
		if ((net_time - last_time) >= 1.0)
		{
			adhoc_SendControlMessage (sock, &net_message);
			last_time = net_time;
			Con_Printf("trying...\n"); SCR_UpdateScreen ();
		}
		ret = adhoc_GetMessage (sock);
	}
	while (ret == 0 && (net_time - start_time) < 5.0);

	if (ret == 0)
	{
		Con_Printf("Unable to connect, no response\n");
		NET_FreeQSocket(sock);
		return NULL;
	}

	if (ret == -1)
	{
		Con_Printf("Connection request error\n");
		NET_FreeQSocket(sock);
		NULL;
	}

	MSG_BeginReading ();
	ret = MSG_ReadByte();
	if (ret == CCREP_REJECT)
	{
		Con_Printf(MSG_ReadString());
		NET_FreeQSocket(sock);
		return NULL;
	}
	if (ret != CCREP_ACCEPT)
	{
		Con_Printf("Unknown connection response\n");
		NET_FreeQSocket(sock);
		return NULL;
	}
	
	sock->lastMessageTime = net_time;

	Con_Printf ("Connection accepted\n");

	return sock;
}

qsocket_t *adhoc_Connect (char *host)
{
	printf("Doing an ad-hoc connection to \'%s\'\n", host);
	return _adhoc_Connect(host);
}


qsocket_t *adhoc_CheckNewConnections (void)
{
	adhoc_server->sendMessageLength = 0;
	adhoc_server->receiveMessageLength = 0;
	adhoc_client->sendMessageLength = 0;
	adhoc_client->receiveMessageLength = 0;
#ifdef USE_EXTRA_RAM
	byte_write(&adhoc_server->canSend, true);
	byte_write(&adhoc_client->canSend, true);
#else
	adhoc_server->canSend = true;
	adhoc_client->canSend = true;
#endif
	return adhoc_server;
}


static int IntAlign(int value)
{
	return (value + (sizeof(int) - 1)) & (~(sizeof(int) - 1));
}


int adhoc_GetMessage (qsocket_t *sock)
{
	int		ret;
	int		length;

	if (sock->receiveMessageLength == 0)
		return 0;

	ret = sock->receiveMessage[0];
	length = sock->receiveMessage[1] + (sock->receiveMessage[2] << 8);
	// alignment byte skipped here
	SZ_Clear (&net_message);
	SZ_Write (&net_message, &sock->receiveMessage[4], length);

	length = IntAlign(length + 4);
	sock->receiveMessageLength -= length;

	if (sock->receiveMessageLength)
		Q_memcpy(sock->receiveMessage, &sock->receiveMessage[length], sock->receiveMessageLength);

	return ret;
}


int adhoc_SendMessage (qsocket_t *sock, sizebuf_t *data)
{
	unsigned int	packetLen;
	unsigned int	dataLen;
	unsigned int	eom;

	Q_memcpy(sock->sendMessage, data->data, data->cursize);
	sock->sendMessageLength = data->cursize;

	if (data->cursize <= MAX_DATAGRAM)
	{
		dataLen = data->cursize;
		eom = NETFLAG_EOM;
	}
	else
	{
		dataLen = MAX_DATAGRAM;
		eom = 0;
	}
	packetLen = NET_HEADERSIZE + dataLen;

	packetBuffer.length = BigLong(packetLen | (NETFLAG_DATA | eom));
	packetBuffer.sequence = BigLong(sock->sendSequence++);
	Q_memcpy (packetBuffer.data, sock->sendMessage, dataLen);

	sock->canSend = false;

	if (sfunc.Write (sock->socket, (byte *)&packetBuffer, packetLen, &sock->addr) == -1)
		return -1;

	sock->lastSendTime = net_time;
	packetsSent++;
	return 1;
}


int adhoc_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *data)
{
	byte *buffer;
	int  *bufferLength;

	if (!sock->driverdata)
		return -1;

	bufferLength = &((qsocket_t *)sock->driverdata)->receiveMessageLength;

	if ((*bufferLength + data->cursize + sizeof(byte) + sizeof(short)) > NET_MAXMESSAGE)
		return 0;

	buffer = ((qsocket_t *)sock->driverdata)->receiveMessage + *bufferLength;

	// message type
	

#ifdef USE_EXTRA_RAM
	byte_write(buffer, 2);
	buffer++;
	
	byte_write(buffer, data->cursize & 0xff);
	buffer++;
	byte_write(buffer, data->cursize >> 8);
	buffer++;
#else
	*buffer++ = 2;
	
	*buffer++ = data->cursize & 0xff;
	*buffer++ = data->cursize >> 8;
#endif
	// align
	buffer++;

	// message
	Q_memcpy(buffer, data->data, data->cursize);
	*bufferLength = IntAlign(*bufferLength + data->cursize + 4);
	return 1;
}


qboolean adhoc_CanSendMessage (qsocket_t *sock)
{
	if (!sock->driverdata)
		return false;
	return sock->canSend;
}


qboolean adhoc_CanSendUnreliableMessage (qsocket_t *sock)
{
	return true;
}


void adhoc_Close (qsocket_t *sock)
{
	printf("Closing ad-hoc connection (doing nothing\n");
}

#endif
