@Override
    public boolean hasMoreTokens()
    {
        // Already found a token
        if (_hasToken)
            return true;

        _lastStart = _i;

        int state = 0;
        boolean escape = false;
        while (_i < _string.length())
        {
            char c = _string.charAt(_i++);

            switch (state)
            {
              case 0: // Start
                  if (_delim.indexOf(c) >= 0)
                  {
                      if (_returnDelimiters)
                      {
                          _token.append(c);
                          return _hasToken = true;
                      }
                  }
                  else if (c == '\'' && _single)
                  {
                      if (_returnQuotes)
                          _token.append(c);
                      state = 2;
                  }
                  else if (c == '\"' && _double)
                  {
                      if (_returnQuotes)
                          _token.append(c);
                      state = 3;
                  }
                  else
                  {
                      _token.append(c);
                      _hasToken = true;
                      state = 1;
                  }
                  continue;

              case 1: // Token
                  _hasToken = true;
                  if (escape)
                  {
                      escape = false;
                      if (ESCAPABLE_CHARS.indexOf(c) < 0)
                          _token.append('\\');
                      _token.append(c);
                  }
                  else if (_delim.indexOf(c) >= 0)
                  {
                      if (_returnDelimiters)
                          _i--;
                      return _hasToken;
                  }
                  else if (c == '\'' && _single)
                  {
                      if (_returnQuotes)
                          _token.append(c);
                      state = 2;
                  }
                  else if (c == '\"' && _double)
                  {
                      if (_returnQuotes)
                          _token.append(c);
                      state = 3;
                  }
                  else if (c == '\\')
                  {
                      escape = true;
                  }
                  else
                      _token.append(c);
                  continue;


              case 2: // Single Quote
                  _hasToken = true;
                  if (escape)
                  {
                      escape = false;
                      if (ESCAPABLE_CHARS.indexOf(c) < 0)
                          _token.append('\\');
                      _token.append(c);
                  }
                  else if (c == '\'')
                  {
                      if (_returnQuotes)
                          _token.append(c);
                      state = 1;
                  }
                  else if (c == '\\')
                  {
                      if (_returnQuotes)
                          _token.append(c);
                      escape = true;
                  }
                  else
                      _token.append(c);
                  continue;


              case 3: // Double Quote
                  _hasToken = true;
                  if (escape)
                  {
                      escape = false;
                      if (ESCAPABLE_CHARS.indexOf(c) < 0)
                          _token.append('\\');
                      _token.append(c);
                  }
                  else if (c == '\"')
                  {
                      if (_returnQuotes)
                          _token.append(c);
                      state = 1;
                  }
                  else if (c == '\\')
                  {
                      if (_returnQuotes)
                          _token.append(c);
                      escape = true;
                  }
                  else
                      _token.append(c);
                  continue;

              default:
                  break;
            }
        }

        return _hasToken;
    }
@Test
    public void testHasMoreToken() {
        QuotedStringTokenizer tokenizer = new QuotedStringTokenizer("");
        assertFalse(tokenizer.hasMoreTokens());
        tokenizer = new QuotedStringTokenizer("one");
        assertTrue(tokenizer.hasMoreTokens());
    }