// Copyright 2026 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.

///|
fn Tokenizer::emit_current_processing_instruction(self : Tokenizer) -> Token {
  ProcessingInstruction(
    target=self.current_pi_target.to_string(),
    data=self.current_pi_data.to_string(),
  )
}

///|
fn Tokenizer::convert_pi_target_to_comment(self : Tokenizer) -> Unit {
  self.reset_comment()
  self.current_comment.write_char('?')
  self.current_comment.write_string(self.temp_buffer.to_string())
}

///|
/// 13.2.5.72 Processing instruction open state
fn Tokenizer::run_processing_instruction_open_state(self : Tokenizer) -> Token? {
  match self.consume() {
    Some(c) if is_ascii_alpha(c) || c == '_' => {
      self.reconsume()
      self.state = ProcessingInstructionTarget
      None
    }
    None => {
      self.emit_error(EofInProcessingInstruction)
      Some(EOF)
    }
    Some(_) => {
      self.emit_error(InvalidFirstCharacterOfProcessingInstructionTarget)
      self.convert_pi_target_to_comment()
      self.reconsume()
      self.state = BogusComment
      None
    }
  }
}

///|
/// 13.2.5.73 Processing instruction target state
fn Tokenizer::run_processing_instruction_target_state(
  self : Tokenizer,
) -> Token? {
  match self.consume() {
    Some(c) if is_whitespace(c) || c == '?' || c == '>' => {
      let target = self.temp_buffer.to_string()
      let target_lower = target.to_lower()
      if target_lower == "xml" || target_lower == "xml-stylesheet" {
        self.emit_error(DisallowedProcessingInstructionTarget)
        self.convert_pi_target_to_comment()
        self.reconsume()
        self.state = BogusComment
      } else {
        self.current_pi_target.reset()
        self.current_pi_target.write_string(target)
        self.current_pi_data.reset()
        self.reconsume()
        self.state = AfterProcessingInstructionTarget
      }
      None
    }
    Some(c) if is_ascii_alphanumeric(c) || c == '-' || c == '_' => {
      self.temp_buffer.write_char(c)
      None
    }
    None => {
      self.emit_error(EofInProcessingInstruction)
      Some(EOF)
    }
    Some(_) => {
      self.emit_error(InvalidProcessingInstructionTarget)
      self.convert_pi_target_to_comment()
      self.reconsume()
      self.state = BogusComment
      None
    }
  }
}

///|
/// 13.2.5.74 After processing instruction target state
fn Tokenizer::run_after_processing_instruction_target_state(
  self : Tokenizer,
) -> Token? {
  match self.consume() {
    Some(c) if is_whitespace(c) => None
    Some(_) => {
      self.reconsume()
      self.state = ProcessingInstructionData
      None
    }
    None => {
      self.emit_error(EofInProcessingInstruction)
      Some(EOF)
    }
  }
}

///|
/// 13.2.5.75 Processing instruction data state
fn Tokenizer::run_processing_instruction_data_state(self : Tokenizer) -> Token? {
  match self.consume() {
    Some('?') => {
      self.state = ProcessingInstructionQuestionable
      None
    }
    Some('>') => {
      self.state = Data
      Some(self.emit_current_processing_instruction())
    }
    None => {
      self.emit_error(EofInProcessingInstruction)
      Some(EOF)
    }
    Some(c) => {
      self.current_pi_data.write_char(c)
      None
    }
  }
}

///|
/// 13.2.5.76 Processing instruction questionable state
fn Tokenizer::run_processing_instruction_questionable_state(
  self : Tokenizer,
) -> Token? {
  match self.consume() {
    Some('>') => {
      self.state = Data
      Some(self.emit_current_processing_instruction())
    }
    None => {
      self.emit_error(EofInProcessingInstruction)
      Some(EOF)
    }
    Some(_) => {
      self.current_pi_data.write_char('?')
      self.reconsume()
      self.state = ProcessingInstructionData
      None
    }
  }
}