window.HELP_IMPROVE_VIDEOJS = false;

var IMG_EXT = ".webp";

// var COMPARISON_BASE =
//   "https://storage.googleapis.com/fm-task-evals-website/images/model_comparison_carousel";
var COMPARISON_BASE =
  "https://storage.googleapis.com/fm-task-evals-website/images/model_comparison_carousel";
var COMPARISON_NUM_IMGS = 5;
var comparison_img_idx = 0;

var SAM_BASE =
  "https://storage.googleapis.com/fm-task-evals-website/images/all_overlayed_imgs";
var SAM_NUM_IMGS = 4;
var SAM_NUM_SUB_IMGS = [52, 43, 42, 53];
var sam_sub_imgs = new Array(1);
var sam_img_idx = 0;

var BOWLING_BASE =
  "https://storage.googleapis.com/fm-task-evals-website/images/bowling";
var BOWLING_NUM_IMGS = 4;
var bowling_img_idx = 0;

var MULTITASK_BASE =
  "https://storage.googleapis.com/fm-task-evals-website/images/multitask";
var MULTITASK_NUM_FRAMES = 5;
var MULTITASK_NUM_IMGS = 4;
var multitask_img_idx = 0;

var VIDEO_BASE =
  "https://storage.googleapis.com/fm-task-evals-website/images/video_slider";
var VIDEO_NUM_FRAMES = [19, 14, 12, 13];
var VIDEO_NUM_IMGS = 4;
var video_img_idx = 0;

var predictionsInterval; // Stores the interval timer
var isPredictionsPlaying = false;
var predictionsPlaySpeed = 350; // (ms)

var multitask_img_rgb = null;
var predicted_imgs = new Array(MULTITASK_NUM_FRAMES);
var multitask_subtitles = [
  "Bounding boxes",
  "Semantic segmentation",
  "Grouping",
  "Depth prediction",
  "Surface normal prediction",
];

// Cache objects to store preloaded images
var multitaskCache = {};
var comparisonCache = {};
var videoCache = {};

function preloadMultitaskImages(img_idx) {
  multitask_img_rgb = new Image();
  multitask_img_rgb.src = MULTITASK_BASE + "/" + String(img_idx) + ".jpg";
  for (var i = 0; i < MULTITASK_NUM_FRAMES; i++) {
    var pred_path =
      MULTITASK_BASE + "/" + String(img_idx) + "/" + String(i) + ".png";
    predicted_imgs[i] = new Image();
    predicted_imgs[i].src = pred_path;
  }
}

var video_img_rgb = null;
var predicted_video_rgb_imgs = new Array(VIDEO_NUM_FRAMES[0]);
var predicted_video_imgs = new Array(VIDEO_NUM_FRAMES[0]);
var video_subtitles = [
  "Bounding box prediction",
  "Segmentation prediction",
  "Depth prediction",
  "Surface normal prediction",
];

function preloadVideoImages(img_idx) {
  var predicted_video_rgb_imgs = new Array(VIDEO_NUM_FRAMES[img_idx]);
  var predicted_video_imgs = new Array(VIDEO_NUM_FRAMES[img_idx]);

  for (var i = 0; i < VIDEO_NUM_FRAMES[img_idx]; i++) {
    var pred_path =
      VIDEO_BASE + "/" + String(img_idx) + "/rgb_" + String(i) + ".webp";
    predicted_video_rgb_imgs[i] = new Image();
    predicted_video_rgb_imgs[i].src = pred_path;
  }

  for (var i = 0; i < VIDEO_NUM_FRAMES[img_idx]; i++) {
    var pred_path =
      VIDEO_BASE + "/" + String(img_idx) + "/" + String(i) + ".webp";
    predicted_video_imgs[i] = new Image();
    predicted_video_imgs[i].src = pred_path;
  }
}

function setMultitaskImage(i) {
  var rgb_img = multitask_img_rgb;
  rgb_img.ondragstart = function () {
    return false;
  };
  rgb_img.oncontextmenu = function () {
    return false;
  };
  $("#multitask-wrapper-rgb").empty().append(rgb_img);

  var image_pred = predicted_imgs[i];
  image_pred.ondragstart = function () {
    return false;
  };
  image_pred.oncontextmenu = function () {
    return false;
  };
  $("#multitask-pred").empty().append(image_pred);
}

