import * as dicomViewer from "./dicomViewer.js"

window.dicomViewer = dicomViewer;

window.marked_answers = {
  "correct": [],
  "half-correct": [],
  "incorrect": [],
}

window.control_pressed = false;


$(document).ready(function () {
    // Select all text input fields and textareas with the clear button
    clearableTextAreaSetup();




  document.body.addEventListener("htmx:responseError", function(e) {
      let el = document.getElementById("htmx-error");
      if (!el) {
          // No global error container available; log and return to avoid JS errors
          console.error('htmx:responseError but no #htmx-error element present', e.detail);
          return;
      }
      var error;
      if (e.detail.pathInfo.requestPath.includes("cimar") && e.detail.xhr.status == 403) {
        error = "Cimar permission error, please login and refresh the page.";
        //document.getElementById("cimar-login-form").focus();
        htmx.trigger("#cimar-login-needed", "cimar-login-needed");

        
      } else {
        error = e.detail.xhr.response;
      }
      el.innerHTML = error;
      el.classList.remove("hidden");
  });


  $("table thead th input").click((e) => {
    let status = e.currentTarget.checked;
    $("table tbody input").prop("checked", status);
  })

  //$(".answer-list li").each(function (index, element) {
  //  $(element).append($("<span class='google-link' title='search for answer with google'><a href='https://www.google.com/search?q=" + $(element).text() + "' target='_blank'>G</a></span>"));
  //});

  // Legacy per-element click handler: skip on the new mark2 page which
  // manages clicks via a delegated handler (it uses #answer-list). This
  // prevents duplicate/colliding handlers when mark2 is rendered.
  if (!document.getElementById('answer-list')) {
    $(".answer-list span.answer").each(function (index, element) {
      console.log(element);

      $(element).click(function (e) {

        var classes = ['answer correct', 'answer half-correct', 'answer incorrect'];
        $(element).each(function () {
          let mark = classes[($.inArray(this.className, classes) + 1) % classes.length];
          this.className = mark
          this.dataset.newmark = mark.split(" ")[1]
        });

        prepAnswerData();

      });
    });
  }
  prepAnswerData();

  if ($(".post-form").length > 0) {
    $(".post-form").get(0).addEventListener("submit", function (e) {
      //if ($(".not-marked").length > 0 && e.submitter.name != "skip") {
      //  e.preventDefault(); // before the code
      //  alert("Ensure all answers are marked first");
      //}

    });
  }

  let dicom_images = document.getElementsByClassName("dicom-image");
  if (dicom_images.length) {

    for (let element of dicom_images) {
      setUpDicom3d(element)
    }

  }
  let dicom_images_legacy = document.getElementsByClassName("dicom-image-legacy");
  if (dicom_images_legacy.length) {

    for (let element of dicom_images_legacy) {
      setUpDicomLegacy(element)
    }

  }


  loadDicomViewer();

  if ($("#question-mark-list").length) {
    $(".show-all-button").click(() => {
      $("#question-mark-list li").show();
    });
    $(".show-unmarked-button").click(() => {
      $("#question-mark-list li").each((n, el) => {
        // Can't seem to get django to output this as a int....
        if (parseInt(el.dataset.markcount) < 1) {
          $(el).hide();
        }
      })
    });

  }

  //  $(document).keydown(keyDownHandler);
  //  $(document).keyup(keyUpHandler);

  $("#button-select-add-exam").click(function (evt) {
    // Find selected objects



    var jqxhr = $.get(evt.target.dataset.exam_list_url, function (data) {
        console.log(data);
        $("#exam-options").empty();
        data.forEach((obj, n) => {
          $("#exam-options").append($(document.createElement('button')).prop({
            type: 'button',
            innerHTML: obj.name,
            class: '',

          }).data("exam-id", obj.id).click((evt) => {
            addToExam(evt)
          }))
        })
      })
      .done(function () {
        //alert( "second success" );
      })
      .fail(function () {
        //alert( "error" );
      })
      .always(function () {
        //alert( "finished" );
      });

    return;


    function addToExam(evt) {

      let ids = []
      $("tbody input:checked").each((n, el) => {
        ids.push(el.value)
      })

      // if no question selected 
      if (ids.length < 1) {
        toastr.info('No question selected.');
        return
      }
      let post_url = document.getElementById("button-select-add-exam").dataset.exam_json_edit_url;
      let type = document.getElementById("button-select-add-exam").dataset.type;
      let csrf = document.getElementById("button-select-add-exam").dataset.csrf;
      $.ajax({
          url: post_url,
          data: {
            csrfmiddlewaretoken: csrf,
            add_exam_questions: JSON.stringify(ids),
            type: type,
            exam_id: $(evt.target).data("exam-id"),
          },
          type: "POST",
          dataType: "json",
        })
        // $.ajax().done(), $.ajax().fail(), $ajax().always() are upto you. Add/change accordingly
        .done(function (data) {
          console.log(data);

          if (data.status == "success") {
            toastr.info('Questions added to exams.')
          }
        })
        .always(function () {
          console.log('[Done]');
          $("#exam-options").empty();
        })
    }
  });


});

