import {
  PlotBase,
  excludeFilterByTag,
  filterInit,
  filterJoin,
  filterPromptInit,
  getNormalRoot,
  negateFilter,
  renderPreAnalysisData,
  renderTable
} from "./chunk-SA7APTJR.js";
import "./chunk-HJ6L54YS.js";
import "./chunk-LSEFWW72.js";
import "./chunk-SKREEF3H.js";
import "./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 {
  dofetch3
} from "./chunk-7EMWHCVW.js";
import "./chunk-7IYJZZQI.js";
import {
  copyMerge,
  getCompInit
} from "./chunk-M3J4MINX.js";
import "./chunk-PF4DSFDR.js";
import "./chunk-QH6W3NVF.js";
import "./chunk-NOEAT6CX.js";
import {
  getColors
} from "./chunk-4UWS5Y3N.js";
import "./chunk-DD4R5P6W.js";
import "./chunk-JNITUVXP.js";
import "./chunk-KSGA62R2.js";
import "./chunk-LOZEKOES.js";
import "./chunk-TOU7EVFQ.js";
import "./chunk-OAWQ6LOO.js";
import "./chunk-TLT4YIG3.js";
import "./chunk-KYBIQBXE.js";
import "./chunk-I6Y4O3RR.js";
import {
  rgb
} from "./chunk-OMR2DT66.js";
import "./chunk-DQC5FFGV.js";
import "./chunk-HFNDKYVF.js";