function setVideoImage(i) {
  var rgb_img = predicted_video_rgb_imgs[i];
  rgb_img.ondragstart = function () {
    return false;
  };
  rgb_img.oncontextmenu = function () {
    return false;
  };
  $("#video-wrapper-rgb").empty().append(rgb_img);

  var image_pred = predicted_video_imgs[i];
  image_pred.ondragstart = function () {
    return false;
  };
  image_pred.oncontextmenu = function () {
    return false;
  };
  $("#video-pred").empty().append(image_pred);
}

function setSpecificComparisonImage(img_idx) {
  var path = COMPARISON_BASE + "/" + "comparison_" + String(img_idx) + ".webp";
  document.getElementById("rgb2allFrame").src = path;
}

function setSpecificSamImage(img_idx) {
  var path = SAM_BASE + "/" + String(img_idx) + ".webp";
  document.getElementById("samImg").src = path;
}

function setSpecificBowlingImage(img_idx) {
  var path_1 = BOWLING_BASE + "/" + "bowling_" + String(img_idx) + ".png";
  var path_2 = BOWLING_BASE + "/" + "depth_bowling_" + String(img_idx) + ".png";
  document.getElementById("bowlingFrame1").src = path_1;
  document.getElementById("bowlingFrame2").src = path_2;
}

function setSpecificMultitaskImage(img_idx, i) {
  // To avoid flicker, we do it this way when next image is requested
  var rgb_path = MULTITASK_BASE + "/" + String(img_idx) + ".jpg";
  var rgb_img = new Image();
  rgb_img.onload = function () {
    $("#multitask-wrapper-rgb").empty().append(rgb_img);
  };
  rgb_img.src = rgb_path;
  rgb_img.ondragstart = function () {
    return false;
  };
  rgb_img.oncontextmenu = function () {
    return false;
  };

  var pred_path =
    MULTITASK_BASE + "/" + String(img_idx) + "/" + String(i) + ".png";
  var image_pred = new Image();
  image_pred.onload = function () {
    $("#multitask-pred").empty().append(image_pred);
  };
  image_pred.src = pred_path;
  image_pred.ondragstart = function () {
    return false;
  };
  image_pred.oncontextmenu = function () {
    return false;
  };

  $("#multitask-subtitle").empty().append(multitask_subtitles[i]);
}

function setSpecificVideoImage(img_idx, i) {
  // To avoid flicker, we do it this way when next image is requested
  var rgb_path =
    VIDEO_BASE + "/" + String(img_idx) + "/rgb_" + String(i) + ".webp";
  var rgb_img = new Image();
  rgb_img.onload = function () {
    $("#video-wrapper-rgb").empty().append(rgb_img);
  };
  rgb_img.src = rgb_path;
  rgb_img.ondragstart = function () {
    return false;
  };
  rgb_img.oncontextmenu = function () {
    return false;
  };

  var pred_path =
    VIDEO_BASE + "/" + String(img_idx) + "/" + String(i) + ".webp";
  var image_pred = new Image();
  image_pred.onload = function () {
    $("#video-pred").empty().append(image_pred);
  };
  image_pred.src = pred_path;
  image_pred.ondragstart = function () {
    return false;
  };
  image_pred.oncontextmenu = function () {
    return false;
  };

  $("#video-subtitle").empty().append(video_subtitles[img_idx]);
}

// Enhanced multitask preloading with adjacent buffer
function preloadMultitaskImagesWithBuffer(center_idx) {
  var indices = [
    mod(center_idx - 1, MULTITASK_NUM_IMGS),
    center_idx,
    mod(center_idx + 1, MULTITASK_NUM_IMGS),
  ];

  indices.forEach(function (img_idx) {
    if (!multitaskCache[img_idx]) {
      multitaskCache[img_idx] = {
        rgb: new Image(),
        predictions: new Array(MULTITASK_NUM_FRAMES),
      };

      // Load RGB image
      multitaskCache[img_idx].rgb.src =
        MULTITASK_BASE + "/" + String(img_idx) + ".jpg";

      // Load all prediction frames
      for (var i = 0; i < MULTITASK_NUM_FRAMES; i++) {
        var pred_path =
          MULTITASK_BASE + "/" + String(img_idx) + "/" + String(i) + ".png";
        multitaskCache[img_idx].predictions[i] = new Image();
        multitaskCache[img_idx].predictions[i].src = pred_path;
      }
    }
  });
}

