import {
  make_one_checkbox,
  renderTable,
  sayerror,
  table2col,
  to_svg
} 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 {
  icons
} from "./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 "./chunk-M3J4MINX.js";
import "./chunk-PF4DSFDR.js";
import "./chunk-QH6W3NVF.js";
import "./chunk-NOEAT6CX.js";
import {
  bplen,
  class2SOterm,
  dtsnvindel,
  mclass
} from "./chunk-4UWS5Y3N.js";
import "./chunk-DD4R5P6W.js";
import "./chunk-JNITUVXP.js";
import "./chunk-KSGA62R2.js";
import {
  axisLeft
} from "./chunk-LOZEKOES.js";
import "./chunk-TOU7EVFQ.js";
import {
  linear
} from "./chunk-OAWQ6LOO.js";
import "./chunk-TLT4YIG3.js";
import "./chunk-KYBIQBXE.js";
import {
  select_default
} from "./chunk-I6Y4O3RR.js";
import "./chunk-OMR2DT66.js";
import "./chunk-DQC5FFGV.js";
import "./chunk-HFNDKYVF.js";

// gdc/grin2/ui-components.ts
var STYLES = {
  // Layout styles
  flexRow: {
    display: "flex",
    "align-items": "center",
    gap: "8px"
  },
  gridTwoColumn: {
    display: "grid",
    "grid-template-columns": "auto auto",
    gap: "15px",
    "max-width": "fit-content"
  },
  // Form element styles
  label: {
    "font-size": "14px",
    "font-weight": "500"
  },
  numberInput: {
    padding: "4px 8px",
    border: "1px solid #ccc",
    "border-radius": "4px",
    "font-size": "14px"
  },
  checkbox: {
    margin: "0",
    cursor: "pointer"
  },
  checkboxLabel: {
    cursor: "pointer",
    "font-weight": "500"
  },
  // Table styles
  tableHeader: {
    padding: "12px",
    "background-color": "#f8f9fa",
    border: "1px solid #ddd",
    "font-weight": "bold",
    "text-align": "left"
  },
  tableCell: {
    padding: "12px",
    border: "1px solid #ddd",
    "vertical-align": "top"
  },
  optionsTable: {
    width: "auto",
    "border-collapse": "collapse",
    "margin-top": "10px",
    border: "1px solid #ddd"
  },
  // Panel styles
  infoPanel: {
    padding: "8px",
    "background-color": "#f8f9fa",
    "border-radius": "4px",
    "border-left": "3px solid #6c757d",
    "font-size": "12px",
    color: "#495057",
    "line-height": "1.4"
  },
  // Expandable section styles
  expandableHeader: {
    display: "flex",
    "align-items": "center",
    gap: "8px",
    cursor: "pointer",
    padding: "8px",
    "border-radius": "4px",
    transition: "background-color 0.2s"
  },
  expandIcon: {
    "font-size": "12px",
    transition: "transform 0.2s"
  },
  expandableContent: {
    display: "none",
    "margin-top": "12px",
    padding: "12px",
    "background-color": "#fff",
    "border-radius": "4px",
    "box-shadow": "inset 0 1px 3px rgba(0, 0, 0, 0.1)"
  },
  expandHeaderText: {
    "text-decoration": "underline",
    "font-size": "13px",
    "font-weight": "500"
  }
};
function applyStyles(selection, styles) {
  Object.entries(styles).forEach(([property, value]) => {
    selection.style(property, value);
  });
  return selection;
}
function createNumberInput(container, config) {
  const inputContainer = container.append("div");
  applyStyles(inputContainer, STYLES.flexRow);
  const label = inputContainer.append("label");
  applyStyles(label, STYLES.label);
  if (config.labelWidth) {
    label.style("min-width", config.labelWidth);
  }
  label.text(config.label);
  const input = inputContainer.append("input").attr("type", "number").attr("value", config.value);
  applyStyles(input, STYLES.numberInput);
  if (config.min !== void 0) input.attr("min", config.min);
  if (config.max !== void 0) input.attr("max", config.max);
  if (config.step !== void 0) input.attr("step", config.step);
  if (config.width) input.style("width", config.width);
  input.on("input", function() {
    const value = parseFloat(this.value);
    if (!isNaN(value)) {
      config.onChange(value);
    }
  });
  return { container: inputContainer, input, label };
}
function createCheckbox(container, config) {
  const checkboxContainer = container.append("div");
  applyStyles(checkboxContainer, STYLES.flexRow);
  const checkbox = checkboxContainer.append("input").attr("type", "checkbox").attr("id", config.id).property("checked", config.checked);
  applyStyles(checkbox, STYLES.checkbox);
  const label = checkboxContainer.append("label").attr("for", config.id).text(config.label);
  applyStyles(label, STYLES.checkboxLabel);
  checkbox.on("change", function() {
    config.onChange(this.checked);
  });
  return { container: checkboxContainer, checkbox, label };
}
function createOptionsTable(container) {
  const table = container.append("table");
  applyStyles(table, STYLES.optionsTable);
  return table;
}
function createTableHeader(table, columns) {
  const headerRow = table.append("tr");
  columns.forEach((columnText, index) => {
    const th = headerRow.append("th");
    applyStyles(th, STYLES.tableHeader);
    if (index === 0) {
      th.style("width", "200px");
    }
    th.text(columnText);
  });
  return headerRow;
}
function createDataTypeRow(table, config) {
  const row = table.append("tr");
  const checkboxCell = row.append("td");
  applyStyles(checkboxCell, STYLES.tableCell);
  const { checkbox } = createCheckbox(checkboxCell, {
    id: config.id,
    label: config.label,
    checked: config.checked,
    onChange: config.onChange
  });
  const optionsCell = row.append("td");
  applyStyles(optionsCell, STYLES.tableCell);
  const optionsContainer = optionsCell.append("div").style("display", config.checked ? "block" : "none");
  config.createOptionsContent(optionsContainer);
  return { row, optionsContainer, checkbox };
}
function createInfoPanel(container, config) {
  const panel = container.append("div");
  applyStyles(panel, STYLES.infoPanel);
  if (config.color) {
    panel.style("border-left-color", config.color);
  }
  if (config.title) {
    panel.append("strong").text(config.title);
    panel.append("br");
  }
  panel.append("span").html(config.content);
  return panel;
}

