#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include "base_includes.h"
#include "set_i.h"
#include "window_i.h"
#include "level.h"
#include "winfunc.h"
#ifdef USE_DEFINES_H
#include "defines.h"
#endif
#include "binding.h"

extern server_ptr gsrv;
extern win_ptr gwin;
 
static char status_window[MAXLEN] = DEFAULT_STATUS_WINDOW;
static char status_server[MAXLEN] = DEFAULT_STATUS_SERVER;
static char status_query[MAXLEN] = DEFAULT_STATUS_QUERY;
static char status_overwrite[MAXLEN] = DEFAULT_STATUS_OVERWRITE;
static char status_oper[MAXLEN] = DEFAULT_STATUS_OPER;
static char status_mode[MAXLEN] = DEFAULT_STATUS_MODE;
static char status_mail[MAXLEN] = DEFAULT_STATUS_MAIL;
static char status_insert[MAXLEN] = DEFAULT_STATUS_INSERT;
static char status_hold_lines[MAXLEN] = DEFAULT_STATUS_HOLD_LINES;
static char status_format[MAXLEN] = DEFAULT_STATUS_FORMAT;
static char status_clock[MAXLEN] = DEFAULT_STATUS_CLOCK;
static char status_channel[MAXLEN] = DEFAULT_STATUS_CHANNEL;
static char status_away[MAXLEN] = DEFAULT_STATUS_AWAY;
static char status_activity[MAXLEN] = DEFAULT_STATUS_ACTIVITY;
static char status_user[MAXLEN] = DEFAULT_STATUS_USER;
static char nameserver[MAXLEN] = DEFAULT_NAMESERVER;
static char logfile[MAXLEN] = DEFAULT_LOGFILE;
static char load_path[MAXLEN] = DEFAULT_LOAD_PATH;
static char input_prompt[MAXLEN] = DEFAULT_INPUT_PROMPT;
static char hostname[MAXLEN] = DEFAULT_HOSTNAME;
static char history_file[MAXLEN] = DEFAULT_HISTORY_FILE;
static char help_path[MAXLEN] = DEFAULT_HELP_PATH;
static char def_binding[MAXLEN] = DEFAULT_BINDING;

static void ss_binding(char *str, int *numb, int type, char *option);
static void setshow_lastlog(char *str, int *numb, int type, char *option);
static void setshow_onoff(char *str, int *numb, int type, char *option);
static void setshow_numeric(char *str, int *numb, int type, char *option);
static void setshow_level(char *str, int *numb, int type, char *option);
static void setshow_string(char *str, int *numb, int type, char *option);

/* ---------------------------------------------------------------------- */ 
#define SET_DELETE  0
#define SET_SET     1
#define SET_SHOW    2
#define SET_GET     3
/* ---------------------------------------------------------------------- */ 
static void ss_win_hold(char *str, int *numb, int type, char *option)
{
  int ret;

  if (type == SET_GET) { strcpy(str, *numb?"ON":"OFF"); return; }
  ret = *numb;
  setshow_onoff(str, numb, type, option);
  if (gwin) {
    gwin->hold_mode = *numb;
    if (*numb && !ret) init_hold_mode();
  }
}

/* ---------------------------------------------------------------------- */ 
static void ss_win_hold_max(char *str, int *numb, int type, char *option)
{
  if (type == SET_GET) { sprintf(str, "%d", *numb); return; }
  setshow_numeric(str, numb, type, option);
  if (gwin) gwin->hold_mode_max = *numb;
}
/* ---------------------------------------------------------------------- */ 
static void ss_logfile(char *str, char *numb, int type, char *option)
{
  char old[MAXLEN], *walk;
  if (type == SET_GET) { strcpy(str, numb); return; }
  walk = str;
  if (type!=SET_SHOW)
  {
    if (gwin) strcpy(old, gwin->logfile);
    else old[0] = 0;
    win_set_logfile("", &walk, (int)option);
    if (strcasecmp(old, gwin->logfile) != 0)
      setshow_string(str, (int *)numb, type, option);
  } else
    setshow_string(str, (int *)numb, type, option);
}

/* ---------------------------------------------------------------------- */ 
static void ss_log(char *str, int *numb, int type, char *option)
{
  int old = 0;
  char *walk;
  if (type == SET_GET) { strcpy(str, *numb?"ON":"OFF"); return; }
  if (!gwin) return;
  walk = str;
  if (type!=SET_SHOW)
  {
    old = (int)gwin->logfile;
    win_set_log("", &walk, (int)option);
    if (old != (int)gwin->logfile)
    setshow_onoff(str, numb, type, option);
  } else
    setshow_onoff(str, numb, type, option);
}