window.loadDicomViewerEvent = new Event('loadDicomViewer');
window.addEventListener('loadDicomViewer', function (e) {
  console.log("LoadDicomViewer event", e.detail)
  let images = [];
  //console.log($("#image_form_set img"));
  $(e.detail).each((n, el) => {
    images.push($(el).attr("src"));
  });
  //console.log("listen2", images)
  loadDicomViewer(images);
}, false);

window.loadDicomViewerEvent = new Event('loadDicomViewerUrls');
window.addEventListener('loadDicomViewerUrls', function (e) {
  console.log("LoadDicomViewer unls event", e.detail)

  // Skip loading old viewer if using new dv3d viewer (set on new_uploads page)
  if (window.skipLoadDicomViewer) {
    console.log("Skipping old loadDicomViewer - using dv3d instead");
    return;
  }

  loadDicomViewer(e.detail.images, e.detail.annotations);
}, false);

function clearableTextAreaSetup() {
  const textFields = document.querySelectorAll(".position-relative input[type='text'], .position-relative textarea");

  textFields.forEach((field) => {
    const wrapper = field.closest(".position-relative");
    if (!wrapper) return;
    const clearButton = wrapper.querySelector(".clear-input-button");
    if (!clearButton) return;

    // Function to toggle the visibility of the clear button
    const toggleClearButton = () => {
      if (field.value.trim() !== "" && wrapper.matches(":hover")) {
        clearButton.style.display = "inline-block"; // Show the button
      } else {
        clearButton.style.display = "none"; // Hide the button
      }
    };

    // Initial check
    toggleClearButton();

    // Add event listeners to monitor changes in the input field or textarea
    field.addEventListener("input", toggleClearButton);

    // Add hover event listeners to the wrapper
    wrapper.addEventListener("mouseenter", toggleClearButton);
    wrapper.addEventListener("mouseleave", toggleClearButton);

    // Add click event to clear the field or textarea
    clearButton.addEventListener("click", function () {
      field.value = ""; // Clear the field
      toggleClearButton();
    });
  });
}

function loadDicomViewer(images_to_load, annotations_to_load) {
  // Skip loading old viewer if using new dv3d viewer (set on new_uploads page)
  if (window.skipLoadDicomViewer) {
    console.log("Skipping old loadDicomViewer - using dv3d instead");
    return;
  }
  
  console.log("loadDicomViewer", images_to_load);
  let single_dicom = document.getElementById("single-dicom-viewer");
  if (single_dicom) {
    console.log("Load single dicom viewer");
    $(single_dicom).empty()
    let images = single_dicom.dataset.images;

    if (images_to_load != undefined) {
      images = images_to_load;
      //} else if (images.indexOf(",") > 0) {
    } else if (images == undefined || images == "") {
      // No images to load
      return
    } else {
      images = JSON.parse(images);
    }


    let annotations = single_dicom.dataset.annotations;
    if (annotations_to_load != undefined) {
      annotations = annotations_to_load;
    } else if (annotations && annotations.indexOf(",") > 0) {
      annotations = JSON.parse(annotations);
    } else {
      annotations = undefined;
    }

    let load_as_stack;
    if (images.length > 5) {
      load_as_stack = true;
    } else {
      load_as_stack = false;
    }

    if (images) {
      dicomViewer.loadCornerstone($(single_dicom), null, images, annotations, load_as_stack);
    }
  }
}
window.loadDicomViewer = loadDicomViewer

