#include "scripts.h"
#include "engine.h"
#include "stdlib.h"
#include "stdio.h"
#include "Winsock2.h"
#include <Windows.h>
#include "Misc.h"

void GetFiles(const char *Path, char **Data, int DataLength)
{
	WIN32_FIND_DATA FindFileData;
	HANDLE hFind = INVALID_HANDLE_VALUE;

	hFind = FindFirstFile(Path, &FindFileData);
	if(FindFileData.dwFileAttributes != FILE_ATTRIBUTE_DIRECTORY)
	{
		char *file = new char[strlen(FindFileData.cFileName)+1];
		strcpy(file, FindFileData.cFileName);
		for(int i = 0; i < DataLength; i++)
		{
			if(!Data[i])
			{
				Data[i] = file;
				break;
			}
		}
	}
	while (FindNextFile(hFind, &FindFileData) != 0) 
	{
		if(FindFileData.dwFileAttributes != FILE_ATTRIBUTE_DIRECTORY)
		{
			char *file = new char[strlen(FindFileData.cFileName)+1];
			strcpy(file, FindFileData.cFileName);
			for(int i = 0; i < DataLength; i++)
			{
				if(!Data[i])
				{
					Data[i] = file;
					break;
				}
			}
		}
	}
	FindClose(hFind);
}

TCPSocket::TCPSocket()
{
	memset((void *)this, 0, sizeof(TCPSocket));
}

TCPSocket::TCPSocket(TCPSocket &_Socket)
{
	memcpy((void *)this, &_Socket, sizeof(TCPSocket));
}

TCPSocket::TCPSocket(const char *Host, int Port)
{
	memset((void *)this, 0, sizeof(TCPSocket));
	this->Client(Host, Port);
}

TCPSocket::TCPSocket(const char *IP, int Port, int Backlog)
{
	memset((void *)this, 0, sizeof(TCPSocket));
	this->Server(IP, Port, Backlog);
}

TCPSocket::TCPSocket(SOCKET &_Socket, int _Mode)
{
	memset((void *)this, 0, sizeof(TCPSocket));
	this->Socket = _Socket;
	this->Mode = _Mode;
	this->Connected = 1;
}

TCPSocket::~TCPSocket()
{
	shutdown(this->Socket, SD_BOTH);
	closesocket(this->Socket);
	memset((void *)this, 0, sizeof(TCPSocket));
}

bool TCPSocket::Client(const char *Host, int Port)
{
	hostent *he;
	if ((he = gethostbyname(Host)) == 0) 
	{
		return 0;
	}
	SOCKET s_ = socket(AF_INET,SOCK_STREAM,0);
	if (s_ == INVALID_SOCKET) 
	{
		return 0;
	}
	sockaddr_in addr;
	addr.sin_family = AF_INET;
	addr.sin_port = htons((u_short)Port);
	addr.sin_addr = *((in_addr *)he->h_addr);
	memset(&(addr.sin_zero), 0, 8); 
	if (connect(s_, (sockaddr *) &addr, sizeof(sockaddr))) 
	{
		return 0;
	}

	this->Socket = s_;
	this->Connected = 1;
	this->Mode = 0;
	this->Port = Port;
	strcpy_s(this->Host, 256, Host);
	return 1;
}

bool TCPSocket::Server(const char *IP, int Port, int Backlog)
{
	SOCKET server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (server == INVALID_SOCKET) 
	{
		return 0;
	}

	sockaddr_in service;
	service.sin_family = AF_INET;
	service.sin_addr.s_addr = inet_addr(IP == 0 ? "127.0.0.1" : IP);
	service.sin_port = htons((u_short)Port);

	if(bind(server, (SOCKADDR*) &service, sizeof(service)) == SOCKET_ERROR) 
	{
		return 0;
	}

	if (listen(server, Backlog) == SOCKET_ERROR) 
	{
		return 0;
	}
	
	this->Socket = server;
	this->Mode = 1;
	this->Connected = 1;
	return 1;
}