/* ---------------------------------------------------------------------- */ 
static CmdList set_list[] =
{
/*
 {"AUTO_UNMARK_AWAY",      setshow_onoff,    (int)&auto_unmark_away      },
*/
 {"AUTO_WHOWAS",           setshow_onoff,    DEFAULT_AUTO_WHOWAS         },
 {"BEEP",                  setshow_onoff,    DEFAULT_BEEP                },
 {"BEEP_MAX",              setshow_numeric,  DEFAULT_BEEP_MAX            },
/*
 {"BEEP_ON_MSG",           sethow_level,     DEFAULT_BEEP_ON_MSG         },
*/
 {"BEEP_WHEN_AWAY",        setshow_onoff,    DEFAULT_BEEP_WHEN_AWAY      },
 {"BINDING",               ss_binding,       (int)def_binding            },
 {"CHANNEL_NAME_WIDTH",    setshow_numeric,  DEFAULT_CHANNEL_NAME_WIDTH  },
 {"COMMAND_MODE",          setshow_onoff,    DEFAULT_COMMAND_MODE        },
 {"DEBUG",                 setshow_numeric,  DEFAULT_DEBUG               },
 {"DISPLAY",               setshow_onoff,    DEFAULT_DISPLAY             },
 {"EXEC_PROTECTION",       setshow_onoff,    DEFAULT_EXEC_PROTECTION     },
 {"FLOOD_AFTER",           setshow_numeric,  DEFAULT_FLOOD_AFTER         },
 {"FLOOD_RATE",            setshow_numeric,  DEFAULT_FLOOD_RATE          },
 {"FLOOD_USERS",           setshow_numeric,  DEFAULT_FLOOD_USERS         },
 {"FLOOD_WARNING",         setshow_onoff,    DEFAULT_FLOOD_WARNING       },
 {"HELP_PATH",             setshow_string,   (int)help_path              },
 {"HISTORY",               setshow_numeric,  DEFAULT_HISTORY             },
/*
 {"HISTORY_FILE",          setshow_string,   (int)history_file           },
*/
 {"HOLD_MODE",             ss_win_hold,      DEFAULT_HOLD_MODE           },
 {"HOLD_MODE_MAX",         ss_win_hold_max,  DEFAULT_HOLD_MODE_MAX       },
 {"HOSTNAME",              setshow_string,   (int)hostname               },
 {"INPUT_ALIASES",         setshow_onoff,    DEFAULT_INPUT_ALIASES       },
 {"INPUT_PROMPT",          setshow_string,   (int)input_prompt           },
 {"INSERT_MODE",           setshow_onoff,    DEFAULT_INSERT_MODE         },
 {"LASTLOG",               setshow_lastlog,  DEFAULT_LASTLOG             },
 {"LASTLOG_LEVEL",         setshow_level,    DEFAULT_LASTLOG_LEVEL       },
 {"LOAD_PATH",             setshow_string,   (int)load_path              },
 {"LOG",                   ss_log,           DEFAULT_LOGGING             },
 {"LOGFILE",               ss_logfile,       (int)logfile                },
/*
 {"MAIL",                  setshow_numeric,  DEFAULT_MAIL                },
*/
 {"MAX_RECURSIONS",        setshow_numeric,  DEFAULT_MAX_RECURSIONS      },
 {"NAMESERVER",            setshow_string,   (int)nameserver                  },
 {"NO_CTCP_FLOOD",         setshow_onoff,    DEFAULT_NO_CTCP_FLOOD       },
 {"NOTIFY_LEVEL",          setshow_level,    DEFAULT_NOTIFY_LEVEL        },
/*
 {"NOTIFY_ON_TERMINATION", setshow_onoff,    DEFAULT_NOTIFY_ON_TERMINATION },
*/
 {"NOVICE",                setshow_onoff,    DEFAULT_NOVICE              },
 {"SCROLL",                setshow_onoff,    DEFAULT_SCROLL              },
 {"SEND_IGNORE_MESSAGE",   setshow_onoff,    DEFAULT_SEND_IGNORE_MESSAGE },
/*
 {"SHELL_LIMIT",           setshow_numeric,  DEFAULT_SHELL_LIMIT         },
 {"SHOW_CHANNEL_NAMES",    setshow_onoff,    DEFAULT_SHOW_CHANNEL_NAMES  },
*/
 {"SHOW_END_OF_MSGS",      setshow_onoff,    DEFAULT_SHOW_END_OF_MSGS    },
 {"SHOW_NUMERICS",         setshow_onoff,    DEFAULT_SHOW_NUMERICS       },
 {"STATUS_ACTIVITY",       setshow_string,   (int)status_activity        },
 {"STATUS_AWAY",           setshow_string,   (int)status_away            },
 {"STATUS_CHANNEL",        setshow_string,   (int)status_channel         },
/*
 {"STATUS_CHANOP",         setshow_string,   (int)status_chanop          },
*/
 {"STATUS_CLOCK",          setshow_string,   (int)status_clock           },
 {"STATUS_FORMAT",         setshow_string,   (int)status_format          },
/*
 {"STATUS_HOLD",           setshow_string,   (int)status_hold            },
*/
 {"STATUS_HOLD_LINES",     setshow_string,   (int)status_hold_lines      },
 {"STATUS_INSERT",         setshow_string,   (int)status_insert          },
/*
 {"STATUS_MAIL",           setshow_string,   (int)status_mail            },
*/
 {"STATUS_MODE",           setshow_string,   (int)status_mode            },
/*
 {"STATUS_NOTIFY",         setshow_string,   (int)status_notify          },
 {"STATUS_OPER",           setshow_string,   (int)status_oper            },
*/
 {"STATUS_OVERWRITE",      setshow_string,   (int)status_overwrite       },
 {"STATUS_QUERY",          setshow_string,   (int)status_query           },
/*
 {"STATUS_SERVER",         setshow_string,   (int)status_server          },
 {"STATUS_UMODE",          setshow_string,   (int)status_umode           },
 {"STATUS_USER",           setshow_string,   (int)status_user            },
 {"STATUS_USER1",          setshow_string,   (int)status_user1           },
 {"STATUS_USER2",          setshow_string,   (int)status_user2           },
 {"STATUS_USER2",          setshow_string,   (int)status_user3           },
*/
 {"STATUS_WINDOW",         setshow_string,   (int)status_window          },
 {"VERBOSE_CTCP",          setshow_onoff,    DEFAULT_VERBOSE_CTCP        },
 {"WARN_OF_IGNORES",       setshow_onoff,    DEFAULT_WARN_OF_IGNORES     },
};
 
