#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <gtk/gtk.h>
#include <unistd.h>
#include <signal.h>
#include "gtkhtml.h"
#include "libirc.h"

#define BUF_LEN 2048


typedef struct _ircuser
{
    	gchar name[128];
    	int count;
	GList *channels;
} ircuser;

typedef struct _chatwindow
{
	gchar name[128];
	GtkWidget *window;
	GtkWidget *entry;
	GtkWidget *chat;
	GtkWidget *vbox;
	GtkWidget *scroll;
} chatwindow;


GList *channels = NULL;
GList *ircusers = NULL;

irc_conn *connection;

void send_message (GtkWidget *widget, chatwindow *cw);
chatwindow *find_channel_by_name(gchar *name);
void open_chat (irc_conn *conn, gchar *name);

gchar * irc_normalize( gchar * user )
{
	int i = 0;
	int j = 0;
	static gchar buff[255];
	for( i = 0; user[i]; i++ )
	{
		if( user[i] != '@' && user[i] != '+' && user[i] != ' '  )
		{
			buff[j++] = user[i];
		}
	}
	buff[j] = '\0';
	return buff;
}

gchar * irc_channel_normalize( gchar * channel )
{
	static gchar buff[255];
	gchar * c = irc_normalize( channel );

	if(c[0] == '#')
	{
		strcpy( buff, c );
	}
	else
	{
		buff[0] = '#';
		strcpy( buff+1, c );
	}
	return buff;
}

void cdump()
{
	GList *ctemp;
	GList *itemp = ircusers;

	while (itemp)
	{
		ircuser *iu = (ircuser *)(itemp->data);
		ctemp = iu->channels;
//		printf("%s\n", iu->name);
		while (ctemp)
		{
			gchar *cc = (gchar *)(ctemp->data);
	//		printf("\t%s\n", cc);
			ctemp=ctemp->next;
		}
		itemp=itemp->next;
	}
}

ircuser *find_irc_user_by_name(gchar *name)
{
	GList *itemp = ircusers;
	while (itemp)
	{
		ircuser *iu = (ircuser *)(itemp->data);
		if (g_strcasecmp(iu->name, name) == 0)
		{
			return iu;
		}
		itemp = itemp->next;
	}
	return NULL;
}

char * is_user_in_chan(gchar *user, gchar *channel)
{
	ircuser *iu = find_irc_user_by_name(user);
	GList *ctemp;

	if (!iu) { return 0; }
	ctemp = iu->channels;
//	printf("Checking channels of: %s\n", iu->name);
	while (ctemp)
	{
		gchar *c = (gchar *)(ctemp->data);
//		printf("\tchannel: %s\n", c);
		if (g_strcasecmp(c, channel) == 0)
		{
			return c;
		}
		ctemp=ctemp->next;
	}	
	return 0;
}

void add_channel_to_user(gchar *user, gchar *channel)
{
	ircuser *iu = find_irc_user_by_name(user);
//	printf("BEFORE\n");
	cdump();
	if (!iu)
	{
		iu = g_new0(ircuser, 1);
		strcpy(iu->name, user);
		iu->channels = NULL;
		iu->count=0;
		ircusers = g_list_append(ircusers, iu);
		iu = find_irc_user_by_name(user);
	}

	if (is_user_in_chan(user, channel)) { return; }
//	printf("%s aint in %s\n", user, channel);
	iu->count = iu->count + 1;
	iu->channels = g_list_append(iu->channels, strdup(channel));
//	printf("AFTER\n");
	cdump();
}

void remove_channel_from_user(gchar *user, gchar *channel)
{
	ircuser *iu = find_irc_user_by_name(user);
	GList *ctemp;
	char * my_chan;

//	printf("BEFORE\n");
	cdump();
	if (!iu)
	{
		return;
	}

	if (!(my_chan = is_user_in_chan(user, channel))) 
	{ 
		return; 
	}
	iu->channels = g_list_remove(iu->channels, my_chan);
	free(my_chan);
	iu->count = (iu->count) - 1;
	if (iu->count == 0)
	{
		printf("Count is 0 for %s, removing.\n", iu->name);
		ircusers = g_list_remove(ircusers, iu);
	}	
//	printf("AFTER\n");
	cdump();
}

