/* * * * * * * * * * * * * * * * 
 * 	 ______     __  __     ______     __  __     ______     ______     __  __    
 *	/\  __ \   /\ \/\ \   /\  == \   /\ \_\ \   /\  __ \   /\  ___\   /\ \/ /    
 *	\ \ \/\ \  \ \ \_\ \  \ \  __<   \ \  __ \  \ \  __ \  \ \ \____  \ \  _"-.  
 *	 \ \_____\  \ \_____\  \ \_____\  \ \_\ \_\  \ \_\ \_\  \ \_____\  \ \_\ \_\ 
 *	  \/_____/   \/_____/   \/_____/   \/_/\/_/   \/_/\/_/   \/_____/   \/_/\/_/ 
 *
 *  - Version : 3L
 *  - By Oubliette
 * * * * * * * * * * * * * * * */

#include "oubhack_sock.h"

#include "oubhack.h"

/* ========================================
	Name : ISocket::ISocket
	Returns :
=========================================== */

ISocket::ISocket( SOCKET sock ){

	this->m_Socket = sock;
	this->m_bIsValid = false;

}

ISocket::ISocket( const char* ccAddr, const char* ccPort ){

	this->m_bIsValid = false;

	WSADATA wsaData;
	SOCKET cSock = INVALID_SOCKET;

	struct addrinfo *result = NULL, *ptr = NULL, hints = {0};

	int iRes;

	// Initialize Winsock
	iRes = WSAStartup( MAKEWORD( 2, 2 ), &wsaData );

	if ( iRes != 0 ) return;

	// Get address information
	ZeroMemory( &hints, sizeof(hints) );

	hints.ai_family = AF_UNSPEC;
	hints.ai_socktype = SOCK_STREAM;
	hints.ai_protocol = IPPROTO_TCP;

	// Resolve the IP address and port
	iRes = getaddrinfo(ccAddr, ccPort, &hints, &result);

	if ( iRes != 0 ) {
		WSACleanup();
		return;
	}

	// Attempt to connect to an address until one succeeds
	iRes = SOCKET_ERROR;

	for ( ptr = result; ptr != NULL; ptr = ptr->ai_next ){

		cSock = socket( ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol );

		if ( cSock == INVALID_SOCKET ){

			WSACleanup();
			return;

		}

		iRes = connect( cSock, ptr->ai_addr, (int)ptr->ai_addrlen );

		if ( iRes == SOCKET_ERROR ){

			closesocket(cSock);
			cSock = INVALID_SOCKET;

		}


	}

	if (cSock == INVALID_SOCKET) {
		WSACleanup();
		return;
	}

	this->m_Socket = cSock;
	this->m_bIsValid = true;

}

/* ========================================
	Name : ISocket::WriteInt
	Returns : void
=========================================== */

void ISocket::WriteInt( int iVal ){

	char buf[ sizeof( int ) ];
	memcpy( &buf, &iVal, sizeof( int ) );

	send( this->m_Socket, buf, sizeof( int ), 0 );

}

/* ========================================
	Name : ISocket::WriteString
	Returns : void
=========================================== */

void ISocket::WriteString( const char* ccStr ){

	std::string strBuf = ccStr;

	this->WriteInt(strBuf.size());

	send(this->m_Socket, ccStr, strBuf.size(), 0 );

	oubhack->Debug(ccStr);

}

/* ========================================
	Name : ISocket::WriteLong
	Returns : void
=========================================== */

void ISocket::WriteLong( long lVal ){

	char buf[ sizeof( long ) ];
	memcpy( &buf, &lVal, sizeof( long ) );

	send( this->m_Socket, buf, sizeof( long ), 0 );

}

/* ========================================
	Name : ISocket::WriteFloat
	Returns : void
=========================================== */

void ISocket::WriteFloat( float fVal ){

	char buf[ sizeof( float ) ];
	memcpy( &buf, &fVal, sizeof( float ) );

	send( this->m_Socket, buf, sizeof( float ), 0 );

}