#define NUM_SETS (sizeof(set_list) / sizeof(CmdList)) - 1
 
/* ---------------------------------------------------------------------- */
static CmdList *var_ptr(char *str)
{
  return exact_find_command(set_list, NUM_SETS, str);
}

/* ---------------------------------------------------------------------- */
int getbvar(int option)
{
  return (set_list[option].varpar)?TRUE:FALSE;
}

int getivar(int option)
{
  return set_list[option].varpar;
}

void setivar(int option, int new)
{
  set_list[option].varpar = new;
}

int get_variable(char *var, int *val, char *result)
{
  CmdList *command;
  int cmd_cnt, value;
  if ((command = var_ptr(var)) == NULL) {
    if (result) *result = 0;
    if (val) *val = 0;
    return 0;
  }
  value = command->varpar;
  if (command->cmdfcn == setshow_string) {
    if (val) *val = 0;
    if (result) (void)strcpy(result, (char *)command->varpar);
  } else if (command->cmdfcn == setshow_onoff) {
    if (val) *val = value;
    if (result) (void)sprintf(result, "%s\0", value?"ON":"OFF");
  }
  else if (command->cmdfcn == setshow_numeric) {
    if (val) *val = value;
    if (result) (void)sprintf(result, "%d\0", value);
  }
  else if (command->cmdfcn == setshow_level) {
    if (val) *val = value;
    if (result) show_level(NULL, value, 0, result);
  }
  return TRUE;
}

static char dummy[MAXLEN];
static char *getvar_raw(CmdList *cmd)
{
  int *value, opt_temp;
  *dummy = 0;
  if (!cmd) return dummy;
  value = (int *)cmd->varpar;
  if ((cmd->cmdfcn == setshow_string) ||
      (cmd->cmdfcn == ss_logfile)) return (char *)value;
  if (cmd->cmdfcn==setshow_level)
    show_level(NULL, *value, 0, dummy);
  else if (cmd->cmdfcn==setshow_onoff)
    strcpy(dummy, (cmd->varpar)?"ON":"OFF");
  else {
    for (opt_temp = 0; &(set_list[opt_temp]) != cmd; opt_temp++) ;
    cmd->cmdfcn(dummy, &cmd->varpar, SET_GET, NULL);
  }
  return dummy;

}