void send_private (chatwindow *cw, gchar *buff)
{
	gchar **b;
	chatwindow *c;

	b = g_strsplit(buff, " ", 2);
	c = find_channel_by_name(b[1]);
	if (!c)
	{
		open_chat(connection, b[1]);
		c = find_channel_by_name(b[1]);
	}
	
	gtk_entry_set_text(GTK_ENTRY(c->entry), b[2]);
	send_message(NULL, c);
}

void parse_join ( chatwindow *c, gchar *buff)
{
	gchar **b;
	chatwindow *cw;
	gchar buff2[BUF_LEN];

	b = g_strsplit(buff, " ", 1);
	cw = find_channel_by_name(b[1]);
	if (cw)
	{
		g_snprintf(buff2, BUF_LEN, "<FONT COLOR=\"#FF0077\"><B><I>* You are already a member of %s</I></B></FONT><BR>", b[1]);
		gtk_html_append_text(GTK_HTML(c->chat), buff2, 0);
		return;
	}
	open_chat(connection, b[1]);
}

void parse_action ( chatwindow *c, gchar *buff)
{
	gchar **b;
	gchar buff2[BUF_LEN];
	
	b = g_strsplit(buff, " ", 1);

	g_snprintf(buff2, BUF_LEN, "<FONT COLOR=\"#666699\"><B><I>%s %s</I></B></FONT><BR>", connection->nick, b[1]);	
	gtk_html_append_text(GTK_HTML(c->chat), buff2, 0);

	irc_send_action (connection, c->name, b[1]);
}

void parse_topic ( chatwindow *c, gchar *buff )
{
	int x;
	int sc;
	gchar **b;
	gchar buff2[BUF_LEN];

	sc = 0;

	for (x = 0; x < strlen(buff); x++)
	{
		if (buff[x] == ' ') 
			sc++;
	}		
	
	if (sc == 0)
	{
		irc_chat_room_set_topic(connection, irc_channel_normalize(c->name), NULL);
	} 
	else
	if (sc == 1)
	{
		b = g_strsplit(buff, " ", 1);
		if (b[1][0] == '#') 
		{
			irc_chat_room_set_topic(connection, irc_channel_normalize(b[1]), NULL);
		}
		else
		{
			irc_chat_room_set_topic(connection, irc_channel_normalize(c->name), b[1]);		
		}
	}
	else
	{
		b = g_strsplit(buff, " ", 2);
		if (b[1][0] == '#') 
		{
			irc_chat_room_set_topic(connection, irc_channel_normalize(b[1]), b[2]);
		}
		else
		{
			g_snprintf(buff2, BUF_LEN, "%s %s", b[1], b[2]);
			irc_chat_room_set_topic(connection, irc_channel_normalize(c->name), buff2);
		}
	}
}

void parse_version ( chatwindow *c, gchar *buff )
{
	gchar **b;
	gchar buff2[BUF_LEN];

	b = g_strsplit(buff, " ", 1);
	
	g_snprintf(buff2, BUF_LEN, "<FONT COLOR=\"#DD4444\"><B><I>VERSION %s</I></B></FONT><BR>", connection->nick, b[1]);
	gtk_html_append_text(GTK_HTML(c->chat), buff2, 0);
	
	irc_send_ctcp_version(  connection, b[1] );
}