// Enhanced comparison preloading with adjacent buffer
function preloadComparisonImagesWithBuffer(center_idx) {
  var indices = [
    mod(center_idx - 1, COMPARISON_NUM_IMGS),
    center_idx,
    mod(center_idx + 1, COMPARISON_NUM_IMGS),
  ];

  indices.forEach(function (img_idx) {
    if (!comparisonCache[img_idx]) {
      comparisonCache[img_idx] = new Image();
      var path =
        COMPARISON_BASE + "/" + "comparison_" + String(img_idx) + ".webp";
      comparisonCache[img_idx].src = path;
    }
  });
}

// Enhanced video preloading with adjacent buffer
function preloadVideoImagesWithBuffer(center_idx) {
  var indices = [
    mod(center_idx - 1, VIDEO_NUM_IMGS),
    center_idx,
    mod(center_idx + 1, VIDEO_NUM_IMGS),
  ];

  indices.forEach(function (img_idx) {
    if (!videoCache[img_idx]) {
      videoCache[img_idx] = {
        rgb_frames: new Array(VIDEO_NUM_FRAMES[img_idx]),
        pred_frames: new Array(VIDEO_NUM_FRAMES[img_idx]),
      };

      // Load RGB frames
      for (var i = 0; i < VIDEO_NUM_FRAMES[img_idx]; i++) {
        var rgb_path =
          VIDEO_BASE + "/" + String(img_idx) + "/rgb_" + String(i) + ".webp";
        videoCache[img_idx].rgb_frames[i] = new Image();
        videoCache[img_idx].rgb_frames[i].src = rgb_path;
      }

      // Load prediction frames
      for (var i = 0; i < VIDEO_NUM_FRAMES[img_idx]; i++) {
        var pred_path =
          VIDEO_BASE + "/" + String(img_idx) + "/" + String(i) + ".webp";
        videoCache[img_idx].pred_frames[i] = new Image();
        videoCache[img_idx].pred_frames[i].src = pred_path;
      }
    }
  });
}

function mod(n, m) {
  return ((n % m) + m) % m;
}

function prevComparisonImage() {
  comparison_img_idx = mod(comparison_img_idx - 1, COMPARISON_NUM_IMGS);

  // Preload buffer around new index
  preloadComparisonImagesWithBuffer(comparison_img_idx);

  // Use cached image if available
  if (comparisonCache[comparison_img_idx]) {
    document.getElementById("rgb2allFrame").src =
      comparisonCache[comparison_img_idx].src;
  } else {
    setSpecificComparisonImage(comparison_img_idx);
  }
}

function nextComparisonImage() {
  comparison_img_idx = (comparison_img_idx + 1) % COMPARISON_NUM_IMGS;

  // Preload buffer around new index
  preloadComparisonImagesWithBuffer(comparison_img_idx);

  // Use cached image if available
  if (comparisonCache[comparison_img_idx]) {
    document.getElementById("rgb2allFrame").src =
      comparisonCache[comparison_img_idx].src;
  } else {
    setSpecificComparisonImage(comparison_img_idx);
  }
}

function prevSamImage() {
  sam_img_idx = mod(sam_img_idx - 1, SAM_NUM_IMGS);

  setSpecificSamImage(sam_img_idx);
}

function nextSamImage() {
  sam_img_idx = (sam_img_idx + 1) % SAM_NUM_IMGS;

  setSpecificSamImage(sam_img_idx);
}

function prevBowlingImage() {
  bowling_img_idx = mod(bowling_img_idx - 1, BOWLING_NUM_IMGS);
  setSpecificBowlingImage(bowling_img_idx);
}

function nextBowlingImage() {
  bowling_img_idx = (bowling_img_idx + 1) % BOWLING_NUM_IMGS;
  setSpecificBowlingImage(bowling_img_idx);
}