// plots/manhattan/manhattanGDC.ts
function plotManhattanGDC(div, data, settings, app) {
  settings = {
    pngDotRadius: 2,
    plotWidth: 1e3,
    plotHeight: 400,
    yAxisX: 70,
    yAxisY: 40,
    yAxisSpace: 40,
    fontSize: 12,
    showLegend: true,
    legendItemWidth: 80,
    legendDotRadius: 3,
    legendRightOffset: 15,
    legendTextOffset: 12,
    legendVerticalOffset: 4,
    legendFontSize: 12,
    showInteractiveDots: true,
    showDownload: true,
    interactiveDotRadius: 3,
    interactiveDotStrokeWidth: 1,
    ...settings
  };
  div.style("position", "relative");
  const geneTip = new Menu({ padding: "" });
  const svg = div.append("svg").attr("width", data.plotData.png_width + settings.yAxisX + settings.yAxisSpace).attr("height", data.plotData.png_height + settings.yAxisY * 4);
  const yAxisG = svg.append("g").attr("transform", `translate(${settings.yAxisX + settings.yAxisSpace},${settings.yAxisY})`);
  const yScale = linear().domain([0, data.plotData.y_max]).range([data.plotData.png_height, 0]);
  yAxisG.call(axisLeft(yScale));
  svg.append("text").attr("x", -(data.plotData.png_height / 2) - settings.yAxisY).attr("y", settings.yAxisX / 2).attr("transform", "rotate(-90)").attr("text-anchor", "middle").attr("font-size", `${settings.fontSize}px`).attr("fill", "black").text("-log\u2081\u2080(q-value)");
  svg.append("image").attr("transform", `translate(${settings.yAxisX + settings.yAxisSpace},${settings.yAxisY})`).attr("width", data.plotData.png_width).attr("height", data.plotData.png_height).attr("href", `data:image/png;base64,${data.pngImg || data.png}`);
  const xScale = linear().domain([-data.plotData.x_buffer, data.plotData.total_genome_length + data.plotData.x_buffer]).range([0, data.plotData.png_width]);
  if (settings.showInteractiveDots && data.plotData.points && data.plotData.points.length > 0) {
    const pointsLayer = svg.append("g").attr("transform", `translate(${settings.yAxisX + settings.yAxisSpace},${settings.yAxisY})`);
    pointsLayer.selectAll("circle").data(data.plotData.points).enter().append("circle").attr("cx", (d) => xScale(d.x)).attr("cy", (d) => yScale(d.y)).attr("r", settings.interactiveDotRadius).attr("fill-opacity", 0).attr("stroke", "black").attr("stroke-width", settings.interactiveDotStrokeWidth).attr("stroke-opacity", 0).on("mouseover", (event, d) => {
      event.target.setAttribute("stroke-opacity", 1);
      geneTip.clear().show(event.clientX, event.clientY);
      const table = table2col({
        holder: geneTip.d.append("div"),
        margin: "10px"
      });
      table.addRow("Gene", d.gene);
      const [t1, t2] = table.addRow();
      t1.text("Type");
      t2.html(`<span style="color:${d.color}">\u25CF</span> ${d.type.charAt(0).toUpperCase() + d.type.slice(1)}`);
      table.addRow("-log\u2081\u2080(q-value)", d.y.toFixed(3));
      if (d.nsubj) table.addRow("Subject count", d.nsubj);
      table.addRow("Chromosome", d.chrom);
    }).on("mouseout", (event) => {
      event.target.setAttribute("stroke-opacity", 0);
      geneTip.hide();
    }).on("click", (event, d) => {
      if (app) {
        app.dispatch({
          type: "plot_create",
          config: {
            chartType: "genomeBrowser",
            geneSearchResult: { geneSymbol: d.gene }
          }
        });
      }
    });
  }
  if (data.plotData.chrom_data) {
    const chromLabelY = data.plotData.png_height + settings.yAxisY + 20;
    Object.entries(data.plotData.chrom_data).forEach(([chrom, chromData]) => {
      const chromLabel = chrom.replace("chr", "");
      if (chromLabel === "M") return;
      const centerPos = settings.yAxisX + settings.yAxisSpace + xScale(chromData.center);
      svg.append("text").attr("x", centerPos).attr("y", chromLabelY).attr("text-anchor", "middle").attr("font-size", `${settings.fontSize - 2}px`).attr("fill", "black").text(chromLabel);
    });
  }
  svg.append("text").attr("x", settings.yAxisX + settings.yAxisSpace + data.plotData.png_width / 2).attr("y", data.plotData.png_height + settings.yAxisY + 45).attr("text-anchor", "middle").attr("font-size", `${settings.fontSize}px`).attr("fill", "black").text("Chromosomes");
  svg.append("text").attr("x", settings.yAxisX + settings.yAxisSpace).attr("y", settings.yAxisY / 2).attr("text-anchor", "left").attr("font-weight", "bold").attr("font-size", `${settings.fontSize + 2}px`).attr("fill", "black").text("Manhattan Plot");
  if (settings.showDownload) {
    const downloadDiv = div.append("div").style("position", "absolute").style("top", "5px").style("left", `${settings.yAxisX + settings.yAxisSpace + 108}px`).style("z-index", "10").style("background", `${settings.background}`).style("padding", `${settings.padding + 2}px`).style("border-radius", `${settings.borderRadius + 10}px`);
    icons["download"](downloadDiv, {
      width: 16,
      height: 16,
      title: "Download Manhattan plot",
      handler: () => {
        to_svg(
          svg.node(),
          `manhattan_plot_${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, -5)}`,
          { apply_dom_styles: true }
        );
      }
    });
  }
  const mutationTypes = [...new Set(data.plotData.points.map((p) => p.type))];
  const legendData = mutationTypes.map((type) => {
    const point = data.plotData.points.find((p) => p.type === type);
    return {
      type: String(type).charAt(0).toUpperCase() + String(type).slice(1),
      color: point?.color
    };
  });
  if (settings.showLegend && legendData.length > 0) {
    const legendY = settings.yAxisY / 2;
    const totalWidth = legendData.length * settings.legendItemWidth;
    const legendX = settings.yAxisX + settings.yAxisSpace + data.plotData.png_width - totalWidth - settings.legendRightOffset;
    legendData.forEach((item, i) => {
      const x = legendX + i * settings.legendItemWidth;
      svg.append("circle").attr("cx", x + 8).attr("cy", legendY).attr("r", settings.legendDotRadius).attr("fill", item.color).attr("stroke", "black").attr("stroke-width", 1);
      svg.append("text").attr("x", x + 8 + settings.legendTextOffset).attr("y", legendY + settings.legendVerticalOffset).attr("font-size", `${settings.legendFontSize}px`).attr("fill", "black").text(item.type);
    });
  }
}