void send_message (GtkWidget *widget, chatwindow *cw) 
{
	gchar buff[2048];
	gchar buff2[2048];
	int tmp = 0;

	strcpy(buff2, gtk_entry_get_text(GTK_ENTRY(cw->entry)));
/*
	if ( (g_strncasecmp(buff2, "/me ", 4) == 0) && (strlen(buff2)>4))
	{
		gtk_editable_delete_text(GTK_EDITABLE(cw->entry), 0, -1);
		parse_action(cw, buff2);
		return;
	}

	if ( (g_strncasecmp(buff2, "/version ", 10) == 0) && (strlen(buff2)>10))
	{
		gtk_editable_delete_text(GTK_EDITABLE(cw->entry), 0, -1);
		parse_version(cw, buff2);
		return;
	}

	if ( (g_strncasecmp(buff2, "/topic", 6) == 0))
	{
		gtk_editable_delete_text(GTK_EDITABLE(cw->entry), 0, -1);
		parse_topic(cw, buff2);
		return;
	}

*/
	gtk_editable_delete_text(GTK_EDITABLE(cw->entry), 0, -1);	

	tmp = irc_parse_command(connection, cw->name, buff2);
	if (tmp == 0)  
	{
		gchar **tmpg;
		chatwindow *tmpc;

		tmpg = g_strsplit(buff2, " ", 2);
		tmpc = find_channel_by_name(tmpg[1]);
		if (!tmpc)
		{
			open_chat(connection, tmpg[1]);
			tmpc = find_channel_by_name(tmpg[1]);
		}
	
		g_snprintf(buff, 2048, "<FONT COLOR=\"#0000ff\"><B>&lt;%s&gt;</B></FONT> %s<BR>", connection->nick, tmpg[2]); 
		gtk_html_append_text(GTK_HTML(tmpc->chat), buff, 0);
		return;
	}
	else
	if (tmp == 2)
	{
		gchar **tmpg;

		tmpg = g_strsplit(buff2, " ", 1);
        	g_snprintf(buff2, BUF_LEN, "<FONT COLOR=\"#666699\"><B><I>%s %s</I></B></FONT><BR>", connection->nick, tmpg[1]);  
        	gtk_html_append_text(GTK_HTML(cw->chat), buff2, 0);

		return ;

	}

	if (tmp == -1) { return; }

	g_snprintf(buff, 2048, "<FONT COLOR=\"#0000ff\"><B>&lt;%s&gt;</B></FONT> %s<BR>", connection->nick, buff2);

	gtk_html_append_text(GTK_HTML(cw->chat), buff, 0);

	irc_send_privmsg(connection, cw->name, buff2); 
}

chatwindow * find_channel_by_name(gchar *name)
{
	GList *ctemp = channels;

	while (ctemp)
	{
		chatwindow *c = (chatwindow *)(ctemp->data);
		if (strcasecmp(c->name, name) == 0)
		{
			return c;
		}
		ctemp = ctemp->next;
	}

	return NULL;
}

void close_chat(GtkWidget *widget, chatwindow *cw)
{
	GList *ctemp = channels;
	gchar chantemp[255];

	strcpy(chantemp, cw->name);
	if (chantemp[0] == '#')
	{
		GList *itemp = ircusers;

		while(itemp)
		{
			ircuser *iu = (ircuser *)(itemp->data);
			remove_channel_from_user(iu->name, chantemp);

			itemp=itemp->next;
		}
		printf("Exiting Channel %s\n", chantemp);
		irc_part_channel(connection, cw->name); 
	}

	gtk_widget_destroy(cw->window);
	
	while (ctemp)
	{
		chatwindow *c = (chatwindow *)(ctemp->data);
		if (c == cw)
		{
			printf("Removed window: %s\n", cw->name);
			channels = g_list_remove(channels, cw->name);
		}
		ctemp = ctemp->next;
	}
}

void open_chat(irc_conn *conn, gchar *channel)
{
	chatwindow *cw;

	cw = find_channel_by_name(channel);

	if (cw)
	{
		gtk_widget_show(cw->window);
		return;
	}

	cw = g_new0(chatwindow, 1);

	strcpy(cw->name, channel);
	cw->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);

	cw->vbox = gtk_vbox_new(FALSE, 5);

	cw->scroll = gtk_scrolled_window_new (NULL, NULL);
	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(cw->scroll),
			GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
	gtk_widget_set_usize(cw->scroll, 375, 150);	

	cw->chat = gtk_html_new (NULL, NULL);
	gtk_container_add(GTK_CONTAINER(cw->scroll), cw->chat);
	gtk_html_set_editable (GTK_HTML(cw->chat), FALSE);
	gtk_html_set_transparent(GTK_HTML(cw->chat), FALSE);

	cw->entry = gtk_entry_new();
	gtk_signal_connect (GTK_OBJECT(cw->entry), "activate",
			GTK_SIGNAL_FUNC(send_message), cw);
	gtk_box_pack_start(GTK_BOX(cw->vbox), cw->scroll, TRUE, TRUE, 5);
	gtk_box_pack_start(GTK_BOX(cw->vbox), cw->entry, FALSE, FALSE, 5);

	gtk_widget_show(cw->entry);
	gtk_widget_show(cw->scroll);
	gtk_widget_show(cw->chat);
	gtk_widget_show(cw->vbox);
	gtk_container_add(GTK_CONTAINER(cw->window), cw->vbox);

	gtk_signal_connect (GTK_OBJECT(cw->window), "destroy",
			GTK_SIGNAL_FUNC(close_chat), cw);
	gtk_widget_show(cw->window);
	gtk_window_set_title(GTK_WINDOW(cw->window), channel);
	channels = g_list_append(channels, cw);

	if (channel[0] == '#')
	{
		irc_join_channel(conn, irc_channel_normalize(channel));
	}
}

