#include <stdio.h>

#include <sys/types.h>
#include <sys/socket.h>

#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include "bot.h"

char *myname = "MiniBot 4000";
char *mynick = "MiniBot";

hash_t mynick_h;

int get_line(char *buffer,int length) {
	int c = fgetc(stdin);
	int r = 0;
	while(c != EOF && r < (length - 1) && (char)c != '\n') {
		(*buffer) = (char)c;
		++buffer;
		++r;
		c = fgetc(stdin);
	}
	*buffer = '\n';
	++buffer;
	*buffer = '\0';
	fprintf(stderr,"\tGet_line:end\n");
	if (c == EOF) {
		return c;
	} else {
		return r + 2;
	}
}

int get_line_soc(int s,char *buffer,int length) {
	char c;
	int r = 0;
	int l = 0;
	while(r != -1 && l < (length - 1) && c != '\n') {
		if (c != '\r') {(*buffer) = c;}
		++buffer;
		++r;
		recv(s,&c,1,0);
	}
	*buffer = '\n';
	++buffer;
	*buffer = '\0';
	if (c == -1) {
		return EOF;
	} else {
		return r + 2;
	}
}

void login(int s) {
	int i;
	char *cp;
	char buffer[BUFSIZE];
	sprintf(buffer,"user guest 8 *: %s\nnick %s\r\n",myname,mynick);
	i = strlen(buffer);
	cp = malloc(i+1);
	strcpy(cp,buffer);
	send(s,cp,i,0);
	free(cp);
}

void join(int s,const char *channel) {
	char *cp;
	int len = strlen(channel);
	len += 5 + 1 + 1;
	cp = malloc(len);
	sprintf(cp,"JOIN %s\r\n",channel);
	send(s,cp,len,0);
	free(cp);
}

void ping(int s,char *buffer) {
	int i;
	char *b2;
	char *temp;
	if(strncmp("PING",buffer,4) == 0) {
		temp = buffer + 4;
		while ((*temp) != ':') {
			++temp;
		}
		b2 = malloc(BUFSIZE);
		sprintf(b2,"PONG %s\r\n",temp);
		i = strlen(b2);
		temp = malloc(i + 1);
		strcpy(temp,b2);
		send(s,temp,i,0);
		printf("%s",temp);
		free(temp);
		free(b2);
	}
}

int text_to_command(char *command) {
	// fprintf(stderr,"text_to_command: %s\n",command);
	hash_t h = hash(command);
	if(h == commands[PRIVMSG]) {
		return PRIVMSG;
	} else if(h == commands[JOIN]) {
		return JOIN;
	} else if(h == commands[QUIT]) {
		return QUIT;
	} else if(h == commands[NICK]) {
		return NICK;
	} else if(h == commands[MODE]) {
		return MODE;
	} else if(h == commands[PART]) {
		return PART;
	}
	return NOCMD;
}

void split_command(int *ct, char *nick, 
		char *channel, char *data, char *buffer) {
	int n,i,r;
	int length = strlen(buffer);
	char *end = buffer + length + 1;
	char *temp = buffer;
	char *mark = buffer;
	char *b2;
	
	/* Find beginning of the Nick */
	while((*temp) == ':' && temp < end) {
		++temp;
	} 
	/* Set Nick */
	while((*temp) != '!' && temp < end) {
		(*(nick++)) = (*(temp++));
	}
	(*nick) = '\0';
	/* Find end of the host */
	while(!isspace(*temp) && temp < end) {
		++temp;
	}
	++temp; /* Skip White Space */
	
	mark = temp; /* Mark Beginning of Command*/
	/* Move to end of Command */
	while(!isspace(*temp) && temp < end) {
		++temp;
	}
	/* Set command type */
	b2 = malloc(temp - mark + 1);
	memset(b2,0,temp - mark + 1);
	strncpy(b2,mark,temp - mark);
	(*ct) = text_to_command(b2);
	free(b2);
	
	++temp; /* Skip White Space */
	
	if ((*ct) == PRIVMSG) {
		/* Set channel */
		while(!isspace(*temp) && temp < end) {
			(*(channel++)) = (*(temp++));
		}
		(*channel) = '\0';
	}
	
	++temp; /* Skip White Space */
	++temp; /* Skip what I hope is a colon */
	
	/* Copy Message Data */
	while((*temp) != '\0' && temp < end) {
		(*(data++)) = (*(temp++));
	}
	(*data) = '\0';
}