char *getvar(int option)
{
  CmdList command;
  command = set_list[option];
  return getvar_raw(&command);
}

char *getvar_by_name(char *var)
{
  CmdList *command;
  command = var_ptr(var);
  return getvar_raw(command);
}
 
/* ---------------------------------------------------------------------- */
static void setshow_onoff(char *str, int *numb, int type, char *option)
{
  char word[MAXLEN];
  int good, ret, old;

  old = *numb;
  if (type == SET_GET) { strcpy(str, *numb?"ON":"OFF"); return; }
  if (type == SET_SET) {
    (void)grab_word(&str, ' ', word);
    ret = onoff_toggle(*numb, word, &good);
    if (good) *numb = ret;
  }
  if ((old<0) && (strcasecmp(option, "DISPLAY")==0)) return;
  say("*** Current value of %s is now %s", option, *numb ? "ON" : "OFF");
}
 
/* ---------------------------------------------------------------------- */
static void setshow_level(char *str, int *numb, int type, char *option)
{
  int dummy = 0;
  char string[80];
  if (type == SET_GET) { show_level(str, *numb, dummy, NULL); return; }
  (void)sprintf(string, "Current value of %s is now", option);
  if ((type == SET_SET) && (*str)) (void)lookup_level(str, numb, &dummy);
  show_level(string, *numb, dummy, NULL);
}
 
static void setshow_string(char *str, int *numb, int type, char *option)
{
  char *orig = (char *)*numb;
  if (type == SET_GET) { strcpy(str, orig); return; }
  if ((type == SET_SET) && (*str)) (void)strcpy(orig, str);
  if (type == SET_DELETE) orig[0] = 0;
  say("*** Current value of %s is now \"%s\"", option, orig);
}
 
static void setshow_numeric(char *str, int *numb, int type, char *option)
{
  int bad, loop;
 
  if (type == SET_GET) { sprintf(str, "%d", *numb); return; }
  if (type == SET_SET) {
    bad = FALSE;
    for (loop=0;loop<strlen(str);loop++)
      if (!isdigit(str[loop])) bad = TRUE;
    if (bad) say("*** Value of %s must be numeric!", option);
    else *numb = atoi(str);
  } else if (type == SET_DELETE)
    *numb = 0;
  say("*** Current value of %s is now %d", option, *numb);
}
 
/* ---------------------------------------------------------------------- */ 
static void ss_binding(char *str, int *numb, int type, char *option)
{
  int do_set = 1;
  if (type == SET_GET) { strcpy(str, (char *)*numb); return; }
  if (type == SET_DELETE) str = DEFAULT_BINDING;
  else if (type == SET_SHOW) do_set = 0;
  else if (type == SET_SET) ;
  if (do_set) do_set = set_binding(str);
  setshow_string(str, numb, do_set?SET_SET:SET_SHOW, option);
}
/* ---------------------------------------------------------------------- */
static void setshow_lastlog(char *str, int *numb, int type, char *option)
{
  if (type == SET_GET) { sprintf(str, "%d", *numb); return; }
  setshow_numeric(str, numb, type, option);
  set_list_limit(gwin->lastlog, *numb);
}

/* ---------------------------------------------------------------------- */
void user_set(char *string, int varpar, char *subparams)
{
  char word[MAXLEN];
  int cmd_cnt, ret, len, loop, eval, dummy;
  int delete;
  char tempstring[MAXLEN];
  CmdList *command;

  delete = SET_SET;
  if (*string == '-')
  {
    delete = SET_DELETE;
    string++;
  }
  (void)grab_word(&string, ' ', word);
  if (!*string && (delete!=SET_DELETE)) delete = SET_SHOW;
  command = find_command(set_list, NUM_SETS, word, &cmd_cnt);
  
  if (cmd_cnt == 0)
    say("*** No such variable \"%s\"", word);
  else if (((cmd_cnt < 0) || (cmd_cnt == 1)) && command)
    command->cmdfcn(string, &command->varpar, delete, command->command);
  else {
    len = strlen(word);
    if (*word) say("*** \"%s\" is ambiguous", word);
 
    for(loop=0;loop<NUM_SETS;loop++)
      if (strncasecmp(word, set_list[loop].command, len) == 0)
        (*set_list[loop].cmdfcn)(word, &set_list[loop].varpar, SET_SHOW,
                                 set_list[loop].command);
  }
}
