#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#include <ctype.h>
#include <conio.h>
#include <wslib.h>
#include <misclib.h>

#include "connap.h"
#include "io.h"
#include "connect.h"
#include "command.h"
#include "chat.h"
#include "message.h"
#include "sound.h"
#include "util.h"


CHAN *channels = NULL;
PRIV *privs = NULL;
PING *pings = NULL;

char *join_chan = NULL;
char *priv_nick = NULL;


void ping(char *nick)
{
   PING *new_ping, *ping, *prev_ping = NULL;

   for (ping = pings; ping; ping = ping->next) {
               if (! strcmp(ping->nick, nick))
               break;
               prev_ping = ping;
   }
   if (ping) {
               if (prev_ping) {
               prev_ping->next = ping->next;
               } else {
               pings = pings->next;
               }
               free(ping->nick);
               free((char*)ping);
   }
   new_ping = (PING*)malloc(sizeof(PING));
       new_ping->nick = new_string(nick);
   new_ping->start = time(NULL);
   new_ping->next = NULL;
   if (! pings)
               pings = new_ping;
   else {
               for (ping = pings; ping->next; ping = ping->next);
               ping->next = new_ping;
   }
   if (send_msg(MSG_CLIENT_PING, new_ping->nick))
               disconnect(ws_strerror());
}


static char *get_ping_time(char *nick)
{
   char *ping_str;
   PING *ping, *prev_ping = NULL;
   int ping_time;

   for (ping = pings; ping; ping = ping->next) {
               if (! strcmp(nick, ping->nick))
               break;
               prev_ping = ping;
   }
   if (! ping)
               return NULL;

   if (prev_ping) {
               prev_ping->next = ping->next;
   } else {
               pings = pings->next;
   }

   ping_time = time(NULL) - ping->start;
   ping_str = (char*)malloc(80);
   if (ping_time != 1) {
               sprintf(ping_str, "%d seconds", ping_time);
   } else {
               sprintf(ping_str, "%d second", ping_time);
   }

   free(ping->nick);
   free((char*)ping);
   return ping_str;
}


void rcv_global(int type, char *data)
{
   char *nick, *text, *ptr, *tmp = (char*)malloc(8192);
   CHAN *c;
   PRIV *p;
   char *ping_str;

   ptr = strtok(data, " ");
       nick = new_string(ptr);
   if ((ptr = strtok(NULL, "\0")))
               text = new_string(ptr);
       else
               text = new_string("");

   switch (type) {
               case MSG_CLIENT_PRIVMSG:
               sprintf(tmp, "[%s] %s", nick, text);
               put_rcvd(tmp, PRIVMSG_COLOR);
                       if (priv_nick)
                               free(priv_nick);
                       priv_nick = new_string(nick);
                       play_sound(sound[PRIVMSG_SOUND]);
                       break;

               case MSG_SERVER_WALLOP:
               sprintf(tmp, "*** OPERATOR MESSAGE from %s: %s",
                       nick, text);
               put_rcvd(tmp, INFO_COLOR);
               break;

               case MSG_SERVER_ANNOUNCE:
               sprintf(tmp, "*** GLOBAL MESSAGE from %s: %s",
                               nick, text);
               put_rcvd(tmp, INFO_COLOR);
               break;

               case MSG_SERVER_PING:
               sprintf(tmp, "*** %s PING", nick);
               put_rcvd(tmp, INFO_COLOR);
               strcpy(tmp, nick);
               if (send_msg(MSG_CLIENT_PONG, tmp))
                               disconnect(ws_strerror());
               break;

               case MSG_SERVER_PONG:
               if (! (ping_str = get_ping_time(nick)))
                               goto end;
               sprintf(tmp, "*** PONG received from %s: %s",
                               nick, ping_str);
               put_rcvd(tmp, INFO_COLOR);
               free(ping_str);
               break;
   }

end:
   free(tmp);
   free(nick);
   free(text);
}


void rcv_channel(int type, char *data)
{
   char *topic, *channel, *nick, *text, *empty = "";
   char *tmp = (char*)malloc(8192);
   CHAN *c;

   channel = strtok(data, " ");

   c = find_chan_by_name(channel);

   if (! c)
               goto end;

   switch (type) {
               case MSG_SERVER_PUBLIC:
               nick = strtok(NULL, " ");
               if (! (text = strtok(NULL, "\0")))
                               text = empty;
               sprintf(tmp, "<%s> %s", nick, text);
               put_rcvd(tmp, CHANMSG_COLOR);
                       play_sound(sound[CHANMSG_SOUND]);
               break;

               case MSG_SERVER_TOPIC:
               if ((topic = strtok(NULL, "\0")))
                               sprintf(tmp, "%s  %s", channel, topic);
               else
                               strcpy(tmp, channel);
                       tmp[79] = 0;
                       show_info(tmp);
               break;

               case MSG_CLIENT_EMOTE:
               nick = strtok(NULL, " ");
               if (! (text = strtok(NULL, "\"")))
                               text = empty;
               sprintf(tmp, "* %s %s", nick, text);
               put_rcvd(tmp, INFO_COLOR);
               break;
   }

end:
   free(tmp);
}

