/*
 * input.c: parse and process user input 
 *
 * Copyright(c) 1997,1998 - All Rights Reserved
 *
 * See the COPYRIGHT file.
 */

#ifndef lint
static char rcsid[] = "@(#)$Id: input.c,v 1.28 1998/08/17 20:28:41 kalt Exp $";
#endif

#include "os.h"

#include "struct.h"
#include "server.h"
#include "window.h"
#include "term.h"

extern	void parse_command(char *, int);
extern	int cmd_msgnotice(char *, char *);
extern	char *tab_get();
extern	char *space_get();

extern	struct window_ *current;
extern	struct server_ *server;

static char		inbuf[512] = "";
static char		history[100][512];
static int		curh = -1, nexh = -1;
static unsigned int	inlen = 0, inpos = 0;
  
static void
parse_input()
{
  vsic_slog(LOG_INPUT, ">>> %s", inbuf);

  if (nexh == -1)
      for (nexh = 99; nexh > 0; nexh--)
	  history[nexh][0] = '\0';
  strcpy(history[nexh], inbuf);
  if (nexh++ == 99)
      nexh = 0;
  history[curh = nexh][0] = '\0';

  switch (*inbuf)
    {
  case '/' :
      if (inbuf[1] == '/')
	  if (inbuf[2] == '/')
	      vsic_write(inbuf+3);
	  else
	      parse_command(inbuf+2, 0);
      else
	  parse_command(inbuf+1, 1);
      break;
  default :
      cmd_msgnotice(NULL, inbuf);
      break;
    }

  inbuf[0] = '\0';
  inlen = inpos = 0;
}

void
space_trick()
{
  char obuf[512] = "";
  char *ch;

  if (ch = index(inbuf, ':'))
      strcpy(obuf, (ch[1] == ' ') ? ch+2 : ch+1);
  else
      strcpy(obuf, inbuf);
  ch = space_get();
  if (*ch)
    {
      sprintf(inbuf, "%s: ", ch);
      inpos = strlen(inbuf);
      strcat(inbuf, obuf);
      inlen = strlen(inbuf);
    }
}

void
tab_trick()
{
  char obuf[512] = "";
  char *ch;

  if (ch = index(inbuf, ' '))
      if (ch = index(ch+1, ' '))
	  strcpy(obuf, ch+1);
  ch = tab_get();
  if (*ch)
    {
      char *cmd;

      if (*ch == '@')
	{
	  ch++;
	  cmd = "squery";
	}
      else
	  cmd = "msg";
      sprintf(inbuf, "/%s %s ", cmd, ch);
    }
  else
      strcpy(inbuf, "/msg ");
  inpos = strlen(inbuf);
  strcat(inbuf, obuf);
  inlen = strlen(inbuf);
}

char
in_delprev()
{
  if (inpos)
    {
      char *wp;

      wp = inbuf+inpos-1;
      while (*wp++)
	  *(wp-1) = *wp;
      inlen--; inpos--;
      return 1;
    }
  else
    {
      term_beep();
      return 0;
    }
}

char
in_delnext()
{
  if (inpos < inlen)
    {
      char *wp;

      wp = inbuf+inpos;
      while (*wp++)
	  *(wp-1) = *wp;
      inlen--;
      return 1;
    }
  else
    {
      term_beep();
      return 0;
    }
}

void
in_insert(ch, trunc)
  char ch, *trunc;
{
  int i;

  if (*trunc)
    {
      inbuf[inlen = inpos] = '\0';
      *trunc = 0;
    }
  if (inlen < 400)
    {
      inlen++;
      for (i = inlen; i > inpos; i--)
	  inbuf[i] = inbuf[i-1];
      inbuf[inpos++] = ch;
    }
  else
      term_beep();
}

