/*
 * This module contains functions to parse a command line.
 */

#include <stdio.h>
#ifdef AMIGA
#include <exec/types.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#endif
#include "struct.h"
#include "error.h"
#include "port.h"
#include "calc.h"
#include "draw.h"
#include "parse.h"
#include "memory.h"

/* =======================================================================
 * Private Function Prototypes
 */
void parse_help ( char* command );

/* =======================================================================
 * Private Constant Definitions
 */

#define	WORD	80
#define	MAXARG	25
#define INT(n)	atoi(a[n])
#define	MAXHELP	27
#define	PROMPTSIZE	20
#define VARNAMESIZE	20

/* =======================================================================
 * Private Type Declarations
 */
typedef	struct var_type {
   char	name[VARNAMESIZE];
   APTR	data;
   struct var_type*	next;
} Var;

/* =======================================================================
 * Private Data Definitions
 */
static Var	*var_list = NULL;

static char prompt[PROMPTSIZE] = "=>";
static char	*help_command[MAXHELP] = {
	"#                      - comment line",
	"QUIT                   - exit program",
	"EXIT                   - exit program",
	"SETUP filename         - load fund information setup file",
	"PRICE filename         - load fund price history file",
	"TRANS filename         - load transaction file",
	"COMMAND filename       - load and execute a command file",
	"OPEN [x y w h [title]] - open active drawing window",
	"CLOSE [ALL]            - close active drawing window",
	"WINDOW [n]             - set the active window",
	"DRAW                   - draw in the active window",
	"CLEAR [type]           - clear the active window",
	"VALUE date fund        - value of a fund for a given date",
	"TOTAL [date [fund]]    - calculate the totals up to a given date",
	"SUMMARY [[ALL]|fund|TOTAL] - display a summary of the current totals",
	"HISTORY [date [date [fund|[TOTAL]]]] - display fund price history between two dates",
	"PROMPT string          - set the prompt string",
	"SET attribute value    - set a drawing attribute",
	"RESET                  - reset drawing attributes",
	"CHART type fund date date - display a chart",
	"DEBUG [[ON]|OFF]       - turn command debugging on/off",
	"HELP [command]         - get syntax of a command",
	"? [command]            - get syntax of a command",
	"PRINT [string]		- display a text string",
	"CASE                   - commands are not case sensitive",
	"STRINGS                - strings can be quoted using double quotes.",
	"VAR [VAR] [VALUE]	- assign value to variable"
};

/* =======================================================================
 * Public Data Definitions
 */

BOOL DebugFlag = FALSE;

/* =======================================================================
 * Public Function Definitions
 */

/*
 * This routine reads a line from standard in and return the result in 's'
 *
 * Returns: Length of line read in.
 */


int PARSE_readline ( char buf[], int max )
{
  int c,i;

  printf(prompt);
  for (i=0; i<max-1 && (c=getchar())!=EOF && c!='\n'; i++) buf[i] = c;
  if ( c == '\n') buf[i++] = c;
  buf[i] = '\0';
  return i;
}

/*
 * This routine parses a command line and calls the appropriate function
 *
 * Returns:  TRUE if exit command or error occured, FALSE otherwise.
 */
