// Lexical analyzer for Glob patterns.

///|
/// Tokenizes a glob pattern string into a sequence of Tokens.
pub fn tokenize(pattern : String) -> Result[Array[Token], GlobError] {
  let tokens : Array[Token] = []
  let len = pattern.length()
  let mut i = 0
  let mut in_brackets = false
  let current_text = StringBuilder::new()

  fn flush_text() {
    let s = current_text.to_string()
    if s.length() > 0 {
      tokens.push(Token::Text(s))
      current_text.reset()
    }
  }

  while i < len {
    let c = pattern[i].to_int().unsafe_to_char()
    if in_brackets {
      if c == ']' {
        flush_text()
        tokens.push(Token::RBracket)
        in_brackets = false
        i = i + 1
      } else if c == '!' || c == '^' {
        let last_token_is_lbracket = if tokens.length() > 0 {
          match tokens[tokens.length() - 1] {
            Token::LBracket => true
            _ => false
          }
        } else {
          false
        }
        if last_token_is_lbracket {
          tokens.push(Token::Negate)
        } else {
          tokens.push(Token::Char(c))
        }
        i = i + 1
        // Check for range, e.g. 'a-z'
      } else if i + 2 < len &&
        pattern[i + 1].to_int().unsafe_to_char() == '-' &&
        pattern[i + 2].to_int().unsafe_to_char() != ']' {
        let start = c
        let end = pattern[i + 2].to_int().unsafe_to_char()
        tokens.push(Token::Range(start, end))
        i = i + 3
      } else {
        tokens.push(Token::Char(c))
        i = i + 1
      }
    } else {
      match c {
        '\\' =>
          if i + 1 < len {
            current_text.write_char(pattern[i + 1].to_int().unsafe_to_char())
            i = i + 2
          } else {
            current_text.write_char('\\')
            i = i + 1
          }
        '*' => {
          flush_text()
          if i + 1 < len && pattern[i + 1].to_int().unsafe_to_char() == '*' {
            tokens.push(Token::GlobStar)
            i = i + 2
          } else {
            tokens.push(Token::Star)
            i = i + 1
          }
        }
        '?' => {
          flush_text()
          tokens.push(Token::Question)
          i = i + 1
        }
        '{' => {
          flush_text()
          tokens.push(Token::LBrace)
          i = i + 1
        }
        '}' => {
          flush_text()
          tokens.push(Token::RBrace)
          i = i + 1
        }
        ',' => {
          flush_text()
          tokens.push(Token::Comma)
          i = i + 1
        }
        '[' => {
          flush_text()
          tokens.push(Token::LBracket)
          in_brackets = true
          i = i + 1
        }
        _ => {
          current_text.write_char(c)
          i = i + 1
        }
      }
    }
  }
  flush_text()
  Ok(tokens)
}