#include "ClientConnection.h"
#include "Server.h"



// GET RESPONSE
//
// HTTP/1.1 200 OK
// Date: Tue, 14 Jul 2009 21:47:40 GMT
// Server: Apache
// Last-Modified: Tue, 14 Jul 2009 19:56:46 GMT
// Accept-Ranges: bytes
// Content-Length: 90369
// Connection: close
// Content-Type: text/html; charset=iso-8859-1





ClientConnection::ClientConnection(Server* s){
	this->server=s;
	this->tx="";
	this->rx="";
	this->password_found="";
	this->is_running=false;
}

ClientConnection::~ClientConnection(){
	this->socket_client.close();
	delete this;
}

void ClientConnection::createThread() {
	this->is_running=true;
	pthread_detach(pthread_self());
	try {
		socket_client >> this->rx; // WAIT CONNECT
		if (this->rx=="CONNECT" && this->server->nb_of_job_done<this->server->tab_job.size()) {
			this->CONNECT_ACK();
			sleep(1);
	
			socket_client >> this->rx; // WAIT REQUEST or REPORT
			if (this->rx.substr(0,7)=="REQUEST") {
	
				if (this->rx.substr(8,6)=="MODULE") {
	
					this->SEND_MODULE();

				} else if (this->rx.substr(8,6)=="PARAMS") {
	
					this->SEND_PARAM();
					this->WAIT_PARAM_ACK();
					this->QUIT();

				} else if (this->rx.substr(8,4)=="JOBS") {
	
					this->SEND_JOBS();
					this->WAIT_JOBS_ACK();
					this->QUIT();
				}
			} else if (this->rx.substr(0,6)=="REPORT"){
	
				if (this->rx.substr(7,7)=="RESULTS") {
					this->COMPUTE_RESULTS();
					this->QUIT();
				}
			}
		}
		this->is_running=false;
		this->socket_client.close();
		if (this->server->password!=""){
			this->server->is_running=false;
			this->server->nb_of_job_attributed=0;
			int pid=getpid();
			kill(pid,SIGINT);
		}
		this->exitThread();

	} catch ( SocketException& e ) { 
		if (errno!=0) cerr << "ERROR(" << errno << ") in socket : " << strerror(errno) << endl;
		this->is_running=false;
		this->socket_client.close();
		this->exitThread();
	}
	
}



void ClientConnection::CONNECT_ACK(void){
	cout << "- CONNECT_ACK(" << this->id << ")" << endl;
	this->tx="CONNECT_ACK";
	socket_client << this->tx;
	this->tx="";
}



void ClientConnection::SEND_MODULE(void){
	cout << "- SEND_MODULE(" << this->id << ")" << endl;
	string extension;
	if (this->rx.substr(15)=="WIN32") extension=".dll";
	else if (this->rx.substr(15)=="UNIX") extension=".so";
	string tmp=MODULE_TO_SEND+extension;

	cerr << "\tSENDING MODULE : " << tmp << endl;

	ifstream vFile (tmp.c_str(), ios::in|ios::binary|ios::ate); // ouverture du fichier en mode binary
	if (vFile.is_open()) { // verification du flux avant utilisation
		int size = vFile.tellg(); // recuperation de la longueur du fichier
		char* Memblock = new char [size]; // initialisation du char* e la bonne taille
		vFile.seekg (0, ios::beg); // on se place au debut du fichier
		vFile.read (Memblock, size); // on lit le nombre d'octet correspondant e la taille
		vFile.close(); // on ferme le flux

		for (int i=0;i<size;i++) {
			char c[1];
			c[0]=Memblock[i];
			socket_client.Socket::send(c);
		}
		cerr << "\t" << size << " bytes sent" << endl;
	}

	this->tx="";	

}


void ClientConnection::WAIT_MODULE_ACK(void){
	cout << "- WAIT_MODULE_ACK(" << this->id << ")" << endl;
	while (this->rx!="MODULE_ACK"){
		socket_client >> this->rx;
	}
}


void ClientConnection::SEND_PARAM(void){
	cout << "- SEND_PARAM(" << this->id << ")" << endl;
	std::ostringstream oss;
	oss << "PARAM" << this->server->min_size << "|" << this->server->max_size << "|" << this->server->chars_allowed << "|" << this->server->salt << "|" << this->server->hash_to_hack;
	socket_client << oss.str();	
}


void ClientConnection::WAIT_PARAM_ACK(void){
	cout << "- WAIT_PARAM_ACK(" << this->id << ")" << endl;
	while (this->rx!="PARAM_ACK"){
		socket_client >> this->rx;
	}
}


void ClientConnection::SEND_JOBS(void){
	cout << "- SEND_JOBS(" << this->id << ")" << endl;
	this->tx="JOBS|";
	int idx;
	for (idx=0;idx<NB_OF_JOBS_TO_SEND;idx++){
		Job* j=this->server->AvailableJobs();
		if (j!=NULL) this->tx+=j->begin+"|";
	}
	if (idx==0) this->tx="JOBS|";
	socket_client << this->tx;
}

void ClientConnection::WAIT_JOBS_ACK(void){
	cout << "- WAIT_JOBS_ACK(" << this->id << ")" << endl;
	while (this->rx!="JOBS_ACK"){
		socket_client >> this->rx;
	}
}

void ClientConnection::COMPUTE_RESULTS(void){
	cout << "- COMPUTE_RESULTS(" << this->id << ")" << endl;
	char** results=explode((char*)this->rx.substr(15).c_str(),'|');
	for (int idx=0;results[idx]!=NULL && results[idx+1]!=NULL;idx+=2){
		string res=results[idx];
		server->ReportJob(res);
		if (strcmp(results[idx+1]," ")!=0) {	
			this->server->config->setValeur(MAIN_SECTION,"password",results[idx+1]);
			this->server->password=results[idx+1];
		}
	}
	
}


void ClientConnection::QUIT(void){
	cout << "- QUIT(" << this->id << ")" << endl << endl;
	this->tx="QUIT";
	socket_client << this->tx;
}




char** ClientConnection::explode(char* str,char separator){
	int  nbstr = 1;
	int  from = 0;
	char** res = (char **) malloc(sizeof (char *));
	int len = strlen(str);
	for (int i = 0; i <= len; ++i){
		if ((i == len) || (str[i] == separator)){
			res = (char **) realloc(res, ++nbstr * sizeof (char *));
			res[nbstr - 2] = (char *) malloc((i - from + 1) * sizeof (char));
			for (int j = 0; j < (i - from); ++j)
				res[nbstr - 2][j] = str[j + from];
			res[nbstr - 2][i - from] = '\0';
			from = i + 1;
			++i;
		}
	}
	res[nbstr - 1] =  NULL;
	return res;
}
