#include "socket.hpp"


//------------------------- SOCKET Module -----------------------//
//						  v 05 . 03 .  2007						 //
//																 //
//								MT								 //
//---------------------------------------------------------------//


//--- Connect To Host ---//
void CSocket :: ConnectTo (char *host, int portno)
{
	socketfd = socket(AF_INET,SOCK_STREAM,0);
	
	if(socketfd==-1)   
		error.OnError(ERROR_SOCKET_CREATE);

	addr.sin_family = AF_INET;
	addr.sin_port = htons(portno);
	
	if(! inet_aton (host, & addr.sin_addr))
			error.OnError(ERROR_SOCKET_WRONG_IP);
	
	if(connect(socketfd, (struct sockaddr*)&addr, sizeof(addr)) != 0)
			error.OnError(ERROR_SOCKET_OPEN_HOST);
}


//--- Close Host ---//
void CSocket :: CloseHost() 
{
	close (socketfd);
	socketfd = -1;
	
};


//--- Allocate Buffer ---//
void CSocket :: bufalloc(int new_size, char copy)
{
	int old_size = buf_size;


		// --- realloc
	if ( (new_size > old_size) && (copy == 1))
	{
		char *buf_cpy = new char [old_size];

		for (int i = 0; i<old_size; i++)
			buf_cpy[i] = buf [i];

		buffree();
		buf = new char [new_size];

		for (int i = 0; i<old_size; i++) 
			buf [i] = buf_cpy[i];

	} else {
		//--- simple new
		buffree();
		buf = new char [new_size];
	}

	buf_size = new_size;
};


//--- Buffer Free ---//
void CSocket :: buffree()
{
	if (buf_size == 1) 
		delete buf; 
	else delete[] buf;  

	buf_size = 0;
};


//--- Socket Read ---//
void CSocket :: Read(int size)
{
	bufalloc(size, BUF_NOT_COPY);

	if(!read(socketfd, buf, size)) 
		error.OnError(ERROR_SOCKET_CONNECTION_FAULT);	
};


//--- Socket ReadNext ---//
void CSocket :: ReadNext(int size)
{
	int old_size = buf_size;
	int new_size = buf_size + size;
    	
	bufalloc(new_size);

	if(!read(socketfd, & buf[old_size], size)) 
		error.OnError(ERROR_SOCKET_CONNECTION_FAULT);
};


//--- Socket Read ---//
void CSocket :: Write (char *s)
{ 
	if ( !write(socketfd, s, strlen(s)) )
		error.OnError(ERROR_SOCKET_CONNECTION_FAULT);
};


//--- Send Game Command ---// 
void CSocket :: SendCommand (char *s)
// In end of string s will 
// be automatical add "\n"
{ 
	int size = strlen(s);
	char *tmp = new char [size + 2];
		strcpy(tmp, s); 
		tmp[size] = '\n';
		tmp[size+1] = '\0';

	Write(tmp);
	delete[] tmp;
};

//--- Send Game Command With Int ---// 
void CSocket :: SendCommandWithInt(char *s, int i)
{
	#define INT_SIZE 10
	char tmp[INT_SIZE] = {0};
	char *tmp2 = new char [strlen(s)+INT_SIZE+1];

	snprintf (tmp, INT_SIZE, "%d", i);
	strcpy(tmp2, s);
	strcat(tmp2, tmp);
		SendCommand(tmp2);
	delete[] tmp2;
};


//--- Send Game Command With Int, Int ---// 
void CSocket :: SendCommandWithInt2(char *s, int i, int i2)
{
	#define INT_SIZE 10
	char tmp[INT_SIZE] = {0}, tmp3[INT_SIZE] = {0};
	char *tmp2 = new char [strlen(s)+ INT_SIZE+1  + INT_SIZE +1];

	snprintf (tmp, INT_SIZE, "%d", i);
	snprintf (tmp3, INT_SIZE, "%d", i2);

	strcpy(tmp2, s);
	
	strcat(tmp2, tmp);
	strcat(tmp2, " ");
	strcat(tmp2, tmp3);

		SendCommand(tmp2);

	delete[] tmp2;
};


// --- Wait a phrase ---//
int CSocket :: Wait(char* s)
{ 
	int size = strlen(s);
	char *tmp = new char [size+1];
	int i, j;
	
	tmp[size] = '\0';
	
		do {
			Read(sizeof(char));
			for (i=0;  i<size-1; i++)
				tmp[i] = tmp[i+1];
			tmp[i] = (*buf);
			
		} while( strncmp(tmp, s, size) != 0  );

	buf = strdup(tmp);
	buf_size = strlen(buf) + 1;
	delete[] tmp;

 return 1; 
}


