#ifndef TOKENWAD_INCLUDED
#define TOKENWAD_INCLUDED
//#define TOKENWAD_DEBUGMODE

// Simple string tokenizer class
// Jari Komppa 2001
class tokenwad 
{
public:
  tokenwad() 
  { 
      t = NULL; 
      count = 0; 
  }
  ~tokenwad() 
  { 
      for (int i = 0; i < count; i++) 
          delete[] t[i]; 
      delete[] t; 
  }
  void tokenize(const char * buf, const char * separators) 
  {
    // if reusing this tokenizer, clean up old mess:
    if (t!=NULL) {
      for (int i=0;i<count;i++) 
      {
        delete[] t[i]; 
      }
      delete[] t;
      count = 0;
      t = NULL;
    }
    if (buf == NULL) return;
    int sepcount = 0;
    while (separators[sepcount] != 0) 
        sepcount++;

    // pass 1: count tokens

    count = 1;
    int i = 0;
    while (buf[i] !=0 ) 
    {      
      for (int j = 0; j < sepcount; j++)
        if (buf[i] == separators[j]) 
          count++;
      i++;
    }
    int * offsets = new int[count + 1];
    int * lengths = new int[count + 1];
    count = 0;
    offsets[0] = 0;
    i = 0;

    // pass 2: count token sizes and offsets

    while (buf[i] != 0) 
    {      
      for (int j = 0; j < sepcount; j++)
        if (buf[i] == separators[j]) 
          offsets[++count] = i + 1;
      i++;
    }
    offsets[++count] = i + 1;

    // pass 3: trim
    
    for (i=0;i<count;i++) 
    {
      // ltrim
      //while (buf[offsets[i]]==32 || buf[offsets[i]]==9) offsets[i]++;
      // rtrim
      lengths[i] = offsets[i + 1] - (offsets[i] + 1);
      //while (lengths[i]>0 && (buf[offsets[i]+lengths[i]-1]==32 || buf[offsets[i]+lengths[i]-1]==9)) lengths[i]--;
    }
    
    // pass 4: allocate

    t = new char*[count];
    for (i = 0; i < count; i++) 
    {
      t[i] = new char[lengths[i] + 1];
      t[i][lengths[i]] = 0;
    }

    // pass 5: copy tokens
    for (i = 0; i < count; i++)
      for (int j = offsets[i], c = 0; j < offsets[i] + lengths[i]; j++, c++)
        t[i][c] = buf[j];
    delete[] offsets;
    delete[] lengths;
  }

  void tokenize(const char * buf) 
  {
    tokenize(buf,"=,");
  }

  int tokenequals(int tokenidx, const char * compareto) 
  {
    const char * t1 = token(tokenidx), * t2 = compareto;
    while (*t1 != 0 && *t2 != 0 && *t1 == *t2) 
    { 
        t1++; 
        t2++; 
    }
    if (*t1 == *t2) 
        return 1;
    return 0;
  }

  int tokenequalsnocase(int tokenidx, const char * compareto) 
  {
    const char *t1 = token(tokenidx), *t2 = compareto;
    while (*t1 != 0 && *t2 != 0 && upcase(*t1) == upcase(*t2)) 
    { 
        t1++; 
        t2++; 
    }
    if (*t1 == *t2) 
        return 1;
    return 0;
  }
  
  int tokens() 
  { 
      return count; 
  }

  const char * token(int idx) 
  { 
      return (const char*)t[idx]; 
  }

  char * tokendup(int idx) 
  { 
    int l = 0;
    const char *s = t[idx];
    while (s[l] != 0) 
        l++;
    char *dup = new char[l + 1];
    dup[l] = '\0';
    memcpy(dup,s,l);
    return dup;
  }

#ifdef TOKENWAD_DEBUGMODE
  // Dump contents; buffer had better be big enough =)
  void dumpcontents(char * buf) 
  {
    sprintf(buf,"TokenWad dump - %d tokens:\r\n",count);
    int ofs = strlen(buf);
    for (int i = 0; i < count; i++) {
      buf[ofs++] = '"';
      int l = strlen(t[i]);
      memcpy(buf + ofs, t[i], l);
      ofs += l;
      buf[ofs++] = '"';
      buf[ofs++] = '\r';
      buf[ofs++] = '\n';
    }
    buf[ofs++] = '\0';
  }
#endif

private:
  // Token strings
  char **t;  
  // Number of token strings
  int count;
  // upcase
  char upcase(char i) 
  {
    if (i >= 'a' && i <= 'z') 
        return i - ('a' - 'A');
    return i;
  }
};
#endif // TOKENWAD_INCLUDED