/*********************************************************************/
/* file: parse.c - some utility-functions                            */
/*                             TINTIN III                            */
/*          (T)he K(I)cki(N) (T)ickin D(I)kumud Clie(N)t             */
/*                     coded by peter unold 1992                     */
/*********************************************************************/
#include <string.h>
#include <ctype.h>
#include "tintin.h"

extern struct session *sessionlist, *activesession;
extern struct listnode *common_aliases, *common_actions, *common_subs;
extern char vars[10][BUFFER_SIZE]; /* the &0, &1, &2,....&9 variables */
extern char tintin_char;
extern int term_echoing;
extern int speedwalk;

/**************************************************************************/
/* parse input, check for TINTIN commands and aliases and send to session */
/**************************************************************************/
struct session *parse_input(char *input, struct session *ses)
{
  char command[BUFFER_SIZE], arg[BUFFER_SIZE];
  char *cptr;
  struct listnode *ln;

  if(!term_echoing) {
    term_echo();
    term_echoing=TRUE;
  }

  if(*input=='\0') {
    if(ses)
      write_line_mud("", ses);
    else
      write_com_arg_mud("", "", ses);
    return ses; 
  }
  
  while(*input) {
    if(*input==';')
      input++;
    input=get_arg_stop_spaces(input, command);
    input=get_arg_all(input, arg);


    if(*command==tintin_char) 
      ses=parse_tintin_command(command+1, arg, ses);

    else if((ln=searchnode_list((ses) ? ses->aliases : common_aliases, command))!=NULL) {
      int i;
      char *cpsource, *cpsource2, newcommand[BUFFER_SIZE];

      strcpy(vars[0], arg);

      for(i=1, cpsource=arg; i<10; i++) {
        for(cpsource2=cpsource; *cpsource2 && *cpsource2!=' '; cpsource2++); 
        strncpy(vars[i], cpsource, cpsource2-cpsource);
        cpsource=cpsource2;
        if(*cpsource==' ') 
          cpsource++;
      }

      prepare_actionalias(ln->right, newcommand); 
      if(!strcmp(ln->right, newcommand) && *arg) {
        strcat(newcommand, " "); 
        strcat(newcommand, arg);
      }

      ses=parse_input(newcommand, ses);
    }
    else if(speedwalk && !*arg && is_speedwalk_dirs(command))
      do_speedwalk(command, ses);
    else {
      get_arg_with_spaces(arg, arg);
      write_com_arg_mud(command, arg, ses);
    }
  }

  return(ses);
}

/**********************************************************************/
/* return TRUE if commands only consists of capital letters N,S,E ... */
/**********************************************************************/
int is_speedwalk_dirs(char *cp)
{
  while(*cp) {
    if(*cp!='n' && *cp!='e' && *cp!='s' && *cp!='w' && *cp!='u' && *cp!='d')
      return FALSE;
    cp++;
  }
  return TRUE;
}

/**************************/
/* do the speedwalk thing */
/**************************/
void do_speedwalk(char *cp, struct session *ses)
{
  char sc[2]={'x', '\0'};

  while(*cp) {
    sc[0]=*cp;
    write_com_arg_mud(sc, "", ses);
    cp++;
  }
}


/*************************************/
/* parse most of the tintin-commands */
/*************************************/
struct session *parse_tintin_command(char *command, char *arg, struct session *ses)
{
  struct session *sesptr;

  for(sesptr=sessionlist; sesptr; sesptr=sesptr->next)
    if(strcmp(sesptr->name, command)==0) {
      if(*arg){
        get_arg_with_spaces(arg, arg);
        parse_input(arg, sesptr);  /* was: #sessioname commands */
        return(ses);
      }
      else {
        char buf[BUFFER_SIZE];
        activesession=sesptr;
        sprintf(buf, "#SESSION '%s' ACTIVATED.", sesptr->name);
        tintin_puts(buf, sesptr);
        return(sesptr);
      }
    }
  
  if(isdigit(*command)) {
    int i=atoi(command);
    if(i>0) {
     get_arg_with_spaces(arg, arg);
     while(i-->0)
       ses=parse_input(arg, ses);
    }
    else
      tintin_puts("#YEAH RIGHT! GO REPEAT THAT YOURSELF DUDE.", ses);
    return(ses);
  }

  else if(is_abrev(command, "action"))
    action_command(arg, ses);
   
  else if(is_abrev(command, "alias"))
    alias_command(arg, ses);
   
  else if(is_abrev(command, "all"))
    ses=all_command(arg, ses);

  else if(is_abrev(command, "bell"))
    bell_command(ses);

  else if(is_abrev(command, "boss")) 
    boss_command(ses);

  else if(is_abrev(command, "char"))
    char_command(arg, ses);

  else if(is_abrev(command, "echo"))
    echo_command(ses);

  else if(is_abrev(command, "end")) 
    end_command(command, ses);

  else if(is_abrev(command, "help")) 
    help_command(ses);

  else if(is_abrev(command, "history")) 
    history_command(ses);

  else if(is_abrev(command, "ignore"))
    ignore_command(ses);

  else if(is_abrev(command, "log")) 
    log_command(arg, ses);

  else if(is_abrev(command, "nop")); 

  else if(is_abrev(command, "mark")) 
    mark_command(ses);

