import {
  appear2 as appear,
  axisstyle,
  font,
  gmlst2loci,
  keyupEnter,
  make_table_2col
} from "./chunk-SA7APTJR.js";
import "./chunk-HJ6L54YS.js";
import "./chunk-LSEFWW72.js";
import "./chunk-SKREEF3H.js";
import {
  Menu
} from "./chunk-HYOEWQ5P.js";
import "./chunk-HBW42TDT.js";
import "./chunk-G6O3URDN.js";
import "./chunk-FN5XPUPH.js";
import "./chunk-IIT367QZ.js";
import "./chunk-RZGEKL77.js";
import "./chunk-UI7OCM2A.js";
import "./chunk-YZK37YCC.js";
import {
  dofetch
} from "./chunk-7EMWHCVW.js";
import "./chunk-7IYJZZQI.js";
import "./chunk-M3J4MINX.js";
import "./chunk-PF4DSFDR.js";
import "./chunk-QH6W3NVF.js";
import "./chunk-NOEAT6CX.js";
import "./chunk-4UWS5Y3N.js";
import "./chunk-DD4R5P6W.js";
import "./chunk-JNITUVXP.js";
import "./chunk-KSGA62R2.js";
import {
  axisTop
} from "./chunk-LOZEKOES.js";
import "./chunk-TOU7EVFQ.js";
import {
  linear
} from "./chunk-OAWQ6LOO.js";
import "./chunk-TLT4YIG3.js";
import "./chunk-KYBIQBXE.js";
import "./chunk-I6Y4O3RR.js";
import "./chunk-OMR2DT66.js";
import "./chunk-DQC5FFGV.js";
import "./chunk-HFNDKYVF.js";

