use std::error::Error;
use std::fmt;

/// Errors met when parsing ANSI escape sequences.
#[derive(Debug)]
pub enum ANSIErr {

  /// This error is returned if an escape code is found between a CSI and the
  /// ending character.
  ///
  /// The found escape code is returned, as well as the location (line and
  /// column).
  EscInCSI(u8, usize, usize),

  /// Integer parsing error inside a CSI string.
  ///
  /// The whole string is returned.
  IntParseErrInCSI(String),

  /// Missing number inside a CSI string.
  ///
  /// The CSI code (the letter that ends the control sequence) is returned, as
  /// well as the whole string.
  ///
  /// This happens for instance with color setting, if an integer of the color
  /// is missing.
  MissingCodeInCSI(u8, String),

  /// Found a wrong integer inside the CSI string.
  ///
  /// The CSI code, the wrong integer and the whole CSI string are returned.
  ///
  /// This happens for instance when setting a color, if the code is neither 2
  /// (RGB color) nor 5 (8-bit palette index).
  UnexpectedCodeInCSI(u8, u8, String),

  /// Found an unknown `FeESC` code.
  ///
  /// The unknown code is returned, as well as the location (line and column).
  UnknownEscInFeESC(u8, usize, usize),
 
  /// Unterminated escape sequence.
  ///
  /// An escape sequence start has been matched, but no termination was found.
  ///
  /// The location is returned (line and column).
  UnterminatedEscSeq(usize, usize),

  /// Found a wrong character inside a CSI string
  ///
  /// The found character is neither a character allowed inside the string, nor
  /// a termination character.
  ///
  /// The wrong character is returned, as well as the location (line and
  /// column).
  WrongCharInCSI(u8, usize, usize),
}

impl Error for ANSIErr {}

impl fmt::Display for ANSIErr {

  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {

    match self {

      ANSIErr::EscInCSI(chr, l, c) => write!(f,
        "Found escape sequence 0x1b{chr:02x} inside Control Sequence \
at line {l}, col {c}."),

      ANSIErr::IntParseErrInCSI(s) => write!(f,
        "Error when parsing integer in CSI escape sequence {s}."),

      ANSIErr::MissingCodeInCSI(c, s) => write!(f,
        "Missing code after {c} in CSI escape sequencei {s}."),

      ANSIErr::UnexpectedCodeInCSI(c1, c2, s) => write!(f,
        "Unexpected code {c2} after {c1} in CSI escape sequence {s}."),

      ANSIErr::UnknownEscInFeESC(c, line, col) => write!(f,
        "Unknown escape code {c} in FeESC sequence \
at line {line}, col {col}."),

      ANSIErr::UnterminatedEscSeq(l, c) => write!(f,
        "Unterminated escape sequence at line {l}, col {c}."),

      ANSIErr::WrongCharInCSI(chr, l, c) => write!(f,
        "Wrong character {chr} (0x{chr:02x}) at line {l}, col {c}."),
    }
  }
}