// Updated navigation functions to use cached images and trigger buffer preloading
function prevMultitaskImage() {
  multitask_img_idx = mod(multitask_img_idx - 1, MULTITASK_NUM_IMGS);

  // Preload buffer around new index
  preloadMultitaskImagesWithBuffer(multitask_img_idx);

  // Use cached images if available, otherwise load directly
  if (multitaskCache[multitask_img_idx]) {
    var rgb_img = multitaskCache[multitask_img_idx].rgb;
    rgb_img.ondragstart = function () {
      return false;
    };
    rgb_img.oncontextmenu = function () {
      return false;
    };
    $("#multitask-wrapper-rgb").empty().append(rgb_img);

    var slider_val = $("#multitask-slider").prop("value");
    var pred_img = multitaskCache[multitask_img_idx].predictions[slider_val];
    pred_img.ondragstart = function () {
      return false;
    };
    pred_img.oncontextmenu = function () {
      return false;
    };
    $("#multitask-pred").empty().append(pred_img);
    $("#multitask-subtitle").empty().append(multitask_subtitles[slider_val]);
  } else {
    // Fallback to original method
    preloadMultitaskImages(multitask_img_idx);
    setSpecificMultitaskImage(
      multitask_img_idx,
      $("#multitask-slider").prop("value")
    );
  }
}

function nextMultitaskImage() {
  multitask_img_idx = (multitask_img_idx + 1) % MULTITASK_NUM_IMGS;

  // Preload buffer around new index
  preloadMultitaskImagesWithBuffer(multitask_img_idx);

  // Use cached images if available, otherwise load directly
  if (multitaskCache[multitask_img_idx]) {
    var rgb_img = multitaskCache[multitask_img_idx].rgb;
    rgb_img.ondragstart = function () {
      return false;
    };
    rgb_img.oncontextmenu = function () {
      return false;
    };
    $("#multitask-wrapper-rgb").empty().append(rgb_img);

    var slider_val = $("#multitask-slider").prop("value");
    var pred_img = multitaskCache[multitask_img_idx].predictions[slider_val];
    pred_img.ondragstart = function () {
      return false;
    };
    pred_img.oncontextmenu = function () {
      return false;
    };
    $("#multitask-pred").empty().append(pred_img);
    $("#multitask-subtitle").empty().append(multitask_subtitles[slider_val]);
  } else {
    // Fallback to original method
    preloadMultitaskImages(multitask_img_idx);
    setSpecificMultitaskImage(
      multitask_img_idx,
      $("#multitask-slider").prop("value")
    );
  }
}

function prevVideoImage() {
  video_img_idx = mod(video_img_idx - 1, VIDEO_NUM_IMGS);
  $("#video-slider").prop("max", VIDEO_NUM_FRAMES[video_img_idx] - 1);

  // Preload buffer around new index
  preloadVideoImagesWithBuffer(video_img_idx);

  // Use cached images if available
  if (videoCache[video_img_idx]) {
    var slider_val = $("#video-slider").prop("value");

    var rgb_img = videoCache[video_img_idx].rgb_frames[slider_val];
    rgb_img.ondragstart = function () {
      return false;
    };
    rgb_img.oncontextmenu = function () {
      return false;
    };
    $("#video-wrapper-rgb").empty().append(rgb_img);

    var pred_img = videoCache[video_img_idx].pred_frames[slider_val];
    pred_img.ondragstart = function () {
      return false;
    };
    pred_img.oncontextmenu = function () {
      return false;
    };
    $("#video-pred").empty().append(pred_img);
    $("#video-subtitle").empty().append(video_subtitles[video_img_idx]);
  } else {
    // Fallback to original method
    preloadVideoImages(video_img_idx);
    setSpecificVideoImage(video_img_idx, $("#video-slider").prop("value"));
  }
}

function nextVideoImage() {
  video_img_idx = (video_img_idx + 1) % VIDEO_NUM_IMGS;
  $("#video-slider").prop("max", VIDEO_NUM_FRAMES[video_img_idx] - 1);

  // Preload buffer around new index
  preloadVideoImagesWithBuffer(video_img_idx);

  // Use cached images if available
  if (videoCache[video_img_idx]) {
    var slider_val = $("#video-slider").prop("value");

    var rgb_img = videoCache[video_img_idx].rgb_frames[slider_val];
    rgb_img.ondragstart = function () {
      return false;
    };
    rgb_img.oncontextmenu = function () {
      return false;
    };
    $("#video-wrapper-rgb").empty().append(rgb_img);

    var pred_img = videoCache[video_img_idx].pred_frames[slider_val];
    pred_img.ondragstart = function () {
      return false;
    };
    pred_img.oncontextmenu = function () {
      return false;
    };
    $("#video-pred").empty().append(pred_img);
    $("#video-subtitle").empty().append(video_subtitles[video_img_idx]);
  } else {
    // Fallback to original method
    preloadVideoImages(video_img_idx);
    setSpecificVideoImage(video_img_idx, $("#video-slider").prop("value"));
  }
}