/* ========================================
	Name : ISocket::WriteDouble
	Returns : void
=========================================== */

void ISocket::WriteDouble( double dVal ){

	char buf[ sizeof( double ) ];
	memcpy( &buf, &dVal, sizeof( double ) );

	send( this->m_Socket, buf, sizeof( double ), 0 );

}

/* ========================================
	Name : ISocket::WriteShort
	Returns : void
=========================================== */

void ISocket::WriteShort( short sVal ){

	char buf[ sizeof( short ) ];
	memcpy( &buf, &sVal, sizeof( short ) );

	send( this->m_Socket, buf, sizeof( short ), 0 );

}


/* ========================================
	Name : ISocket::WriteI64
	Returns : void
=========================================== */

void ISocket::WriteI64( int64_t llVal ){

	char buf[ sizeof( int64_t ) ];
	memcpy( &buf, &llVal, sizeof( int64_t ) );

	send( this->m_Socket, buf, sizeof( int64_t ), 0 );

}


/* ========================================
	Name : ISocket::WriteUI64
	Returns : void
=========================================== */

void ISocket::WriteUI64( unsigned long long ullVal ){

	char buf[ sizeof( unsigned long long ) ];
	memcpy( &buf, &ullVal, sizeof( unsigned long long ) );

	send( this->m_Socket, buf, sizeof( unsigned long long ), 0 );


}

/* ========================================
	Name : ISocket::WriteBool
	Returns : void
=========================================== */

void ISocket::WriteBool( bool bVal ){

	char buf[ sizeof( bool ) ];
	memcpy( &buf, &bVal, sizeof( bool ) );

	send( this->m_Socket, buf, sizeof( bool ), 0 );

}

/* ========================================
	Name : ISocket::WriteChar
	Returns : void
=========================================== */

void ISocket::WriteChar( char cVal ){

	char buf[ sizeof( char ) ];
	memcpy( &buf, &cVal, sizeof( char ) );

	send( this->m_Socket, buf, sizeof( char ), 0 );

}

/* ========================================
	Name : ISocket::WriteByte
	Returns : void
=========================================== */

void ISocket::WriteByte( byte bVal ){

	char buf[ sizeof( byte ) ];
	memcpy( &buf, &bVal, sizeof( byte ) );

	send( this->m_Socket, buf, sizeof( byte ), 0 );

}

/* ========================================
	Name : ISocket::WriteBytes
	Returns : void
=========================================== */

void ISocket::WriteBytes( byte bVal[], int iSize ){

	for (int i = 0; i < iSize; i++){

		this->WriteByte(bVal[i]);

	}

}

/* ========================================
	Name : ISocket::ReadInt
	Returns : int
=========================================== */

int ISocket::ReadInt( ){
	
	int obj;

	char buf[ sizeof( int ) ];

	recv(this->m_Socket, buf, sizeof( int ), 0);
	memcpy(&obj, &buf, sizeof( int ) );

	return obj;
	 
}

/* ========================================
	Name : ISocket::ReadString
	Returns : const char*
=========================================== */

std::string ISocket::ReadString(){

	std::string sBuf = "";

	int iLen = this->ReadInt();

	for (int i = 0; i < iLen; i ++){

		char c = this->ReadChar();

		sBuf += c;
	
	}

	return sBuf;

}

/* ========================================
	Name : ISocket::ReadLong
	Returns : long
=========================================== */

long ISocket::ReadLong( ){

	long obj;

	char buf[ sizeof( long ) ];

	recv(this->m_Socket, buf, sizeof( long ), 0);
	memcpy(&obj, &buf, sizeof( long ) );

	return obj;

}

/* ========================================
	Name : ISocket::ReadFloat
	Returns : float
=========================================== */

