///|
pub(all) enum Format {
  GFF3
  GTF
} derive(Debug, Eq)

///|
pub fn Format::to_string(self : Format) -> String {
  match self {
    GFF3 => "GFF3"
    GTF => "GTF"
  }
}

///|
pub(all) enum Strand {
  Plus
  Minus
  Unknown
  NotApplicable
} derive(Debug, Eq)

///|
pub fn Strand::to_string(self : Strand) -> String {
  match self {
    Plus => "+"
    Minus => "-"
    Unknown => "?"
    NotApplicable => "."
  }
}

///|
pub(all) struct Attribute {
  key : String
  value : String
} derive(Debug, Eq)

///|
pub(all) struct Feature {
  seqid : String
  source : String
  feature_type : String
  start : Int
  end : Int
  score : String?
  strand : Strand
  phase : String?
  attributes : Array[Attribute]
} derive(Debug, Eq)

///|
pub fn Feature::attribute(self : Feature, key : String) -> String? {
  for attr in self.attributes {
    if attr.key == key {
      return Some(attr.value)
    }
  }
  None
}

///|
pub fn Feature::length(self : Feature) -> Int {
  self.end - self.start + 1
}

///|
pub(all) struct Diagnostic {
  line : Int
  message : String
} derive(Debug, Eq)

///|
pub(all) struct Annotation {
  format : Format
  features : Array[Feature]
  diagnostics : Array[Diagnostic]
} derive(Debug, Eq)

///|
pub(all) struct TranscriptModel {
  id : String
  name : String?
  feature : Feature
  exons : Array[Feature]
  cds : Array[Feature]
  utrs : Array[Feature]
  others : Array[Feature]
} derive(Debug, Eq)

///|
pub(all) struct GeneModel {
  id : String
  name : String?
  feature : Feature
  transcripts : Array[TranscriptModel]
  others : Array[Feature]
} derive(Debug, Eq)

///|
pub(all) struct Summary {
  feature_count : Int
  gene_count : Int
  transcript_count : Int
  exon_count : Int
  cds_count : Int
} derive(Debug, Eq)

///|
pub(all) struct FeatureCount {
  feature_type : String
  count : Int
} derive(Debug, Eq)

///|
pub(all) enum Severity {
  Info
  Warning
  Error
} derive(Debug, Eq)

///|
pub fn Severity::to_string(self : Severity) -> String {
  match self {
    Info => "info"
    Warning => "warning"
    Error => "error"
  }
}

///|
pub(all) struct ValidationIssue {
  severity : Severity
  code : String
  line : Int
  feature_type : String
  message : String
} derive(Debug, Eq)

///|
pub(all) struct ValidationReport {
  issues : Array[ValidationIssue]
} derive(Debug, Eq)

///|
pub(all) struct Span {
  seqid : String
  start : Int
  end : Int
} derive(Debug, Eq)

///|
pub(all) struct IntervalHit {
  feature : Feature
  index : Int
} derive(Debug, Eq)

///|
pub(all) struct IntervalIndex {
  features : Array[Feature]
} derive(Debug, Eq)

///|
pub(all) struct Bed12Record {
  chrom : String
  chrom_start : Int
  chrom_end : Int
  name : String
  score : String
  strand : String
  thick_start : Int
  thick_end : Int
  item_rgb : String
  block_count : Int
  block_sizes : Array[String]
  block_starts : Array[String]
} derive(Debug, Eq)

///|
pub(all) struct TranscriptMetrics {
  transcript_id : String
  exon_count : Int
  cds_count : Int
  utr_count : Int
  exon_bases : Int
  cds_bases : Int
  utr_bases : Int
  intron_count : Int
  intron_bases : Int
  span_bases : Int
} derive(Debug, Eq)

///|
pub(all) struct GeneMetrics {
  gene_id : String
  transcript_count : Int
  total_exon_bases : Int
  total_cds_bases : Int
  longest_transcript_id : String
  longest_transcript_bases : Int
  gene_span_bases : Int
} derive(Debug, Eq)

///|
pub(all) struct AnnotationMetrics {
  feature_count : Int
  gene_count : Int
  transcript_count : Int
  exon_count : Int
  cds_count : Int
  seqid_count : Int
  total_feature_bases : Int
} derive(Debug, Eq)

///|
pub(all) struct TypeReportRow {
  feature_type : String
  count : Int
  total_bases : Int
} derive(Debug, Eq)

///|
pub(all) struct AttributeFrequency {
  key : String
  count : Int
} derive(Debug, Eq)

///|
pub(all) enum FeatureClass {
  GeneClass
  TranscriptClass
  ExonClass
  CdsClass
  UtrClass
  RegulatoryClass
  RepeatClass
  OtherClass(String)
} derive(Debug, Eq)

///|
pub(all) enum AttributePresence {
  Required
  Optional
  Rare
} derive(Debug, Eq)

///|
pub(all) struct AttributeSchemaRow {
  key : String
  count : Int
  feature_count : Int
  presence : AttributePresence
  example_value : String
} derive(Debug, Eq)

///|
pub(all) struct AttributeSchema {
  rows : Array[AttributeSchemaRow]
} derive(Debug, Eq)

///|
pub(all) struct SequenceSummary {
  seqid : String
  feature_count : Int
  min_start : Int
  max_end : Int
  strand_plus_count : Int
  strand_minus_count : Int
  strand_unknown_count : Int
} derive(Debug, Eq)

///|
pub(all) struct ReferenceTerm {
  name : String
  category : String
  description : String
} derive(Debug, Eq)

///|
pub(all) struct QualityReport {
  score : Int
  feature_count : Int
  gene_count : Int
  transcript_count : Int
  exon_count : Int
  validation_errors : Int
  validation_warnings : Int
  has_required_hierarchy : Bool
  has_attributes : Bool
  has_multiple_seqids : Bool
} derive(Debug, Eq)

///|
pub(all) struct AttributeReference {
  key : String
  format : String
  category : String
  description : String
  typical_scope : String
} derive(Debug, Eq)

///|
pub(all) struct BiotypeReference {
  name : String
  family : String
  coding : Bool
  description : String
} derive(Debug, Eq)

///|
pub(all) struct ValidationRuleReference {
  code : String
  severity : Severity
  format : String
  description : String
  repair_hint : String
} derive(Debug, Eq)

///|
pub(all) struct FeatureTermReference {
  name : String
  category : String
  parent : String
  description : String
  typical_attribute : String
} derive(Debug, Eq)

///|
pub(all) struct EvidenceReference {
  code : String
  category : String
  source : String
  description : String
  typical_scope : String
} derive(Debug, Eq)

///|
pub(all) struct SequenceRegionReference {
  name : String
  category : String
  topology : String
  description : String
  typical_scope : String
} derive(Debug, Eq)