package org.apache.xerces.util;

public class SymbolTable {
  protected static final int TABLE_SIZE = 101;
  
  protected Entry[] fBuckets = null;
  
  protected int fTableSize;
  
  public SymbolTable() {
    this(101);
  }
  
  public SymbolTable(int tableSize) {
    this.fTableSize = tableSize;
    this.fBuckets = new Entry[this.fTableSize];
  }
  
  public String addSymbol(String symbol) {
    int bucket = hash(symbol) % this.fTableSize;
    int length = symbol.length();
    Entry entry;
    for (entry = this.fBuckets[bucket]; entry != null; entry = entry.next) {
      if (length == entry.characters.length) {
        int i = 0;
        while (true) {
          if (i < length) {
            if (symbol.charAt(i) != entry.characters[i])
              break; 
            i++;
            continue;
          } 
          return entry.symbol;
        } 
      } 
    } 
    entry = new Entry(symbol, this.fBuckets[bucket]);
    this.fBuckets[bucket] = entry;
    return entry.symbol;
  }
  
  public String addSymbol(char[] buffer, int offset, int length) {
    int bucket = hash(buffer, offset, length) % this.fTableSize;
    Entry entry;
    for (entry = this.fBuckets[bucket]; entry != null; entry = entry.next) {
      if (length == entry.characters.length) {
        int i = 0;
        while (true) {
          if (i < length) {
            if (buffer[offset + i] != entry.characters[i])
              break; 
            i++;
            continue;
          } 
          return entry.symbol;
        } 
      } 
    } 
    entry = new Entry(buffer, offset, length, this.fBuckets[bucket]);
    this.fBuckets[bucket] = entry;
    return entry.symbol;
  }
  
  public int hash(String symbol) {
    int code = 0;
    int length = symbol.length();
    for (int i = 0; i < length; i++)
      code = code * 37 + symbol.charAt(i); 
    return code & 0x7FFFFFF;
  }
  
  public int hash(char[] buffer, int offset, int length) {
    int code = 0;
    for (int i = 0; i < length; i++)
      code = code * 37 + buffer[offset + i]; 
    return code & 0x7FFFFFF;
  }
  
  public boolean containsSymbol(String symbol) {
    int bucket = hash(symbol) % this.fTableSize;
    int length = symbol.length();
    for (Entry entry = this.fBuckets[bucket]; entry != null; entry = entry.next) {
      if (length == entry.characters.length) {
        int i = 0;
        while (true) {
          if (i < length) {
            if (symbol.charAt(i) != entry.characters[i])
              break; 
            i++;
            continue;
          } 
          return true;
        } 
      } 
    } 
    return false;
  }
  
  public boolean containsSymbol(char[] buffer, int offset, int length) {
    int bucket = hash(buffer, offset, length) % this.fTableSize;
    for (Entry entry = this.fBuckets[bucket]; entry != null; entry = entry.next) {
      if (length == entry.characters.length) {
        int i = 0;
        while (true) {
          if (i < length) {
            if (buffer[offset + i] != entry.characters[i])
              break; 
            i++;
            continue;
          } 
          return true;
        } 
      } 
    } 
    return false;
  }
  
  protected static final class Entry {
    public String symbol;
    
    public char[] characters;
    
    public Entry next;
    
    public Entry(String symbol, Entry next) {
      this.symbol = symbol.intern();
      this.characters = new char[symbol.length()];
      symbol.getChars(0, this.characters.length, this.characters, 0);
      this.next = next;
    }
    
    public Entry(char[] ch, int offset, int length, Entry next) {
      this.characters = new char[length];
      System.arraycopy(ch, offset, this.characters, 0, length);
      this.symbol = (new String(this.characters)).intern();
      this.next = next;
    }
  }
}