function restartVideo(videoID) {
  var video = document.getElementById(videoID);
  video.currentTime = 0;
  video.play();
}

function playPauseVideo(videoID) {
  var video = document.getElementById(videoID);
  if (video.currentTime > video.duration - 0.1) {
    video.currentTime = 0;
    video.play();
  } else if (video.paused) {
    video.play();
  } else {
    video.pause();
  }
}

function togglePredictionsPlayPause() {
  if (isPredictionsPlaying) {
    pausePredictions();
  } else {
    playPredictions();
  }
}

function playPredictions() {
  isPredictionsPlaying = true;
  updatePredictionsButton();
  predictionsInterval = setInterval(function () {
    var $slider = $("#video-slider");
    var current = parseInt($slider.val(), 10);
    var max = parseInt($slider.prop("max"), 10);
    var nextFrame = current < max ? current + 1 : 0; // Loop back to the beginning
    $slider.val(nextFrame).trigger("input");
  }, predictionsPlaySpeed);
}

function pausePredictions() {
  isPredictionsPlaying = false;
  updatePredictionsButton();
  clearInterval(predictionsInterval);
}

function updatePredictionsButton() {
  var button = $("#predictions-play-pause-button");
  if (isPredictionsPlaying) {
    button.find("svg").removeClass("fa-play").addClass("fa-pause");
    button.find("span:not(.icon)").text("Pause");
  } else {
    button.find("svg").removeClass("fa-pause").addClass("fa-play");
    button.find("span:not(.icon)").text("Play");
  }
}

// Enhanced slider handlers that use cached images when available
function setSpecificMultitaskImageFromCache(img_idx, frame_idx) {
  if (multitaskCache[img_idx]) {
    var rgb_img = multitaskCache[img_idx].rgb;
    rgb_img.ondragstart = function () {
      return false;
    };
    rgb_img.oncontextmenu = function () {
      return false;
    };
    $("#multitask-wrapper-rgb").empty().append(rgb_img);

    var pred_img = multitaskCache[img_idx].predictions[frame_idx];
    pred_img.ondragstart = function () {
      return false;
    };
    pred_img.oncontextmenu = function () {
      return false;
    };
    $("#multitask-pred").empty().append(pred_img);
    $("#multitask-subtitle").empty().append(multitask_subtitles[frame_idx]);
  } else {
    setSpecificMultitaskImage(img_idx, frame_idx);
  }
}

function setSpecificVideoImageFromCache(img_idx, frame_idx) {
  if (videoCache[img_idx]) {
    var rgb_img = videoCache[img_idx].rgb_frames[frame_idx];
    rgb_img.ondragstart = function () {
      return false;
    };
    rgb_img.oncontextmenu = function () {
      return false;
    };
    $("#video-wrapper-rgb").empty().append(rgb_img);

    var pred_img = videoCache[img_idx].pred_frames[frame_idx];
    pred_img.ondragstart = function () {
      return false;
    };
    pred_img.oncontextmenu = function () {
      return false;
    };
    $("#video-pred").empty().append(pred_img);
    $("#video-subtitle").empty().append(video_subtitles[img_idx]);
  } else {
    setSpecificVideoImage(img_idx, frame_idx);
  }
}

// Updated document ready function
$(document).ready(function () {
  // Initialize with buffer preloading for all three systems
  preloadMultitaskImagesWithBuffer(multitask_img_idx);
  preloadComparisonImagesWithBuffer(comparison_img_idx);
  preloadVideoImagesWithBuffer(video_img_idx);

  // Multitask slider - use cached images when available
  $("#multitask-slider").on("input", function (event) {
    setSpecificMultitaskImageFromCache(multitask_img_idx, parseInt(this.value));
  });

  // Initialize multitask display
  setTimeout(function () {
    setSpecificMultitaskImageFromCache(multitask_img_idx, 0);
  }, 100);
  $("#multitask-slider").prop("max", MULTITASK_NUM_FRAMES - 1);
  bulmaSlider.attach();

  // Video slider - use cached images when available
  $("#video-slider").on("input", function (event) {
    setSpecificVideoImageFromCache(video_img_idx, parseInt(this.value));
  });

  // Initialize video display
  setTimeout(function () {
    setSpecificVideoImageFromCache(video_img_idx, 0);
  }, 100);
  $("#video-slider").prop("max", VIDEO_NUM_FRAMES[video_img_idx] - 1);
  bulmaSlider.attach();
});