// src/mds.fimo.js
var headerheight = 80;
var headerunderpad = 5;
async function init(obj) {
  window.obj = obj;
  obj.errdiv = obj.div.append("div");
  try {
    init_ui(obj);
    await do_query(obj);
  } catch (e) {
    obj.errdiv.text(e.message || e);
    if (e.stack) console.log(e.stack);
  }
}
function init_ui(obj) {
  obj.motifrowheight = 16;
  obj.gaincolor = "red";
  obj.losscolor = "blue";
  obj.flankspan = 15;
  if (!obj.fimo_thresh) obj.fimo_thresh = 1e-3;
  if (!obj.minabslogp) obj.minabslogp = 1;
  obj.tip = new Menu();
  const table = obj.div.append("table").style("border-spacing", "3px").style("border-collapse", "separate").style("margin", "10px");
  {
    const tr = table.append("tr");
    tr.append("td").text("Flanking sequence (#nt)");
    const td = tr.append("td");
    td.append("input").attr("type", "number").style("margin", "0px 10px").style("width", "100px").property("value", obj.flankspan).on("keyup", (event) => {
      if (!keyupEnter(event)) return;
      const v = Number.parseInt(event.target.value);
      if (v < 10) {
        window.alert("Enter integer above 10");
        return;
      }
      if (v == obj.flankspan) return;
      obj.flankspan = v;
      do_query(obj);
    });
    td.append("span").style("font-size", "0.7em").style("opacity", 0.5).text("Press ENTER to update");
  }
  {
    const tr = table.append("tr");
    tr.append("td").text("P-value cutoff");
    const td = tr.append("td");
    td.append("input").attr("type", "number").style("margin", "0px 10px").style("width", "100px").property("value", obj.fimo_thresh).on("keyup", (event) => {
      if (!keyupEnter(event)) return;
      const v = Number.parseFloat(event.target.value);
      if (v <= 0) {
        window.alert("Enter a p value between 0 to 1");
        return;
      }
      if (v == obj.fimo_thresh) return;
      obj.fimo_thresh = v;
      do_query(obj);
    });
    td.append("span").style("font-size", "0.7em").style("opacity", 0.5).text("Press ENTER to update");
  }
  {
    const tr = table.append("tr");
    tr.append("td").text("Minimum log10 p-value difference");
    const td = tr.append("td");
    td.append("input").attr("type", "number").style("margin", "0px 10px").style("width", "100px").property("value", obj.minabslogp).on("keyup", (event) => {
      if (!keyupEnter(event)) return;
      const v = Number.parseFloat(event.target.value);
      if (v <= 0) {
        window.alert("Enter a number above 0");
        return;
      }
      if (v == obj.minabslogp) return;
      obj.minabslogp = v;
      do_query(obj);
    });
    td.append("span").style("font-size", "0.7em").style("opacity", 0.5).text("Press ENTER to update");
  }
  obj.wait = obj.div.append("div");
  obj.svg = obj.div.append("svg");
  obj.dynamic_g = obj.svg.append("g");
  obj.legend = {};
  obj.legend.logpvaluediv = obj.div.append("div");
  may_init_factorprofiles(obj);
}
function may_init_factorprofiles(obj) {
  if (!obj.factor_profiles) return;
  if (!Array.isArray(obj.factor_profiles)) throw "factor_profiles is not array";
  for (const profile of obj.factor_profiles) {
    if (!profile.name) throw "name missing for a profile";
    if (!profile.leftpad) profile.leftpad = 20;
    if (!profile.width) profile.width = 300;
    profile.headerg = obj.svg.append("g");
    profile.textlabel = profile.headerg.append("text").text(profile.name).attr("x", profile.width / 2).attr("text-anchor", "middle").attr("y", -30);
    if (profile.isgenevalue) {
      profile.color = "green";
      profile.axisg = profile.headerg.append("g");
      continue;
    }
    if (profile.isgenevalueonesample) {
      if (!profile.samplename) throw "samplename missing for isgenevalueonesample";
      profile.barcolor = "#62945B";
      profile.axisg = profile.headerg.append("g");
      continue;
    }
    throw "unknown profile type";
  }
}
function do_query(obj) {
  appear(obj.wait.text("Loading..."));
  obj.dynamic_g.selectAll("*").remove();
  const arg = {
    genome: obj.genome.name,
    m: obj.m,
    fimo_thresh: obj.fimo_thresh,
    flankspan: obj.flankspan,
    minabslogp: obj.minabslogp
  };
  return dofetch("fimo", arg).then((data) => {
    if (data.error) throw "Error: cannot do motif finding: " + data.error;
    if (obj.callback_once) {
      obj.callback_once();
      delete obj.callback_once;
    }
    if (!data.items || data.items.length == 0) throw "Found no motif change due to this mutation";
    obj.wait.style("display", "none");
    for (const m of data.items) {
      if (m.attr) {
        m.gene = m.attr["Transcription factor"];
      } else {
        m.gene = m.name;
      }
    }
    return show_result(data, obj);
  }).catch((e) => {
    obj.wait.style("display", "block").text(e.message || e);
    if (e.stack) console.log(e.stack);
  });
}
async function show_result(data, obj) {
  draw_motif_simplified(data, obj);
  if (obj.factor_profiles) {
    await get_gene_position(data, obj);
    let width = Number.parseInt(obj.svg.attr("width"));
    for (const profile of obj.factor_profiles) {
      profile.headerg.attr("transform", "translate(" + (width + profile.leftpad) + "," + headerheight + ")");
      profile.motifs = [];
      for (const motif of data.items) {
        const pg = motif.layer1_g.append("g").attr("transform", "translate(" + (width + profile.leftpad) + ",0)");
        profile.motifs.push({
          motif,
          g: pg,
          message: pg.append("text").text("Loading...").attr("dominant-baseline", "central").attr("fill", "#ccc")
        });
      }
      width += profile.leftpad + profile.width;
      obj.svg.attr("width", width + 5);
      await load_factorprofile(obj, profile);
      for (const m of data.items) {
        m.bgbox.attr("width", width);
        m.coverbox.attr("width", width);
      }
    }
  }
}
function draw_motif_simplified(data, obj) {
  const ntwidth = 14;
  const motifgraphwidth = ntwidth * data.refseq.length;
  const ntfontsize = 16;
  const rulerheight = 30;
  {
    const x = (obj.m.pos - data.refstart + 0.5) * ntwidth;
    const g2 = obj.dynamic_g.append("g").attr("transform", "translate(" + x + "," + headerheight + ")");
    g2.append("rect").attr("x", -ntwidth / 2).attr("y", -10).attr("width", ntwidth).attr("height", 10).attr("fill", "#666");
    g2.append("text").attr("y", -15).attr("text-anchor", "middle").text(obj.m.chr + ":" + obj.m.pos + " " + obj.m.ref + ">" + obj.m.alt);
  }
  let svgheight = headerheight + headerunderpad;
  const rowspace = 1;
  const g = obj.dynamic_g.append("g").attr("transform", "translate(0," + svgheight + ")");
  for (const [i, motif] of data.items.entries()) {
    motif.g = g.append("g").attr("transform", "translate(0," + (obj.motifrowheight * (i + 0.5) + rowspace * i) + ")");
    motif.layer1_g = motif.g.append("g");
    motif.layer2_g = motif.g.append("g");
    motif.bgbox = motif.layer1_g.append("rect").attr("y", -obj.motifrowheight / 2).attr("width", motifgraphwidth).attr("height", obj.motifrowheight).attr("fill", "white");
    const x = (motif.start - data.refstart) * ntwidth;
    const w = (Math.min(motif.stop, data.refstop) - motif.start) * ntwidth;
    motif.layer1_g.append("rect").attr("x", x).attr("y", -obj.motifrowheight / 2).attr("width", w).attr("height", obj.motifrowheight).attr("fill", motif.gain ? obj.gaincolor : obj.losscolor).attr("fill-opacity", motif.logpvaluediff / (motif.gain ? data.valuemax : data.valuemin));
    let str;
    if (motif.strand == "+") {
      str = ">  " + motif.name + "  >";
    } else {
      str = "<  " + motif.name + "  <";
    }
    motif.layer1_g.append("text").text(str).attr("x", x + w / 2).attr("dominant-baseline", "central").attr("text-anchor", "middle").attr("stroke", "white").attr("stroke-width", 3).attr("font-size", obj.motifrowheight - 3).attr("font-family", font).style("white-space", "pre");
    motif.layer1_g.append("text").text(str).attr("x", x + w / 2).attr("dominant-baseline", "central").attr("text-anchor", "middle").attr("font-size", obj.motifrowheight - 3).attr("font-family", font).style("white-space", "pre");
    motif.coverbox = motif.layer2_g.append("rect").attr("y", -obj.motifrowheight / 2).attr("width", motifgraphwidth).attr("height", obj.motifrowheight).attr("fill", "white").attr("fill-opacity", 0).on("mouseover", (event) => {
      motif.bgbox.attr("fill", "#f9fabd");
      motif_tooltip(motif, obj, event);
    }).on("mouseout", () => {
      motif.bgbox.attr("fill", "white");
      obj.tip.hide();
    });
  }
  svgheight += (rowspace + obj.motifrowheight) * data.items.length + 20;
  make_legend(data, obj);
  obj.svg.attr("width", motifgraphwidth).attr("height", svgheight);
}
function motif_tooltip(motif, obj, event) {
  obj.tip.clear();
  if (motif.attr) {
    obj.tip.d.append("div").text("MOTIF").style("font-weight", "bold");
    const lst1 = [
      { k: "P-values", v: htmlpvalue(motif, obj) },
      { k: "Strand", v: motif.strand }
    ];
    make_table_2col(obj.tip.d, lst1);
    obj.tip.d.append("div").text("FACTOR").style("font-weight", "bold");
    const lst2 = [];
    for (const k in motif.attr) {
      lst2.push({ k, v: motif.attr[k] });
    }
    make_table_2col(obj.tip.d, lst2);
  } else {
    const lst = [
      { k: "TF", v: motif.name },
      { k: "P-values", v: htmlpvalue(motif, obj) },
      { k: "Strand", v: motif.strand }
    ];
    make_table_2col(obj.tip.d, lst);
  }
  obj.tip.show(event.clientX, event.clientY);
}
function htmlpvalue(m, obj) {
  return (m.pvalue_ref == void 0 ? '<span style="opacity:.5;padding:2px"><span style="font-size:.7em">REF</span> not found</span>' : '<span style="background-color:' + obj.losscolor + ';padding:2px;color:white;"><span style="font-size:.7em">REF</span> ' + m.pvalue_ref + "</span>") + "<br>" + (m.pvalue_alt == void 0 ? '<span style="opacity:.5;padding:2px"><span style="font-size:.7em">ALT</span> not found</span>' : '<span style="background-color:' + obj.gaincolor + ';padding:2px;color:white;"><span style="font-size:.7em">ALT</span> ' + m.pvalue_alt + "</span>");
}
function make_legend(data, obj) {
  obj.legend.logpvaluediv.selectAll("*").remove();
  const leftpad = 50, axistickh = 4, fontsize = 12, barw = 55, barh = 20;
  obj.legend.logpvaluediv.append("span").text("Log10 p-value difference");
  const svg = obj.legend.logpvaluediv.append("svg").attr("width", (leftpad + barw) * 2).attr("height", fontsize + axistickh + barh);
  const axisg = svg.append("g").attr("transform", "translate(" + leftpad + "," + (fontsize + axistickh) + ")");
  axisstyle({
    axis: axisg.call(
      axisTop().scale(
        linear().domain([data.valuemin, 0, data.valuemax]).range([0, barw, barw * 2])
      ).tickValues([data.valuemin, 0, data.valuemax]).tickSize(axistickh)
    )
  });
  const gain_id = Math.random().toString();
  const loss_id = Math.random().toString();
  const defs = svg.append("defs");
  {
    const grad = defs.append("linearGradient").attr("id", loss_id);
    grad.append("stop").attr("offset", "0%").attr("stop-color", obj.losscolor);
    grad.append("stop").attr("offset", "100%").attr("stop-color", "white");
  }
  {
    const grad = defs.append("linearGradient").attr("id", gain_id);
    grad.append("stop").attr("offset", "0%").attr("stop-color", "white");
    grad.append("stop").attr("offset", "100%").attr("stop-color", obj.gaincolor);
  }
  svg.append("rect").attr("x", leftpad).attr("y", fontsize + axistickh).attr("width", barw).attr("height", barh).attr("fill", "url(#" + loss_id + ")");
  svg.append("rect").attr("x", leftpad + barw).attr("y", fontsize + axistickh).attr("width", barw).attr("height", barh).attr("fill", "url(#" + gain_id + ")");
  svg.append("text").attr("x", leftpad - 5).attr("y", fontsize + axistickh + barh / 2).attr("font-family", font).attr("font-size", fontsize).attr("text-anchor", "end").attr("dominant-baseline", "central").attr("fill", "black").text("Loss");
  svg.append("text").attr("x", leftpad + barw * 2 + 5).attr("y", fontsize + axistickh + barh / 2).attr("font-family", font).attr("font-size", fontsize).attr("dominant-baseline", "central").attr("fill", "black").text("Gain");
}
async function get_gene_position(data, obj) {
  obj.gene2position = {};
  const factornames = /* @__PURE__ */ new Set();
  for (const m of data.items) {
    factornames.add(m.gene);
  }
  for (const genename of factornames) {
    const pos = await get_one_gene_position(genename, obj);
    if (pos) {
      obj.gene2position[genename] = pos;
    }
  }
}
function get_one_gene_position(genename, obj) {
  return dofetch("genelookup", { genome: obj.genome.name, input: genename, deep: 1 }).then((data) => {
    if (!data.gmlst) return null;
    const loci = gmlst2loci(data.gmlst);
    return loci[0];
  });
}
function load_factorprofile(obj, profile) {
  if (profile.isgenevalue) {
    return load_factorprofile_genevalue(obj, profile);
  }
  if (profile.isgenevalueonesample) {
    return load_factorprofile_genevalueonesample(obj, profile);
  }
  throw "unknown profile type";
}
async function load_factorprofile_genevalueonesample(obj, profile) {
  const arg = {
    genome: obj.genome.name,
    genes: [],
    sample: profile.samplename
  };
  if (profile.mdslabel) {
    arg.dslabel = profile.mdslabel;
    arg.querykey = profile.querykey;
    if (profile.samplegroup_attrlst) {
      arg.getgroup = profile.samplegroup_attrlst;
    }
  } else {
    arg.iscustom = 1;
    arg.file = profile.file;
    arg.url = profile.url;
    arg.indexURL = profile.indexURL;
  }
  for (const g in obj.gene2position) {
    const r = obj.gene2position[g];
    arg.genes.push({
      gene: g,
      chr: r.chr,
      start: r.start,
      stop: r.stop
    });
  }
  return dofetch("mdsgenevalueonesample", arg).then((data) => {
    if (data.error) throw data.error;
    for (const m of profile.motifs) {
      m.message.text("No data");
    }
    if (data.nodata) return;
    if (!data.result) throw "error";
    let min = 0, max = 0;
    for (const g in data.result) {
      min = Math.min(min, data.result[g]);
      max = Math.max(max, data.result[g]);
    }
    const scale = linear().domain([min, max]).range([0, profile.width]);
    axisstyle({
      axis: profile.axisg.call(axisTop().scale(scale).ticks(4)),
      showline: 1
    });
    for (const m of profile.motifs) {
      const v = data.result[m.motif.gene];
      if (Number.isFinite(v)) {
        m.message.text("");
        m.g.append("rect").attr("y", -obj.motifrowheight / 2).attr("width", Math.max(1, scale(v))).attr("height", obj.motifrowheight).attr("shape-rendering", "crispEdges").attr("fill", profile.barcolor);
      }
    }
    profile.textlabel.attr("x", profile.width / 2).attr("text-anchor", "middle").attr("y", -30);
  }).catch((e) => {
    if (e.stack) console.log(e.stack);
    appear(obj.wait.text(e.message || e));
  });
}
async function load_factorprofile_genevalue(obj, profile) {
  profile.gene2result = /* @__PURE__ */ new Map();
  for (const gene in obj.gene2position) {
    const data = await factorprofile_genevalue_onegene_loadboxplot(obj, profile, gene);
    if (data) {
      factorprofile_genevalue_onegene_makeboxplot(obj, profile, gene, data);
      profile.gene2result.set(gene, data);
      factorprofile_genevalue_updatescale(obj, profile);
    }
  }
  factorprofile_genevalue_finish(obj, profile);
}
function factorprofile_genevalue_onegene_makeboxplot(obj, profile, gene, data) {
  if (data.nodata) return;
  for (const m of profile.motifs) {
    if (m.motif.gene != gene) continue;
    m.boxplot = {
      out: []
    };
    if (data.w1 != void 0) {
      m.boxplot.hline = m.g.append("line").attr("stroke", profile.color).attr("shape-rendering", "crispEdges");
      m.boxplot.linew1 = m.g.append("line").attr("stroke", profile.color).attr("shape-rendering", "crispEdges");
      m.boxplot.linew2 = m.g.append("line").attr("stroke", profile.color).attr("shape-rendering", "crispEdges");
      m.boxplot.box = m.g.append("rect").attr("fill", "white").attr("stroke", profile.color).attr("shape-rendering", "crispEdges");
      m.boxplot.linep50 = m.g.append("line").attr("stroke", profile.color).attr("shape-rendering", "crispEdges");
    }
    if (data.out) {
      for (const d of data.out) {
        const circle = m.g.append("circle").attr("stroke", profile.color).attr("fill", "white").attr("fill-opacity", 0);
        m.boxplot.out.push({
          value: d.value,
          circle
        });
      }
    }
  }
}
function factorprofile_genevalue_updatescale(obj, profile) {
  let min = 0, max = 0;
  for (const g of profile.gene2result.values()) {
    min = Math.min(min, g.min);
    max = Math.max(max, g.max);
  }
  const scale = linear().domain([min, max]).range([0, profile.width]);
  const h = obj.motifrowheight - 2;
  for (const [g, r] of profile.gene2result) {
    for (const m of profile.motifs) {
      if (m.motif.gene != g) continue;
      const bp = m.boxplot;
      if (!bp) continue;
      if (bp.hline) {
        const w1 = scale(r.w1);
        const w2 = scale(r.w2);
        const p25 = scale(r.p25);
        const p50 = scale(r.p50);
        const p75 = scale(r.p75);
        bp.hline.transition().attr("x1", w1).attr("x2", w2);
        bp.linew1.transition().attr("x1", w1).attr("x2", w1).attr("y1", -h / 2).attr("y2", h / 2);
        bp.linew2.transition().attr("x1", w2).attr("x2", w2).attr("y1", -h / 2).attr("y2", h / 2);
        bp.box.transition().attr("x", p25).attr("y", -h / 2).attr("width", p75 - p25).attr("height", h);
        bp.linep50.transition().attr("x1", p50).attr("x2", p50).attr("y1", -h / 2).attr("y2", h / 2);
      }
      for (const d of bp.out) {
        d.circle.transition().attr("cx", scale(d.value)).attr("r", h / 3);
      }
    }
  }
  axisstyle({
    axis: profile.axisg.transition().call(axisTop().scale(scale).ticks(4)),
    showline: 1
  });
}
function factorprofile_genevalue_onegene_loadboxplot(obj, profile, gene) {
  const r = obj.gene2position[gene];
  const arg = {
    genome: obj.genome.name,
    gene,
    chr: r.chr,
    start: r.start,
    stop: r.stop,
    getgroup2boxplot: 1
  };
  if (profile.mdslabel) {
    arg.dslabel = profile.mdslabel;
    arg.querykey = profile.querykey;
    if (profile.samplegroup_attrlst) {
      arg.getgroup = profile.samplegroup_attrlst;
    }
  } else {
    arg.iscustom = 1;
    arg.file = profile.file;
    arg.url = profile.url;
    arg.indexURL = profile.indexURL;
  }
  return dofetch("mdsgeneboxplot", arg).then((data) => {
    if (data.error) throw "Error: " + data.error;
    if (data.nodata) throw "No data";
    for (const m of profile.motifs) {
      if (m.motif.gene == gene) {
        m.message.text("");
      }
    }
    return data;
  }).catch((e) => {
    if (e.stack) console.log(e.stack);
    for (const m of profile.motifs) {
      if (m.motif.gene == gene) {
        m.message.text(e.message || e);
      }
    }
  });
}
function factorprofile_genevalue_finish(obj, profile) {
  let n = 0;
  for (const g of profile.gene2result.values()) {
    n = Math.max(n, g.n);
  }
  profile.textlabel.text(profile.name + " (n=" + n + ")").attr("x", profile.width / 2).attr("text-anchor", "middle").attr("y", -30);
}
export {
  init
};
//# sourceMappingURL=mds.fimo-ZJSEPLD7.js.map