function prepAnswerData() {
  //$("#id_correct").val($("li.correct").map(function() {
  //    ans = $(this).text();
  //    window.marked_answers["correct"].push(ans);
  //    return ans
  //}).get().join('--//--'));
  //$("#id_half_correct").val($("li.half-correct").map(function() {
  //    ans = $(this).text();
  //    window.marked_answers["half-correct"].push(ans);
  //    return ans;
  //}).get().join('--//--'));
  //$("#id_incorrect").val($("li.incorrect").map(function() {
  //    ans = $(this).text();
  //    window.marked_answers["incorrect"].push(ans);
  //    return ans;
  //}).get().join('--//--'));

  window.marked_answers["correct"] = [];
  window.marked_answers["half-correct"] = [];
  window.marked_answers["incorrect"] = [];
  $("li span.correct").map(function () {
    let ans = $(this).text();
    window.marked_answers["correct"].push(ans);
  })
  $("li span.half-correct").map(function () {
    let ans = $(this).text();
    window.marked_answers["half-correct"].push(ans);
  })
  $("li span.incorrect").map(function () {
    let ans = $(this).text();
    window.marked_answers["incorrect"].push(ans);
  })
  $("#id_marked_answers").val(JSON.stringify(window.marked_answers));
}

function loadJsonToolStateOnCurrentImage(element, json) {
  let el = element;

  const toolStateManager = cornerstoneTools.globalImageIdSpecificToolStateManager;

  const c = cornerstone.getEnabledElement(el);

  let image_id = c.image.imageId;

  let tool_state_no_id = JSON.parse(json);

  let tool_state = {};
  tool_state[image_id] = tool_state_no_id;

  toolStateManager.restoreToolState(tool_state);

  cornerstone.reset(el);

  return tool_state;


}

// Called by HTMX after a fragment swap; initializes any dicom-image-legacy viewers
window.initAnatomyFragment = function(fragmentRoot) {
  console.log("initAnatomyFragment", fragmentRoot);
  try {
    const root = fragmentRoot && fragmentRoot.nodeType ? fragmentRoot : (fragmentRoot && fragmentRoot.detail && fragmentRoot.detail.target) ? fragmentRoot.detail.target : document;
    const imgs = (root && root.querySelectorAll) ? root.querySelectorAll('.dicom-image-legacy') : [];
    imgs.forEach((el) => {
      try {
        // Avoid double initialization
        if (el.dataset && (el.dataset.dicomInitialised === '1' || el.dataset.dicomInitialised === 'true')) return;
        if (typeof window.setUpDicomLegacy === 'function') {
          window.setUpDicomLegacy(el);
          if (el.dataset) el.dataset.dicomInitialised = '1';
        }
      } catch (err) {
        console.warn('initAnatomyFragment: setUpDicomLegacy failed for element', el, err);
      }
    });
  } catch (err) {
    console.warn('initAnatomyFragment error', err);
  }
}

// Global fallback: listen for HTMX swaps and initialise any viewers inside
document.addEventListener('htmx:afterSwap', function (e) {
  try {
    const root = e && e.target ? e.target : (e && e.detail && e.detail.target ? e.detail.target : document);
    if (window.initAnatomyFragment) window.initAnatomyFragment(root);
  } catch (err) {
    console.warn('htmx afterSwap listener error', err);
  }
});