void libirc_test_chat_room_set_window_title( irc_conn * conn, gchar * channel, gchar * topic, gchar * nick)
{
	chatwindow *cw;
	gchar buff[BUF_LEN];

	cw = find_channel_by_name(irc_channel_normalize(channel));
	if (!cw)
	{
		return;
	}

	g_snprintf(buff, BUF_LEN, "%s: %s", channel, topic);
	gtk_window_set_title(GTK_WINDOW(cw->window), buff);

	if (nick == NULL)
	{
		g_snprintf(buff, BUF_LEN, "<FONT COLOR=\"#009900\"><B>Topic is %s</B></FONT><BR>", topic);
	}
	else
	{
		g_snprintf(buff, BUF_LEN, "<FONT COLOR=\"#009900\"><B>%s changed the topic to %s</B></FONT><BR>", nick, topic);
	}
        gtk_html_append_text(GTK_HTML(cw->chat), buff, 0);

}

void libirc_test_chat_room_in( irc_conn * conn, gchar * nick, gchar * channel,
                                                                gchar * message )
{
	chatwindow *cw;
	gchar buff[BUF_LEN];

	cw = find_channel_by_name(irc_channel_normalize(channel));
	if (!cw)
	{
		return;
	}
	g_snprintf(buff, BUF_LEN, "<FONT COLOR=\"ff0000\"><B>&lt;%s&gt;</B></FONT> %s<BR>", nick, message);
	gtk_html_append_text(GTK_HTML(cw->chat), buff, 0);
}

void libirc_test_im_in( irc_conn * conn, gchar * nick, gchar * message )
{
	chatwindow *cw;
	gchar buff[BUF_LEN];

	cw = find_channel_by_name(nick);
	if (!cw)
	{
		open_chat(connection, nick);
		cw = find_channel_by_name(nick);
	}

	g_snprintf(buff, BUF_LEN, "<FONT COLOR=\"ff0000\"><B>&lt;%s&gt;</B></FONT> %s<BR>", nick, message);
        gtk_html_append_text(GTK_HTML(cw->chat), buff, 0);
}

void libirc_test_ctcp_version_reply_in ( irc_conn * conn, gchar * nick, gchar * message )
{
	printf("VERSION on %d from %s of %s\n", conn->fd, nick, message);	
}

void libirc_test_ctcp_version_request_in ( irc_conn * conn, gchar * nick )
{
	printf("VERSION request from %s\n", nick);
	irc_send_ctcp_version_reply(conn, nick, "libIRC v0.0.0", "Spooky", "livin la jibba jabba!"); 
}


void libirc_test_action_in( irc_conn * conn, gchar * nick, gchar * channel, gchar * message )
{
	chatwindow *cw;
	gchar buff[BUF_LEN];

	cw = find_channel_by_name(channel);
	if (!cw)
	{
		open_chat(connection, channel);
		cw = find_channel_by_name(channel);
	}

	g_snprintf(buff, BUF_LEN, "<FONT COLOR=\"#666699\"><B><I>%s %s</I></B></FONT><BR>", nick, message);
	gtk_html_append_text(GTK_HTML(cw->chat), buff, 0);
}

