#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include "global.h"
#include "command.h"
#include "constants.h"
#include "window.h"

#ifdef ENABLE_ON
/* ------------------------------------------------------------------------ */

#define ON_SILENT   0
#define ON_QUIET    1
#define ON_NORMAL   2
#define ON_NOISY    3

char ON_LEVELS[4][10] = {{"[silent]"}, {"[quiet]"}, {"[normal]"}, {"[noisy]"}};

typedef struct onlist_struct *on_list;
struct onlist_struct
{
  int number;
  char *event;
  int style, serial;
  char *effects;
  on_list next;
};

extern server_ptr gsrv;
extern int display;

/* ------------------------------------------------------------------------ */

struct command_node list_ons[] =                  
{
  {{"ACTION"},         NULL},        {{"CHANNEL_SIGNOFF"},NULL},
  {{"CONNECT"},        NULL},
  {{"CTCP"},           NULL},        {{"CTCP_REPLY"},     NULL},
  {{"DCC_CHAT"},       NULL},        {{"DCC_RAW"},        NULL},
  {{"DISCONNECT"},     NULL},        {{"EXEC"},           NULL},
  {{"EXEC_ERRORS"},    NULL},        {{"EXEC_EXIT"},      NULL},
  {{"EXEC_PROMPT"},    NULL},        {{"FLOOD"},          NULL},
  {{"HOOK"},           NULL},        {{"IDLE"},           NULL},
  {{"INPUT"},          NULL},        {{"INVITE"},         NULL},
  {{"JOIN"},           NULL},        {{"LEAVE"},          NULL},
  {{"MODE"},           NULL},        {{"MSG"},            NULL},
  {{"NICKNAME"},       NULL},        {{"NOTE"},           NULL},
  {{"NOTICE"},         NULL},        {{"NOTIFY_SIGNON"},  NULL},
  {{"NOTIFY_SIGNOFF"}, NULL},        {{"PUBLIC"},         NULL},
  {{"PUBLIC_OTHER"},   NULL},        {{"RAW_IRC"},        NULL},
  {{"SEND_ACTION"},    NULL},        {{"SEND_DCC_CHAT"},  NULL},
  {{"SEND_MSG"},       NULL},        {{"SEND_NOTICE"},    NULL},
  {{"SEND_PUBLIC"},    NULL},        {{"SERVER_NOTICE"},  NULL},
  {{"SIGNOFF"},        NULL},        {{"TIMER"},          NULL},
  {{"WALL"},           NULL},        {{"WALLOP"},         NULL},
  {{"WINDOW"},         NULL},        {{"WINDOW_KILL"},    NULL},
  {{"NUMERIC"},        NULL},        {{NULL},             NULL}
};

/* ------------------------------------------------------------------------ */
int in_on = FALSE;
/* ------------------------------------------------------------------------ */

int handle_on(list_id, string, num)
  int list_id;
  char *string;
  int num;
{
  char msg[MAXLEN], *expanded;
  on_list list, temp;
  int max, curr, disp, serial, ret = FALSE, old_in_on;

  list = (on_list)(list_ons[list_id].constant);
  while (list != NULL)
  {
    max = -1;
    temp = NULL;
    serial = list->serial;
    while (list && (list->serial == serial)) {
      if ((list->number == num) &&
          ((curr = wild_match(list->event, string)) > max)) {
        max = curr;
        temp = list;
      }
      list = list->next;
    }
    if (temp!=NULL) {
      if (temp->style >= ON_NORMAL) {
        if (num)
          say("*** On %d activated by \"%s\" <%d>", num, string, serial);
        else
          say("*** On %s activated by \"%s\" <%d>", list_ons[list_id].command,
              string, serial);
      }
      disp = display;
      if (temp->style == ON_SILENT) display = -1;
      old_in_on = in_on;
      in_on = TRUE;
      parse_line(temp->effects, string, TRUE, FALSE);
      in_on = old_in_on;
      if (display==-1) display = disp;
      if ((temp->style == ON_SILENT) && (serial==0)) ret = TRUE;
    }
  }
  return ret;
}

/* ------------------------------------------------------------------------ */

void print_on(int indx, on_list list, int num)
{
  char msg[MAXLEN], form[MAXLEN];
  if (num)
    (void)sprintf(msg, "*** On %d from \"%s\" do ", num,
                  list->event);
  else 
    (void)sprintf(msg, "*** On %s from \"%s\" do ", list_ons[indx].command,
                  list->event);
  (void) strcat(msg, list->effects);
  (void)strcat(msg, ON_LEVELS[list->style]);
  (void)sprintf(form, " <%d>", list->serial);
  (void)strcat(msg, form);
  say("%s", msg);
}

/* ------------------------------------------------------------------------ */

void show_on_list(indx, num)
  int indx, num;
{
  on_list list;
  list = (on_list)(list_ons[indx].constant);
  if (list==NULL) {
    if (indx==o_numeric)
      say("*** The %d list is empty.", num);
    else
      say("*** The %s list is empty.", list_ons[indx].command);
  }
  else while ((list!=NULL) && (list->number == num))
       {
         print_on(indx, list, num);
         list = list->next;
       }
}