/* Speak, yeah say something */
void speak(int s, const char *channel, const char *message) {
	char buffer[BUFSIZE];
	snprintf(buffer,BUFSIZE,"PRIVMSG %s :%s\r\n",channel,message);
	send(s,buffer,strlen(buffer),0);
	printf("[%s][%s]:%s\n",mynick,channel,message);
}

void command(int s, char *buffer) {
	int command_type = NOCMD;
	int talking_to_me = 0;
	int pm = 0; 				/* Private Message */
	char *membuf = malloc(BUFSIZE * 4);	/* Allocate a Memory Buffer */
	char *nick = membuf;			/* Allocate BUFSIZE of it */
	char *data = (membuf + 1*BUFSIZE);	/* to each subbuffer */
	char *channel = (membuf + 2*BUFSIZE);
	char *temp_buf = (membuf + 3*BUFSIZE);
	char *temp_ptr;
	char *word1;
	char *word2;
	hash_t word1_h;
	hash_t word2_h;
	fprintf(stderr,"Start Command Loop\n");
	split_command(&command_type, nick, channel, data, buffer);
	if (command_type == PRIVMSG) {
		if (strcasecmp(channel,mynick) == 0) {
			talking_to_me = 1;
			pm = 1;
			word1 = word(data,1);
			word2 = word(data,2);
		} else {
			word1 = word(data,1);
			if (contains(word1,mynick)) {
				talking_to_me = 1;
				free(word1);
				word1 = word(data,2);
				word2 = word(data,3);
			} else {
				word2 = word(data,2);
			}
		}
		word1_h = hash(word1);
		word2_h = hash(word2);
		printf("\[%s]\[%s]:%s\n", nick, channel, data);
		if(talking_to_me) {
			if(pm) {
				temp_ptr = channel;
				channel = nick;
			}
			if(word1_h == words[ASCII]
				        && word2_h == words[RAVE]) {
				ascii_rave(s,channel);
			} else if(word1_h == words[STATS]) {
				output_stats(s,channel,word2);
			} else if(word1_h == words[KICK]) {
				meta_kick(s,channel,word2);
			} else if(word1_h == words[HUG]) {
				hug(s,channel,word2);
			} else if(pm) {
				speak(s,nick,"Sorry :|");
			}
		}
		free(word1);
		free(word2);
		if (pm) {
			channel = temp_ptr;
		}
		update_stats(nick, channel, data);
	} /*
	     else if (command_type == JOIN) {
		sprintf(b2,"lo %s",nick);
		b3[0] = '#';
		b3[1] = '\0';
		strcat(b3,data);
		speak(s,b3,b2);
	} 
	   */
	free(membuf); /* Free the whole memory buffer */
	fprintf(stderr,"End Command Loop\n");
}

int main() {
	int s,r1,r2;
	int c;
	char buffer_data[BUFSIZE];
	char *buffer = buffer_data;
	struct sockaddr_in addr;
	init_commands();
	init_words();
	mynick_h = hash(mynick);
	
	s = socket(PF_INET,SOCK_STREAM,0);
	inet_aton("194.159.164.195",(struct in_addr *)&(addr.sin_addr.s_addr));
	addr.sin_family = AF_INET;
	addr.sin_port = htons(6667);
	r1 = connect(s,&addr,sizeof(addr));
	if (r1 == 0) {
		printf("Done\n");
	} else {
		printf("Fail\n");
		return 1;
	}
	login(s);
	join(s,"#fu2k");
	r1 = get_line_soc(s,buffer,BUFSIZE);
	r2 = 1;
	while (r1 != EOF && r2 > 0) {
		chomp(buffer,r1); 	/* Remove \r\n from server lines */
		++buffer; 		/* Remove @ from server lines */ 
		//printf("%s\n",buffer); 	/* Print Server Lines */
		if ((*buffer) != ':') {
			printf("%s\n",buffer);
			ping(s,buffer);
		} else {
			command(s,buffer);
		}
		--buffer; 		/* Pull the buffer back to start */
		memset(buffer,0,r1);	/* Clean used buffer, safety :) */
		r1 = get_line_soc(s,buffer,BUFSIZE);
	}
	printf("r1:%d, r2:%d\n",r1,r2);	
	close(s);
	return 0;	
}
