#include<iostream.h>
#include<stdlib.h>
#include<stdio.h>
#include<fstream.h>
#include<winsock.h>

short MYPROGLISTENPORT = 10100;
short SERVERLISTENPORT = 10100;
int MYPROGNEWLISTENPORT = 15000;
int SERVERNEWLISTENPORT;
short BACKLOG = 1;
char SERVERIPADDRESS[] = "217.205.42.212";
char CHARNAME[50];
int VALIDCOORDS[100][2];
int CURRENTCOORD = 0;
int PINGPACKETSSINCETELEPORT = 0;
int LAST_SIGHTED_WAS_MONSTER = 0;
int CURRENT_X = 0;
int CURRENT_Y = 0;
char RECENT_MONSTERS[10][25];
int CURRENT_MONSTER = 0;
int IGNORE_PACKETS_TILL_PING = 0;
int ENEMIES_KILLED_SINCE_PING = 0;

fd_set master;  // list of all fd
fd_set read_fds;
unsigned int login_server_fd;
unsigned int login_client_fd;
unsigned int pri_server_fd = -10;
unsigned int pri_client_fd = -10;
unsigned int sec_server_fd = -10;
unsigned int sec_client_fd = -10;
struct sockaddr_in login_client_addr;
struct sockaddr_in login_server_addr;
struct sockaddr_in login_myprog_addr;
struct sockaddr_in pri_client_addr;
struct sockaddr_in pri_server_addr;
struct sockaddr_in pri_myprog_addr;
struct sockaddr_in sec_client_addr;
struct sockaddr_in sec_server_addr;
struct sockaddr_in sec_myprog_addr;
int nbytes;
char splitbuf[20000][500];
FILE *log = 0;
fstream coord;
int k = 0;
int CONNECTIONS = 0;

void getsettings();
#include"settings.cpp"
#include"actions.h"
#include"filters.h"
#include"actions.cpp"
#include "filters.cpp"