async function setUpDicomLegacy(element) {
  console.log("setUpDicom (original)", element);

  $(element).bind('contextmenu', function (e) {
    return false;
  });

  $(element).dblclick((evt) => {
    element.requestFullscreen();
  })

  cornerstoneBase64ImageLoader.external.cornerstone = cornerstone;
  cornerstoneWebImageLoader.external.cornerstone = cornerstone;
  cornerstoneWADOImageLoader.external.cornerstone = cornerstone;

  cornerstoneTools.init();
  const PanTool = cornerstoneTools.PanTool;
  const ZoomTool = cornerstoneTools.ZoomTool;
  const ZoomMouseWheelTool = cornerstoneTools.ZoomMouseWheelTool;
  const WwwcTool = cornerstoneTools.WwwcTool;
  const WwwcRegionTool = cornerstoneTools.WwwcRegionTool;
  const RotateTool = cornerstoneTools.RotateTool;
  const StackScrollTool = cornerstoneTools.StackScrollTool;
  const MagnifyTool = cornerstoneTools.MagnifyTool;
  const ArrowAnnotateTool = cornerstoneTools.ArrowAnnotateTool;


  const images = element.dataset.url.split(",");

  const annotation = element.dataset.annotations;

  //console.log("Dicom - load imageId: ", imageIds);
  //for (let index = 0; index < imageIds.length; index++) {
  //  if (imageIds[index].endsWith("dcm")) {
  //    imageIds[index] = "wadouri:" + imageIds[index];
  //  }

  //}
  let imageIds = [];
  for (let i = 0; i < images.length; i++) {
    let data_url = images[i];
    // check stack type
    if (data_url.startsWith("data:image")) {
      let imageId = "base64://" + data_url.split(",")[1];

      imageIds.push(imageId);
    } else if (data_url.startsWith("base64://") || data_url.startsWith("wadouri:")) {

      imageIds.push(data_url);

      // Treat application/octet-stream as if they are dicoms
    } else if (data_url.startsWith("data:application/dicom") || data_url.startsWith("data:application/octet-stream")) {
      //stack = stack.split(";")[1];

      let dfile = await urltoFile(data_url, "dicom", "application/dicom");

      const imageId = cornerstoneWADOImageLoader.wadouri.fileManager.add(
        dfile
      );

      loadAnnotation(imageId, annotation);

      imageIds.push(imageId);
      //cornerstone.loadImage(imageId).then(function(image) {
      //    tempFunction(image);
      //});
    } else {
      let url;
      // This doesn't seem to have any benefit
      //if (data_url.startsWith("http")) {
      //    url = data_url;
      //} else {
      //    url = window.location.href.replace(/\/\#\/?$/, '') + "/" + data_url
      //}
      url = data_url;

      if (url.endsWith("dcm")) {
        url = "wadouri:" + url;
      }

      // if there is no extension treat it as a dicom
      if (/(?:\/|^)[^.\/]+$/.test(url)) {
        url = "wadouri:" + url;
      }

      imageIds.push(url);


    }
  }

  cornerstone.enable(element);
  cornerstone.loadAndCacheImage(imageIds[0]).then(function (image) {
    cornerstone.displayImage(element, image);

    cornerstoneTools.addToolForElement(element, PanTool);
    cornerstoneTools.addToolForElement(element, ZoomTool);
    cornerstoneTools.addToolForElement(element, ZoomMouseWheelTool);
    cornerstoneTools.addToolForElement(element, WwwcTool);
    cornerstoneTools.addToolForElement(element, WwwcRegionTool);
    cornerstoneTools.addToolForElement(element, RotateTool);
    cornerstoneTools.addToolForElement(element, StackScrollTool);
    cornerstoneTools.addToolForElement(element, MagnifyTool);

    cornerstoneTools.addToolForElement(element, ArrowAnnotateTool, {
      configuration: {
        getTextCallback: () => {},
        changeTextCallback: () => {},
        allowEmptyLabel: true,
        renderDashed: false,
        drawHandles: false,
        drawHandlesOnHover: true,
      },
    });



    // Enable our tools
    // Avoid incorrect aspect ratio
    cornerstoneTools.setToolActiveForElement(element, "Pan", {
      mouseButtonMask: 1
    });
    cornerstoneTools.setToolActiveForElement(element, "Wwwc", {
      mouseButtonMask: 2
    });
    cornerstoneTools.setToolActiveForElement(element, "ZoomMouseWheel", {
      mouseButtonMask: 3
    });
    cornerstoneTools.setToolActiveForElement(element, "Zoom", {
      mouseButtonMask: 4
    });

    if (element.dataset.edit_annotation == "true") {
      cornerstoneTools.setToolActiveForElement(element, "ArrowAnnotate", {
        mouseButtonMask: 2
      });
    } else {
      cornerstoneTools.setToolEnabledForElement(element, "ArrowAnnotate");
    }

    if (element.dataset.annotations) {
      loadJsonToolStateOnCurrentImage(element, element.dataset.annotations)
    }

    cornerstone.resize(element);


  }).catch((err, err2) => {
    console.log(err);
  });

}
console.log("setUpDicom defined");

// keep reference to the existing 2D setup
window.setUpDicomLegacy = setUpDicomLegacy;

