///|
/// Bioconductor DOSE demo — Disease Ontology enrichment analysis.
///
/// Ported from the Bioconductor DOSE package (Yu et al., 2020),
/// this demo shows Fisher exact enrichment over a synthetic disease
/// term database, BH–FDR correction, and fold enrichment / odds ratio.
fn main {
  println("=== Bioconductor DOSE Demo ===")
  println("Disease Ontology enrichment analysis via Fisher's exact test")
  println("")

  // ---------------------------------------------------------------------
  // 1. Build a synthetic disease-term database.
  //    Each term contains a mix of query and background genes so we
  //    get clean enrichment signals.
  // ---------------------------------------------------------------------
  println("1. Build synthetic disease-term database")
  let db : Map[String, Array[String]] = Map([])

  // TERM_A: 28 of 180 query genes are in this term → strong enrichment
  let ta : Array[String] = Array(capacity=0)
  let mut i = 1
  while i <= 600 {
    ta.push("TA" + i.to_string())
    i = i + 1
  }
  let qa = [
    "Q001", "Q002", "Q003", "Q004", "Q005", "Q006", "Q007", "Q008", "Q009", "Q010",
    "Q011", "Q012", "Q013", "Q014", "Q015", "Q016", "Q017", "Q018", "Q019", "Q020",
    "Q021", "Q022", "Q023", "Q024", "Q025", "Q026", "Q027", "Q028",
  ]
  i = 0
  while i < qa.length() {
    ta[i] = qa[i]
    i = i + 1
  }
  db["TERM_A (Cancer Signaling)"] = ta

  // TERM_B: 15 of 180 → weak enrichment
  let tb : Array[String] = Array(capacity=0)
  i = 1
  while i <= 900 {
    tb.push("TB" + i.to_string())
    i = i + 1
  }
  let qb = [
    "Q001", "Q002", "Q003", "Q004", "Q005", "Q006", "Q007", "Q008", "Q009", "Q010",
    "Q011", "Q012", "Q013", "Q014", "Q015",
  ]
  i = 0
  while i < qb.length() {
    tb[i] = qb[i]
    i = i + 1
  }
  db["TERM_B (Cell Cycle)"] = tb

  // TERM_C: 12 of 180 → moderate enrichment
  let tc : Array[String] = Array(capacity=0)
  i = 1
  while i <= 400 {
    tc.push("TC" + i.to_string())
    i = i + 1
  }
  let qc = [
    "Q001", "Q002", "Q003", "Q004", "Q005", "Q006", "Q007", "Q008", "Q009", "Q010",
    "Q011", "Q012",
  ]
  i = 0
  while i < qc.length() {
    tc[i] = qc[i]
    i = i + 1
  }
  db["TERM_C (Apoptosis)"] = tc

  // TERM_D: 8 of 180 in a huge 1500-gene term → depletion
  let td : Array[String] = Array(capacity=0)
  i = 1
  while i <= 1500 {
    td.push("TD" + i.to_string())
    i = i + 1
  }
  let qd = ["Q001", "Q002", "Q003", "Q004", "Q005", "Q006", "Q007", "Q008"]
  i = 0
  while i < qd.length() {
    td[i] = qd[i]
    i = i + 1
  }
  db["TERM_D (Ubiquitous Housekeeping)"] = td

  // TERM_E: 15 of 180 in a small 250-gene term → strong enrichment
  let te : Array[String] = Array(capacity=0)
  i = 1
  while i <= 250 {
    te.push("TE" + i.to_string())
    i = i + 1
  }
  let qe = [
    "Q010", "Q011", "Q012", "Q013", "Q014", "Q015", "Q016", "Q017", "Q018", "Q019",
    "Q020", "Q021", "Q022", "Q023", "Q024",
  ]
  i = 0
  while i < qe.length() {
    te[i] = qe[i]
    i = i + 1
  }
  db["TERM_E (DNA Repair)"] = te

  println(
    "   Number of disease terms: " + db.keys().collect().length().to_string(),
  )

  // ---------------------------------------------------------------------
  // 2. Build query gene list and background.
  // ---------------------------------------------------------------------
  println("\n2. Query and background")
  let query : Array[String] = Array(capacity=0)
  i = 1
  while i <= 180 {
    // Pad to 3 digits so "Q1" → "Q001", matching the term-gene names.
    let s = i.to_string()
    let suffix = if i < 10 { "00" + s } else if i < 100 { "0" + s } else { s }
    query.push("Q" + suffix)
    i = i + 1
  }
  let bg : Array[String] = Array(capacity=0)
  let keys = db.keys().collect()
  i = 0
  while i < keys.length() {
    let genes = db[keys[i]]
    let mut j = 0
    while j < genes.length() {
      bg.push(genes[j])
      j = j + 1
    }
    i = i + 1
  }
  // Add query genes to background too.
  i = 0
  while i < query.length() {
    bg.push(query[i])
    i = i + 1
  }
  // Pad to 12000 with unique markers.
  i = 1
  while bg.length() < 12000 {
    bg.push("BG" + i.to_string())
    i = i + 1
  }
  println("   Query size:     " + query.length().to_string())
  println("   Background size: " + bg.length().to_string())

  // ---------------------------------------------------------------------
  // 3. Run Fisher-exact enrichment with BH–FDR correction.
  // ---------------------------------------------------------------------
  println("\n3. Enrichment analysis (Fisher exact + BH–FDR)")
  let result = @src.enrich_disease_fisher(query, db, bg)
  println("   Terms returned:  " + result.terms.length().to_string())
  println("   Summary:         " + @src.dose_summarize(result))

  // ---------------------------------------------------------------------
  // 4. Print top 3 results.
  // ---------------------------------------------------------------------
  println("\n4. Top 3 enriched terms")
  let top = @src.dose_top_terms(result, 3)
  i = 0
  while i < top.terms.length() {
    let t = top.terms[i]
    println("   #" + (i + 1).to_string() + "  " + t.term_id)
    println(
      "      overlap=" +
      t.overlap_count.to_string() +
      "/" +
      t.gene_count.to_string() +
      "  FE=" +
      t.fold_enrichment.to_string() +
      "  OR=" +
      t.odds_ratio.to_string(),
    )
    println(
      "      raw p=" +
      t.p_value.to_string() +
      "  adj p=" +
      t.adjusted_p_value.to_string(),
    )
    i = i + 1
  }

  // ---------------------------------------------------------------------
  // 5. Show Fisher-exact helpers directly.
  // ---------------------------------------------------------------------
  println("\n5. Direct Fisher-exact / hypergeometric calls")
  // 2×2 table: a=28, b=152, c=572, d=11248  (TERM_A enrichment)
  let r = @src.fisher_exact_greater(28, 152, 572, 11248)
  println(
    "   Fisher greater (TERM_A): p=" +
    r.p_value.to_string() +
    "  OR=" +
    r.odds_ratio.to_string(),
  )

  // Hypergeometric: k=12, query=180, term=400, bg=12000  (TERM_C)
  let p_hyp = @src.dose_hypergeometric_test(12, 180, 400, 12000)
  println("   Hypergeometric (TERM_C): p=" + p_hyp.to_string())

  println("\n=== DOSE demo complete ===")
}