/* Copyright (C) 1998, 1999  Free Software Foundation

   This file is part of libgcj.

This software is copyrighted work licensed under the terms of the
Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
details.  */

package java.util;

/**
 * @author Warren Levy <warrenl@cygnus.com>
 * @date August 24, 1998.
 */
/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
 * "The Java Language Specification", ISBN 0-201-63451-1
 * plus online API docs for JDK 1.2 beta from http://www.javasoft.com.
 * Status:  Believed complete and correct
 */

public class StringTokenizer implements Enumeration
{
  /* String to be parsed */
  private String inputString;

  /* String to be parsed put into a char array for efficient access */
  private char[] chArray;

  /* Set of delimiter characters for separating tokens */
  private String delimiters;

  /* Whether delimiters in this instance are treated as tokens themselves */
  private boolean returnDelimiters;

  /* Index into the input string to start parsing for the next token */
  private int inputStringIndex;

  public StringTokenizer(String str)
  {
    this(str, " \t\n\r", false);
  }

  public StringTokenizer(String str, String delims)
  {
    this(str, delims, false);
  }

  public StringTokenizer(String str, String delims, boolean retDelim)
  {
    inputString = str;
    delimiters = delims;
    returnDelimiters = retDelim;
    inputStringIndex = 0;

    // Work on a copy of the remaining string in a char array
    // to gain efficiency of using primitives
    chArray = new char[inputString.length()];
    inputString.getChars(0, inputString.length(), chArray, 0);
  }

  public int countTokens()
  {
    int count = 0;
    int delimiterCount = 0;
    boolean tokenFound = false;		// Set when a non-delimiter is found
    int offset = inputStringIndex;

    // Note for efficiency, we count up the delimiters rather than check
    // returnDelimiters every time we encounter one.  That way, we can
    // just do the conditional once at the end of the method
    while (offset < chArray.length)
      {
	if (isDelimiter(chArray[offset++]))
	  {
	    if (tokenFound)
	      {
		// Got to the end of a token
	        count++;
	        tokenFound = false;
	      }

	    delimiterCount++;		// Increment for this delimiter
	  }
	else
	  {
	    tokenFound = true;

	    // Get to the end of the token
	    while (offset < chArray.length && !isDelimiter(chArray[offset]))
	      offset++;
	  }
      }

    // Make sure to count the last token 
    if (tokenFound)
      count++;

    // if counting delmiters add them into the token count
    return returnDelimiters ? count + delimiterCount : count;
  }

  public boolean hasMoreElements()
  {
    return hasMoreTokens();
  }

  public boolean hasMoreTokens()
  {
    int offset = inputStringIndex;

    while (offset < chArray.length)
      if (!isDelimiter(chArray[offset++]) || returnDelimiters)
	{
	  // update the current position with the start of the next token
	  inputStringIndex = --offset;

	  return true;
	}

    return false;
  }

  public Object nextElement()
  {
    return nextToken();
  }

  public String nextToken()
  {
    int offset = inputStringIndex;
    int startSubstr = -1;

    // Make sure we have more chars left to parse
    // and then find the start of the next token
    while (offset < chArray.length && startSubstr < 0)
      {
	// Find the start of the token; skipping initial delimiters
	if (!isDelimiter(chArray[offset++]))
	  startSubstr = offset - 1;
	else if (returnDelimiters)
	  {
	    // The single char delimiter is treated as a token
	    inputStringIndex = offset;		// update the current position

	    return inputString.substring(offset - 1, inputStringIndex);
	  }
      }

    // Now look for the end of the token
    while (offset < chArray.length)
      {
	if (isDelimiter(chArray[offset++]))
	  {
	    // Found the end of token
            inputStringIndex = offset - 1;	// update the current position

            return inputString.substring(startSubstr, inputStringIndex);
	  }
      }

    // Got to the end of the string without finding the start of a token
    if (startSubstr < 0)
      throw new NoSuchElementException();

    // Got to the end of the string before a delimiter
    inputStringIndex = offset;		// update the current position

    return inputString.substring(startSubstr, inputStringIndex);
  }

  public String nextToken(String delims)
  {
    // First replace with new set of delimiters
    delimiters = delims;

    return nextToken();
  }

  // This private method could be inlined but the other methods are
  // more readable this way, so we'll take the hit on efficiency.
  private boolean isDelimiter(char ch)
  {
    return delimiters.indexOf(ch, 0) >= 0;
  }
}