async function setUpDicom3d(element) {
  console.log("setUpDicom3d (cornerstone3d) for", element);

  // parse images from dataset
  let raw = element.dataset.url || "";
  if (!raw) return;
  let images;
  try {
    images = JSON.parse(raw);
  } catch (e) {
    images = raw.split(",").map(s => s.trim()).filter(Boolean);
  }
  if (!images || images.length === 0) return;

  // ensure element has a viewport-like appearance
  element.style.width = element.style.width || "500px";
  element.style.height = element.style.height || "500px";
  element.style.position = element.style.position || "relative";
  element.innerHTML = ""; // clear

  // Disable right-click context menu on the element
  element.addEventListener('contextmenu', function (e) {
    e.preventDefault();
  });

  element.addEventListener('dblclick', function (e) {
    if (element.requestFullscreen) {
      element.requestFullscreen();
    } else if (element.webkitRequestFullscreen) {
      element.webkitRequestFullscreen();
    } else if (element.mozRequestFullScreen) {
      element.mozRequestFullScreen();
    } else if (element.msRequestFullscreen) {
      element.msRequestFullscreen();
    }
  });

  // create a unique rendering engine / viewport ids per element
  const renderingEngineId = `rendingEngine`;
  const viewportId = `1`;

  try {
    // dynamic import of cornerstone3D core + dicom loader
    const coreModule = window.cornerstone3d
    const dicomLoaderModule = window.cornerstoneDICOMImageLoader
    const toolsModule = window.cornerstone3dTools;

    await coreModule.init();
    await dicomLoaderModule.init();


    await toolsModule.init();

    const { RenderingEngine, Enums } = coreModule;
    const { chunkManager } = dicomLoaderModule; // may exist for some setups

    // create engine and enable a Stack viewport
    const renderingEngine = new RenderingEngine(renderingEngineId);
    console.log(renderingEngine)

    const viewportInput = {
      viewportId,
      type: Enums.ViewportType.STACK,
      element,
      //viewportType: Enums.ViewportType.STACK, // Stack viewport for slice stacks
    };

    try {
      renderingEngine.enableElement(viewportInput);
    } catch (err) {
      // Some bundlings / integrations (dv3d wrapper) may reject the provided
      // viewport type (e.g. "Viewport is not a valid type"). In that case
      // fall back to the 2D cornerstone loader which is more permissive.
      console.warn('renderingEngine.enableElement failed, falling back to 2D loader:', err);
      try {
        dicomViewer.loadCornerstone($(element), null, images, undefined, images.length > 5);
        element._cornerstone3d = { fallback: 'cornerstone2d', imageCount: images.length };
        return element._cornerstone3d;
      } catch (err2) {
        console.error('2D fallback after enableElement failure also failed:', err2);
        throw err;
      }
    }

    const viewport = renderingEngine.getViewport(viewportId);


    // --- Register basic interaction tools (best-effort with @cornerstonejs/tools) ---
      // dynamic import so bundlers/CDNs provide the package
      // prefer module import, fall back to global if present

      const { ToolGroupManager } = toolsModule;

    toolsModule.addTool(toolsModule.PanTool)
    toolsModule.addTool(toolsModule.WindowLevelTool)
    //toolsModule.addTool(toolsModule.StackScrollTool)
    toolsModule.addTool(toolsModule.ZoomTool)



      const toolGroupId = `toolgroup-${viewportId}`;
      console.log("ToolGroup id", toolGroupId);
      console.log("ToolGroupManager", ToolGroupManager);
      if (!ToolGroupManager.getToolGroup(toolGroupId)) {
        ToolGroupManager.createToolGroup(toolGroupId);
      }
      const toolGroup = ToolGroupManager.getToolGroup(toolGroupId);

      toolGroup.addTool(toolsModule.PanTool.toolName);
      toolGroup.addTool(toolsModule.WindowLevelTool.toolName);
      //toolGroup.addTool(toolsModule.StackScrollTool.toolName);
      toolGroup.addTool(toolsModule.ZoomTool.toolName);

      // use actual tool names if available, else fall back to common strings
      //const stackName = (StackScrollTool && (StackScrollTool.toolName || StackScrollTool.name)) || 'StackScroll';

      //toolGroup.setToolEnabled(toolsModule.PanTool.toolName, { bindings: [{ mouseButton: 1 }] });
      toolGroup.setToolActive(toolsModule.PanTool.toolName, { bindings: [{ mouseButton: 1 }] });
      toolGroup.setToolActive(toolsModule.WindowLevelTool.toolName, { bindings: [{ mouseButton: 2 }] });
      toolGroup.setToolActive(toolsModule.ZoomTool.toolName, { bindings: [{ mouseButton: 4 }] });
      toolGroup.setToolActive(toolsModule.ZoomTool.toolName, { bindings: [{ mouseButton: 524288 }] });
      toolGroup.addViewport(viewportId, renderingEngineId);

      window.toolGroup = toolGroup; // expose for debugging


    // Prepare imageIds: ensure remote URLs are usable by dicom-image-loader (wadouri:)
    // but avoid forcing wadouri: for standard web images (png/jpg/etc) because
    // the dicom parser will fail when given non-DICOM files. For such images
    // return the raw URL so the appropriate web-image loader can handle them.
    // If any image looks like a plain web image (png/jpg/etc) prefer the
    // existing 2D cornerstone loader which handles http(s) image schemes.
    // This avoids a situation where the 3D dicom loader has no handler for
    // the 'https' scheme and throws "No image loader found for scheme 'https'".
    const looksLikeWebImage = (u) => {
      if (!u) return false;
      try { u = u.trim(); } catch (e) {}
      if (u.startsWith('data:image')) return true;
      if (u.match(/\.(png|jpe?g|gif|bmp|webp)$/i)) return true;
      return false;
    };

    if (images.some(looksLikeWebImage)) {
      // Fallback: use the 2D cornerstone loader which has web-image handling
      // and is more tolerant of raw http(s) URLs. We reuse the project's
      // dicomViewer helper (it expects a jQuery element).
      console.warn('setUpDicom3d: contains web-image(s) — falling back to 2D loader');
      try {
        // Remove any partially-created dv3d DOM and ensure the element is a
        // clean container for the 2D viewer. This ensures the `.canvas-panel`
        // appended by `loadCornerstone` overlays exactly the element area.
        try { element.innerHTML = ""; } catch (e) { $(element).empty(); }
        element.style.position = element.style.position || 'relative';
        // annotations are not available in this scope in the 3d code path; pass
        // undefined for annotations and let the loader handle it.
        dicomViewer.loadCornerstone($(element), null, images, undefined, images.length > 5);
        // store a lightweight marker so callers can inspect what happened
        element._cornerstone3d = { fallback: 'cornerstone2d', imageCount: images.length };
        return element._cornerstone3d;
      } catch (err) {
        console.warn('Fallback 2D loader failed; will continue to try 3D loader', err);
        // fallthrough to attempt 3D loading below
      }
    }

    const imageIds = images.map((url) => {
      url = url.trim();
      // if it's already a scheme we pass through
      if (/^(wadouri:|base64:|data:|http:|https:)/i.test(url)) return url;

      // default: treat as wadouri (likely a DICOM file)
      return `wadouri:${url}`;
    });

    // If dicom-image-loader provides a metadata cache factory, pre-cache metadata
    if (typeof dicomLoaderModule.createImageIdsAndCacheMetaData === "function") {
      try {
        // attempt to call helper to cache meta-data for the first image (best-effort)
        await dicomLoaderModule.createImageIdsAndCacheMetaData({
          imageIds,
        });
      } catch (e) {
        // not fatal — continue
        console.warn("createImageIdsAndCacheMetaData failed (continuing):", e);
      }
    }

    try {
      await viewport.setStack(imageIds, 0);
    } catch (err) {
      // If the 3D loader fails because it doesn't know how to load 'https'
      // URLs, fallback to the 2D cornerstone loader which handles web images.
      console.warn('viewport.setStack failed, attempting 2D fallback:', err);
      try {
        try { element.innerHTML = ""; } catch (e) { $(element).empty(); }
        element.style.position = element.style.position || 'relative';
        dicomViewer.loadCornerstone($(element), null, images, undefined, images.length > 5);
        element._cornerstone3d = { fallback: 'cornerstone2d', imageCount: images.length };
        return element._cornerstone3d;
      } catch (err2) {
        console.error('2D fallback also failed:', err2);
        throw err; // rethrow original error
      }
    }

    viewport.render();


    // store references for debugging/use elsewhere
    element._cornerstone3d = {
      renderingEngineId,
      viewportId,
      renderingEngine,
      viewport,
      imageIds,
    };

    console.log("setUpDicom3d complete", element._cornerstone3d);
    return element._cornerstone3d;
  } catch (err) {
    console.error("setUpDicom3d failed:", err);
    // per request: no fallback here — rethrow so caller can handle if desired
    throw err;
  }
}