document.addEventListener("DOMContentLoaded", () => {
  // Get all "navbar-burger" elements
  const $navbarBurgers = Array.prototype.slice.call(
    document.querySelectorAll(".navbar-burger"),
    0
  );

  // Add a click event on each of them
  $navbarBurgers.forEach((el) => {
    el.addEventListener("click", () => {
      // Get the target from the "data-target" attribute
      const target = el.dataset.target;
      const $target = document.getElementById(target);

      // Toggle the "is-active" class on both the "navbar-burger" and the "navbar-menu"
      el.classList.toggle("is-active");
      $target.classList.toggle("is-active");
    });
  });
});

function smoothScroll(targetId) {
  // Only enable smooth scroll on screens wider than 768px (not mobile)
  if (window.innerWidth <= 768) {
    return; // Skip on mobile
  }

  var targetElement = document.getElementById(targetId);
  var offset = document.getElementById("navbar").offsetHeight * 1.5; // You can adjust this value to control the scroll offset

  if (targetElement) {
    var elementPosition = targetElement.getBoundingClientRect();
    var targetPosition = elementPosition.top - offset + window.scrollY;

    window.scrollTo({
      top: targetPosition,
      behavior: "smooth",
    });
  } else if (targetId.length === 0) {
    window.scrollTo({
      top: 0,
      behavior: "smooth",
    });
  }
}

document.addEventListener("DOMContentLoaded", () => {
  var navLinks = document.querySelectorAll(
    "a.navbar-item, a.navbar-link, a.tile"
  );

  navLinks.forEach(function (link) {
    var targetId = link.getAttribute("href").substring(1); // Get the target ID
    link.addEventListener("click", function (event) {
      // Only prevent default and smooth scroll if not on mobile
      if (window.innerWidth > 768) {
        event.preventDefault(); // Prevent default link behavior
        smoothScroll(targetId);
      }
    });
  });
});

