//
// Copyright (C) 1991 Texas Instruments Incorporated.
//
// Permission is granted to any individual or institution to use, copy, modify,
// and distribute this software, provided that this complete copyright and
// permission notice is maintained, intact, in all copies and supporting
// documentation.
//
// Texas Instruments Incorporated provides this software "as is" without
// express or implied warranty.
//
//
// Created: LGO 05/22/89 -- Initial design and implementation
//

#include <cool/String.h>
#include <cool/char.h>
#include <cool/Package.h>

//
// Compare an unknown WORD to a KNOWN word, giving up after GRACE errors.
// Returns the number of errors.
//
int spell_compare_sensitive(const char* word, const char* known, int grace) {
  int errors = 0;
  while(errors <= grace &&
	*word != END_OF_STRING &&
	*known != END_OF_STRING) {
    if(*word == *known) {
      word++;
      known++;
    } else {
      errors++;
      if(*(word+1) != END_OF_STRING &&	  /* ABCD known */
	 *(word+1) == *known) {		  /* AXBX word  */
	if(*(known+1) != END_OF_STRING &&
	   *(known+1) == *word) {
	  word += 2;			  /* Transposed */
	  known += 2;
	} else {
	  word++;			  /* Unknown */
	}
      } else {
	if(*(known+1) != END_OF_STRING && /* ABCD known */
	   *(known+1) == *word) {	   /* ACD  word */
	  known++;			  /* omit */
	} else {
	  word++;				// unknown
	  known++;
	}
      } 
    } // if mismatch
  } // end while
  while(*word++ != END_OF_STRING) errors++;
  while(*known++ != END_OF_STRING) errors++;
  return errors;
}

int spell_compare(const char* word, const char* known, int grace) {
  int errors = 0;
  char wc, kc, tc;
  while(errors <= grace &&
	(wc=*word) != END_OF_STRING &&
	(kc=*known) != END_OF_STRING) {
    if(wc == kc || TO_UPPER(wc) == TO_UPPER(kc)) {
      word++;
      known++;
    } else {
      errors++;
      if((tc=*(word+1)) != END_OF_STRING &&	       /* ABCD known */
	 (tc == kc || TO_UPPER(tc) == TO_UPPER(kc))) { /* AXBX word  */
	if((tc=*(known+1)) != END_OF_STRING &&
	   (wc == tc || TO_UPPER(wc) == TO_UPPER(tc))) {
	  word += 2;			  /* Transposed */
	  known += 2;
	} else {
	  word++;			  /* Unknown */
	}
      } else {
	if((tc=*(known+1)) != END_OF_STRING &&           /* ABCD known*/
	   (wc == tc || TO_UPPER(wc) == TO_UPPER(tc))) { /* ACD  word */
	  known++;			  /* omit */
	} else {
	  word++;				// unknown
	  known++;
	}
      } 
    } // if mismatch
  } // end while
  while(*word++ != END_OF_STRING) errors++;
  while(*known++ != END_OF_STRING) errors++;
  return errors;
}

// Does "interlisp" style spelling correction on a symbol name.
// Returns the number of matches and sets the current position
// to the best match found. The number of errors is available
// by passing a pointer to an int as the last parameter.
int correct(Package& pkg, const char* name, Boolean sensitive, int* errors) {
  int len = strlen(name);
  int count = 0;
  int grace = 1;
  if (len > 9) grace += 3;
  else if (len > 5) grace += 2;
  else if (len > 3) grace += 1;
  Symbol* best = NULL;

  for(pkg.reset(); pkg.next();) {
    int new_grace = (sensitive) ?
	spell_compare_sensitive(name, pkg.value()->name(), grace) :
	spell_compare(name, pkg.value()->name(), grace);
    if (new_grace == grace) {
      best = pkg.value();
      count += 1;
    } else if (new_grace < grace) {
      grace = new_grace;
      best = pkg.value();
      count = 1;
    }
  }
  if (errors != NULL) *errors = grace;
  if (count > 0) {
    char* bname = (char*) best->name();
    pkg.find(bname);
  }
  return count;
}