// expose globally like existing code expects
window.setUpDicom = setUpDicom3d;





function create_popup_window(url, title) {
  newwindow = window.open(url, title, 'height=800,width=600');
  if (window.focus) {
    newwindow.focus()
  }
  return false;
}

window.create_popup_window = create_popup_window

function delete_multiple(url, csrf_token) {

  let answer_ids = [];
  $("tbody input:checked").each((n, el) => {
    answer_ids.push(el.value);
  })
  if (confirm(`Delete ${answer_ids.length} answers?`)) {
    $.ajax({
        url: url,
        data: {
          csrfmiddlewaretoken: csrf_token,
          answer_ids: JSON.stringify(answer_ids) // true if checked else false
        },
        type: "POST",
        dataType: "json",
      })
      // $.ajax().done(), $.ajax().fail(), $ajax().always() are upto you. Add/change accordingly
      .done(function (data) {
        console.log(data);

        if (data.status == "success") {
          toastr.info('Deleted.')
        }
        // show some message according to the response. 
        // For eg. A message box showing that the status has been changed
      })
      .always(function () {
        console.log('[Done]');
      })
  }

}
window.delete_multiple = delete_multiple



function getTimeRemaining(endtime) {
  const total = Date.parse(endtime) - Date.parse(new Date());
  const seconds = Math.floor((total / 1000) % 60);
  const minutes = Math.floor((total / 1000 / 60) % 60);
  const hours = Math.floor((total / (1000 * 60 * 60)) % 24);
  //const days = Math.floor(total / (1000 * 60 * 60 * 24));

  return {
    total,
    //days,
    hours,
    minutes,
    seconds
  };
}