/* ------------------------------------------------------------------------ */

int add_on(int ret, char *str, char *rest, int level, int num, int serial)
{
  int depth;
  char *line, *save, oldc = 0, *end;
  on_list temp, walk, back = NULL;

  if ((temp = (on_list)malloc(sizeof(struct onlist_struct))) == NULL)
    return FALSE;
  walk = (on_list)(list_ons[ret].constant);
  while (walk && (serial>walk->serial)) {
    back = walk;
    walk = walk->next;
  }
  while (isspace(*rest)) rest++;
  if (*rest == '{') {
    end = matching_end(++rest, '{', '}');
    oldc = *end;
    *end = 0;
  }
  temp->next = walk;
  if (back) back->next = temp;
  else list_ons[ret].constant = (char *)temp;
  temp->number = num;
  temp->event = ms_strcpy(str);
  temp->effects = ms_strcpy(rest);
  if (oldc) *end = oldc;
  temp->style = level;
  temp->serial = serial;
  print_on(ret, temp, num);
  return TRUE;
}

/* ------------------------------------------------------------------------ */

delete_on_node(on_list node)
{
  free(node->event);
  free(node->effects);
  free(node);
}

/* ------------------------------------------------------------------------ */

int delete_on(int indx, char *word, int num, int serial)
{
  on_list list, back = NULL;
  list = (on_list)(list_ons[indx].constant);
  while (list) {
    if ((strcasecmp(word, list->event) == 0) && (list->number == num) &&
        (serial==list->serial)) {
      if (!back) list_ons[indx].constant = (char *)list->next;
      else back->next = list->next;
      delete_on_node(list);
      return TRUE;
    }
    back = list;
    list = list->next;
  }
  return FALSE;
}

/* ------------------------------------------------------------------------ */

delete_all_ons(int indx)
{
  on_list walk, save = NULL;
  walk = (on_list)list_ons[indx].constant;
  while (walk) {
    save = walk;
    walk = walk->next;
    delete_on_node(save);
  }
  list_ons[indx].constant = 0;
}

/* ------------------------------------------------------------------------ */

void search_on_list(int list_num, char *string, int level, int num, int serial)
{
  char *word, tmp[MAXLEN];
  int delete = FALSE, all = FALSE;
  int did;

  if (*string==0) {show_on_list(list_num, num); return;}
  if (*string=='-') {
     delete = TRUE;
     string++;
     if (!*string) {
       delete_all_ons(list_num);
       if (list_num==o_numeric)
         say("*** ON %d list is empty", num);
       else
         say("*** ON %s list is empty", list_ons[list_num].command);
       return;
     }
  }

  if (*string=='"') {string++; word = m_grab_word(&string, '"');}
  else word = m_grab_word(&string, ' ');

  did = delete_on(list_num, word, num, serial);
  if (!delete) (void)add_on(list_num, word, string, level, num, serial);
  else if (did) {
    if (list_num == o_numeric) sprintf(tmp, "%d", num);
    else strcpy(tmp, list_ons[list_num].command);
    say("*** ON %s from \"%s\" deleted", tmp, word);
  }
  free(word);
}

/* ------------------------------------------------------------------------ */

void on(char *string)
{
  char *temp;
  int dummy_ret;
  char word[20], dummy[80];
  int level = ON_NORMAL, indx, list;
  int num = 0, isnum, new_word, serial;

  if (*string == '#') {
    new_word = TRUE;
    string++;
  } else new_word = FALSE;
  if (*string == '+') {        /* Noisy - show everything */
    level = ON_NOISY;
    string++;
  }
  else if (*string == '-') {   /* Quiet will not display any actions */
    level = ON_QUIET;
    string++;
  }
  else if (*string == '^') {   /* Quiet but inhibits normal event */
    level = ON_SILENT;
    string++;
  }
  temp = string;

  (void)grab_word(&temp, ' ', word);
  if (new_word) {
    (void)grab_word(&temp, ' ', dummy);
    serial = atoi(dummy);
  } else serial = 0;
  isnum = word[0] != 0;
  for (indx=0;word[indx];indx++)
   if (isdigit(word[indx])) num = num * 10 + word[indx] - 48;
   else isnum = FALSE;
  if (!isnum) {
    num = 0;
    list = lookup_command(list_ons, word, &dummy_ret);
  }
  else list = o_numeric;

  if (list == c_none)
    say("No such ON function: %s", word);
  else if (list == c_amb) {
    say("Ambiguous ON function: \"%s\"", word);
    for (indx = 0; list_ons[indx].command; indx++)
      if ((strncasecmp(list_ons[indx].command, word, strlen(word)) == 0) &&
          (list_ons[indx].constant))
        show_on_list(indx, num, serial);
  } else
   search_on_list(list, temp, level, num, serial);
}

/* ------------------------------------------------------------------------ */

#else  /* ENABLE_ON */

int handle_on(list_id, string, num)
  int list_id;
  char *string;
  int num;
{
  return FALSE;
}

#endif /* ENABLE_ON */

