///|
pub(all) enum ZoneErrorCode {
  InvalidCharacter
  UnterminatedQuote
  UnterminatedEscape
  UnbalancedParenthesis
  TokenLimitExceeded
  InvalidDomainName
  InvalidDomainLabel
  DomainNameTooLong
  RelativeNameWithoutOrigin
  InvalidTtl
  TtlOverflow
  InvalidDirective
  UnsupportedDirective
  MissingRecordField
  InvalidRecordClass
  InvalidRecordType
  InvalidRecordData
  NumericFieldOutOfRange
  DuplicateSingletonRecord
  ConflictingCname
  MissingSoa
  MissingApexNs
  IntegrityViolation
} derive(Eq, Debug)

///|
pub(all) struct SourceSpan {
  start_line_value : Int
  start_column_value : Int
  end_line_value : Int
  end_column_value : Int
} derive(Eq, Debug)

///|
pub struct ZoneError {
  code_value : String
  message_value : String
  span_value : SourceSpan
} derive(Eq, Debug)

///|
pub fn ZoneErrorCode::code(self : ZoneErrorCode) -> String {
  match self {
    InvalidCharacter => "lex.invalid_character"
    UnterminatedQuote => "lex.unterminated_quote"
    UnterminatedEscape => "lex.unterminated_escape"
    UnbalancedParenthesis => "lex.unbalanced_parenthesis"
    TokenLimitExceeded => "lex.token_limit_exceeded"
    InvalidDomainName => "name.invalid"
    InvalidDomainLabel => "name.invalid_label"
    DomainNameTooLong => "name.too_long"
    RelativeNameWithoutOrigin => "name.relative_without_origin"
    InvalidTtl => "ttl.invalid"
    TtlOverflow => "ttl.overflow"
    InvalidDirective => "directive.invalid"
    UnsupportedDirective => "directive.unsupported"
    MissingRecordField => "record.missing_field"
    InvalidRecordClass => "record.invalid_class"
    InvalidRecordType => "record.invalid_type"
    InvalidRecordData => "record.invalid_data"
    NumericFieldOutOfRange => "record.numeric_out_of_range"
    DuplicateSingletonRecord => "zone.duplicate_singleton"
    ConflictingCname => "zone.conflicting_cname"
    MissingSoa => "zone.missing_soa"
    MissingApexNs => "zone.missing_apex_ns"
    IntegrityViolation => "zone.integrity_violation"
  }
}

///|
pub fn SourceSpan::point(line : Int, column : Int) -> SourceSpan {
  {
    start_line_value: line,
    start_column_value: column,
    end_line_value: line,
    end_column_value: column,
  }
}

///|
pub fn SourceSpan::range(
  start_line : Int,
  start_column : Int,
  end_line : Int,
  end_column : Int,
) -> SourceSpan {
  {
    start_line_value: start_line,
    start_column_value: start_column,
    end_line_value: end_line,
    end_column_value: end_column,
  }
}

///|
pub fn SourceSpan::start_line(self : SourceSpan) -> Int {
  self.start_line_value
}

///|
pub fn SourceSpan::start_column(self : SourceSpan) -> Int {
  self.start_column_value
}

///|
pub fn SourceSpan::end_line(self : SourceSpan) -> Int {
  self.end_line_value
}

///|
pub fn SourceSpan::end_column(self : SourceSpan) -> Int {
  self.end_column_value
}

///|
pub fn ZoneError::new(
  code : ZoneErrorCode,
  message : String,
  span : SourceSpan,
) -> ZoneError {
  { code_value: code.code(), message_value: message, span_value: span }
}

///|
pub fn ZoneError::code(self : ZoneError) -> String {
  self.code_value
}

///|
pub fn ZoneError::message(self : ZoneError) -> String {
  self.message_value
}

///|
pub fn ZoneError::span(self : ZoneError) -> SourceSpan {
  self.span_value
}

///|
pub fn ZoneError::start_line(self : ZoneError) -> Int {
  self.span_value.start_line()
}

///|
pub fn ZoneError::start_column(self : ZoneError) -> Int {
  self.span_value.start_column()
}

///|
pub fn ZoneError::end_line(self : ZoneError) -> Int {
  self.span_value.end_line()
}

///|
pub fn ZoneError::end_column(self : ZoneError) -> Int {
  self.span_value.end_column()
}