// gdc/grin2.ts
var defaultCheckedClasses = ["M", "F", "N", "StopLost", "StartLost", "L", "I", "D", "ProteinAltering"];
var skipMAFclasses = ["WT", "Blank", "X"];
function transformRows(rows, columns) {
  return rows.map((row) => {
    const transformedRow = [];
    for (let i = 0; i < columns.length; i++) {
      const cellData = row[i];
      let value = null;
      if (cellData && cellData.value && Array.isArray(cellData.value)) {
        value = cellData.value[0];
      } else if (cellData && "value" in cellData) {
        value = cellData.value;
      } else {
        value = cellData;
      }
      transformedRow.push({ value });
    }
    return transformedRow;
  });
}
function parseRecordsByCaseData(recordsByCase, excludedByMaxRecord = {}) {
  const columns = [
    { label: "Case ID", sortable: true },
    { label: "MAF Total Processed", sortable: true },
    { label: "MAF Included", sortable: true },
    { label: "MAF Excluded by Depth", sortable: true },
    { label: "MAF Excluded by Alt Count", sortable: true },
    { label: "MAF Excluded by Consequence", sortable: true },
    { label: "MAF Skipped Chromosomes", sortable: true },
    { label: "MAF Excluded by Records Cap", sortable: true },
    { label: "CNV Total Processed", sortable: true },
    { label: "CNV Included", sortable: true },
    { label: "CNV Excluded by Thresholds", sortable: true },
    { label: "CNV Excluded by Length", sortable: true },
    { label: "CNV Skipped Chromosomes", sortable: true },
    { label: "CNV Excluded by Records Cap", sortable: true },
    { label: "Invalid Rows", sortable: true }
  ];
  const rows = [];
  Object.entries(recordsByCase).forEach(([caseId, caseData]) => {
    const row = [];
    row.push({ value: caseId });
    let parsedData;
    try {
      parsedData = typeof caseData === "string" ? JSON.parse(caseData) : caseData;
    } catch (_e) {
      parsedData = caseData;
    }
    let mafTotalProcessed = 0;
    let mafIncluded = 0;
    let mafExcludedByDepth = 0;
    let mafExcludedByAltCount = 0;
    let mafExcludedByConsequence = 0;
    let mafSkippedChromosomes = 0;
    if (parsedData.maf) {
      mafTotalProcessed = parsedData.maf.total_processed || 0;
      mafIncluded = parsedData.maf.total_included || 0;
      mafExcludedByDepth = parsedData.maf.excluded_by_min_depth || 0;
      mafExcludedByAltCount = parsedData.maf.excluded_by_min_alt_count || 0;
      mafExcludedByConsequence = parsedData.maf.excluded_by_consequence_type || 0;
      if (parsedData.maf.skipped_chromosomes && typeof parsedData.maf.skipped_chromosomes === "object") {
        mafSkippedChromosomes = Object.values(parsedData.maf.skipped_chromosomes).reduce(
          (sum, count) => sum + (Number(count) || 0),
          0
        );
      }
    }
    row.push({ value: mafTotalProcessed });
    row.push({ value: mafIncluded });
    row.push({ value: mafExcludedByDepth });
    row.push({ value: mafExcludedByAltCount });
    row.push({ value: mafExcludedByConsequence });
    if (parsedData.maf?.skipped_chromosomes && Object.keys(parsedData.maf.skipped_chromosomes).length > 0) {
      const chromosomeEntries = Object.entries(parsedData.maf.skipped_chromosomes);
      const tableHtml = `
				<div style="text-align: center;">
				<table style="border-collapse: collapse; margin: 0 auto; font-size: 11px; border: 1px solid #ddd;">
					<thead>
					<tr style="background-color: #f8f9fa;">
						<th style="border: 1px solid #ddd; padding: 2px 6px;">Chr</th>
						<th style="border: 1px solid #ddd; padding: 2px 6px;">Count</th>
					</tr>
					</thead>
					<tbody>
					${chromosomeEntries.map(
        ([chr, count]) => `<tr>
						<td style="border: 1px solid #ddd; padding: 2px 6px;">${chr}</td>
						<td style="border: 1px solid #ddd; padding: 2px 6px; text-align: right;">${count}</td>
						</tr>`
      ).join("")}
					</tbody>
				</table>
				</div>
			`;
      row.push({
        html: tableHtml,
        value: mafSkippedChromosomes,
        rawData: parsedData.maf.skipped_chromosomes,
        dataType: "chromosome-details"
      });
    } else {
      row.push({
        value: mafSkippedChromosomes,
        rawData: null,
        dataType: "chromosome-details"
      });
    }
    const mafExcludedByMax = excludedByMaxRecord.maf?.includes(caseId) ? "Yes" : "No";
    row.push({
      value: mafExcludedByMax,
      html: mafExcludedByMax === "Yes" ? `<span style="color: #dc3545; font-weight: bold;">${mafExcludedByMax}</span>` : mafExcludedByMax
    });
    let cnvTotalProcessed = 0;
    let cnvIncluded = 0;
    let cnvExcludedByThresholds = 0;
    let cnvExcludedByLength = 0;
    let cnvSkippedChromosomes = 0;
    if (parsedData.cnv) {
      cnvTotalProcessed = parsedData.cnv.total_processed || 0;
      cnvIncluded = parsedData.cnv.total_included || 0;
      cnvExcludedByThresholds = (parsedData.cnv.excluded_by_loss_threshold || 0) + (parsedData.cnv.excluded_by_gain_threshold || 0);
      cnvExcludedByLength = parsedData.cnv.excluded_by_segment_length || 0;
      if (parsedData.cnv.skipped_chromosomes && typeof parsedData.cnv.skipped_chromosomes === "object") {
        cnvSkippedChromosomes = Object.values(parsedData.cnv.skipped_chromosomes).reduce(
          (sum, count) => sum + (Number(count) || 0),
          0
        );
      }
    }
    row.push({ value: cnvTotalProcessed });
    row.push({ value: cnvIncluded });
    row.push({ value: cnvExcludedByThresholds });
    row.push({ value: cnvExcludedByLength });
    if (parsedData.cnv?.skipped_chromosomes && Object.keys(parsedData.cnv.skipped_chromosomes).length > 0) {
      const chromosomeEntries = Object.entries(parsedData.cnv.skipped_chromosomes);
      const tableHtml = `
    <div style="text-align: center;">
      <table style="border-collapse: collapse; margin: 0 auto; font-size: 11px; border: 1px solid #ddd;">
        <thead>
          <tr style="background-color: #f8f9fa;">
            <th style="border: 1px solid #ddd; padding: 2px 6px;">Chr</th>
            <th style="border: 1px solid #ddd; padding: 2px 6px;">Count</th>
          </tr>
        </thead>
        <tbody>
          ${chromosomeEntries.map(
        ([chr, count]) => `<tr>
              <td style="border: 1px solid #ddd; padding: 2px 6px;">${chr}</td>
              <td style="border: 1px solid #ddd; padding: 2px 6px; text-align: right;">${count}</td>
            </tr>`
      ).join("")}
        </tbody>
      </table>
    </div>
  `;
      row.push({
        html: tableHtml,
        value: cnvSkippedChromosomes,
        rawData: parsedData.cnv.skipped_chromosomes,
        dataType: "chromosome-details"
      });
    } else {
      row.push({
        value: cnvSkippedChromosomes,
        rawData: null,
        dataType: "chromosome-details"
      });
    }
    const cnvExcludedByMax = excludedByMaxRecord.cnv?.includes(caseId) ? "Yes" : "No";
    row.push({
      value: cnvExcludedByMax,
      html: cnvExcludedByMax === "Yes" ? `<span style="color: #dc3545; font-weight: bold;">${cnvExcludedByMax}</span>` : cnvExcludedByMax
    });
    let totalInvalidRows = 0;
    if (parsedData.maf && parsedData.maf.invalid_rows !== void 0) {
      totalInvalidRows += Number(parsedData.maf.invalid_rows) || 0;
    }
    if (parsedData.cnv && parsedData.cnv.invalid_rows !== void 0) {
      totalInvalidRows += Number(parsedData.cnv.invalid_rows) || 0;
    }
    row.push({ value: totalInvalidRows });
    rows.push(row);
  });
  return { columns, rows };
}
function addExpandableFailedFilesToStats(statsContainer, failedFilesInfo) {
  const expandableContainer = statsContainer.append("div").style("margin-top", "12px");
  const expandableHeader = expandableContainer.append("div").style("display", "flex").style("align-items", "center").style("gap", "8px").style("cursor", "pointer").style("padding", "8px").style("border-radius", "4px").style("transition", "background-color 0.2s").style("background-color", "rgba(220, 53, 69, 0.1)").style("border", "1px solid rgba(220, 53, 69, 0.2)").on("mouseenter", function() {
    select_default(this).style("background-color", "rgba(220, 53, 69, 0.15)");
  }).on("mouseleave", function() {
    select_default(this).style("background-color", "rgba(220, 53, 69, 0.1)");
  });
  const expandIcon = expandableHeader.append("span").style("font-size", "12px").style("color", "#dc3545").style("transition", "transform 0.2s").text("\u25B6");
  expandableHeader.append("span").style("color", "#dc3545").style("text-decoration", "underline").style("font-size", "13px").style("font-weight", "500").text(`View ${failedFilesInfo.count} failed files details`);
  if (failedFilesInfo.errorSummary) {
    const { errorSummary } = failedFilesInfo;
    const summaryItems = [];
    if (errorSummary.connectionErrors > 0) {
      summaryItems.push(`${errorSummary.connectionErrors} connection`);
    }
    if (errorSummary.timeoutErrors > 0) {
      summaryItems.push(`${errorSummary.timeoutErrors} timeout`);
    }
    if (errorSummary.serverErrors > 0) {
      summaryItems.push(`${errorSummary.serverErrors} server`);
    }
    if (errorSummary.otherErrors > 0) {
      summaryItems.push(`${errorSummary.otherErrors} other`);
    }
    if (summaryItems.length > 0) {
      expandableHeader.append("span").style("margin-left", "8px").style("font-size", "12px").style("color", "#666").style("font-weight", "normal").text(`(${summaryItems.join(", ")})`);
    }
  }
  const expandableContent = expandableContainer.append("div").style("display", "none").style("margin-top", "12px").style("padding", "12px").style("background-color", "#fff").style("border", "1px solid #f5c6cb").style("border-radius", "4px").style("box-shadow", "inset 0 1px 3px rgba(0, 0, 0, 0.1)");
  const tableSection = expandableContent.append("div");
  tableSection.append("h6").style("margin", "0 0 12px 0").style("color", "#721c24").style("font-size", "14px").style("font-weight", "bold").text("Failed Files Details");
  const tableContainer = tableSection.append("div").style("max-height", "300px").style("overflow-y", "auto").style("border", "1px solid #dee2e6").style("border-radius", "4px");
  renderTable({
    div: tableContainer,
    columns: failedFilesInfo.tableData.headers.map((header) => ({
      label: header,
      sortable: true
    })),
    rows: failedFilesInfo.tableData.rows.map((row) => row.map((cell) => ({ value: cell }))),
    showLines: true,
    striped: true,
    showHeader: true,
    maxHeight: "280px",
    resize: false,
    header: {
      allowSort: true,
      style: {
        "background-color": "#f8f9fa",
        "font-weight": "bold",
        "border-bottom": "2px solid #dee2e6"
      }
    }
  });
  expandableContent.append("div").style("margin-top", "12px").style("padding", "8px").style("background-color", "#f8f9fa").style("border-radius", "4px").style("font-size", "12px").style("color", "#495057").style("line-height", "1.4").text("These files could not be downloaded due to network or server issues and were excluded from the analysis.");
  let isExpanded = false;
  expandableHeader.on("click", function() {
    isExpanded = !isExpanded;
    if (isExpanded) {
      expandableContent.style("display", "block");
      expandIcon.style("transform", "rotate(90deg)").text("\u25BC");
    } else {
      expandableContent.style("display", "none");
      expandIcon.style("transform", "rotate(0deg)").text("\u25B6");
    }
  });
}
function createExpandableDeduplicationSection(container, deduplicationStats) {
  const duplicatesRemoved = deduplicationStats.duplicatesRemoved || 0;
  const sizeFilteredCount = deduplicationStats.filteredFiles ? deduplicationStats.filteredFiles.length : 0;
  const totalExcluded = duplicatesRemoved + sizeFilteredCount;
  if (totalExcluded === 0) {
    return;
  }
  const expandableContainer = container.append("div").style("margin-top", "8px");
  const expandableHeader = expandableContainer.append("div").style("display", "flex").style("align-items", "center").style("gap", "8px").style("cursor", "pointer").style("padding", "6px 8px").style("border-radius", "4px").style("transition", "background-color 0.2s").style("background-color", "rgba(216, 67, 21, 0.1)").style("border", "1px solid rgba(216, 67, 21, 0.2)").on("mouseenter", function() {
    select_default(this).style("background-color", "rgba(216, 67, 21, 0.15)");
  }).on("mouseleave", function() {
    select_default(this).style("background-color", "rgba(216, 67, 21, 0.1)");
  });
  const expandIcon = expandableHeader.append("span").style("font-size", "12px").style("color", "#d84315").style("transition", "transform 0.2s").text("\u25B6");
  expandableHeader.append("span").style("color", "#d84315").style("text-decoration", "underline").style("font-size", "12px").style("font-weight", "500").text("View excluded files details");
  const exclusionDetails = [];
  if (duplicatesRemoved > 0) {
    exclusionDetails.push(`${duplicatesRemoved} duplicates`);
  }
  if (sizeFilteredCount > 0) {
    exclusionDetails.push(`${sizeFilteredCount} oversized`);
  }
  if (exclusionDetails.length > 0) {
    expandableHeader.append("span").style("margin-left", "8px").style("font-size", "11px").style("color", "#666").style("font-weight", "normal").text(`(${exclusionDetails.join(", ")})`);
  }
  const expandableContent = expandableContainer.append("div").style("display", "none").style("margin-top", "8px").style("padding", "12px").style("background-color", "#fff").style("border", "1px solid rgba(216, 67, 21, 0.3)").style("border-radius", "4px").style("box-shadow", "inset 0 1px 3px rgba(0, 0, 0, 0.1)").style("max-height", "400px").style("overflow-y", "auto");
  if (deduplicationStats.caseDetails && deduplicationStats.caseDetails.length > 0) {
    const duplicatesSection = expandableContent.append("div").style("margin-bottom", "16px");
    duplicatesSection.append("h6").style("margin", "0 0 8px 0").style("color", "#d84315").style("font-size", "13px").style("font-weight", "bold").text("Duplicate Files Removed");
    duplicatesSection.append("p").style("margin", "0 0 12px 0").style("font-size", "12px").style("color", "#666").text(`${deduplicationStats.duplicatesRemoved} duplicate files were removed (largest file kept for each case)`);
    const duplicatesCasesContainer = duplicatesSection.append("div").style("display", "grid").style("grid-template-columns", "repeat(auto-fill, minmax(300px, 1fr))").style("gap", "8px");
    deduplicationStats.caseDetails.forEach((caseInfo) => {
      const caseDiv = duplicatesCasesContainer.append("div").style("padding", "6px 8px").style("background-color", "#fff3e0").style("border-radius", "3px").style("border-left", "3px solid #ff9800");
      caseDiv.append("div").style("font-size", "12px").style("color", "#333").style("line-height", "1.3").html(
        `<strong>Case ${caseInfo.caseName}:</strong> Found ${caseInfo.fileCount} MAF files, keeping largest (${bplen(
          caseInfo.keptFileSize
        )})`
      );
    });
  }
  if (deduplicationStats.filteredFiles && deduplicationStats.filteredFiles.length > 0) {
    if (deduplicationStats.caseDetails && deduplicationStats.caseDetails.length > 0) {
      expandableContent.append("hr").style("margin", "12px 0").style("border", "none").style("border-top", "1px solid #e0e0e0");
    }
    const sizeFilterSection = expandableContent.append("div");
    sizeFilterSection.append("h6").style("margin", "0 0 8px 0").style("color", "#c62828").style("font-size", "13px").style("font-weight", "bold").text("Files Excluded by Size");
    sizeFilterSection.append("p").style("margin", "0 0 12px 0").style("font-size", "12px").style("color", "#666").text(`${deduplicationStats.filteredFiles.length} files were excluded for being too large (>${bplen(1e6)})`);
    const oversizedFilesContainer = sizeFilterSection.append("div").style("display", "grid").style("grid-template-columns", "repeat(auto-fill, minmax(280px, 1fr))").style("gap", "8px");
    deduplicationStats.filteredFiles.forEach((fileInfo) => {
      const fileDiv = oversizedFilesContainer.append("div").style("padding", "6px 8px").style("background-color", "#ffebee").style("border-radius", "3px").style("border-left", "3px solid #f44336");
      fileDiv.append("div").style("font-size", "11px").style("color", "#333").style("margin-bottom", "2px").style("line-height", "1.2").html(`<strong>File ID:</strong> ${fileInfo.fileId}`);
      fileDiv.append("div").style("font-size", "10px").style("color", "#666").style("line-height", "1.2").text(`Size: ${bplen(fileInfo.fileSize)} - ${fileInfo.reason}`);
    });
  }
  expandableContent.append("div").style("margin-top", "12px").style("padding", "6px 8px").style("background-color", "#f8f9fa").style("border-radius", "4px").style("font-size", "11px").style("color", "#495057").style("line-height", "1.3").text("Files are filtered to ensure optimal performance and avoid duplicates.");
  let isExpanded = false;
  expandableHeader.on("click", function() {
    isExpanded = !isExpanded;
    if (isExpanded) {
      expandableContent.style("display", "block");
      expandIcon.style("transform", "rotate(90deg)").text("\u25BC");
    } else {
      expandableContent.style("display", "none");
      expandIcon.style("transform", "rotate(0deg)").text("\u25B6");
    }
  });
}
function updateDedupStatus(obj, deduplicationStats) {
  if (!obj.dedupStatusElement) return;
  const dedupElement = obj.dedupStatusElement;
  dedupElement.selectAll("*").remove();
  if (!deduplicationStats) {
    dedupElement.style("color", "#666").text("No deduplication data available");
    return;
  }
  const dedupContainer = dedupElement.append("div").style("display", "flex").style("flex-direction", "column").style("gap", "6px");
  const duplicatesRemoved = deduplicationStats.duplicatesRemoved || 0;
  const sizeFilteredCount = deduplicationStats.filteredFiles ? deduplicationStats.filteredFiles.length : 0;
  const totalExcluded = duplicatesRemoved + sizeFilteredCount;
  const originalTotal = deduplicationStats.originalFileCount + sizeFilteredCount;
  if (totalExcluded > 0) {
    const summaryDiv = dedupContainer.append("div").style("font-size", "14px").style("color", "#d84315").style("font-weight", "500");
    summaryDiv.html(
      `Found <strong>${originalTotal}</strong> total MAF files, excluded <strong>${totalExcluded}</strong>`
    );
    const resultDiv = dedupContainer.append("div").style("font-size", "13px").style("color", "#28a745").style("font-weight", "500");
    resultDiv.html(`Showing <strong>${deduplicationStats.deduplicatedFileCount}</strong> unique cases`);
    if (duplicatesRemoved > 0) {
      resultDiv.append("span").style("color", "#666").style("font-weight", "normal").text(" (largest file per case)");
    }
    createExpandableDeduplicationSection(dedupContainer, deduplicationStats);
  } else {
    dedupContainer.append("div").style("color", "#28a745").style("font-weight", "500").style("font-size", "14px").html(`All <strong>${deduplicationStats.deduplicatedFileCount}</strong> files included`);
    dedupContainer.append("div").style("color", "#666").style("font-size", "13px").text("No duplicates or oversized files found");
  }
}
function createMAFOptionsContent(container, obj) {
  container.selectAll("*").remove();
  const optionsGrid = container.append("div");
  applyStyles(optionsGrid, STYLES.gridTwoColumn);
  optionsGrid.style("margin-top", "10px");
  createNumberInput(optionsGrid, {
    label: "Min Total Depth:",
    value: obj.mafOptions.minTotalDepth || 10,
    min: 0,
    step: 1,
    width: "80px",
    labelWidth: "140px",
    onChange: (value) => {
      if (value >= 0) obj.mafOptions.minTotalDepth = value;
    }
  });
  createNumberInput(optionsGrid, {
    label: "Min Mutant Allele Count:",
    value: obj.mafOptions.minAltAlleleCount || 2,
    min: 0,
    step: 1,
    width: "80px",
    labelWidth: "160px",
    onChange: (value) => {
      if (value >= 0) obj.mafOptions.minAltAlleleCount = value;
    }
  });
  createConsequencesSection(optionsGrid, obj);
  createNumberInput(optionsGrid, {
    label: "Hypermutator Max Cut Off:",
    value: obj.mafOptions.hyperMutator || 8e3,
    min: 0,
    step: 100,
    width: "70px",
    labelWidth: "160px",
    onChange: (value) => {
      if (value >= 0) obj.mafOptions.hyperMutator = value;
    }
  });
  createWorkflowSection(optionsGrid);
  createDeduplicationSection(optionsGrid, obj);
}
function createConsequencesSection(optionsGrid, obj) {
  const consequencesContainer = optionsGrid.append("div").style("display", "flex").style("align-items", "flex-start").style("gap", "8px").style("grid-column", "1 / -1");
  consequencesContainer.append("label").style("font-size", "14px").style("font-weight", "500").style("min-width", "100px").style("margin-top", "4px").text("Consequences:");
  const selectionDiv = consequencesContainer.append("div").style("flex", "1");
  const checkboxContainer = selectionDiv.append("div").style("display", "grid").style("grid-template-columns", "repeat(auto-fit, minmax(200px, 1fr))").style("gap", "8px").style("margin-bottom", "12px");
  createMutationClassCheckboxes(checkboxContainer, obj);
  createInfoPanel(selectionDiv, {
    title: "Mutation Types:",
    content: `Select the types of mutations to include in your analysis.
              High-impact mutations (missense, nonsense, frameshift) are selected by default.
              Silent/synonymous mutations are excluded by default as they don't change protein sequence.`
  });
}
function createMutationClassCheckboxes(container, obj) {
  const seenLabels = /* @__PURE__ */ new Set();
  for (const cls in mclass) {
    if (mclass[cls].dt !== dtsnvindel) continue;
    if (skipMAFclasses.includes(cls)) continue;
    const labelText = mclass[cls].label;
    if (seenLabels.has(labelText)) continue;
    seenLabels.add(labelText);
    const isDefaultChecked = defaultCheckedClasses.includes(cls);
    const checkboxDiv = container.append("div");
    make_one_checkbox({
      holder: checkboxDiv,
      labeltext: labelText,
      checked: isDefaultChecked,
      id: `consequence-${cls}`,
      divstyle: {
        "font-size": "13px",
        margin: "0"
      },
      callback: async (isChecked) => {
        if (isChecked) {
          if (!obj.mafOptions.consequences.includes(cls)) {
            obj.mafOptions.consequences.push(cls);
          }
        } else {
          obj.mafOptions.consequences = obj.mafOptions.consequences.filter((c) => c !== cls);
        }
      }
    });
    checkboxDiv.select("label").attr("title", mclass[cls].desc);
    if (isDefaultChecked && !obj.mafOptions.consequences.includes(cls)) {
      obj.mafOptions.consequences.push(cls);
    }
  }
}
function createWorkflowSection(optionsGrid) {
  const workflowContainer = optionsGrid.append("div");
  applyStyles(workflowContainer, STYLES.flexRow);
  workflowContainer.style("grid-column", "1 / -1");
  const label = workflowContainer.append("label");
  applyStyles(label, STYLES.label);
  label.style("min-width", "100px").text("Workflow Type:");
  workflowContainer.append("span").style("font-size", "14px").style("color", "#666").text("Aliquot Ensemble Somatic Variant Merging and Masking");
}
function createDeduplicationSection(optionsGrid, obj) {
  const dedupContainer = optionsGrid.append("div");
  applyStyles(dedupContainer, STYLES.flexRow);
  dedupContainer.style("grid-column", "1 / -1");
  const label = dedupContainer.append("label");
  applyStyles(label, STYLES.label);
  label.style("min-width", "100px").text("Deduplication:");
  const dedupStatus = dedupContainer.append("span").attr("id", "dedup-status").style("font-size", "14px").style("color", "#666");
  obj.dedupStatusElement = dedupStatus;
}
function createCNVOptionsContent(container, obj) {
  container.selectAll("*").remove();
  if (!obj.cnvOptions.dataType) {
    obj.cnvOptions.dataType = "segment_mean";
  }
  const optionsGrid = container.append("div");
  applyStyles(optionsGrid, STYLES.gridTwoColumn);
  optionsGrid.style("margin-top", "10px");
  createDataTypeRadioSection(optionsGrid, obj);
  createNumberInput(optionsGrid, {
    label: "Loss Threshold:",
    value: obj.cnvOptions.lossThreshold || -0.4,
    min: -10,
    max: 0,
    step: 0.1,
    width: "70px",
    labelWidth: "120px",
    onChange: (value) => {
      if (value <= 0) obj.cnvOptions.lossThreshold = value;
    }
  });
  createNumberInput(optionsGrid, {
    label: "Gain Threshold:",
    value: obj.cnvOptions.gainThreshold || 0.3,
    min: 0,
    max: 10,
    step: 0.1,
    width: "70px",
    labelWidth: "120px",
    onChange: (value) => {
      if (value >= 0) obj.cnvOptions.gainThreshold = value;
    }
  });
  createNumberInput(optionsGrid, {
    label: "Hypermutator Max Cut Off:",
    value: obj.cnvOptions.hyperMutator || 500,
    min: 0,
    step: 100,
    width: "70px",
    labelWidth: "160px",
    onChange: (value) => {
      if (value >= 0) obj.cnvOptions.hyperMutator = value;
    }
  });
  createSegmentLengthSection(optionsGrid, obj);
  createCNVHelpSection(optionsGrid);
}
function createDataTypeRadioSection(optionsGrid, obj) {
  const dataTypeContainer = optionsGrid.append("div");
  applyStyles(dataTypeContainer, STYLES.flexRow);
  dataTypeContainer.style("grid-column", "1 / -1");
  const label = dataTypeContainer.append("label");
  applyStyles(label, STYLES.label);
  label.style("min-width", "80px").text("Data Type:");
  const radioContainer = dataTypeContainer.append("div");
  applyStyles(radioContainer, STYLES.flexRow);
  radioContainer.style("gap", "6px");
  const radio = radioContainer.append("input").attr("type", "radio").attr("id", "cnv-segment-mean").attr("name", "cnv-data-type").attr("value", "segment_mean").property("checked", obj.cnvOptions.dataType === "segment_mean").style("margin", "0").style("cursor", "pointer");
  radioContainer.append("label").attr("for", "cnv-segment-mean").style("cursor", "pointer").style("font-size", "14px").style("color", "#333").text("Segment mean");
  radio.on("change", function() {
    if (this.checked) {
      obj.cnvOptions.dataType = this.value;
    }
  });
}
function createSegmentLengthSection(optionsGrid, obj) {
  const segmentContainer = optionsGrid.append("div");
  applyStyles(segmentContainer, STYLES.flexRow);
  segmentContainer.style("grid-column", "1 / -1");
  const label = segmentContainer.append("label");
  applyStyles(label, STYLES.label);
  label.style("min-width", "140px").text("Segment Length Cutoff:");
  const input = segmentContainer.append("input").attr("type", "number").attr("min", "0").attr("max", "2000000").attr("step", "1000").attr("value", obj.cnvOptions.segLength || 0);
  applyStyles(input, STYLES.numberInput);
  input.style("width", "100px");
  segmentContainer.append("span").style("font-size", "13px").style("color", "#666").text("bp");
  input.on("input", function() {
    const value = parseInt(this.value, 10);
    if (!isNaN(value) && value >= 0) {
      obj.cnvOptions.segLength = value;
    }
  });
}
function createCNVHelpSection(optionsGrid) {
  const helpContainer = optionsGrid.append("div").style("grid-column", "1 / -1").style("margin-top", "8px");
  createInfoPanel(helpContainer, {
    title: "CNV Options:",
    content: `\u2022 Loss Threshold: Log2 ratio for copy number loss (negative values)<br>
              \u2022 Gain Threshold: Log2 ratio for copy number gain (positive values)<br>
              \u2022 Hypermutator Max Cut Off: Maximum number of CNVs per case<br>
              \u2022 Segment Length: Maximum CNV segment size to include (no filter if 0)`
  });
}
function makeControls(obj) {
  if (!obj.mafOptions) {
    obj.mafOptions = {
      minTotalDepth: 10,
      minAltAlleleCount: 2,
      consequences: [],
      hyperMutator: 8e3
    };
  }
  if (!obj.cnvOptions) {
    obj.cnvOptions = {
      lossThreshold: -0.4,
      gainThreshold: 0.3,
      segLength: 0,
      hyperMutator: 500
    };
  }
  obj.dataTypeStates = {
    maf: true,
    cnv: true,
    fusion: false
  };
  const optionsTable = createOptionsTable(obj.controlDiv);
  createTableHeader(optionsTable, ["Data Type", "Options"]);
  const mafRow = createDataTypeRow(optionsTable, {
    id: "maf-checkbox",
    label: "MAF (Mutation)",
    checked: true,
    onChange: (isChecked) => {
      obj.dataTypeStates.maf = isChecked;
      mafRow.optionsContainer.style("display", isChecked ? "block" : "none");
      obj.updateSubmitButtonState?.();
    },
    createOptionsContent: (container) => createMAFOptionsContent(container, obj)
  });
  const cnvRow = createDataTypeRow(optionsTable, {
    id: "cnv-checkbox",
    label: "CNV (Copy Number)",
    checked: true,
    onChange: (isChecked) => {
      obj.dataTypeStates.cnv = isChecked;
      cnvRow.optionsContainer.style("display", isChecked ? "block" : "none");
      if (isChecked) {
        createCNVOptionsContent(cnvRow.optionsContainer, obj);
      }
      obj.updateSubmitButtonState?.();
    },
    createOptionsContent: (container) => createCNVOptionsContent(container, obj)
  });
  const fusionRow = createDataTypeRow(optionsTable, {
    id: "fusion-checkbox",
    label: "Fusion",
    checked: false,
    onChange: (isChecked) => {
      obj.dataTypeStates.fusion = isChecked;
      fusionRow.optionsContainer.style("display", isChecked ? "block" : "none");
      obj.updateSubmitButtonState?.();
    },
    createOptionsContent: (container) => {
      container.append("div").style("color", "#666").style("font-style", "italic").text("Please login to access RNA fusion data.");
    }
  });
  createGRIN2InfoRow(optionsTable);
  createSubmitButton(obj);
  obj.mafOptionsContainer = mafRow.optionsContainer;
  obj.cnvOptionsContainer = cnvRow.optionsContainer;
  obj.fusionOptionsContainer = fusionRow.optionsContainer;
}
function createGRIN2InfoRow(optionsTable) {
  const grin2Row = optionsTable.append("tr");
  const labelCell = grin2Row.append("td");
  applyStyles(labelCell, STYLES.tableCell);
  labelCell.append("div").style("font-weight", "500").style("color", "#333").text("GRIN2 Analysis");
  const optionsCell = grin2Row.append("td");
  applyStyles(optionsCell, STYLES.tableCell);
  optionsCell.append("div").style("color", "#666").text("GRIN2 analysis options will be configured here");
}
function createSubmitButton(obj) {
  const submitButtonContainer = obj.controlDiv.append("div").style("margin-top", "2px").style("margin-bottom", "2px").style("text-align", "left");
  const submitButton = submitButtonContainer.append("button").attr("id", "submit-options-button").style("margin", "10px 10px 0 0").text("Apply Options & Refresh Files");
  obj.submitButton = submitButton;
  submitButton.on("click", function() {
    if (!this.disabled) {
      getFilesAndShowTable(obj);
    }
  });
  obj.updateSubmitButtonState = function() {
    const hasAnyDataTypeSelected = obj.dataTypeStates.maf || obj.dataTypeStates.cnv || obj.dataTypeStates.fusion;
    if (hasAnyDataTypeSelected) {
      submitButton.attr("disabled", null).text("Apply Options & Refresh Files");
    } else {
      submitButton.attr("disabled", true).text("Select at least one data type");
    }
  };
  obj.updateSubmitButtonState();
}
async function getFilesAndShowTable(obj) {
  obj.tableDiv.selectAll("*").remove();
  obj.resultDiv.selectAll("*").remove();
  const wait = obj.tableDiv.append("div").style("margin", "30px 10px 10px 10px").text("Loading...");
  let result;
  try {
    const body = {};
    if (obj.opts.filter0) body.filter0 = obj.opts.filter0;
    if (obj.dataTypeStates.maf) {
      body.mafOptions = {
        experimentalStrategy: obj.opts.experimentalStrategy || "WXS"
      };
    }
    if (obj.dataTypeStates.cnv) {
      body.cnvOptions = {
        dataType: obj.cnvOptions.dataType
      };
    }
    console.log("Request body for GRIN2list:", body);
    result = await dofetch3("gdc/GRIN2list", { body });
    console.log("GRIN2list result:", result);
    if (result.error) throw result.error;
    if (obj.dataTypeStates.maf && (!result.mafFiles || !Array.isArray(result.mafFiles.files))) {
      throw "Invalid response: missing mafFiles.files array";
    }
    if (obj.dataTypeStates.cnv && (!result.cnvFiles || !Array.isArray(result.cnvFiles.files))) {
      throw "Invalid response: missing cnvFiles.files array";
    }
    const hasMafFiles = result.mafFiles?.files?.length > 0;
    const hasCnvFiles = result.cnvFiles?.files?.length > 0;
    if (obj.dataTypeStates.maf && !hasMafFiles) {
      throw "No MAF files available for the selected criteria.";
    }
    if (obj.dataTypeStates.cnv && !hasCnvFiles) {
      throw "No CNV files available for the selected criteria.";
    }
    if (!hasMafFiles && !hasCnvFiles) {
      throw "No files available for the selected data types.";
    }
    if (result.mafFiles && result.mafFiles.deduplicationStats) {
      updateDedupStatus(obj, result.mafFiles.deduplicationStats);
    }
    const cnvFilesByCase = /* @__PURE__ */ new Map();
    if (obj.dataTypeStates.cnv && result.cnvFiles && result.cnvFiles.files) {
      for (const cnvFile of result.cnvFiles.files) {
        const caseId = cnvFile.case_submitter_id;
        if (!cnvFilesByCase.has(caseId)) {
          cnvFilesByCase.set(caseId, cnvFile);
        }
      }
    }
    let filteredFiles = result.mafFiles ? result.mafFiles.files : [];
    let filteringMessage = "";
    const mafSelected = obj.dataTypeStates.maf;
    const cnvSelected = obj.dataTypeStates.cnv;
    if (mafSelected && cnvSelected) {
      const originalCount = filteredFiles.length;
      filteredFiles = filteredFiles.filter((mafFile) => {
        const caseId = mafFile.case_submitter_id;
        const hasCnv = cnvFilesByCase.has(caseId);
        return hasCnv;
      });
      const filteredCount = filteredFiles.length;
      const excludedCount = originalCount - filteredCount;
      if (excludedCount > 0) {
        filteringMessage = `Filtered to ${filteredCount} cases with both MAF and CNV files (excluded ${excludedCount} cases with only MAF files)`;
      } else {
        filteringMessage = `All ${filteredCount} cases have both MAF and CNV files`;
      }
    } else if (cnvSelected && !mafSelected) {
      const originalCount = filteredFiles.length;
      filteredFiles = result.cnvFiles ? result.cnvFiles.files : [];
      const filteredCount = filteredFiles.length;
      const excludedCount = originalCount - filteredCount;
      if (excludedCount > 0) {
        filteringMessage = `Filtered to ${filteredCount} cases with CNV files (excluded ${excludedCount} cases without CNV files)`;
      }
    } else if (mafSelected && !cnvSelected) {
      filteringMessage = `Showing ${filteredFiles.length} cases with MAF files`;
    }
    if (filteredFiles.length === 0) {
      throw "No files match the selected data type criteria. Try adjusting your data type selections.";
    }
    const mafFiles = result.mafFiles ? result.mafFiles.files : [];
    const cnvFiles = result.cnvFiles ? result.cnvFiles.files : [];
    const mafTotal = result.mafFiles ? result.mafFiles.filesTotal : 0;
    let statusMessage = "";
    if (mafSelected && cnvSelected) {
      if (mafTotal > mafFiles.length) {
        statusMessage = `Showing first ${mafFiles.length.toLocaleString()} files out of ${mafTotal.toLocaleString()} total.`;
      } else {
        statusMessage = `Showing ${filteredFiles.length.toLocaleString()} files.`;
      }
    } else if (mafSelected && !cnvSelected) {
      if (mafTotal > mafFiles.length) {
        statusMessage = `Showing first ${mafFiles.length.toLocaleString()} MAF files out of ${mafTotal.toLocaleString()} total.`;
      } else {
        statusMessage = `Showing ${filteredFiles.length.toLocaleString()} MAF files.`;
      }
    } else if (!mafSelected && cnvSelected) {
      statusMessage = `Showing ${cnvFiles.length.toLocaleString()} CNV files.`;
    }
    wait.html(`
			${statusMessage}<br>
			${filteringMessage ? `<span style="color: #666; font-style: italic;">${filteringMessage}</span>` : ""}
		`);
    const dynamicTableColumns = [
      { label: "Case", sortable: true },
      { label: "Project", sortable: true }
    ];
    if (obj.dataTypeStates.maf) {
      dynamicTableColumns.push({ label: "MAF Sample", sortable: false }, {
        label: "MAF File Size",
        barplot: { tickFormat: "~s" },
        sortable: true
      });
    }
    if (obj.dataTypeStates.cnv) {
      dynamicTableColumns.push({ label: "CNV File ID", sortable: true }, { label: "CNV Sample", sortable: false }, {
        label: "CNV File Size",
        barplot: { tickFormat: "~s" },
        sortable: true
      });
    }
    if (obj.dataTypeStates.fusion) {
      dynamicTableColumns.push(
        { label: "Fusion File ID", sortable: true },
        { label: "Fusion Sample", sortable: false },
        { label: "Fusion File Size", barplot: { tickFormat: "~s" }, sortable: true }
      );
    }
    const rows = [];
    for (const f of filteredFiles) {
      const row = [];
      row.push(
        {
          html: `<a href=https://portal.gdc.cancer.gov/files/${f.id} target=_blank>${f.case_submitter_id}</a>`,
          value: f.case_submitter_id
        },
        { value: f.project_id }
      );
      if (obj.dataTypeStates.maf) {
        row.push(
          {
            html: f.sample_types.map((i) => {
              return '<span class="sja_mcdot" style="padding:1px 8px;background:#ddd;color:black;white-space:nowrap">' + i + "</span>";
            }).join(" ")
          },
          { value: f.file_size }
        );
      }
      if (obj.dataTypeStates.cnv) {
        const cnvFile = cnvFilesByCase.get(f.case_submitter_id);
        if (cnvSelected && !cnvFile) {
          console.warn(`Expected CNV file for case ${f.case_submitter_id} but not found`);
        }
        row.push(
          {
            html: cnvFile ? `<a href=https://portal.gdc.cancer.gov/files/${cnvFile.id} target=_blank>${cnvFile.id}</a>` : '<span style="color: #dc3545; font-weight: 500;">Missing CNV file</span>',
            value: cnvFile ? cnvFile.id : "Missing CNV file"
          },
          {
            html: cnvFile && cnvFile.sample_types ? cnvFile.sample_types.map((i) => {
              return '<span class="sja_mcdot" style="padding:1px 8px;background:#ddd;color:black;white-space:nowrap">' + i + "</span>";
            }).join(" ") : '<span style="color: #dc3545;">No CNV sample</span>',
            value: cnvFile && cnvFile.sample_types ? cnvFile.sample_types.join(" ") : "No CNV sample"
          },
          {
            value: cnvFile ? cnvFile.file_size : 0
          }
        );
      }
      if (obj.dataTypeStates.fusion) {
        row.push(
          { html: '<span style="color: #6c757d;">No Fusion file</span>', value: "No Fusion file" },
          { html: '<span style="color: #6c757d;">No Fusion sample</span>', value: "No Fusion sample" },
          { value: 0 }
        );
      }
      rows.push(row);
    }
    obj.mafTableArg = {
      rows,
      columns: dynamicTableColumns,
      resize: false,
      div: obj.tableDiv.append("div"),
      selectAll: true,
      dataTestId: "sja_FileTable",
      header: { allowSort: true },
      selectedRows: [],
      buttons: [
        {
          text: "Run GRIN2 Analysis",
          onChange: (lst, button) => updateButtonBySelectionChange(lst, button, filteredFiles),
          callback: (lst, button) => runGRIN2Analysis(lst, button, obj, filteredFiles)
        }
      ]
    };
    renderTable(obj.mafTableArg);
  } catch (e) {
    wait.text(e instanceof Error ? e.message : String(e));
    if (e instanceof Error && e.stack) console.log(e.stack);
  }
  function updateButtonBySelectionChange(lst, button, filteredFiles) {
    if (obj.busy) {
      button.property("disabled", true);
      return;
    }
    let sum = 0;
    for (const i of lst) sum += filteredFiles[i].file_size;
    if (sum == 0) {
      button.innerHTML = "No file selected";
      button.disabled = true;
      return;
    }
    select_default(button.parentElement).style("float", "left");
    button.disabled = false;
    const mafMaxSize = result.mafFiles ? result.mafFiles.maxTotalSizeCompressed : Infinity;
    const cnvMaxSize = result.cnvFiles ? result.cnvFiles.maxTotalSizeCompressed : Infinity;
    const maxSize = Math.min(mafMaxSize, cnvMaxSize);
    button.innerHTML = sum < maxSize ? `Run GRIN2 Analysis` : `Run GRIN2 Analysis (Large Files)`;
  }
  async function runGRIN2Analysis(lst, button, obj2, filteredFiles = result.files) {
    const mafSelected = obj2.dataTypeStates.maf;
    const cnvSelected = obj2.dataTypeStates.cnv;
    const caseFiles = {
      caseFiles: {}
    };
    if (mafSelected) {
      const soTerms = [];
      for (const mclassCode of obj2.mafOptions.consequences) {
        const soTermsForCode = class2SOterm.get(mclassCode) || [];
        soTerms.push(...soTermsForCode);
      }
      caseFiles.mafOptions = {
        minTotalDepth: obj2.mafOptions.minTotalDepth,
        minAltAlleleCount: obj2.mafOptions.minAltAlleleCount,
        consequences: soTerms,
        hyperMutator: obj2.mafOptions.hyperMutator
      };
    }
    if (cnvSelected) {
      caseFiles.cnvOptions = {
        dataType: obj2.cnvOptions.dataType,
        lossThreshold: obj2.cnvOptions.lossThreshold,
        gainThreshold: obj2.cnvOptions.gainThreshold,
        segLength: obj2.cnvOptions.segLength,
        hyperMutator: obj2.cnvOptions.hyperMutator
      };
    }
    const cnvFilesByCase = /* @__PURE__ */ new Map();
    if (result.cnvFiles && result.cnvFiles.files) {
      for (const cnvFile of result.cnvFiles.files) {
        const caseId = cnvFile.case_submitter_id;
        if (!cnvFilesByCase.has(caseId)) {
          cnvFilesByCase.set(caseId, cnvFile);
        }
      }
    }
    for (const i of lst) {
      const file = filteredFiles[i];
      const caseId = file.case_submitter_id;
      if (!caseFiles.caseFiles[caseId]) {
        caseFiles.caseFiles[caseId] = {};
      }
      const mafSelected2 = obj2.dataTypeStates.maf;
      const cnvSelected2 = obj2.dataTypeStates.cnv;
      if (mafSelected2) {
        caseFiles.caseFiles[caseId].maf = file.id;
      }
      if (cnvSelected2) {
        const cnvFile = cnvFilesByCase.get(caseId);
        if (cnvFile) {
          caseFiles.caseFiles[caseId].cnv = cnvFile.id;
        }
      }
    }
    if (Object.keys(caseFiles.caseFiles).length === 0) return;
    const oldText = button.innerHTML;
    button.innerHTML = "Analyzing... Please wait";
    button.disabled = true;
    if (obj2.downloadButtonDiv) {
      obj2.downloadButtonDiv.selectAll("*").remove();
      obj2.downloadButtonDiv.style("display", "none");
    }
    obj2.resultDiv.selectAll("*").remove();
    try {
      obj2.busy = true;
      const response = await dofetch3("gdc/runGRIN2", { body: caseFiles });
      if (!response) throw "invalid response";
      if (response.error) throw Object.assign(new Error(response.error), { code: response.code });
      console.log("GRIN2 response:", response);
      if (response.rustResult) {
      } else {
        console.log("[GRIN2] No rustResult in response");
      }
      const rustData = response.rustResult;
      let failedFilesInfo = null;
      let parsedRustResult;
      let processedData = [];
      try {
        parsedRustResult = typeof rustData === "string" ? JSON.parse(rustData) : rustData;
        if (parsedRustResult) {
          if (parsedRustResult.successful_data && parsedRustResult.summary) {
            processedData = parsedRustResult.successful_data;
            console.log(`[GRIN2] parsedRustResult structure:`, parsedRustResult);
            if (parsedRustResult.failed_files && parsedRustResult.failed_files.length > 0) {
              failedFilesInfo = {
                count: parsedRustResult.failed_files.length,
                files: parsedRustResult.failed_files,
                // Create table data for UI display (similar to your deduplication/filter tables)
                tableData: {
                  headers: ["Case ID", "Data Type", "Error Type", "Error Details", "Attempts"],
                  rows: parsedRustResult.failed_files.map((file) => [
                    file.case_id,
                    file.data_type,
                    file.error_type,
                    file.error_details,
                    file.attempts_made.toString()
                  ])
                },
                // Error summary for the popup
                errorSummary: {
                  connectionErrors: parsedRustResult.failed_files.filter((f) => f.error_type === "connection_error").length,
                  timeoutErrors: parsedRustResult.failed_files.filter((f) => f.error_type === "timeout_error").length,
                  serverErrors: parsedRustResult.failed_files.filter((f) => f.error_type === "server_error").length,
                  otherErrors: parsedRustResult.failed_files.filter(
                    (f) => !["connection_error", "timeout_error", "server_error"].includes(f.error_type)
                  ).length
                }
              };
            }
          }
          console.log(`[GRIN2] Final processed data contains ${processedData.length.toLocaleString()} characters`);
        }
      } catch (parseError) {
        console.error("[GRIN2] Error parsing Rust result:", parseError);
        processedData = [];
        failedFilesInfo = null;
      }
      if (!response.resultData.png) throw "png missing";
      const resultContainer = obj2.resultDiv.append("div").style("text-align", "left").style("margin", "0 auto").style("margin-top", "40px");
      const plotData = response.resultData;
      const plotDiv = resultContainer.append("div");
      plotManhattanGDC(plotDiv, plotData, { yAxisSpace: 0 });
      resultContainer.node().onerror = () => {
        resultContainer.select("img").remove();
        sayerror(resultContainer, "Failed to load image result.");
      };
      if (response.topGeneTable && response.topGeneTable.rows && response.topGeneTable.rows.length > 0) {
        const tableTitle = resultContainer.append("h4").style("margin-bottom", "15px").style("text-align", "left");
        if (response.totalGenes && response.showingTop) {
          tableTitle.text(`Top ${response.showingTop} Genes`);
          resultContainer.append("p").html(
            `Showing top <strong>${response.showingTop}</strong> genes out of <strong>${response.totalGenes.toLocaleString()}</strong> total genes analyzed.`
          ).style("color", "#495057").style("font-size", "14px").style("margin", "10px 0 20px 0");
        } else {
          tableTitle.text("Top Genes");
          resultContainer.append("p").style("color", "#495057").style("font-size", "14px").style("margin", "10px 0 20px 0");
        }
        const tableContainer = resultContainer.append("div").style("margin-bottom", "20px").style("display", "flex").style("flex", "2");
        const statsContainer = resultContainer.append("div").style("flex", "1").style("min-width", "250px").style("max-width", "350px");
        const transformedRows = transformRows(response.topGeneTable.rows, response.topGeneTable.columns);
        renderTable({
          div: tableContainer,
          rows: transformedRows,
          columns: response.topGeneTable.columns,
          showLines: true,
          striped: true,
          showHeader: true,
          maxHeight: "500px",
          maxWidth: "100%",
          resize: false,
          header: {
            allowSort: true,
            style: {
              "background-color": "#f8f9fa",
              "font-weight": "bold",
              "border-bottom": "2px solid #dee2e6"
            }
          },
          download: {
            // Enable table download functionality
            fileName: `GRIN2_TopGenes.tsv`
          }
        });
        if (parsedRustResult?.summary) {
          const statsPanel = statsContainer.append("div").style("background-color", "#f8f9fa").style("border", "1px solid #dee2e6").style("border-radius", "8px").style("padding", "20px").style("box-shadow", "0 2px 4px rgba(0,0,0,0.1)");
          statsPanel.append("h5").text("Analysis Summary").style("margin", "0 0 15px 0").style("color", "#343a40").style("font-weight", "bold").style("border-bottom", "2px solid #dee2e6").style("padding-bottom", "8px");
          if (parsedRustResult && parsedRustResult.summary) {
            const downloadStats = statsPanel.append("div").style("margin-bottom", "20px");
            downloadStats.append("h6").text("File Download & Processing").style("margin", "0 0 10px 0").style("color", "#495057").style("font-size", "14px").style("font-weight", "bold");
            const downloadStatsGrid = downloadStats.append("div").style("display", "grid").style("grid-template-columns", "1fr 1fr").style("gap", "8px").style("font-size", "13px");
            const totalAttempted = parsedRustResult.summary.total_files;
            const successful = parsedRustResult.summary.successful_files;
            const failed = parsedRustResult.summary.failed_files;
            downloadStatsGrid.append("div").style("color", "#6c757d").text("Total Attempted:");
            downloadStatsGrid.append("div").style("font-weight", "bold").text(totalAttempted || 0);
            downloadStatsGrid.append("div").style("color", "#28a745").text("Successfully Downloaded:");
            downloadStatsGrid.append("div").style("font-weight", "bold").style("color", "#28a745").text(successful || 0);
            downloadStatsGrid.append("div").style("color", "#dc3545").text("Failed Downloads:");
            downloadStatsGrid.append("div").style("font-weight", "bold").style("color", "#dc3545").text(failed || 0);
            if (failedFilesInfo && failedFilesInfo.count > 0) {
              addExpandableFailedFilesToStats(downloadStats, failedFilesInfo);
            }
          }
          if (response.timing) {
            const timingStats = statsPanel.append("div").style("margin-bottom", "20px");
            timingStats.append("h6").text("Timings").style("margin", "0 0 10px 0").style("color", "#495057").style("font-size", "14px").style("font-weight", "bold");
            const timingStatsGrid = timingStats.append("div").style("display", "grid").style("grid-template-columns", "1fr 1fr").style("gap", "8px").style("font-size", "13px");
            if (response.timing.rustProcessingTime !== void 0) {
              timingStatsGrid.append("div").style("color", "#6c757d").text("GDC API Data Query and Parsing (s):");
              timingStatsGrid.append("div").style("font-weight", "bold").style("color", "black").text(response.timing.rustProcessingTime);
            }
            if (response.timing.grin2ProcessingTime !== void 0) {
              timingStatsGrid.append("div").style("color", "#6c757d").text("GRIN2 Analysis (s):");
              timingStatsGrid.append("div").style("font-weight", "bold").style("color", "black").text(response.timing.grin2ProcessingTime);
            }
            if (response.timing.totalTime !== void 0) {
              timingStatsGrid.append("div").style("color", "#6c757d").text("Total Processing Time (s):");
              timingStatsGrid.append("div").style("font-weight", "bold").style("color", "black").text(response.timing.totalTime);
            }
          }
          if (response.rustResult.summary && (response.rustResult.summary.filtered_records !== void 0 || response.rustResult.summary.filtered_maf_records !== void 0 || response.rustResult.summary.filtered_cnv_records !== void 0)) {
            const filterStats = statsPanel.append("div").style("margin-bottom", "20px");
            filterStats.append("h6").text("Data Filtering").style("margin", "0 0 10px 0").style("color", "#495057").style("font-size", "14px").style("font-weight", "bold");
            const filterStatsGrid = filterStats.append("div").style("display", "grid").style("grid-template-columns", "1fr 1fr").style("gap", "8px").style("font-size", "13px");
            if (response.rustResult.summary.filtered_records !== void 0) {
              filterStatsGrid.append("div").style("color", "#6c757d").text("Total Number of Excluded Records:");
              filterStatsGrid.append("div").style("font-weight", "bold").style("color", "black").text(response.rustResult.summary.filtered_records.toLocaleString());
            }
            const mafRecords = response.rustResult.summary.included_maf_records || 0;
            const cnvRecords = response.rustResult.summary.included_cnv_records || 0;
            const totalIncludedRecords = mafRecords + cnvRecords;
            filterStatsGrid.append("div").style("color", "#6c757d").text("Total Number of Included Records:");
            filterStatsGrid.append("div").style("font-weight", "bold").style("color", "black").text(totalIncludedRecords.toLocaleString());
            if (response.rustResult.summary.filtered_maf_records !== void 0) {
              filterStatsGrid.append("div").style("color", "#6c757d").text("MAF Records Excluded:");
              filterStatsGrid.append("div").style("font-weight", "bold").style("color", "black").text(response.rustResult.summary.filtered_maf_records.toLocaleString());
            }
            if (response.rustResult.summary.included_maf_records !== void 0) {
              filterStatsGrid.append("div").style("color", "#6c757d").text("MAF Records Included:");
              filterStatsGrid.append("div").style("font-weight", "bold").style("color", "black").text(response.rustResult.summary.included_maf_records.toLocaleString());
            }
            if (response.rustResult.summary.filtered_cnv_records !== void 0) {
              filterStatsGrid.append("div").style("color", "#6c757d").text("CNV Records Excluded:");
              filterStatsGrid.append("div").style("font-weight", "bold").style("color", "black").text(response.rustResult.summary.filtered_cnv_records.toLocaleString());
            }
            if (response.rustResult.summary.included_cnv_records !== void 0) {
              filterStatsGrid.append("div").style("color", "#6c757d").text("CNV Records Included:");
              filterStatsGrid.append("div").style("font-weight", "bold").style("color", "black").text(response.rustResult.summary.included_cnv_records.toLocaleString());
            }
            if (response.rustResult.summary.filtered_records_by_case !== void 0) {
              const { columns, rows } = parseRecordsByCaseData(
                response.rustResult.summary.filtered_records_by_case,
                response.rustResult.summary.excluded_by_max_record
              );
              const recordsByCaseContainer = filterStats.append("div").style("grid-column", "1 / -1").style("margin-top", "15px");
              const expandableHeader = recordsByCaseContainer.append("div").style("display", "flex").style("align-items", "center").style("gap", "8px").style("cursor", "pointer").style("padding", "8px").style("border-radius", "4px").style("transition", "background-color 0.2s").style("background-color", "rgba(0, 123, 255, 0.1)").style("border", "1px solid rgba(0, 123, 255, 0.2)").on("mouseenter", function() {
                select_default(this).style("background-color", "rgba(0, 123, 255, 0.15)");
              }).on("mouseleave", function() {
                select_default(this).style("background-color", "rgba(0, 123, 255, 0.1)");
              });
              const expandIcon = expandableHeader.append("span").style("font-size", "12px").style("color", "#007bff").style("transition", "transform 0.2s").text("\u25B6");
              expandableHeader.append("span").style("color", "#007bff").style("text-decoration", "underline").style("font-size", "13px").style("font-weight", "500").text(
                `View detailed statistics for ${Object.keys(response.rustResult.summary.filtered_records_by_case).length} cases`
              );
              const expandableContent = recordsByCaseContainer.append("div").style("display", "none").style("margin-top", "12px");
              const tableContainer2 = expandableContent.append("div").style("max-height", "400px").style("overflow-y", "auto").style("border", "1px solid #dee2e6").style("border-radius", "4px");
              renderTable({
                div: tableContainer2,
                columns,
                rows,
                showLines: true,
                striped: true,
                showHeader: true,
                maxHeight: "380px",
                resize: false,
                header: {
                  allowSort: true,
                  style: {
                    "background-color": "#f8f9fa",
                    "font-weight": "bold",
                    "border-bottom": "2px solid #dee2e6"
                  }
                }
              });
              expandableContent.append("div").style("margin-top", "12px").style("padding", "8px").style("background-color", "#f8f9fa").style("border-radius", "4px").style("font-size", "12px").style("color", "#495057").style("line-height", "1.4").text("This table shows analysis statistics per case.");
              let isExpanded = false;
              expandableHeader.on("click", function() {
                isExpanded = !isExpanded;
                if (isExpanded) {
                  expandableContent.style("display", "block");
                  expandIcon.style("transform", "rotate(90deg)").text("\u25BC");
                } else {
                  expandableContent.style("display", "none");
                  expandIcon.style("transform", "rotate(0deg)").text("\u25B6");
                }
              });
            }
          }
        }
        console.log(`Displayed table with ${response.topGeneTable.rows.length} genes`);
        if (response.totalGenes && response.showingTop && response.totalGenes > response.showingTop) {
          resultContainer.append("div").style("margin-top", "15px").style("padding", "10px").style("background-color", "#e9ecef").style("border-radius", "4px").style("font-size", "14px").style("max-width", "100%").style("width", "fit-content").style("color", "#495057").html(`
						<strong>Note:</strong> For performance reasons, only the top ${response.showingTop} 
						most significant genes are displayed. The complete analysis identified 
						${response.totalGenes.toLocaleString()} genes total.
					`);
        }
      } else {
        console.log("No table data received or empty results");
        resultContainer.append("div").style("padding", "15px").style("background-color", "#fff3cd").style("border", "1px solid #ffeaa7").style("border-radius", "4px").style("margin", "15px 0").style("max-width", "100%").style("width", "fit-content").text("No significant genes found in the analysis.");
      }
    } catch (e) {
      if (e?.code === "CACHE_BUSY") {
        if (window.confirm(e.message || String(e))) {
          runGRIN2Analysis(lst, button, obj2, filteredFiles);
        }
      } else sayerror(obj2.errDiv, e.message || e);
      if (e.stack) console.log(e.stack);
    }
    button.innerHTML = oldText;
    button.disabled = false;
    obj2.busy = false;
  }
}
async function gdcGRIN2ui({ filter0, callbacks, debugmode = false }, holder) {
  if (debugmode) {
  }
  try {
    if (callbacks) {
      delete callbacks.sjcharts;
      for (const n in callbacks) {
        if (typeof callbacks[n] != "function") throw `callbacks.${n} not function`;
      }
    }
    update({ filter0 });
  } catch (e) {
    console.log(e);
    sayerror(holder, e instanceof Error ? e.message : String(e));
  }
  async function update({ filter0: filter02 }) {
    holder.selectAll("*").remove();
    holder.style("width", "100%").style("max-width", "none");
    const obj = {
      errDiv: holder.append("div"),
      controlDiv: holder.append("div"),
      tableDiv: holder.append("div").style("width", "100%"),
      deduplicationInfoDiv: holder.append("div"),
      downloadButtonDiv: holder.append("div").style("margin-top", "10px").style("display", "none"),
      resultDiv: holder.append("div").style("margin-top", "20px"),
      opts: {
        filter0: filter02,
        experimentalStrategy: "WXS"
      },
      busy: false,
      // when analyzing, set to true for disabling ui interactivity
      mafTableArg: null,
      expStrategyRadio: null
    };
    makeControls(obj);
    await getFilesAndShowTable(obj);
    callbacks?.postRender?.(publicApi);
  }
  const publicApi = { update };
  return publicApi;
}
export {
  gdcGRIN2ui
};
//# sourceMappingURL=grin2-7AOJP5QJ.js.map
