///|
fn feature_term_ref(
  name : String,
  category : String,
  parent : String,
  description : String,
  typical_attribute : String,
) -> FeatureTermReference {
  { name, category, parent, description, typical_attribute }
}

///|
pub fn feature_term_references() -> Array[FeatureTermReference] {
  [
    feature_term_ref(
      "gene", "gene", "region", "A genomic locus with a stable biological identity",
      "ID",
    ),
    feature_term_ref(
      "protein_coding_gene", "gene", "gene", "A gene expected to produce a protein coding transcript",
      "biotype",
    ),
    feature_term_ref(
      "pseudogene", "gene", "gene", "A gene-like locus that has lost ordinary coding capacity",
      "pseudo",
    ),
    feature_term_ref(
      "lncRNA_gene", "gene", "gene", "A gene producing long non-coding RNA products",
      "gene_biotype",
    ),
    feature_term_ref(
      "miRNA_gene", "gene", "gene", "A gene producing micro RNA products", "gene_biotype",
    ),
    feature_term_ref(
      "snRNA_gene", "gene", "gene", "A gene producing small nuclear RNA products",
      "gene_biotype",
    ),
    feature_term_ref(
      "snoRNA_gene", "gene", "gene", "A gene producing small nucleolar RNA products",
      "gene_biotype",
    ),
    feature_term_ref(
      "rRNA_gene", "gene", "gene", "A gene producing ribosomal RNA products", "gene_biotype",
    ),
    feature_term_ref(
      "tRNA_gene", "gene", "gene", "A gene producing transfer RNA products", "gene_biotype",
    ),
    feature_term_ref(
      "transcript", "transcript", "region", "A generic transcribed feature with exon-like children",
      "ID",
    ),
    feature_term_ref(
      "mRNA", "transcript", "transcript", "A processed messenger RNA transcript",
      "Parent",
    ),
    feature_term_ref(
      "primary_transcript", "transcript", "transcript", "An unprocessed primary transcription product",
      "Parent",
    ),
    feature_term_ref(
      "lnc_RNA", "transcript", "transcript", "A long non-coding RNA transcript",
      "transcript_biotype",
    ),
    feature_term_ref(
      "ncRNA", "transcript", "transcript", "A non-coding RNA transcript", "transcript_biotype",
    ),
    feature_term_ref(
      "miRNA", "transcript", "transcript", "A micro RNA transcript", "transcript_biotype",
    ),
    feature_term_ref(
      "snRNA", "transcript", "transcript", "A small nuclear RNA transcript", "transcript_biotype",
    ),
    feature_term_ref(
      "snoRNA", "transcript", "transcript", "A small nucleolar RNA transcript", "transcript_biotype",
    ),
    feature_term_ref(
      "rRNA", "transcript", "transcript", "A ribosomal RNA transcript", "transcript_biotype",
    ),
    feature_term_ref(
      "tRNA", "transcript", "transcript", "A transfer RNA transcript", "transcript_biotype",
    ),
    feature_term_ref(
      "exon", "exon", "transcript_region", "A region retained in a processed transcript",
      "Parent",
    ),
    feature_term_ref(
      "coding_exon", "exon", "exon", "An exon that contributes coding sequence",
      "Parent",
    ),
    feature_term_ref(
      "noncoding_exon", "exon", "exon", "An exon outside the protein coding region",
      "Parent",
    ),
    feature_term_ref(
      "CDS", "coding", "transcript_region", "A coding sequence segment translated into protein",
      "phase",
    ),
    feature_term_ref(
      "start_codon", "coding", "CDS", "The translation initiation codon", "phase",
    ),
    feature_term_ref(
      "stop_codon", "coding", "CDS", "The translation termination codon", "phase",
    ),
    feature_term_ref(
      "selenocysteine", "coding", "CDS", "A recoded codon that yields selenocysteine",
      "exception",
    ),
    feature_term_ref(
      "polypeptide", "coding", "gene_product", "A translated protein product feature",
      "Derives_from",
    ),
    feature_term_ref(
      "five_prime_UTR", "utr", "transcript_region", "An untranslated region before the coding sequence",
      "Parent",
    ),
    feature_term_ref(
      "three_prime_UTR", "utr", "transcript_region", "An untranslated region after the coding sequence",
      "Parent",
    ),
    feature_term_ref(
      "UTR", "utr", "transcript_region", "A generic untranslated transcript region",
      "Parent",
    ),
    feature_term_ref(
      "intron", "intron", "transcript_region", "A region removed during RNA splicing",
      "Parent",
    ),
    feature_term_ref(
      "splice_donor_site", "splice", "splice_site", "The donor side of a splice junction",
      "Parent",
    ),
    feature_term_ref(
      "splice_acceptor_site", "splice", "splice_site", "The acceptor side of a splice junction",
      "Parent",
    ),
    feature_term_ref(
      "splice_region", "splice", "transcript_region", "A region around a splice junction",
      "Parent",
    ),
    feature_term_ref(
      "promoter", "regulatory", "regulatory_region", "A region that initiates or supports transcription",
      "ID",
    ),
    feature_term_ref(
      "enhancer", "regulatory", "regulatory_region", "A distal regulatory region that can increase transcription",
      "ID",
    ),
    feature_term_ref(
      "silencer", "regulatory", "regulatory_region", "A regulatory element that can reduce transcription",
      "ID",
    ),
    feature_term_ref(
      "insulator", "regulatory", "regulatory_region", "A regulatory boundary element",
      "ID",
    ),
    feature_term_ref(
      "regulatory_region", "regulatory", "region", "A generic regulatory genomic interval",
      "ID",
    ),
    feature_term_ref(
      "TF_binding_site", "regulatory", "binding_site", "A transcription factor binding site",
      "Name",
    ),
    feature_term_ref(
      "open_chromatin_region", "regulatory", "regulatory_region", "A region with accessible chromatin signal",
      "Note",
    ),
    feature_term_ref(
      "CpG_island", "regulatory", "sequence_feature", "A CpG-rich genomic interval",
      "ID",
    ),
    feature_term_ref(
      "repeat_region", "repeat", "region", "A repeated sequence interval", "ID",
    ),
    feature_term_ref(
      "transposable_element", "repeat", "repeat_region", "A mobile or mobile-derived genomic element",
      "Name",
    ),
    feature_term_ref(
      "LINE", "repeat", "transposable_element", "A long interspersed nuclear element",
      "Name",
    ),
    feature_term_ref(
      "SINE", "repeat", "transposable_element", "A short interspersed nuclear element",
      "Name",
    ),
    feature_term_ref(
      "LTR_retrotransposon", "repeat", "transposable_element", "An LTR retrotransposon feature",
      "Name",
    ),
    feature_term_ref(
      "DNA_transposon", "repeat", "transposable_element", "A DNA transposon feature",
      "Name",
    ),
    feature_term_ref(
      "simple_repeat", "repeat", "repeat_region", "A simple tandem repeat interval",
      "Name",
    ),
    feature_term_ref(
      "microsatellite", "repeat", "simple_repeat", "A short tandem repeat interval",
      "Name",
    ),
    feature_term_ref(
      "minisatellite", "repeat", "simple_repeat", "A longer tandem repeat interval",
      "Name",
    ),
    feature_term_ref(
      "match", "alignment", "region", "A generic sequence alignment match", "Target",
    ),
    feature_term_ref(
      "match_part", "alignment", "match", "A segment of a larger alignment match",
      "Parent",
    ),
    feature_term_ref(
      "EST_match", "alignment", "match", "An expressed sequence tag alignment match",
      "Target",
    ),
    feature_term_ref(
      "cDNA_match", "alignment", "match", "A cDNA alignment match", "Target",
    ),
    feature_term_ref(
      "protein_match", "alignment", "match", "A protein alignment match", "Target",
    ),
    feature_term_ref(
      "nucleotide_match", "alignment", "match", "A nucleotide alignment match", "Target",
    ),
    feature_term_ref(
      "sequence_variant", "variant", "region", "A sequence variation feature", "Variant_seq",
    ),
    feature_term_ref(
      "SNV", "variant", "sequence_variant", "A single nucleotide variant", "Variant_seq",
    ),
    feature_term_ref(
      "SNP", "variant", "sequence_variant", "A single nucleotide polymorphism", "Dbxref",
    ),
    feature_term_ref(
      "insertion", "variant", "sequence_variant", "An insertion relative to the reference sequence",
      "Variant_seq",
    ),
    feature_term_ref(
      "deletion", "variant", "sequence_variant", "A deletion relative to the reference sequence",
      "Reference_seq",
    ),
    feature_term_ref(
      "indel", "variant", "sequence_variant", "A combined insertion and deletion event",
      "Variant_seq",
    ),
    feature_term_ref(
      "inversion", "variant", "sequence_variant", "A sequence interval inverted relative to reference",
      "Note",
    ),
    feature_term_ref(
      "copy_number_variation", "variant", "sequence_variant", "A copy-number change across an interval",
      "Variant_seq",
    ),
    feature_term_ref(
      "origin_of_replication", "replication", "regulatory_region", "A DNA replication origin",
      "ID",
    ),
    feature_term_ref(
      "replication_regulatory_region", "replication", "regulatory_region", "A region regulating DNA replication",
      "ID",
    ),
    feature_term_ref(
      "centromere", "chromosome", "region", "A centromeric chromosome interval",
      "ID",
    ),
    feature_term_ref(
      "telomere", "chromosome", "region", "A telomeric chromosome interval", "ID",
    ),
    feature_term_ref(
      "chromosome", "assembly", "region", "A chromosome-level assembly feature",
      "ID",
    ),
    feature_term_ref(
      "contig", "assembly", "region", "A contiguous assembled sequence", "ID",
    ),
    feature_term_ref(
      "scaffold", "assembly", "region", "An ordered or oriented assembly scaffold",
      "ID",
    ),
    feature_term_ref(
      "supercontig", "assembly", "region", "A large assembly unit above contig level",
      "ID",
    ),
    feature_term_ref(
      "region", "region", "sequence_feature", "A generic genomic interval", "ID",
    ),
    feature_term_ref(
      "biological_region", "region", "region", "A region annotated for biological relevance",
      "Note",
    ),
    feature_term_ref(
      "sequence_feature", "region", "region", "A generic sequence annotation feature",
      "ID",
    ),
    feature_term_ref(
      "binding_site", "regulatory", "sequence_feature", "A site bound by a molecule or protein complex",
      "Name",
    ),
    feature_term_ref(
      "matrix_attachment_site", "regulatory", "regulatory_region", "A chromatin matrix attachment region",
      "Note",
    ),
    feature_term_ref(
      "response_element", "regulatory", "regulatory_region", "A regulatory site responsive to a signal",
      "Name",
    ),
    feature_term_ref(
      "enhancer_blocking_element", "regulatory", "insulator", "A region that can block enhancer action",
      "Note",
    ),
    feature_term_ref(
      "conserved_region", "comparative", "region", "A sequence interval conserved across species",
      "Dbxref",
    ),
    feature_term_ref(
      "conserved_element", "comparative", "conserved_region", "A shorter conserved annotation element",
      "Dbxref",
    ),
    feature_term_ref(
      "syntenic_region", "comparative", "region", "A region with conserved genomic neighborhood",
      "Dbxref",
    ),
    feature_term_ref(
      "operon", "prokaryotic", "region", "A group of co-transcribed prokaryotic genes",
      "ID",
    ),
    feature_term_ref(
      "transcription_start_site", "regulatory", "regulatory_region", "A site where transcription begins",
      "ID",
    ),
    feature_term_ref(
      "polyA_site", "transcript", "transcript_region", "A transcript polyadenylation site",
      "Parent",
    ),
    feature_term_ref(
      "polyA_signal_sequence", "transcript", "transcript_region", "A signal sequence associated with polyadenylation",
      "Parent",
    ),
  ]
}

///|
pub fn find_feature_term_reference(name : String) -> FeatureTermReference {
  for item in feature_term_references() {
    if item.name == name {
      return item
    }
  }
  feature_term_ref(
    name, "custom", "region", "Project-specific feature term", "Note",
  )
}

///|
pub fn feature_term_references_by_category(
  category : String,
) -> Array[FeatureTermReference] {
  let result : Array[FeatureTermReference] = []
  for item in feature_term_references() {
    if item.category == category {
      result.push(item)
    }
  }
  result
}

///|
pub fn FeatureTermReference::to_tsv_row(self : FeatureTermReference) -> String {
  [
    self.name,
    self.category,
    self.parent,
    self.description,
    self.typical_attribute,
  ].join("\t")
}