/*
static void ShowQuickInfo(CHAN *c, char *nick)
{
   char values[3];
   enum {SHARED, LINK, END};
   ULIST *ul;
   char shared[20], link[20];

   for(ul = c->users; ul; ul = ul->next) {
       if (! strcmp(ul->nick, nick))
           break;
   }
   sprintf(shared, "%d", ul->shared);
   values[SHARED] = shared;
   sprintf(link, "%s", linkStr[ul->link]);
   values[LINK] = link;
   values[END] = NULL;
   ShowInfo("quickInfo", values, 15);
}

*/

void join_channel(char *name)
{
       if (join_chan)
               part_channel(join_chan);

   if (send_msg(MSG_CLIENT_JOIN, name))
               disconnect(ws_strerror());
}


void do_join_channel(char *name)
{
       char tmp[256];
   CHAN *ptr, *new_chn;

   new_chn = (CHAN*)malloc(sizeof(CHAN));
       new_chn->name = new_string(name);
   new_chn->users = NULL;
   new_chn->next = NULL;

   if (! channels)
               channels = new_chn;
   else {
               for (ptr = channels; ptr->next; ptr = ptr->next);
               ptr->next = new_chn;
   }

       if (join_chan)
               free(join_chan);
       join_chan = new_string(name);
}


void part_channel(char *name)
{
   if (send_msg(MSG_CLIENT_PART, name))
               disconnect(ws_strerror());
}


void do_part_channel(char *name)
{
   CHAN *ptr, *prev_ptr = NULL;
   char *p;

   for (ptr = channels; ptr; ptr = ptr->next) {
               if (! strcmp(ptr->name, name))
               break;
               prev_ptr = ptr;
   }
   if (! ptr) {
               err_msg("do_part_channel: no such channel");
               return;
   }

   while (ptr->users) {
               free(ptr->users->nick);
               p = (char*)ptr->users;
               ptr->users = ptr->users->next;
               free(p);
   }

   if (prev_ptr) {
               prev_ptr->next = ptr->next;
   } else {
               channels = channels->next;
   }

   free(ptr->name);
   free((char*)ptr);

       if (join_chan) {
               free(join_chan);
               join_chan = NULL;
               show_info("");
       }
}


void part_all_channels(void)
{
   while (channels)
               do_part_channel(channels->name);
}


void update_userlist(int type, char *data)
{
   char *channel, *nick;
   CHAN *ptr;
   ULIST *new_user, *user_ptr, *prev_ptr = NULL;
   char tmp[256];
   int n, shared, link;

   channel = strtok(data, " ");
   nick = strtok(NULL, " ");
   shared = atoi(strtok(NULL, " "));
   link = atoi(strtok(NULL, " "));

   if (! (ptr = find_chan_by_name(channel))) {
               err_msg("update_user_list: channel not found");
               return;
   }

   if ((type == MSG_SERVER_JOIN) ||
               (type == MSG_SERVER_CHANNEL_USER_LIST)) {
               new_user = (ULIST*)malloc(sizeof(ULIST));
               new_user->nick = new_string(nick);
               new_user->shared = shared;
               new_user->link = link;

               if (! ptr->users) {
               ptr->users = new_user;
               new_user->next = NULL;
               n = 1;
               } else {
               for (user_ptr = ptr->users, n = 1; user_ptr;
                                       user_ptr = user_ptr->next, n++) {
                               if (strcmp(user_ptr->nick, nick) > 0)
                               break;
                               prev_ptr = user_ptr;
               }

               if (prev_ptr) {
                               new_user->next = prev_ptr->next;
                               prev_ptr->next = new_user;
               } else {
                               new_user->next = ptr->users;
                               ptr->users = new_user;
               }
               }

               if (type == MSG_SERVER_JOIN) {
               sprintf(tmp, "*** %s has joined channel %s", nick, channel);
               put_rcvd(tmp, JOIN_PART_COLOR);
                       play_sound(sound[JOIN_SOUND]);
               }
   } else {
               for (user_ptr = ptr->users; user_ptr; user_ptr = user_ptr->next) {
               if (! strcmp(user_ptr->nick, nick))
                       break;
               prev_ptr = user_ptr;
               }
               if (! user_ptr) {
               err_msg("update_user_list: no such nick");
               return;
               }

               if (prev_ptr) {
               prev_ptr->next = user_ptr->next;
               } else {
               ptr->users = ptr->users->next;
               }

               free(user_ptr->nick);
               free(user_ptr);

               sprintf(tmp, "*** %s has left channel %s", nick, channel);
               put_rcvd(tmp, JOIN_PART_COLOR);
               play_sound(sound[PART_SOUND]);
       }
}


void show_users(char *channel)
{
   CHAN *ptr;
   ULIST *user_ptr;
       char *tmp = malloc(1), tmp2[128];

   if (! (ptr = find_chan_by_name(channel))) {
               err_msg("show_users: channel not found");
               return;
   }

       *tmp = '\0';
       for (user_ptr = ptr->users; user_ptr; user_ptr = user_ptr->next) {
               sprintf(tmp2, "%-20.18s", user_ptr->nick);
               tmp = realloc(tmp, strlen(tmp) + strlen(tmp2) + 1);
               strcat(tmp, tmp2);
       }

       sprintf(tmp2, "\nUsers on channel %s\n", channel);
       put_rcvd(tmp2, JOIN_PART_COLOR);
       put_rcvd(tmp, JOIN_PART_COLOR);
       put_rcvd("", JOIN_PART_COLOR);
       free(tmp);
}