  else if(is_abrev(command, "path")) 
    path_command(ses);

  else if(is_abrev(command, "return"))
    return_command(ses);

  else if(is_abrev(command, "read"))
    ses=read_command(arg, ses);

  else if(is_abrev(command, "session"))
    ses=session_command(arg, ses);

  else if(is_abrev(command, "snoop"))
    snoop_command(arg, ses);

  else if(is_abrev(command, "speedwalk"))
    speedwalk_command(ses);

  else if(is_abrev(command, "substitute"))
    parse_sub(arg, ses);

  else if(is_abrev(command, "system"))
    system_command(arg, ses);

  else if(is_abrev(command, "tick")) 
    tick_command(ses);

  else if(is_abrev(command, "tickoff")) 
    tickoff_command(ses);

  else if(is_abrev(command, "tickon")) 
    tickon_command(ses);

  else if(is_abrev(command, "tickset"))
    tickset_command(ses);

  else if(is_abrev(command, "ticksize")) 
    ticksize_command(arg, ses);

  else if(is_abrev(command, "unaction"))
    unaction_command(arg, ses);

  else if(is_abrev(command, "unalias"))
    unalias_command(arg, ses);

  else if(is_abrev(command, "unsubstitute"))
    unsubstitute_command(arg, ses);

  else if(is_abrev(command, "unpath")) 
    unpath_command(ses);

  else if(is_abrev(command, "wizlist")) 
    wizlist_command(ses);

  else if(is_abrev(command, "write"))
    ses=write_command(arg, ses);

  else if(is_abrev(command, "writesession"))
    ses=writesession_command(arg, ses);

  else if(is_abrev(command, "zap"))
    ses=zap_command(ses);

  else
    tintin_puts("#UNKNOWN TINTIN-COMMAND.", ses);

  return(ses);
}


/**********************************************/
/* get all arguments - don't remove "s and \s */
/**********************************************/
char *get_arg_all(char *s, char *arg)
{
  int inside=FALSE;

  s=space_out(s);
  while(*s) {

    if(*s=='\\') {
      *arg++=*s++;
      if(*s)
	*arg++=*s++;
    }

    else if(*s=='"') {
      *arg++=*s++;
      inside=!inside;
    }

    else if(*s==';') {
      if(inside)
	*arg++=*s++;
      else
	break;
    }

    else
      *arg++=*s++;
  }

  *arg='\0';
  return s;
}

/**************************************/
/* get all arguments - remove "s etc. */
/* Example:                           */
/* In: "this is it" way way hmmm;     */
/* Out: this is it way way hmmm       */ 
/**************************************/
char *get_arg_with_spaces(char *s, char *arg)
{
  int inside=FALSE;

  s=space_out(s);
  while(*s) {

    if(*s=='\\') {
      if(*++s)
	*arg++=*s++;
    }

    else if(*s=='"') {
      s++;
      inside=!inside;
    }

    else if(*s==';') {
      if(inside)
	*arg++=*s++;
      else
	break;
    }

    else
      *arg++=*s++;
  }

  *arg='\0';
  return s;
}


/******************************************************/
/* get one argument - stop at spaces - remove "s etc. */
/* example:                                           */
/* in: "yo yo" wayout and no more;                    */
/* out: yo yo                                         */
/******************************************************/
char *get_arg_stop_spaces(char *s, char *arg)
{
  int inside=FALSE;
  s=space_out(s);

  while(*s) {
    if(*s=='\\') {
      if(*++s)
	*arg++=*s++;
    }
    else if(*s=='"') {
      s++;
      inside=!inside;
    }

    else if(*s==';') {
      if(inside)
	*arg++=*s++;
      else
	break;
    }

    else if(!inside && isspace(*s))
      break;
    else
      *arg++=*s++;
  }

  *arg='\0';
  return s;
}

/*********************************************/
/* spaceout - advance ptr to next none-space */
/* return: ptr to the first none-space       */
/*********************************************/ 
char *space_out(char *s)
{
  while(isspace(*s))
    s++;
  return s;
}

/************************************/
/* send command+argument to the mud */
/************************************/
void write_com_arg_mud(char *command, char *argument, struct session *ses)
{
  char outtext[BUFFER_SIZE];
  int i;

  if(!ses) {
    char buf[100];
    sprintf(buf, "#NO SESSION ACTIVE. USE THE %cSESSION-COMMAND TO START ONE.", tintin_char);
    tintin_puts(buf, ses);
  }
  else {
    check_insert_path(command, ses);
    strncpy(outtext, command, BUFFER_SIZE);
    if(*argument) {
      strncat(outtext, " ", BUFFER_SIZE-strlen(command)-1); 
      strncat(outtext, argument, BUFFER_SIZE-strlen(command)-2);
    }
    write_line_mud(outtext, ses);
    outtext[i=strlen(outtext)]='\n';
    if(ses->logfile)
      fwrite(outtext, i+1, 1, ses->logfile);
  }
}


/***************************************************************/
/* show a prompt - mud prompt if we're connected/else just a > */
/***************************************************************/
void prompt(struct session *ses)
{
  if(ses && !PSEUDO_PROMPT)
    write_line_mud("", ses);
  else {
    printf("> ");
    fflush(stdout);
  }
}