/*********************************************************************/
/* file: action.c - funtions related to the action command           */
/*                             TINTIN III                            */
/*          (T)he K(I)cki(N) (T)ickin D(I)kumud Clie(N)t             */
/*                     coded by peter unold 1992                     */
/*********************************************************************/
#include <ctype.h>
#include <string.h>
#include "tintin.h"

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

/***********************/
/* the #action command */
/***********************/
void action_command(char *arg, struct session *ses)
{
  char left[BUFFER_SIZE], right[BUFFER_SIZE];
  struct listnode *myactions, *ln;

  myactions=(ses) ? ses->actions : common_actions;

  arg=get_arg_stop_spaces(arg, left);
  arg=get_arg_with_spaces(arg, right);

  if(!*left) {
    puts("#THESE ACTIONS HAS BEEN DEFINED:");
    show_list(myactions);
    prompt(ses);
  }

  else if(*left && !*right) {
    if((ln=searchnode_list(myactions, left))!=NULL) {
      shownode_list(ln);
      prompt(ses);
    }
    else
      tintin_puts("#THAT ACTION IS NOT DEFINED.", ses);
  }

  else {
    if((ln=searchnode_list(myactions, left))!=NULL)
      deletenode_list(myactions, ln);
    insertnode_list(myactions, left, right);
    tintin_puts("#OK. ACTION DEFINED.", ses);
  }
}

/*************************/
/* the #unaction command */
/*************************/
void unaction_command(char *arg, struct session *ses)
{
  char left[BUFFER_SIZE];
  struct listnode *myactions, *ln;

  myactions=(ses) ? ses->actions : common_actions;
  arg=get_arg_with_spaces(arg, left);

  if((ln=searchnode_list(myactions, left))!=NULL) {
    deletenode_list(myactions, ln);
    tintin_puts("#OK. ACTION DELETED", ses);
  }
  else
    tintin_puts("#THAT ACTION IS NOT DEFINED.", ses);
}

/**************************************************************************/
/* run throught each of the commands on the right side of an alias/action */
/* expression, call substitute_text() for all commands but #alias/#action */
/**************************************************************************/
void prepare_actionalias(char *string, char *result)
{

  char *cptr, command[BUFFER_SIZE], arg[BUFFER_SIZE], both[BUFFER_SIZE];

  *result='\0';

  cptr=string;

  while(*cptr) {

    cptr=get_arg_stop_spaces(cptr, command);
    cptr=get_arg_all(cptr, arg); 

    strcpy(both, command);
    if(*arg) {
      strcat(both, " ");
      strcat(both, arg);
    }

    if(*command==tintin_char && (
       is_abrev(command+1, "alias") || is_abrev(command+1, "unalias") ||
       is_abrev(command+1, "action") || is_abrev(command+1, "unaction") ||
       is_abrev(command+1, "substitute") || is_abrev(command+1, "unsubstitute"))) 
      strcat(result, both); 
    else
      substitute_vars(both, result+strlen(result));
    if(*cptr==';') {
      strcat(result, ";");
      cptr++;   
    }
  }
}

/*************************************************************************/
/* copy the arg text into the result-space, but substitute the variables */
/* &0..&9 with the real variables                                        */
/*************************************************************************/
void substitute_vars(char *arg, char *result)
{
  while(*arg) {

    if(*arg=='&' && isdigit(*(arg+1))) { /* substitute variable */
      int n=*(arg+1)-'0';
      strcpy(result, vars[n]);
      arg+=2;
      result+=strlen(vars[n]);
    }
    else
      *result++=*arg++;
  }
  *result='\0';
}


/*********************************************************/
/* split the lines in the buffer and check'em for action */
/*********************************************************/
void split_check_all_actions(char *buffer, struct session *ses)
{
  char linebuffer[BUFFER_SIZE], *cpsource, *cpdest;

  cpsource=buffer; 
  cpdest=linebuffer;

  while(*cpsource) {  /*cut out each of the lines and check for actions */
    if(*cpsource=='\n' || *cpsource=='\r') {
      cpsource++;
      *cpdest='\0';
      check_all_actions(linebuffer, ses);
      cpsource++;
      if(*cpsource=='\n' || *cpsource=='\r') 
        cpsource++;
      cpdest=linebuffer;
    }
    else
      *cpdest++=*cpsource++;
  }
  *cpdest='\0';
  check_all_actions(linebuffer, ses);
}


/**********************************************/
/* check actions from a sessions against line */
/**********************************************/
void check_all_actions(char *line, struct session *ses)
{

  struct listnode *ln;


 if(check_one_action(line, PROMPT_FOR_PW_TEXT)) {
    term_noecho();
    term_echoing=FALSE;
  } 


  ln=ses->actions;

  while(ln=ln->next) {
    if(check_one_action(line, ln->left)) {
      char buffer[BUFFER_SIZE];
      prepare_actionalias(ln->right, buffer);
      if(echo && activesession==ses) 
        printf("[ACTION: %s]\n", buffer);
      parse_input(buffer, ses);
      return;
    }
  }
}


/******************************************************************/
/* check if a text triggers an action and fill into the variables */
/* return TRUE if triggered                                       */
/******************************************************************/
int check_one_action(char *text, char *action)
{   

  while(*text && !do_tricker(text, action))
    text++;

  while(*action && *text && do_tricker(text, action)) {

    if(*action=='&' && isdigit(*(action+1))) {
      int i;
      char *cptr;

      i=*(action+1)-'0';
      for(cptr=vars[i]; *text && (!*(action+2) || !do_tricker(text, action+2)); text++, cptr++)
	*cptr=*text;
      *cptr='\0';
      action+=2;
    }
    else {
      text++;
      action++;
    }
  }

  return (*action=='\0');
}

/****************************************/
/* returns TRUE is text triggers action */
/****************************************/  
int do_tricker(char *text, char *action)
{
  if(!*action)
    return TRUE;
  if(!*text)
    return FALSE;

  if(*action=='&' && isdigit(*(action+1))) {
    while(*text && !do_tricker(text, action+2))
      text++;
    return do_tricker(text, action+2);
  }
  else
    return (*text==*action && do_tricker(text+1, action+1));
}