// Copyright 2025 International Digital Economy Academy
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

///|
/// 13.2.5.32 Before attribute name state
fn Tokenizer::run_before_attribute_name_state(self : Tokenizer) -> Token? {
  match self.consume() {
    Some(c) if is_whitespace(c) => None // Ignore whitespace
    Some('/') | Some('>') => {
      self.reconsume()
      self.state = AfterAttributeName
      None
    }
    Some('=') => {
      self.emit_error(UnexpectedEqualsSignBeforeAttributeName)
      self.start_new_attribute()
      self.current_attr_name.write_char('=')
      self.state = AttributeName
      None
    }
    Some(_) => {
      self.start_new_attribute()
      self.reconsume()
      self.state = AttributeName
      None
    }
    None => {
      self.reconsume()
      self.state = AfterAttributeName
      None
    }
  }
}

///|
/// 13.2.5.33 Attribute name state
fn Tokenizer::run_attribute_name_state(self : Tokenizer) -> Token? {
  match self.consume() {
    Some(c) if is_whitespace(c) || c == '/' || c == '>' => {
      self.finish_attribute_name()
      self.reconsume()
      self.state = AfterAttributeName
      None
    }
    Some('=') => {
      self.finish_attribute_name()
      self.state = BeforeAttributeValue
      None
    }
    Some(c) if is_ascii_upper_alpha(c) => {
      self.current_attr_name.write_char(to_ascii_lower(c))
      None
    }
    Some('\u{0000}') => {
      self.emit_error(UnexpectedNullCharacter)
      self.current_attr_name.write_char('\u{FFFD}')
      None
    }
    Some('"') | Some('\'') | Some('<') => {
      self.emit_error(UnexpectedCharacterInAttributeName)
      self.current_attr_name.write_char(self.input[self.pos - 1])
      None
    }
    Some(c) => {
      self.current_attr_name.write_char(c)
      None
    }
    None => {
      self.finish_attribute_name()
      self.reconsume()
      self.state = AfterAttributeName
      None
    }
  }
}

///|
/// 13.2.5.34 After attribute name state
fn Tokenizer::run_after_attribute_name_state(self : Tokenizer) -> Token? {
  match self.consume() {
    Some(c) if is_whitespace(c) => None // Ignore whitespace
    Some('/') => {
      self.finish_attribute()
      self.state = SelfClosingStartTag
      None
    }
    Some('=') => {
      self.state = BeforeAttributeValue
      None
    }
    Some('>') => {
      self.finish_attribute()
      self.state = Data
      Some(self.emit_current_tag())
    }
    Some(_) => {
      self.finish_attribute()
      self.start_new_attribute()
      self.reconsume()
      self.state = AttributeName
      None
    }
    None => {
      self.emit_error(EofInTag)
      Some(EOF)
    }
  }
}

///|
/// 13.2.5.35 Before attribute value state
fn Tokenizer::run_before_attribute_value_state(self : Tokenizer) -> Token? {
  match self.consume() {
    Some(c) if is_whitespace(c) => None // Ignore whitespace
    Some('"') => {
      self.state = AttributeValueDoubleQuoted
      None
    }
    Some('\'') => {
      self.state = AttributeValueSingleQuoted
      None
    }
    Some('>') => {
      self.emit_error(MissingAttributeValue)
      self.finish_attribute()
      self.state = Data
      Some(self.emit_current_tag())
    }
    Some(_) => {
      self.reconsume()
      self.state = AttributeValueUnquoted
      None
    }
    None => {
      self.emit_error(EofInTag)
      Some(EOF)
    }
  }
}

///|
/// 13.2.5.36 Attribute value (double-quoted) state
fn Tokenizer::run_attribute_value_double_quoted_state(
  self : Tokenizer,
) -> Token? {
  match self.consume() {
    Some('"') => {
      self.state = AfterAttributeValueQuoted
      None
    }
    Some('&') => {
      self.return_state = AttributeValueDoubleQuoted
      self.state = CharacterReference
      None
    }
    Some('\u{0000}') => {
      self.emit_error(UnexpectedNullCharacter)
      self.current_attr_value.write_char('\u{FFFD}')
      None
    }
    Some(c) => {
      self.current_attr_value.write_char(c)
      None
    }
    None => {
      self.emit_error(EofInTag)
      Some(EOF)
    }
  }
}

///|
/// 13.2.5.37 Attribute value (single-quoted) state
fn Tokenizer::run_attribute_value_single_quoted_state(
  self : Tokenizer,
) -> Token? {
  match self.consume() {
    Some('\'') => {
      self.state = AfterAttributeValueQuoted
      None
    }
    Some('&') => {
      self.return_state = AttributeValueSingleQuoted
      self.state = CharacterReference
      None
    }
    Some('\u{0000}') => {
      self.emit_error(UnexpectedNullCharacter)
      self.current_attr_value.write_char('\u{FFFD}')
      None
    }
    Some(c) => {
      self.current_attr_value.write_char(c)
      None
    }
    None => {
      self.emit_error(EofInTag)
      Some(EOF)
    }
  }
}

///|
/// 13.2.5.38 Attribute value (unquoted) state
fn Tokenizer::run_attribute_value_unquoted_state(self : Tokenizer) -> Token? {
  match self.consume() {
    Some(c) if is_whitespace(c) => {
      self.finish_attribute()
      self.state = BeforeAttributeName
      None
    }
    Some('&') => {
      self.return_state = AttributeValueUnquoted
      self.state = CharacterReference
      None
    }
    Some('>') => {
      self.finish_attribute()
      self.state = Data
      Some(self.emit_current_tag())
    }
    Some('\u{0000}') => {
      self.emit_error(UnexpectedNullCharacter)
      self.current_attr_value.write_char('\u{FFFD}')
      None
    }
    Some('"') | Some('\'') | Some('<') | Some('=') | Some('`') => {
      self.emit_error(UnexpectedCharacterInUnquotedAttributeValue)
      self.current_attr_value.write_char(self.input[self.pos - 1])
      None
    }
    Some(c) => {
      self.current_attr_value.write_char(c)
      None
    }
    None => {
      self.emit_error(EofInTag)
      Some(EOF)
    }
  }
}

///|
/// 13.2.5.39 After attribute value (quoted) state
fn Tokenizer::run_after_attribute_value_quoted_state(
  self : Tokenizer,
) -> Token? {
  match self.consume() {
    Some(c) if is_whitespace(c) => {
      self.finish_attribute()
      self.state = BeforeAttributeName
      None
    }
    Some('/') => {
      self.finish_attribute()
      self.state = SelfClosingStartTag
      None
    }
    Some('>') => {
      self.finish_attribute()
      self.state = Data
      Some(self.emit_current_tag())
    }
    Some(_) => {
      self.emit_error(MissingWhitespaceBetweenAttributes)
      self.finish_attribute()
      self.reconsume()
      self.state = BeforeAttributeName
      None
    }
    None => {
      self.emit_error(EofInTag)
      Some(EOF)
    }
  }
}