// plots/DEinput.ts
var colorScale = getColors(5);
var DEinputPlot = class _DEinputPlot extends PlotBase {
  constructor(opts, api) {
    super(opts, api);
    this.components = {};
    this.type = _DEinputPlot.type;
    this.opts = opts;
    this.dom = this.getDom();
    this.groups = [];
  }
  static {
    this.type = "DEinput";
  }
  getDom() {
    const header = this.opts?.header?.html("Differential Gene Expression") || void 0;
    const holder = this.opts.holder.append("div").style("margin", "10px");
    const table = holder.append("div");
    const btns = holder.append("div").style("margin-top", "5px");
    const addGroup = btns.append("div").style("display", "inline-block");
    const submit = btns.append("div").style("display", "none").style("margin-left", "15px").attr("class", "sja_new_filter_btn sja_menuoption");
    const loading = holder.append("div").style("display", "none").style("margin", "20px 10px").text("Loading...");
    const preAnalysis = holder.append("div").style("display", "none").style("margin-top", "20px").style("margin-left", "5px");
    const dom = { header, table, addGroup, submit, loading, preAnalysis };
    return dom;
  }
  getState(appState) {
    const config = appState.plots.find((p) => p.id === this.id);
    if (!config) {
      throw `No plot with id='${this.id}' found. Did you set this.id before this.api = getComponentApi(this)?`;
    }
    return {
      termfilter: appState.termfilter,
      config,
      // quick fix to skip history tracking as needed
      _scope_: appState._scope_
    };
  }
  async init() {
  }
  // TODO: handle errors
  async main() {
    this.dom.preAnalysis.selectAll("*").remove();
    this.makeGroupsUI();
    this.mayRenderSubmit();
  }
  async makeGroupsUI() {
    if (!this.filterPrompt) {
      this.filterPrompt = await filterPromptInit({
        holder: this.dom.addGroup,
        vocabApi: this.app.vocabApi,
        emptyLabel: "Add group",
        /** 'hide_search' by default expands all terms. Passing the
         * header_mode in opts gives the caller the flexibility to choose. */
        header_mode: this.opts?.header_mode || "hide_search",
        callback: async (f) => {
          const filter2 = getNormalRoot(f);
          this.addNewGroup(filter2, this.groups);
          await this.main();
        },
        debug: this.opts.debug
      });
    }
    const filter = structuredClone(this.state.termfilter.filter);
    this.filterPrompt.main(excludeFilterByTag(filter, "cohortFilter"));
    if (!this.groups.length) {
      this.dom.table.style("display", "none");
      return;
    }
    this.dom.table.style("display", "block").selectAll("*").remove();
    const tableArg = {
      div: this.dom.table,
      columns: [
        {},
        // blank column to add delete buttons
        {
          label: "NAME",
          editCallback: async (i, cell) => {
            const newName = cell.value;
            const index = this.groups.findIndex((group) => group.name == newName);
            if (index != -1) {
              alert(`Group named ${newName} already exists`);
              await this.main();
            } else {
              this.groups[i].name = newName;
              await this.main();
            }
          }
        },
        {
          label: "COLOR",
          editCallback: async (i, cell) => {
            this.groups[i].color = cell.color;
            this.main();
          }
        },
        //{ label: '#SAMPLE' }, // will re-enable when filtered sample count can be supported for gdc
        { label: "FILTER" }
      ],
      rows: [],
      striped: false,
      // no alternating row bg color so delete button appears more visible
      showLines: false
    };
    for (const g of this.groups) {
      tableArg.rows.push([
        {},
        // blank cell to add delete button
        { value: g.name },
        // to allow click to show <input>
        { color: g.color },
        // { value: 'n=' + (await self.vocabApi.getFilteredSampleCount(g.filter)) }, // will re-enable when filtered sample count can be supported for gdc
        {}
        // blank cell to show filter ui
      ]);
    }
    renderTable(tableArg);
    for (const [i, row] of tableArg.rows.entries()) {
      row[0].__td.append("div").attr("class", "sja_menuoption").style("padding", "1px 6px").html("&times;").on("click", () => {
        this.groups.splice(i, 1);
        this.main();
      });
      const group = this.groups[i];
      filterInit({
        holder: row[3].__td,
        vocabApi: this.app.vocabApi,
        header_mode: "hide_search",
        callback: (f) => {
          if (!f || f.lst.length == 0) {
            const i2 = this.groups.findIndex((g) => g.name == group.name);
            this.groups.splice(i2, 1);
          } else {
            group.filter = f;
          }
          this.main();
        }
      }).main(group.filter);
    }
    this.dom.addGroup.select(".sja_new_filter_btn").style("pointer-events", "auto").style("opacity", 1);
  }
  addNewGroup(filter, groups, name) {
    if (!groups) throw "groups is missing";
    if (!name) {
      const base = "New group";
      name = base;
      for (let i = 0; ; i++) {
        name = base + (i === 0 ? "" : " " + i);
        if (!groups.find((g) => g.name === name)) break;
      }
    }
    const newGroup = {
      name,
      filter,
      color: rgb(colorScale(groups.length)).formatHex()
    };
    groups.push(newGroup);
  }
  mayRenderSubmit() {
    if (!this.groups.length) {
      this.dom.submit.style("display", "none");
      return;
    }
    this.dom.submit.style("display", "inline-block");
    if (this.groups.length == 1) {
      this.dom.submit.text(`Submit (${this.groups[0].name} vs others)`);
      this.dom.submit.on("click", async () => {
        const groups = [this.groups[0]];
        const otherGroup = {
          name: "Not in " + groups[0].name,
          color: "#ccc",
          filter: negateFilter(groups[0].filter)
        };
        groups.push(otherGroup);
        await this.clickSubmit(groups);
      });
    } else if (this.groups.length == 2) {
      this.dom.addGroup.select(".sja_new_filter_btn").style("pointer-events", "none").style("opacity", 0.5);
      this.dom.submit.text(`Submit (${this.groups[0].name} vs ${this.groups[1].name})`);
      this.dom.submit.on("click", async () => {
        await this.clickSubmit(this.groups);
      });
    } else {
      throw new Error("cannot exceed 2 groups");
    }
  }
  async clickSubmit(groups) {
    this.dom.loading.style("display", "block");
    const samplelstTW = {
      q: { groups: [] },
      term: {
        name: groups.map((g) => g.name).join(" vs "),
        type: "samplelst",
        values: {}
      }
    };
    for (const g of groups) {
      const samples = await this.app.vocabApi.getFilteredSampleList(
        filterJoin([g.filter, this.state.termfilter.filter])
      );
      const sampleIds = samples.map((s) => {
        return { sampleId: s };
      });
      samplelstTW.q.groups.push({
        name: g.name,
        in: true,
        values: sampleIds
      });
      samplelstTW.term.values[g.name] = {
        color: g.color,
        key: g.name,
        label: g.name,
        list: sampleIds
      };
    }
    const body = {
      genome: this.app.vocabApi.vocab.genome,
      dslabel: this.app.vocabApi.vocab.dslabel,
      samplelst: { groups: samplelstTW.q.groups },
      filter: this.state.termfilter.filter,
      filter0: this.state.termfilter.filter0,
      preAnalysis: true
    };
    const preAnalysisData = await dofetch3("termdb/DE", { body });
    this.dom.loading.style("display", "none");
    this.dom.preAnalysis.style("display", "block");
    this.dom.preAnalysis.append("div").style("font-weight", "bold").text("Samples with gene expression data:");
    renderPreAnalysisData({
      preAnalysisData,
      samplelstTW,
      groups: samplelstTW.q.groups,
      holder: this.dom.preAnalysis,
      self: this
    });
  }
};
var DEinputInit = getCompInit(DEinputPlot);
var componentInit = DEinputInit;
async function getPlotConfig(opts) {
  const config = {
    chartType: "DEinput",
    settings: {}
  };
  return copyMerge(config, opts);
}
export {
  DEinputInit,
  componentInit,
  getPlotConfig
};
//# sourceMappingURL=DEinput-MRUQW6X6.js.map
