#include "server.h"

typedef int UINT_PTR;
#define SOCKET_ERROR -1


int	srv_sendBuffer(Server* srv, unsigned int cli,void* pBuffer, unsigned int dwLen)
{
	int result;
	ServerEventArgs e;
		//abfragen ob client existiert!! wichtig
	if (srv->sConnections[cli] != SOCKET_ERROR)
	{
		result= send(srv->sConnections[cli],(char*)pBuffer,dwLen,0);
		if (srv->_OnWrite!=0)
		{
			e.ClientID = cli;
			e.dwLen = dwLen;
			e.pBuffer = pBuffer;
			srv->_OnWrite(&e);
		}

		return result;
	}
	else
		return -1;
}

void srv_DisconnectClient(Server* srv, unsigned int cli)
{
	ServerEventArgs e;
	closesocket(srv->sConnections[cli]);
	srv->sConnections[cli]=SOCKET_ERROR;
	srv->dwConnections--;
	if (srv->_OnDisconnect!=0)
	{
		e.ClientID = cli;
		e.dwLen = 0;
		e.pBuffer = 0;
		srv->_OnDisconnect(&e);
	}

	memset(&srv->ConnectionsAddr[cli],0,sizeof(struct sockaddr_in));
}
void* srv_WaitForConnection(Server* srv)
{
	SOCKET				tmpClient;
	struct sockaddr_in	tmpAddr;
	int					tmpAddrLen;
	ServerEventArgs		e;
	ServerThreadArgs*	t;
        unsigned int i;


	do
	{
		if (srv->dwConnections < srv->dwMaximumConnections)
		{
			tmpAddrLen = sizeof(struct sockaddr);
			if ((tmpClient=accept(srv->sSocket,(struct sockaddr*)&tmpAddr,&tmpAddrLen)) != SOCKET_ERROR) 
			{
				for(i=0;i<srv->dwMaximumConnections;i++)
				{ 
					if (srv->sConnections[i] == SOCKET_ERROR)
					{
						srv->sConnections[i] = tmpClient;
						srv->ConnectionsAddr[i] = tmpAddr;
						srv->dwConnections++;
			
						if(srv->_OnConnect!=0)
						{
							e.ClientID = i;
							e.dwLen = 0;
							e.pBuffer =0;
							srv->_OnConnect(&e);
						}

                                                t = (ServerThreadArgs*) kmalloc(sizeof(ServerThreadArgs));
						t->ID = i;
						t->srv = srv;
                                                create_kernel_task(&srv->bThreads[i],srv_WaitForPacket,t);

						break;
					}
				}
			}
		}
		else
		{
		}
	}while(1);

	return NULL;

}
void* srv_WaitForPacket(ServerThreadArgs* t)
{
	int iResult=1;
	char pTmpBuffer[DEF_BUFFERSIZE+1];
	ServerEventArgs e;
	Server* srv = t->srv;
	int cli = t->ID;

	while (iResult > 0)
	{
		iResult = recv(srv->sConnections[cli] ,pTmpBuffer, DEF_BUFFERSIZE, 0);
		if (iResult > 0)
		{
			pTmpBuffer[iResult]='\0';
			if(srv->_OnRead!=0)
			{
				e.ClientID = cli;
				e.dwLen = iResult;
				e.pBuffer = pTmpBuffer;
				srv->_OnRead(&e);
			}
		}
		else	//Verbindung geschlossen
		{
			closesocket(srv->sConnections[cli]);
			srv->sConnections[cli]=SOCKET_ERROR;
			if(srv->_OnDisconnect!=0)
			{
				e.ClientID = cli;
				e.dwLen = 0;
				e.pBuffer = 0;
				srv->_OnDisconnect(&e);
			}
			memset(&srv->ConnectionsAddr[cli],0,sizeof(struct sockaddr_in));
			srv->dwConnections--;
			iResult=-1;
		}
	}
	return NULL;
}

int server_init(Server* srv, unsigned short Port, unsigned int dwMaxConnections)
{
	struct sockaddr_in	tmpAddr;
	int					tmpAddrLen;
	ServerThreadArgs	t;
	tmpAddrLen = sizeof(struct sockaddr);

	// Unregister Events
	srv->_OnConnect=0;
        srv->_OnRead=0;
        srv->_OnDisconnect=0;
	srv->_OnWrite=0;
	
        // Allocate needed Memory
        srv->sConnections=(SOCKET*)kmalloc(sizeof(SOCKET)*dwMaxConnections);
        srv->ConnectionsAddr =(struct sockaddr_in*) kmalloc(sizeof(struct sockaddr_in)*dwMaxConnections);
        srv->bThreads = (tid_t*)kmalloc(sizeof(tid_t)*dwMaxConnections);

        if (!srv->sConnections || !srv->ConnectionsAddr || !srv->bThreads)
        {
            kprintf("low on mem -%d- -%d- -%d-",srv->sConnections ,srv->ConnectionsAddr,srv->bThreads);
            return -1;
        }

	srv->dwMaximumConnections=dwMaxConnections;

	memset(srv->sConnections,0xFF,sizeof(SOCKET)*dwMaxConnections);
	memset(srv->ConnectionsAddr,0x00,sizeof(struct sockaddr_in)*dwMaxConnections);

	srv->dwConnections=0;
	srv->wPort = Port;

	srv->adAddr.sin_addr.s_addr = INADDR_ANY;					// IP'S die der Server annehmen soll
	srv->adAddr.sin_family = AF_INET;								// AdressFamilie (TCP/IP)
	srv->adAddr.sin_port = htons(srv->wPort);								// Port auf dem der server erreichbar seien soll

	srv->sSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);		// Einen Socket erstellen

	bind( srv->sSocket,(const struct sockaddr *) &srv->adAddr, sizeof(srv->adAddr));	// Der Server an die Adresse binden;
	listen(srv->sSocket,srv->dwMaximumConnections);							// Den Server in listenig State versetzen

        create_kernel_task(&srv->bThread_listen,srv_WaitForConnection,srv);
//	sConnections[0] = accept(sSocket,(struct sockaddr*)&tmpAddr,&tmpAddrLen);
//	t.ID = 0;
//	bthread_create(&bThreads[0],NULL,(start_routine) srv_WaitForPacket,&t);
}

int server_destroy(Server* srv)
{
        unsigned int i;
	for (i=0;i<srv->dwMaximumConnections;i++) 
	{
		if (srv->sConnections[i] != SOCKET_ERROR)closesocket(srv->sConnections[i]);
                //bthread_terminate(&srv->bThreads[i],0x00);
	}
	closesocket(srv->sSocket);
        //bthread_terminate(&srv->bThread_listen,0x00);

//	free(srv->sConnections);
//	free(srv->ConnectionsAddr);
//	free(srv->bThreads);
		
}