#include "RS232Parser.h"

const char* RS232PNextToken(const char* command) {
  const char *pos=command;
  while ( *pos!=':' && *pos!='?' && *pos!='\0' ) pos++;
  if ( *pos==':' ) return ++pos;
  else return 0;
} 

int RS232PMinTokenLength(const char* keyword) {
  const char* pos=keyword;
  while( isupper(*pos) || *pos=='*' ) pos++;
  return pos-keyword;
}

int RS232PTokenLength(const char* keyword) {
  const char* pos=keyword;
  while( *pos!=':' && *pos!='?' && *pos!='\0' ) pos++;
  return pos-keyword;
}

int RS232PIsQuery(const char* command) {
  if ( command[strlen(command)-1] == '?' ) return 1;
  else return 0;
}

int RS232PMatchCommand(const char* command, const char* template) {
  const char *pos1=command, *pos2=template;
  int minlen, toklen;
  /* skip heading blanks */
  while ( *pos1==' ' ) pos1++; if ( *pos1==':' ) pos1++; 
  while ( *pos2==' ' ) pos2++; if ( *pos2==':' ) pos2++; 
  do {
    minlen = RS232PMinTokenLength(pos2);
    toklen = RS232PTokenLength(pos1);
    if ( strncasecmp(pos1,pos2,minlen) || strncasecmp(pos1,pos2,toklen) )
      return 0;
    pos1 = RS232PNextToken(pos1);
    pos2 = RS232PNextToken(pos2);
  } while (pos1 && pos2); 
  if ( pos1 || pos2 ) return 0; 
  else return 1;
} 

int RS232PTekExtractCommand(const char* buffer, char* command, char* argument) {
  const char *pos, *posc=0, *endc=0, *posa=0;
  int isarg=0, quoted=0;
  char qchar, *endprefix; 
  static char* lastcommand=0;
  int bufferlen, len;

  command[0]='\0';
  if (lastcommand) strcat(command,lastcommand);
  if ( (endprefix=strrchr(command,':')) ) *(endprefix+1)='\0'; 
  else if ( (endprefix=command+strlen(command))!=command ) {
    if (*(endprefix-1)=='?') *(endprefix-1)=':';
    else { *endprefix=':'; *(endprefix+1)='\0'; }
  }

  bufferlen=strlen(buffer);
  for (pos=buffer; pos<buffer+bufferlen; pos++) {
    if ( (*pos==';' || *pos=='\n') && quoted==0 ) break;
    if ( *pos != ' ' && posc==0 ) {
      posc=pos;
      if (*pos==':') command[0]='\0';
    }
    if ( *pos==' ' && posc!=0 && isarg==0 ) {
      endc=pos;
      isarg=1;
    } 
    if ( *pos != ' ' && isarg==1 && posa==0 ) posa=pos;
    if ( ( *pos =='"' || *pos =='\'') && posa!=0 ) {
      if ( quoted==0 ) {
	quoted=1;
	qchar=*pos;
      } else if ( qchar==*pos ) { 
	quoted=0;
      }
    } 
  }
  if (posa != 0 ) {
    strncpy(argument,posa,pos-posa);
    argument[pos-posa]='\0';
  } else argument[0]='\0';
  if (posc!=0) {
    if (endc!=0) {
      strncat(command,posc,endc-posc);
    } else {
      strncat(command,posc,pos-posc);
    }
  } else command[0]='\0';
  
  free(lastcommand);
  if (*pos==';') {
    len =  strlen(command)+1;
    lastcommand=(char*)malloc( len );
    strncpy(lastcommand,command,len);
  } else lastcommand=0;

  return pos-buffer+1;
}

int RS232PSelectString(const char* selection, char *choices[], int Nchoices) {
  int i;
  for (i=0; i<Nchoices; i++) {
    if ( RS232PMatchCommand(selection,choices[i]) ) return i;
  }
  return -1;
}