document.addEventListener("DOMContentLoaded", () => {
  // Reference to the main (Sam) image element
  const originalImg = document.getElementById("samImg");

  // Cache to store JSON data and preloaded images.
  let allSegmentsData = {};
  // The preloaded cache will store each image index's data:
  // {
  //   "0": {
  //     base: HTMLImageElement,
  //     overlays: { overlayIndex: HTMLImageElement, ... }
  //   },
  //   "1": { ... },
  //   ...
  // }
  const preloadedImages = {};

  // Fetch JSON containing the overlay segment arrays for all images
  fetch("static/images/all_overlayed_imgs/starting_segments.json")
    .then((response) => {
      if (!response.ok) {
        throw new Error(`HTTP error! Status: ${response.status}`);
      }
      return response.json();
    })
    .then((data) => {
      allSegmentsData = data;
      preloadAllImages();
    })
    .catch((error) => {
      console.error("Error fetching JSON data:", error);
    });

  /**
   * Preloads images (both base and overlay images) for all sam_img_idxs.
   */
  function preloadAllImages() {
    for (let idx = 0; idx < SAM_NUM_IMGS; idx++) {
      const key = idx.toString();

      preloadedImages[key] = {
        base: null,
        overlays: {},
      };

      const overlayBasePath = `https://storage.googleapis.com/fm-task-evals-website/images/all_overlayed_imgs/${idx}/`;
      const overlayBaseImagePath = `https://storage.googleapis.com/fm-task-evals-website/images/all_overlayed_imgs/`;

      // Preload the base image (when no overlay is active).
      const baseImage = new Image();
      baseImage.src = overlayBaseImagePath + idx + ".webp";
      preloadedImages[key].base = baseImage;

      const segmentsObj = allSegmentsData[key];
      if (!segmentsObj || !segmentsObj.segments) {
        console.warn("No segment data found for image index:", idx);
        continue;
      }

      // Get the raw segments array and transpose it.
      const segments = segmentsObj.segments;
      const transposedSegments = segments[0].map((_, colIndex) =>
        segments.map((row) => row[colIndex])
      );

      const overlayIndices = new Set();
      transposedSegments.forEach((row) => {
        row.forEach((value) => {
          const overlayIndex = value - 1;
          if (overlayIndex >= 0) {
            overlayIndices.add(overlayIndex);
          }
        });
      });

      // Preload each overlay image for this sam_img_idx
      overlayIndices.forEach((overlayIndex) => {
        const overlayImg = new Image();
        overlayImg.src = overlayBasePath + overlayIndex + ".webp";
        preloadedImages[key].overlays[overlayIndex] = overlayImg;
      });
    }
  }

  /**
   * Calculates the cursor's position relative to the natural image dimensions.
   * @param {MouseEvent} event - The mouse event.
   * @param {HTMLImageElement} img - The image element.
   * @returns {Object} An object with x and y coordinates.
   */
  function getCursorPosition(event, img) {
    const rect = img.getBoundingClientRect();
    const x = event.clientX - rect.left;
    const y = event.clientY - rect.top;
    // Clamp values within image boundaries
    const clampedX = Math.max(0, Math.min(x, rect.width));
    const clampedY = Math.max(0, Math.min(y, rect.height));
    // Scale the coordinates to the natural image size
    const scaleX = img.naturalWidth / rect.width;
    const scaleY = img.naturalHeight / rect.height;
    return {
      x: Math.floor(clampedX * scaleX),
      y: Math.floor(clampedY * scaleY),
    };
  }

  /**
   * Event handler for mouse movement over the image.
   * Determines the correct overlay image based on cursor position and swaps the source.
   * @param {MouseEvent} event
   */
  function handleMouseMove(event) {
    const key = sam_img_idx.toString();

    const segmentsObj = allSegmentsData[key];
    if (!segmentsObj || !segmentsObj.segments) {
      return;
    }
    const segmentsRaw = segmentsObj.segments;
    const allSegments = segmentsRaw[0].map((_, colIndex) =>
      segmentsRaw.map((row) => row[colIndex])
    );

    const { x, y } = getCursorPosition(event, originalImg);
    let activeSegmentIndex = -1;

    // Determine if (x, y) falls within bounds of the segments array.
    if (
      x >= 0 &&
      x < allSegments.length &&
      y >= 0 &&
      y < allSegments[0].length
    ) {
      activeSegmentIndex = allSegments[x][y] - 1;
    }

    if (
      activeSegmentIndex !== -1 &&
      preloadedImages[key].overlays[activeSegmentIndex]
    ) {
      originalImg.src = preloadedImages[key].overlays[activeSegmentIndex].src;
    } else {
      // Otherwise, revert to the base image.
      originalImg.src = preloadedImages[key].base.src;
    }
  }

  /**
   * When the mouse leaves the image, revert to the base image.
   */
  function handleMouseLeave() {
    const key = sam_img_idx.toString();
    if (preloadedImages[key] && preloadedImages[key].base) {
      originalImg.src = preloadedImages[key].base.src;
    }
  }

  // Attach event listeners to the image.
  originalImg.addEventListener("mousemove", handleMouseMove);
  originalImg.addEventListener("mouseleave", handleMouseLeave);
});

/**
 * For cleaner table hovering effect
 */

$(document).ready(function () {
  // Handler for the group label cell (the td with a rowspan)
  $("tbody td[rowspan]").hover(
    function () {
      // When hovering over the group label cell, highlight the entire group.
      let $groupCell = $(this);
      let rowspan = parseInt($groupCell.attr("rowspan"), 10);
      let $firstRow = $groupCell.closest("tr");

      let $allRows = $firstRow.closest("tbody").find("tr");
      let rowIndex = $allRows.index($firstRow);
      $allRows.removeClass("individual-hover");
      $allRows.slice(rowIndex, rowIndex + rowspan).addClass("hovered");
    },
    function () {
      // When leaving the group label cell, remove the group highlight.
      let $groupCell = $(this);
      let rowspan = parseInt($groupCell.attr("rowspan"), 10);
      let $firstRow = $groupCell.closest("tr");
      let $allRows = $firstRow.closest("tbody").find("tr");
      let rowIndex = $allRows.index($firstRow);
      $allRows.slice(rowIndex, rowIndex + rowspan).removeClass("hovered");
    }
  );

  // Handler for individual row hover
  $("tbody tr").hover(
    function (e) {
      // If the element that triggered the event is NOT inside a td[rowspan],
      // then add the "individual-hover" class to this row.
      if ($(e.target).closest("td[rowspan]").length === 0) {
        $(this).addClass("individual-hover");
      }
    },
    function () {
      $(this).removeClass("individual-hover");
    }
  );
});
