

#include "MSString.h"
#include "Table.h"
#include "WildcardMatcher.h"
#include "RegexMatcher.h"
#include "AccessFormatPlugin.h"

int TextMatcher::Match(const String &S) {
  int Result = -1;
  
  // See if we have done this match already...
  Result = CachedResults[S];
  if (Result != -1) return Result;
  
  // Match it
  Result = MatchImpl(S);
  
  // Add the result to the list
  CachedResults[S] = Result;
  return Result;
}

int WildcardMatcher::MatchImpl(const char *S) {
  String Temp, F(Pattern);
  
  while (F.Length() != 0) {
    F.Tokenize(";", Temp);
    if (Match121(Temp, S)) return 1;
  }
  return 0;
}


// Match121 - Returns 0 if the string does not match the Filter/pattern returns
//   1 if they do match.
//
int WildcardMatcher::Match121(const char *Fil, const char *Str) {
  const char *p = Fil, *n = Str, *np;
  char c;
  int Not;
  
  while ((c = *p++) != '\0') {
    switch (c) {
    case '?':
      if (*n == '\0') return 0;
      break;
      
    case '\\':
      if (*n != c) return 0;
      break;
      
    case '*':
      // Combine all of the wildcards together if there are multiples...
      for (c = *p++; c == '?' || c == '*'; c = *p++) {
        if (c == '?') {
          if (*n == '\0') return 0;
          n++;
        } 
      }
      
      if (c == '\0') return 1;
      
      for (p--; *n != '\0'; n++) {
        if (((c == '[') || (*n == c)) && (Match121(p, n) == 1))
          return 1;
      }
      
      return 0;
      
    case '[': 
      if (*n == '\0') return 0;
      
      for (np = p; (np) && (*np) && (*np != ']'); np++)
        ;
      
      if (np && !*np) {
        if (*n != '[') return 0;
        break;
      }
      
      Not = ((*p == '!') || (*p == '^'));
      if (Not) p++;
      
      c = *p++;
      
      for (;;) {
        char cstart = c, cend = c;
        
        if (c == '\0') return 0;   // Unterminated [
        
        c = *p++;
        if ((c == '-') && (*p != ']')) {
          cend = *p++;
          if (cend == '\0') return 0;
          
          c = *p++;
        }
        
        if ((*n >= cstart) && (*n <= cend)) {
          while (c != ']') {
            if (c == '\0') return 0;   // Unterminated [
            c = *p++;
          }
          
          if (Not) return 0;
          break;
        }
        
        if (c == ']') break;
      }
      
      if (!Not) return 0;
      break;
      
    default:
      if (c != *n) return 0;
    }
    
    n++;
  }
  
  if (*n == '\0') return 1;
  
  return 0;
}