void libirc_test_chat_room_join ( irc_conn * conn, gchar * channel, gchar * nick, gchar * host)
{
	chatwindow *cw = find_channel_by_name(irc_channel_normalize(channel));
	gchar buff[BUF_LEN];
	gchar my_nick[255];
	gchar my_channel[255];
	
	if (!cw)
	{
		return;
	}
	if (host != NULL)
	{
		g_snprintf(buff, BUF_LEN, "<FONT COLOR=\"#ff9900\"><B><I>%s (%s) has entered the channel</I></B></FONT><BR>", nick, host);
	}
	else
	{
		g_snprintf(buff, BUF_LEN, "<FONT COLOR=\"#ff9900\"><B><I>%s has entered the channel</I></B></FONT><BR>", nick);
	}

	gtk_html_append_text(GTK_HTML(cw->chat), buff, 0);
	strcpy(my_channel, irc_channel_normalize(channel) );
	strcpy(my_nick, irc_normalize(nick) );
	add_channel_to_user(my_nick, my_channel);
}

void libirc_test_chat_room_part ( irc_conn * conn, gchar * channel, gchar * nick, gchar * host)
{
        chatwindow *cw = find_channel_by_name(irc_channel_normalize(channel));
	char my_channel[255];
	char my_nick[255];
        gchar buff[BUF_LEN];

	strcpy(my_channel, irc_channel_normalize(channel));
	strcpy(my_nick, irc_normalize(nick));

	if (!cw)
	{
		printf("Channel not found!");
		return;
	}
        g_snprintf(buff, BUF_LEN, "<FONT COLOR=\"#ff9900\"><B><I>%s (%s) has left the channel</I></B></FONT><BR>", nick, host);
        gtk_html_append_text(GTK_HTML(cw->chat), buff, 0);
	remove_channel_from_user(my_nick, my_channel);
}

void libirc_test_user_quit ( irc_conn * conn, gchar * nick)
{
        printf("%s has quit IRC.\n", nick);
}

void libirc_test_irc_change_user_nick ( irc_conn * conn, gchar * nick, gchar * newnick)
{
        printf("%s has become %s.\n", nick, newnick);
}

void irc_callback_handler(gpointer data, gint source, GdkInputCondition condition)
{
        irc_callback(data);
}


void libirc_test_send_message( irc_conn * conn, gchar * target, gchar * message)
{
	chatwindow * cw;

	cw = find_channel_by_name(target);

	if (!cw)
	{
		open_chat(conn, target);
		cw = find_channel_by_name(target);
	}

	irc_send_privmsg(conn, target, message);
}

void libirc_test_user_join_channel( irc_conn * conn, gchar * target )
{
	chatwindow * cw;
	gchar *buff2;

        cw = find_channel_by_name(target);
        if (cw)
        {
		g_snprintf(buff2, BUF_LEN, "<FONT COLOR=\"#FF0077\"><B><I>* You are already a member of %s</I></B></FONT><BR>", target);  
		gtk_html_append_text(GTK_HTML(cw->chat), buff2, 0);
		return;
	}
        open_chat(connection, target);
}

int main(int argc, char *argv[])
{
 	gtk_init (&argc, &argv);
        irc_im_in = libirc_test_im_in;
        irc_chat_room_in =libirc_test_chat_room_in;
        irc_chat_room_join = libirc_test_chat_room_join;
        irc_chat_room_part = libirc_test_chat_room_part;
	irc_chat_room_set_window_title = libirc_test_chat_room_set_window_title;
        irc_user_quit = libirc_test_user_quit;
        irc_change_user_nick = libirc_test_irc_change_user_nick;
	irc_action_in = libirc_test_action_in;
	irc_ctcp_version_reply_in = libirc_test_ctcp_version_reply_in;
	irc_ctcp_version_request_in = libirc_test_ctcp_version_request_in;
	irc_send_message = libirc_test_send_message;
	irc_user_join_channel = libirc_test_user_join_channel;

	connection = irc_connect("irc.undernet.org", 6667);
	gdk_input_add(connection->fd, GDK_INPUT_READ, irc_callback_handler, connection);
	irc_signon(connection, "RobFlynn", NULL);
	open_chat(connection, "!ircstatus");
	gtk_main();
	return 1;
}