int PARSE_execute ( Account *p, char *buf )
{
  char	*a[MAXARG];
  int	narg = 0;
  int	error = NOERROR;
  int	i = 0;
  /*
   * Check for comment/blank lines
   */
  if (buf[0]=='\0' || buf[0]=='\n' || buf[0] == '#') return FALSE;
  /*
   * Break the command line up into a command and arguments
   */
  for (i=0; i<MAXARG; a[i++]="");
  i = 0;
  while (buf[i] != '\0' && buf[i] != '\n' ) {
    if (buf[i] == ' ' || buf[i] == '\t') i++;
    else {	/* Assign current arg and end it with a NULL */
      a[narg]=&buf[i];
      if(buf[i]=='"') {
	a[narg]=&buf[++i];				/* Skip " */
        while(buf[i]!='"' && buf[i]!='\0')i++;
      }
      else
	while(buf[i]!=' ' && buf[i]!='\t' && buf[i]!='\n' && buf[i]!='\0')i++;
      buf[i] = '\0';
      i++;
      narg++;
    }
  }
  UPPER(a[0]);
  if(DebugFlag) printf("%d ");
  /* See if there are any variable substitutions to be done */
  for (i=0; i < narg; i++ ) {
    if(DebugFlag) printf("[%s]",a[i]);
    if (a[i][0]== '$') {
       Var *v;
       v = var_list;
       while (v && strcmp(v->name,&(a[i][1]))) v = v->next;
       if (v) a[i] = v->data;
       else printf("Variable {%s} not defined\n",a[i]);
    }
  }
  if(DebugFlag) printf("\n");
  /*
   * Miscellaneous
   */
  if (!strcmp(a[0],"EXIT")||!strcmp(a[0],"QUIT")) {
    error = EXIT;
    PARSE_free();
  }
  else if (!strcmp(a[0],"DEBUG")) {
    UPPER(a[1]);
    if (!strcmp(a[1],"OFF")) DebugFlag = FALSE;
    if (!strcmp(a[1],"ON")||!strcmp(a[1],"")) DebugFlag = TRUE;
  }
  else if (!strcmp(a[0],"PROMPT")) {
	strncpy (prompt, a[1], PROMPTSIZE); prompt[PROMPTSIZE-1] = NULL;
  }
  else if (!strcmp(a[0],"HELP")||!strcmp(a[0],"?")) parse_help(a[1]);
  /*
   * Calc functions
   */
  else if (!strcmp(a[0],"VALUE")) {
    UPPER(a[2]);
	printf("%5.2f\n",CALC_find_price(p,CALC_alias_index(p,a[2]),INT(1)));
  }
  else if (!strcmp(a[0],"TOTAL")) {
    UPPER(a[2]);
    CALC_totals(p,INT(1),CALC_alias_index(p,a[2]));
  }
  else if (!strcmp(a[0],"SUMMARY")) {
    int f = CL_all;
    UPPER(a[1]);
	if(narg > 1 ) {
	  if (!strcmp(a[1],"ALL")) f = CL_all;
	  else if (!strcmp(a[1],"TOTAL")) f = CL_totals;
	  else f = CALC_alias_index(p,a[1]);
	}
    CALC_summary(p,f);
  }
  else if (!strcmp(a[0],"HISTORY")) {
    int f = CL_totals;
    if (narg > 3) {
	  UPPER(a[3]);
	  if (!strcmp(a[3],"TOTAL")) f = CL_totals;
	  else f = CALC_alias_index(p,a[3]);
	}
    CALC_history(p,INT(1),INT(2),f);
  }
  else if (!strcmp(a[0],"TEST")) CALC_test(p);
  /*
   * File loading functions
   */
  else if (!strcmp(a[0],"SETUP")) error = PORT_setup(p, a[1]);
  else if (!strcmp(a[0],"PRICE")) error = PORT_price(p, a[1]);
  else if (!strcmp(a[0],"TRANS")) error = PORT_trans(p, a[1]);
  else if (!strcmp(a[0],"COMMAND")) error = PORT_command(p, a[1]);
  else if (!strcmp(a[0],"TEST")) CALC_test(p);
  /*
   * Graphics functions
   */
  else if (!strcmp(a[0],"OPEN"))
    error = DRAW_open(INT(1), INT(2), INT(3), INT(4), a[5]);
  else if (!strcmp(a[0],"CLOSE")) {
    if (narg > 1) {
      UPPER(a[1]);
      if (!strcmp(a[1],"ALL")) error = DRAW_close(TRUE);
      else error = DRAW_close(FALSE);
	}
    else error = DRAW_close(FALSE);
  }
  else if (!strcmp(a[0],"WINDOW")) error = DRAW_window(INT(1));
  else if (!strcmp(a[0],"CLEAR")) error = DRAW_clear();
  else if (!strcmp(a[0],"RESET")) error = DRAW_reset();
  else if (!strcmp(a[0],"SET")) {
    if (narg < 3) error = MISSINGARG;
    else {
      UPPER(a[1]);
      error = DRAW_set( a[1], a[2] );
    }
  }
  else if (!strcmp(a[0],"DRAW")) error = DRAW_do( );
  /*
   * Chart functions
   */
  else if (!strcmp(a[0],"CHART")) {
    UPPER(a[2]);
    if (narg < 5) error = MISSINGARG;
	else error = DRAW_chart( p, a[1], CALC_alias_index(p,a[2]), INT(3), INT(4) );
  }
  else if (!strcmp(a[0],"PRINT")) printf("%s\n",a[1]);
  else if (!strcmp(a[0],"VAR")) {
    Var *v= NULL;
    v = var_list;
    if (strcmp(a[1],"")) {
      /* See if variable already exists */
      while (v && strcmp(v->name,a[1])) v =v->next;

      /* New Node */
      if (!v) {
        v = (Var *) MEM_malloc (sizeof (Var));
        v->next = var_list;
        var_list = v;
        strcpy(v->name,a[1]);
      }
      else {
        MEM_free ( v->data, strlen(v->data));
      }
      v->data = (char *) MEM_malloc (strlen(a[2]));
      strcpy(v->data,a[2]);
    }
    else while (v) {
      printf("%s = %s\n",v->name, v->data);
      v = v->next;
    }
  }

  else error = INVALID;

  if(DebugFlag) fprintf(stderr,"status:%d\n",error); 
  /*
   * Error handling
   */
  if ( error > NOERROR && error != INVALID ) {
    for (i=0; i < narg; i++) printf("%s ",a[i]);
	printf("\n");
  }
  if ( error == INVALID) printf("Invalid Command: '%s'\n",buf);
  else if (error > WARNING) printf("Warning: %d\n", error);
  else if (error > NOERROR) {
    printf("Error: %d\n", error);
    return TRUE;
  }
  else if ( error == EXIT ) return EXIT;
  return FALSE;
}

/*
 * Free all variable memory
 */
void PARSE_free ( void )
{
  Var *v= NULL, *n;
  v = var_list;
  while(v) {
    n = v->next;
    MEM_free (v->data, strlen(v->data));
    MEM_free (v, sizeof(Var));
    v = n;
  }
  var_list = NULL;
}

/* =======================================================================
 * Private Function Definitions
 */

void parse_help ( char* command )
{
  int l, i = 0;

  if (command && command[0]) {
    l = strlen(command);
    UPPER(command);
	while ( i < MAXHELP && strncmp(command,help_command[i],l) ) i++;
	if ( i < MAXHELP )  printf("%s\n",help_command[i]);
	else printf("Command not found, type HELP for a complete list\n");
  }
  else while (i < MAXHELP) printf("%s\n",help_command[i++]);
}