int main(void)
{
	//Read in settings.cfg
	getsettings();

	//Start Redmoon
	if( RM_AUTOSTART )
	{
		printf( "Starting Redmoon...\n" );
		system( RM_LOCATION );
	}

	if ( ( log = fopen( "loggedpackets.txt", "w")) == NULL )
	{
		printf("Error opening file loggedpackets.txt\n");
		exit(EXIT_FAILURE);
	}

	//Get local socket settings correct
	login_myprog_addr.sin_family = AF_INET;
	login_myprog_addr.sin_port = htons( MYPROGLISTENPORT );
	login_myprog_addr.sin_addr.s_addr = htonl( INADDR_ANY );
	memset( &( login_myprog_addr.sin_zero ), '\0', 8 );

	WSADATA wsaData;
	if( WSAStartup( MAKEWORD( 1, 1 ), &wsaData ) != 0 )
	{
		cout << "WSAStartup failed.\n";
		exit( 1 );
	}


	//Get myprog listen port ready for connection to RM client
	int sin_size;
	char yes = '1';

	if( ( login_client_fd = socket( AF_INET, SOCK_STREAM, 0 ) ) == -1 )
	{
		perror( "socket" );
		printf( "socket error in main_client_fd\n" );
		fprintf( log, "socket error in main_client_fd\n" );
		exit( 1 );
	}
	if( setsockopt( login_client_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof( int ) ) == -1 )
	{
		perror( "setsockopt" );
		exit( 1 );
	}

	if( bind( login_client_fd, ( struct sockaddr * )&login_myprog_addr, sizeof( struct sockaddr ) ) == -1 )
	{
		perror( "bind" );
		exit( 1 );
	}

	listen( login_client_fd, BACKLOG );
	printf( "Listening for Redmoon Client..." );
	fprintf( log, "Listening for Redmoon Client..." );

	sin_size = sizeof( struct sockaddr_in );

	login_client_fd = accept( login_client_fd, ( struct sockaddr * )&login_client_addr, &sin_size );
	if( login_client_fd == -1 )
	{
		perror( "accept" );
		exit( 1 );
	}
	printf( "Done\n" );
	fprintf( log, "Done\n" );
	printf( "Connecting to Redmoon Server..." );
	fprintf( log, "Connecting to Redmoon Server..." );


	//Open socket for connection to Redmoon server
	if( ( login_server_fd = socket( AF_INET, SOCK_STREAM, 0 ) ) == -1 )
	{
		perror( "socket" );
		exit( 1 );
	}


	login_server_addr.sin_family = AF_INET;
	login_server_addr.sin_port = htons( SERVERLISTENPORT );
	login_server_addr.sin_addr.s_addr = inet_addr( SERVERIPADDRESS );
	memset( &( login_server_addr.sin_zero ), '\0', 8 );

	if( connect( login_server_fd, ( struct sockaddr * )&login_server_addr, sizeof( struct sockaddr ) ) == -1 )
	{
		perror( "connect" );
		exit( 1 );
	}
	printf( "Done\n" );
	fprintf( log, "Done\n" );


	FD_ZERO( &master ); // initialize to zero
	FD_ZERO( &read_fds ); // same

	FD_SET( login_client_fd, &master ); // add client_fd to master list
	FD_SET( login_server_fd, &master ); // add server_fd to master list
	CONNECTIONS = 2;

	char buf[1000000];

	//generate_coords_from_file( "by.", 0 );

	//Recieve packets from client and server, forward all exactly as recieved
	while( 1 )
	{
		read_fds = master;  //Refresh the read_fds list
		if( select( CONNECTIONS, &read_fds, NULL, NULL, NULL ) == -1 )
		{
			perror( "select" );
			printf( "There was an error in select.\n" );
			fprintf( log, "There was an error in select.\n" );
		}
		if( FD_ISSET( login_client_fd, &read_fds )) //Data from login_client_fd
		{
			if(( nbytes = recv( login_client_fd, buf, sizeof(buf), 0 )) <= 0 ) //Recieve it
			{
				if( nbytes == 0 ) // Client closed connection
				{
					printf( "login_client_fd connection was closed.\n" );
					fprintf( log, "login_client_fd connection was closed.\n" );
					break;
				}
				else
				{
					perror( "recv" );
					printf( "recv error in login_client_fd.\n" );
					fprintf( log, "recv error in login_client_fd.\n" );
				}
			}
			else
			{
				buf[ nbytes ] = '\0';
				int max = SplitBuf( buf );
				int q = 0;
				while( buf[q] != 0 )
				{
					fprintf( log, "%d ", buf[q] );
					q++;
				}
				fflush( log );
				for( int i = 0; i < max; i++ )
				{
					LoginClientPacket( splitbuf[i] );
				}
				FD_CLR( login_client_fd, &read_fds );
			}
		}
		if( FD_ISSET( login_server_fd, &read_fds )) //Data from login_server_fd
		{
			if(( nbytes = recv( login_server_fd, buf, sizeof(buf), 0 )) <= 0 ) //Recieve it
			{
				if( nbytes == 0 ) // Server closed connection
				{
					printf( "login_server_fd connection was closed.\n" );
					fprintf( log, "login_server_fd connection was closed.\n" );
					break;
				}
				else
				{
					perror( "recv" );
					printf( "recv error in login_server_fd.\n" );
					fprintf( log, "recv error in login_server_fd.\n" );
				}
			}
			else
			{
				buf[ nbytes ] = '\0';
				int max = SplitBuf( buf );
				for( int i = 0; i < max; i++ )
				{
					LoginServerPacket( splitbuf[i] );
				}
				FD_CLR( login_server_fd, &read_fds );
			}
		}
		if( FD_ISSET( pri_client_fd, &read_fds ) ) //Data from main_client_fd
		{
			if(( nbytes = recv( pri_client_fd, buf, sizeof(buf), 0 )) <= 0 ) //Recieve it
			{
				if( nbytes == 0 ) // Client closed connection
				{
					printf( "pri_client_fd connection closed.\n" );
					fprintf( log, "pri_client_fd connection closed.\n" );
					FD_CLR( pri_client_fd, &master );
					FD_CLR( pri_server_fd, &master );
					FD_ZERO( &read_fds );
					closesocket( pri_client_fd );
					closesocket( pri_server_fd );
					CONNECTIONS = CONNECTIONS - 2;
				}
				else
				{
					perror( "recv" );
					printf( "recv error in pri_client_fd.\n" );
					fprintf( log, "recv error in pri_client_fd.\n" );
				}
			}
			else
			{
				buf[ nbytes ] = '\0';
				int max = SplitBuf( buf );
				for( int i = 0; i < max; i++ )
				{
					PriClientPacket( splitbuf[i] );
				}
				FD_CLR( pri_client_fd, &read_fds );
			}
		}
		if( FD_ISSET( pri_server_fd, &read_fds ) ) //Data from main_server_fd
		{
			if(( nbytes = recv( pri_server_fd, buf, sizeof(buf), 0 )) <= 0 ) //Recieve it
			{
				if( nbytes == 0 ) // Server closed connection
				{
					printf( "pri_server_fd connection closed.\n" );
					fprintf( log, "pri_server_fd connection closed.\n" );
					FD_CLR( pri_server_fd, &master );
					FD_CLR( pri_client_fd, &master );
					FD_ZERO( &read_fds );
					closesocket( pri_client_fd );
					closesocket( pri_server_fd );
					CONNECTIONS = CONNECTIONS - 2;
				}
				else
				{
					perror( "recv" );
					printf( "recv error in pri_server_fd.\n" );
					fprintf( log, "recv error in pri_main_server_fd.\n" );
				}
			}
			else
			{
				buf[ nbytes ] = '\0';
				int max = SplitBuf( buf );
				for( int i = 0; i < max; i++ )
				{
					PriServerPacket( splitbuf[i] );
				}
				FD_CLR( pri_server_fd, &read_fds );
			}
		}
		if( FD_ISSET( sec_client_fd, &read_fds ) ) //Data from main_client_fd
		{
			if(( nbytes = recv( sec_client_fd, buf, sizeof(buf), 0 )) <= 0 ) //Recieve it
			{
				if( nbytes == 0 ) // Client closed connection
				{
					printf( "sec_client_fd connection closed.\n" );
					fprintf( log, "sec_client_fd connection closed.\n" );
					FD_CLR( sec_client_fd, &master );
					FD_CLR( sec_server_fd, &master );
					FD_ZERO( &read_fds );
					closesocket( sec_client_fd );
					closesocket( sec_server_fd );
					CONNECTIONS = CONNECTIONS - 2;
				}
				else
				{
					perror( "recv" );
					printf( "recv error in sec_client_fd.\n" );
					fprintf( log, "recv error in sec_client_fd.\n" );
				}
			}
			else
			{
				buf[ nbytes ] = '\0';
				int max = SplitBuf( buf );
				for( int i = 0; i < max; i++ )
				{
					SecClientPacket( splitbuf[i] );
				}
				FD_CLR( sec_client_fd, &read_fds );
			}
		}
		if( FD_ISSET( sec_server_fd, &read_fds ) ) //Data from main_server_fd
		{
			if(( nbytes = recv( sec_server_fd, buf, sizeof(buf), 0 )) <= 0 ) //Recieve it
			{
				if( nbytes == 0 ) // Server closed connection
				{
					printf( "sec_server_fd connection closed.(UNEXPECTED)\n" );
					fprintf( log, "sec_server_fd connection closed. (UNEXPECTED)\n" );
					FD_CLR( sec_client_fd, &master );
					FD_CLR( sec_server_fd, &master );
					closesocket( sec_client_fd );
					closesocket( sec_server_fd );
					CONNECTIONS = CONNECTIONS - 2;

				}
				else
				{
					perror( "recv" );
					printf( "recv error in sec_server_fd.\n" );
					fprintf( log, "recv error in sec_server_fd.\n" );
				}
			}
			else
			{
				buf[ nbytes ] = '\0';
				int max = SplitBuf( buf );
				for( int i = 0; i < max; i++ )
				{
					SecServerPacket( splitbuf[i] );
				}
				FD_CLR( sec_server_fd, &read_fds );
			}
		}
	}

	fclose( log );
	printf( "Quitting...\n" );
	closesocket( sec_client_fd );
	closesocket( sec_server_fd );
	closesocket( pri_client_fd );
	closesocket( pri_server_fd );
	closesocket( login_client_fd );
	closesocket( login_server_fd );


	WSACleanup();
	printf( "Press any key to continue" );
	cin.get();

	return( EXIT_SUCCESS );
}