float ISocket::ReadFloat( ){
		
	float obj;

	char buf[ sizeof( float ) ];

	recv(this->m_Socket, buf, sizeof( float ), 0);
	memcpy(&obj, &buf, sizeof( float ) );

	return obj;

}

/* ========================================
	Name : ISocket::ReadDouble
	Returns : double
=========================================== */

double ISocket::ReadDouble( ){
	
	double obj;

	char buf[ sizeof( double ) ];

	recv(this->m_Socket, buf, sizeof( double ), 0);
	memcpy(&obj, &buf, sizeof( double ) );

	return obj;

}

/* ========================================
	Name : ISocket::ReadShort
	Returns : short
=========================================== */

short ISocket::ReadShort( ){
	
	short obj;

	char buf[ sizeof( short ) ];

	recv(this->m_Socket, buf, sizeof( short ), 0);
	memcpy(&obj, &buf, sizeof( short ) );

	return obj;

}

/* ========================================
	Name : ISocket::ReadI64
	Returns : long long
=========================================== */

long long ISocket::ReadI64( ){

	long long obj;

	char buf[ sizeof( long long ) ];

	recv(this->m_Socket, buf, sizeof( long long ), 0);
	memcpy(&obj, &buf, sizeof( long long ) );

	return obj;

}


/* ========================================
	Name : ISocket::ReadUI64
	Returns : unsigned long long
=========================================== */

unsigned long long ISocket::ReadUI64( ){

	unsigned long long obj;

	char buf[ sizeof( unsigned long long ) ];

	recv(this->m_Socket, buf, sizeof( unsigned long long ), 0);
	memcpy(&obj, &buf, sizeof( unsigned long long ) );

	return obj;

}

/* ========================================
	Name : ISocket::ReadBool
	Returns : bool
=========================================== */

bool ISocket::ReadBool( ){

	bool obj;

	char buf[ sizeof( bool ) ];

	recv(this->m_Socket, buf, sizeof( bool ), 0);
	memcpy(&obj, &buf, sizeof( bool ) );

	return obj;

}

/* ========================================
	Name : ISocket::ReadChar
	Returns : char
=========================================== */

char ISocket::ReadChar( ){

	char obj;

	char buf[ sizeof( char ) ];

	recv(this->m_Socket, buf, sizeof( char ), 0);
	memcpy(&obj, &buf, sizeof( char ) );

	return obj;

}

/* ========================================
	Name : ISocket::ReadByte
	Returns : char
=========================================== */

byte ISocket::ReadByte( ){

	byte obj;

	char buf[ sizeof( byte ) ];

	if (recv(this->m_Socket, buf, sizeof( byte ), 0) != sizeof(byte)) oubhack->Debug("Failed");

	memcpy(&obj, &buf, sizeof( byte ) );

	return obj;

}

/* ========================================
	Name : ISocket::ReadByte
	Returns : char
=========================================== */

byte* ISocket::ReadBytes( int iSize ){

	byte obj[1024];

	for (int i = 0; i < iSize; i++){

		obj[i] = this->ReadByte();

	}

	return obj;

}

/* ========================================
	Name : ISocket::ReadByte
	Returns : char
=========================================== */

const char* ISocket::ReadBytes2String( int iSize, int* iRead ){

	std::string srbBuf  = "";

	char buf[1024];

	*iRead = recv( this->m_Socket, buf, iSize, 0 );

	if (*iRead != 1024){

		oubhack->Debug("Adding null char");
		srbBuf = buf;
		srbBuf += '\0';
		srbBuf.resize(*iRead + 1);

	}



	return srbBuf.c_str();

}

/* ========================================
	Name : ISocket::IsValid
	Returns : bool
=========================================== */

bool ISocket::IsValid( ){

	return this->m_bIsValid;

}

/* ========================================
	Name : ISocket::Shutdown
	Returns : void
=========================================== */

void ISocket::Shutdown( ){

	if ( !this->IsValid() ) return; 

	WSACleanup();
	closesocket( this->m_Socket );

}