function initializeClock(id, endtime) {
  const clock = document.getElementById(id);
  clock.style.display = "block"
  const daysSpan = clock.querySelector('.days');
  const hoursSpan = clock.querySelector('.hours');
  const minutesSpan = clock.querySelector('.minutes');
  const secondsSpan = clock.querySelector('.seconds');

  function updateClock() {
    const t = getTimeRemaining(endtime);

    //daysSpan.innerHTML = t.days;
    hoursSpan.innerHTML = ('0' + t.hours).slice(-2);
    minutesSpan.innerHTML = ('0' + t.minutes).slice(-2);
    secondsSpan.innerHTML = ('0' + t.seconds).slice(-2);

    if (t.total <= 0) {
      clearInterval(timeinterval);
      timeup.style.display = "block"
      clock.style.display = "none"
    }
  }

  const timeinterval = setInterval(updateClock, 1000);
  updateClock();
}

window.initializeClock = initializeClock



  // Unwrap single-root <p> elements from TinyMCE content before any form submit.
  // This prevents a single wrapping <p> from being sent to the server while
  // preserving other markup. We use a delegated submit listener so it works
  // for dynamically-added forms as well (e.g. admin inlines).
  document.addEventListener('submit', function(evt) {
    try {
      var form = evt.target;
      if (!form || !form.querySelector) return;
      // Find all tinyMCE textareas inside the form
      var areas = form.querySelectorAll('textarea.tinymce');
      areas.forEach(function(area) {
        var id = area.id;
        if (!id) return;
        var ed = (typeof tinyMCE !== 'undefined') ? tinyMCE.get(id) : null;
        if (!ed) return;
        var html = (ed.getContent && typeof ed.getContent === 'function') ? ed.getContent({format: 'html'}) : area.value;
        if (!html) return;
        // Use a temporary container to inspect top-level elements safely
        var tmp = document.createElement('div');
        tmp.innerHTML = html.trim();
        // If there is exactly one top-level element and it is a <p>, unwrap it
        if (tmp.childElementCount === 1 && tmp.firstElementChild && tmp.firstElementChild.tagName.toLowerCase() === 'p') {
          var inner = tmp.firstElementChild.innerHTML;
          // Update editor content and the underlying textarea value
          try {
            ed.setContent(inner);
          } catch (e) {
            // fallback: set textarea value directly
            area.value = inner;
          }
          // Ensure the textarea value matches (some setups sync on save, some don't)
          area.value = inner;
        }
      });
    } catch (e) {
      // be resilient; don't prevent form submission if something goes wrong here
      console.error('TinyMCE submit postprocess error', e);
    }
  }, true);