// --- Wait 2 - or ---//
int CSocket :: Wait2(char *s, char *s2)
{ 
	int size = strlen(s);
	int size2 = strlen(s2);
	char *tmp = new char[size+1];
	char *tmp2 = new char[size2+1];
	int i;
	
	tmp[size] = '\0';
	tmp2[size2] = '\0';
		
		do {
			Read(sizeof(char));
			for (i=0;  i<size-1; i++)
				tmp[i] = tmp[i+1];
			tmp[i] = (*buf);
			 
			for (i=0;  i<size2-1; i++)
				tmp2[i] = tmp2[i+1];
			tmp2[i] = (*buf);

		} while( (strncmp(tmp, s, size) != 0) && (strncmp(tmp2, s2, size2) != 0) );
 //----------------------------------
	int res = 1;
	
	if (!strncmp(tmp2, s2, size2))
	 { buf = strdup(tmp2); res = -1; } 
	else buf = strdup(tmp);
//----------------------------------	

	buf_size = strlen(buf) + 1;

	delete[] tmp;
	delete[] tmp2;

 return res; 
}





// --- ReadAfterWait a phrase ---//
int CSocket :: ReadAfterWait_Int(char *s, int space, int length)
// and than read int symbols 
//     size of length. 
//    Processing space.
{	
	if ( (length < 1) && (length != -1) ) 
	{ error.OnError(ERROR_SOCKET_LENGTH_ERROR); return 0; };
	
		if (Wait(s) == -1) {
			error.OnQuietError(ERROR_SOCKET_QUIET_NOT_FIND_S);
			return -1;
		}
	
		/* Read(sizeof(char));
		while ( (buf [buf_size-1] != '\n') && (buf_size != length) )
			ReadNext(sizeof(char));
			    
		if ( buf [buf_size-1] != '\n') 
			bufalloc(buf_size+1);
		   
		buf [buf_size-1] = '\0'; */

	return  Read_Int() ;//atoi(buf);
}


// --- ReadAfterWait2 ---//
int CSocket :: ReadAfterWait2_Int(char *s,  char *s2, int space, int length)
// and than read int symbols 
//     size of length. 
//    Processing space.
{	
	if ( (length < 1) && (length != -1) ) 
	{ error.OnError(ERROR_SOCKET_LENGTH_ERROR); return 0; };
	
		if (Wait2(s, s2) == -1) {
			error.OnQuietError(ERROR_SOCKET_QUIET_NOT_FIND_S);
			return -1;
		}

		/*Read(sizeof(char));
		while ( (buf [buf_size-1] != '\n') && (buf_size != length) )
			ReadNext(sizeof(char));

		if ( buf [buf_size-1] != '\n') 
			bufalloc(buf_size+1);
		   
		    buf [buf_size-1] = '\0';*/

 return  Read_Int();//atoi(buf);
}


// --- Read Int at the current position  ---//
int  CSocket :: Read_Int()
{
		Read(sizeof(char));
	//----------------------
		while (    
				   (buf [buf_size-1] != '\n') 
				&& (buf [buf_size-1] != '\0') 
				&& (buf [buf_size-1] != '$' )
			  )
		{
			ReadNext(sizeof(char));
			if (buf_size > 2)
				if ( (buf [buf_size-1] == ' ' ) && (buf [buf_size-2] != ' ') )
					break;
		}
	//----------------------
		
		if ( buf [buf_size-1] != '\n') 
			bufalloc(buf_size+1);
		   
		    buf [buf_size-1] = '\0';

 return atoi(buf);
}


// --- Read String at the current position  ---//
int  CSocket :: Read_Str()
{
		Read(sizeof(char));
	//----------------------
		while (    
				   (buf [buf_size-1] != '\n') 
				&& (buf [buf_size-1] != '\0') 
			  )
		{
			ReadNext(sizeof(char));
			if (buf_size > 2)
				if ( (buf [buf_size-1] == ' ' ) && (buf [buf_size-2] != ' ') )
					break;
		}
	//----------------------
		
		if ( (buf [buf_size-1] != '\n')  &&  (buf [buf_size-1] != ' ') ) 
			bufalloc(buf_size+1);
		   
		    buf [buf_size-1] = '\0';
	
 return buf_size;
}


// --- Get buf Address  ---//
char* CSocket :: GetBufAddr() { return buf; };


// --- Get buf Size  ---//
int CSocket :: GetBufSize() { return buf_size; };


// --- Delete Spaces In Buf  ---//
void CSocket :: DelSpacesInBuf()
{
	char *tmp;
	int new_size = 0;
	int i = 0;
	
	for (i=0; i<buf_size; i++)
		if (buf[i] != ' ') break;
	if (i == buf_size-1) return;
	
	new_size = buf_size - i; 
	tmp = new char [new_size];
	for (int j = 0;  j<new_size;  j++, i++)
		tmp[j] = buf[i];

	bufalloc(new_size);
	for (i=0; i<new_size; i++)
		buf[i] = tmp[i];

	delete[] tmp;
};