int
sic_getch()
{
  static char escape = 0, screen = 0, search = 0, quote = 0, replace = 0;
  static char cursor = 0;
  char	ch, chg = 0;
  
  assert(inlen == strlen(inbuf));
  assert(inpos <= inlen);

  if (read(0, &ch, 1) != 1)
      abort(); /* should simply exit? */
  
  server = current->via;
  if (quote)
    {
      quote = 0;
      in_insert(ch, &replace);
      chg = 1;
    }
  else
    {
      select_active(NULL, 2);
      if (search)
	{
	  if (ch == '/')
	      sic_scroll2(search = +2, inbuf);
	  else if (ch == '?')
	      sic_scroll2(search = -2, inbuf);
	  else
	    {
	      search = 0;
	      inbuf[0] = '\0';
	      inlen = inpos = 0;
	      chg = 1;
	    }
	}
      if (search == 0)
	{
	  if (screen)
	    {
	      screen = 0;
	      switch (ch)
		{
	      case 'a':
	      case ctrl('A'):
	      case ctrl('X'):
		  sic_chgwin(-3); chg = 1;
		  break;
	      case 'c':
	      case ctrl('C'):
		  sic_newwin();
		  sic_chgwin(-3); chg = 1;
		  break;
	      case 'd':
	      case ctrl('D'):
		  sic_wdcc();
		  break;
	      case 'k':
	      case ctrl('K'):
		  sic_wkill();
		  break;
	      case 'l':
	      case ctrl('L'):
		  sic_wlist();
		  break;
	      case '\0': /* ^-space */
	      case ' ':
	      case 'n':
	      case ctrl('N'):
		  sic_chgwin(-1); chg = 1;
		  break;
	      case 'p':
	      case ctrl('P'):
		  sic_chgwin(-2); chg = 1;
		  break;
	      case 's':
		  sic_swin(2);
		  break;
	      default:
		  if (ch >= 48 && ch <= 57)
		      sic_chgwin((int) ch - 48); chg = 1;
		}
	    }
	  else if (escape)
	    {
	      switch (ch)
		{
		  case '[':
		  cursor = 1;
		  break;
	      case '0': case '1': case '2': case '3': case '4':
	      case '5': case '6': case '7': case '8': case '9':
		  current->fnb = ch - 48;
		  sic_redowin(0);
		  break;
	      case '/':
		  sic_scroll2(search = +2, inbuf);
		  break;
	      case '?':
		  sic_scroll2(search = -2, inbuf);
		  break;
	      case '<':
		  sic_scroll2(-1, NULL);
		  break;
	      case '>':
		  sic_scroll2(+1, NULL);
		  break;
	      case '-':
		  sic_scroll(-1);
		  break;
	      case '+':
		  sic_scroll(+1);
		  break;
	      case '.':
		  sic_clog(0);
		  sic_redowin(0);
		  break;
	      case 'b':
		  if (inpos)
		    {
		      if (!isspace(inbuf[inpos]))
			  inpos -= 1;
		      while (inpos && isspace(inbuf[inpos--]));
		      while (inpos && !isspace(inbuf[inpos-1]))
			  inpos -= 1;
		      chg = 1;
		    }
		  replace = 0;
		  break;
	      case 'f':
		  if (inpos < inlen)
		    {
		      while (isspace(inbuf[inpos++]));
		      while (inbuf[inpos] && !isspace(inbuf[inpos]))
			  inpos += 1;
		      chg = 1;
		    }
		  replace = 0;
		  break;
	      case 'd':
		  if (inpos < inlen)
		    {
		      while (isspace(inbuf[inpos]))
			  in_delnext();
		      while (inbuf[inpos] && !isspace(inbuf[inpos]))
			  in_delnext();
		      chg = 1;
		    }
		  replace = 0;
		  break;
	      case ctrl('H'):
	      case 127:
		  if (inpos)
		    {
		      while (inpos && isspace(inbuf[inpos-1]))
			  in_delprev();
		      while (inpos && !isspace(inbuf[inpos-1]))
			  in_delprev();
		      chg = 1;
		    }
		  replace = 0;
		  break;
	      case 'n':
		  sic_scroll((LI-2)/2);
		  break;
	      case 'N':
		  sic_scroll2(+2, NULL);
		  break;
	      case 'p':
		  sic_scroll(-(LI-2)/2);
		  break;
	      case 'P':
		  sic_scroll2(-2, NULL);
		  break;
	      case 's':
		  if (inbuf[0])
		    {
		      sic_scroll2(0, inbuf);
		      inbuf[0] = '\0';
		      inpos = inlen = replace = 0; chg = 1;
		    }
		  else
		      sic_scroll2(0, NULL);
		  sic_redowin(0);
		  break;
	      case 'S':
		  if (option(current->custw.zopt_on, Z_SHOWALL))
		      unset_option(current->custw.zopt_on, Z_SHOWALL);
		  else
		      set_option(current->custw.zopt_on, Z_SHOWALL);
		  sic_redowin(0);
		  break;
	      case 't':
		  sic_wptoggle();
		  sic_redowin(0);
		  break;
	      case 'u':
		  if (option(current->custw.zopt_on, Z_UNDEL))
		      unset_option(current->custw.zopt_on, Z_UNDEL);
		  else
		      set_option(current->custw.zopt_on, Z_UNDEL);
		  sic_redowin(0);
		  break;
		}
	      escape = 0;
	    }
	  else if (cursor)
	  {
		switch (ch)
		{
		  case 'C': /* cursor right */ 
			if (inpos < inlen)
			{
			  inpos++;
			  chg = 1;
			}
			replace = 0;
			break;
		  case 'D': /* cursor left */
			if (inpos)
			{
			  inpos--;
			  chg = 1;
			}
			replace = 0;
			break;
		  case 'B': /* cursor down */
			if (curh != -1)
			{
			  do
				if (curh++ == 99)
				  curh = 0;
			  while (*history[curh] == '\0');
			  strcpy(inbuf, history[curh]);
			  inlen = strlen(inbuf);
			  inpos = 0;
			  replace = 1;
			  chg = 1;
			}
			else
			  term_beep();
			break;
		  case 'A': /* cursor up */
			if (curh != -1)
			{
			  do
				if (curh-- == 0)
				  curh = 99;
			  while (*history[curh] == '\0');
			  strcpy(inbuf, history[curh]);
			  inlen = strlen(inbuf);
			  inpos = 0;
			  replace = 1;
			  chg = 1;
			}
			else
			  term_beep();
			break;
		}
		cursor = 0;
	  }
	  else
	      switch (ch)
		{
	      case 0:
		  space_trick();
		  replace = 1;
		  chg = 1;
		  break;
	      case 27: /* escape */
		  escape = 1;
		  break;
	      case ctrl('A'):
		  inpos = 0;
		  replace = 0;
		  chg = 1;
		  break;
	      case ctrl('B'):
		  if (inpos)
		    {
		      inpos--;
		      chg = 1;
		    }
		  replace = 0;
		  break;
	      case ctrl('D'):
		  replace = 0;
		  chg = in_delnext();
		  break;
	      case ctrl('E'):
		  inpos = inlen;
		  replace = 0;
		  chg = 1;
		  break;
	      case ctrl('F'):
		  if (inpos < inlen)
		    {
		      inpos++;
		      chg = 1;
		    }
		  replace = 0;
		  break;
	      case ctrl('I'):
		  tab_trick();
		  replace = 1;
		  chg = 1;
		  break;
	      case ctrl('H'):
	      case 127:
		  chg = in_delprev();
		  replace = 0;
		  break;
	      case ctrl('K'):
		  inbuf[inpos] = '\0';
		  inlen = inpos;
		  chg = 1;
		  replace = 0;
		  break;
	      case ctrl('L'):
		  sic_redowin(1);
		  chg = 1;
		  break;
	      case ctrl('N'):
		  if (curh != -1)
		    {
		      do
			  if (curh++ == 99)
			      curh = 0;
		      while (*history[curh] == '\0');
		      strcpy(inbuf, history[curh]);
		      inlen = strlen(inbuf);
		      inpos = 0;
		      replace = 1;
		      chg = 1;
		    }
		  else
		      term_beep();
		  break;
	      case ctrl('P'):
		  if (curh != -1)
		    {
		      do
			  if (curh-- == 0)
			      curh = 99;
		      while (*history[curh] == '\0');
		      strcpy(inbuf, history[curh]);
		      inlen = strlen(inbuf);
		      inpos = 0;
		      replace = 1;
		      chg = 1;
		    }
		  else
		      term_beep();
		  break;
	      case ctrl('T'):
		  if (inpos)
		    {
		      char sw = inbuf[inpos];
		      
		      inbuf[inpos] = inbuf[inpos-1];
		      inbuf[inpos-1] = sw;
		      chg = 1;
		    }
		  else
		      term_beep();
		  replace = 0;
		  break;
	      case ctrl('U'):
		  inbuf[0] = '\0';
		  inlen = inpos = 0;
		  replace = 0;
		  chg = 1;
		  break;
	      case ctrl('V'):
		  quote = 1;
		  break;
	      case ctrl('X'):
		  screen = 1;
		  break;
	      case ctrl('J'):
	      case ctrl('M'):
		  if (*inbuf)
		    {
		      parse_input();
		      chg = 1;
		    }
		  else
		      sic_scroll(LI-4);
		  replace = 0;
		  break;
	      default:
		  in_insert(ch, &replace);
		  chg = 1;
		}
	}
    }

  if (chg)
      term_input(inbuf + ((CO-10)*(inpos/(CO-10))) - ((inpos>=CO-10) ? 10 :0),
		 inpos - ((CO-10)*(inpos/(CO-10))) + ((inpos>=CO-10) ? 10:0));
  return 1;
}