bool TCPSocket::Is_Connected()
{
	if(this->Mode == 1)
	{
		return 1;
	}

	fd_set fd;
	TIMEVAL tv;

	tv.tv_sec = 0;
	tv.tv_usec = 1000;

	FD_ZERO(&fd);
	FD_SET(this->Socket, &fd);

	if(select((int)this->Socket, 0, &fd, 0, &tv) == -1)
	{
		return 0;
	}

	if(FD_ISSET(this->Socket, &fd))
	{
		FD_CLR(this->Socket, &fd);
		return 1;
	}
	FD_CLR(this->Socket, &fd);

	return 0;
}

bool TCPSocket::Is_DataAvaliable()
{
	if(!this->Is_Connected())
	{
		return 0;
	}
	if(this->Mode != 0)
	{
		return 0;
	}
	
	fd_set fd;
	TIMEVAL tv;

	tv.tv_sec = 0;
	tv.tv_usec = 1000;

	FD_ZERO(&fd);
	FD_SET(this->Socket, &fd);

	if(select((int)this->Socket, &fd, 0, 0, &tv) == -1)
	{
		return 0;
	}

	if(FD_ISSET(this->Socket, &fd))
	{
		FD_CLR(this->Socket, &fd);
		return 1;
	}
	FD_CLR(this->Socket, &fd);
	return 0;
}

bool TCPSocket::Is_ConnectionWaiting()
{
	if(this->Mode != 1)
	{
		return 0;
	}
	
	fd_set fd;
	TIMEVAL tv;

	tv.tv_sec = 0;
	tv.tv_usec = 1000;

	FD_ZERO(&fd);
	FD_SET(this->Socket, &fd);

	if(select((int)this->Socket, &fd, 0, 0, &tv) == -1)
	{
		return 0;
	}

	if(FD_ISSET(this->Socket, &fd))
	{
		FD_CLR(this->Socket, &fd);
		return 1;
	}
	FD_CLR(this->Socket, &fd);
	return 0;
}

bool TCPSocket::RecviveData(char *Data, int *Length)
{
	if(this->Is_DataAvaliable())
	{
		int ret = recv(this->Socket, Data, *Length, 0);
		if(ret <= 0)
		{
			this->Destroy();
			return 0;
		}
		*Length = ret;
	}
	else
	{
		return 0;
	}
	return 1;
}

bool TCPSocket::RecviveData(char *Data, int Length)
{
	if(this->Is_DataAvaliable())
	{
		int ret = recv(this->Socket, Data, Length, 0);
		if(ret <= 0)
		{
			this->Destroy();
			return 0;
		}
	}
	else
	{
		return 0;
	}
	return 1;
}

bool TCPSocket::SendData(const char *Data, int Length)
{
	if(!this->Is_Connected())
	{
		return 0;
	}

	int Send_ = send(this->Socket, Data, Length, 0);
	if(Send_ != Length)
	{
		if(Send_ == -1)
		{
			return 0;
		}
		else
		{
			this->SendData(Data+Send_, Length-Send_);
		}
	}

	return 1;
}

bool TCPSocket::Destroy()
{
	shutdown(this->Socket, SD_BOTH);
	closesocket(this->Socket);

	memset((void *)this, 0, sizeof(TCPSocket));
	return 0;
}

bool TCPSocket::Accept(TCPSocket *NewConnection)
{
	if(!this->Is_ConnectionWaiting())
	{
		return 0;
	}

	sockaddr_in addr;
	int s_sa = sizeof(sockaddr);
	SOCKET client = accept(this->Socket, (sockaddr *)&addr, &s_sa);
	if(client == INVALID_SOCKET) 
	{
		return 0;
	}

	NewConnection->TCPSocket::TCPSocket(client, 0);
	return 1;
}