import defined from "../../Core/defined.js";
import destroyObject from "../../Core/destroyObject.js";
import DeveloperError from "../../Core/DeveloperError.js";
import knockout from "../../ThirdParty/knockout.js";
import getElement from "../getElement.js";
import InspectorShared from "../InspectorShared.js";
import CesiumInspectorViewModel from "./CesiumInspectorViewModel.js";

/**
 * Inspector widget to aid in debugging
 *
 * @alias CesiumInspector
 * @constructor
 *
 * @param {Element|String} container The DOM element or ID that will contain the widget.
 * @param {Scene} scene The Scene instance to use.
 *
 * @demo {@link https://sandcastle.cesium.com/index.html?src=Cesium%20Inspector.html|Cesium Sandcastle Cesium Inspector Demo}
 */
function CesiumInspector(container, scene) {
  //>>includeStart('debug', pragmas.debug);
  if (!defined(container)) {
    throw new DeveloperError("container is required.");
  }

  if (!defined(scene)) {
    throw new DeveloperError("scene is required.");
  }
  //>>includeEnd('debug');

  container = getElement(container);

  const performanceContainer = document.createElement("div");

  const viewModel = new CesiumInspectorViewModel(scene, performanceContainer);
  this._viewModel = viewModel;
  this._container = container;

  const element = document.createElement("div");
  this._element = element;
  const text = document.createElement("div");
  text.textContent = "Cesium Inspector";
  text.className = "cesium-cesiumInspector-button";
  text.setAttribute("data-bind", "click: toggleDropDown");
  element.appendChild(text);
  element.className = "cesium-cesiumInspector";
  element.setAttribute(
    "data-bind",
    'css: { "cesium-cesiumInspector-visible" : dropDownVisible, "cesium-cesiumInspector-hidden" : !dropDownVisible }'
  );
  container.appendChild(this._element);

  const panel = document.createElement("div");
  this._panel = panel;
  panel.className = "cesium-cesiumInspector-dropDown";
  element.appendChild(panel);

  const createSection = InspectorShared.createSection;
  const createCheckbox = InspectorShared.createCheckbox;

  // General
  const generalSection = createSection(
    panel,
    "General",
    "generalVisible",
    "toggleGeneral"
  );

  const debugShowFrustums = createCheckbox("Show Frustums", "frustums");
  const frustumStatistics = document.createElement("div");
  frustumStatistics.className = "cesium-cesiumInspector-frustumStatistics";
  frustumStatistics.setAttribute(
    "data-bind",
    "visible: frustums, html: frustumStatisticText"
  );
  debugShowFrustums.appendChild(frustumStatistics);
  generalSection.appendChild(debugShowFrustums);

  generalSection.appendChild(
    createCheckbox("Show Frustum Planes", "frustumPlanes")
  );
  generalSection.appendChild(
    createCheckbox("Performance Display", "performance")
  );

  performanceContainer.className = "cesium-cesiumInspector-performanceDisplay";
  generalSection.appendChild(performanceContainer);

  const shaderCacheDisplay = document.createElement("div");
  shaderCacheDisplay.className = "cesium-cesiumInspector-shaderCache";
  shaderCacheDisplay.setAttribute("data-bind", "html: shaderCacheText");
  generalSection.appendChild(shaderCacheDisplay);

  const depthFrustum = document.createElement("div");
  generalSection.appendChild(depthFrustum);

  // Use a span with HTML binding so that we can indent with non-breaking spaces.
  const gLabel = document.createElement("span");
  gLabel.setAttribute(
    "data-bind",
    'html: "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Frustum:"'
  );
  depthFrustum.appendChild(gLabel);

  const gText = document.createElement("span");
  gText.setAttribute("data-bind", "text: depthFrustumText");
  depthFrustum.appendChild(gText);

  const gMinusButton = document.createElement("input");
  gMinusButton.type = "button";
  gMinusButton.value = "-";
  gMinusButton.className = "cesium-cesiumInspector-pickButton";
  gMinusButton.setAttribute("data-bind", "click: decrementDepthFrustum");
  depthFrustum.appendChild(gMinusButton);

  const gPlusButton = document.createElement("input");
  gPlusButton.type = "button";
  gPlusButton.value = "+";
  gPlusButton.className = "cesium-cesiumInspector-pickButton";
  gPlusButton.setAttribute("data-bind", "click: incrementDepthFrustum");
  depthFrustum.appendChild(gPlusButton);

  // Primitives
  const primSection = createSection(
    panel,
    "Primitives",
    "primitivesVisible",
    "togglePrimitives"
  );
  const pickPrimRequired = document.createElement("div");
  pickPrimRequired.className = "cesium-cesiumInspector-pickSection";
  primSection.appendChild(pickPrimRequired);

  const pickPrimitiveButton = document.createElement("input");
  pickPrimitiveButton.type = "button";
  pickPrimitiveButton.value = "Pick a primitive";
  pickPrimitiveButton.className = "cesium-cesiumInspector-pickButton";
  pickPrimitiveButton.setAttribute(
    "data-bind",
    'css: {"cesium-cesiumInspector-pickButtonHighlight" : pickPrimitiveActive}, click: pickPrimitive'
  );
  let buttonWrap = document.createElement("div");
  buttonWrap.className = "cesium-cesiumInspector-center";
  buttonWrap.appendChild(pickPrimitiveButton);
  pickPrimRequired.appendChild(buttonWrap);

  pickPrimRequired.appendChild(
    createCheckbox(
      "Show bounding sphere",
      "primitiveBoundingSphere",
      "hasPickedPrimitive"
    )
  );
  pickPrimRequired.appendChild(
    createCheckbox(
      "Show reference frame",
      "primitiveReferenceFrame",
      "hasPickedPrimitive"
    )
  );

  this._primitiveOnly = createCheckbox(
    "Show only selected",
    "filterPrimitive",
    "hasPickedPrimitive"
  );
  pickPrimRequired.appendChild(this._primitiveOnly);

  // Terrain
  const terrainSection = createSection(
    panel,
    "Terrain",
    "terrainVisible",
    "toggleTerrain"
  );
  const pickTileRequired = document.createElement("div");
  pickTileRequired.className = "cesium-cesiumInspector-pickSection";
  terrainSection.appendChild(pickTileRequired);
  const pickTileButton = document.createElement("input");
  pickTileButton.type = "button";
  pickTileButton.value = "Pick a tile";
  pickTileButton.className = "cesium-cesiumInspector-pickButton";
  pickTileButton.setAttribute(
    "data-bind",
    'css: {"cesium-cesiumInspector-pickButtonHighlight" : pickTileActive}, click: pickTile'
  );
  buttonWrap = document.createElement("div");
  buttonWrap.appendChild(pickTileButton);
  buttonWrap.className = "cesium-cesiumInspector-center";
  pickTileRequired.appendChild(buttonWrap);
  const tileInfo = document.createElement("div");
  pickTileRequired.appendChild(tileInfo);
  const parentTile = document.createElement("input");
  parentTile.type = "button";
  parentTile.value = "Parent";
  parentTile.className = "cesium-cesiumInspector-pickButton";
  parentTile.setAttribute("data-bind", "click: selectParent");
  const nwTile = document.createElement("input");
  nwTile.type = "button";
  nwTile.value = "NW";
  nwTile.className = "cesium-cesiumInspector-pickButton";
  nwTile.setAttribute("data-bind", "click: selectNW");
  const neTile = document.createElement("input");
  neTile.type = "button";
  neTile.value = "NE";
  neTile.className = "cesium-cesiumInspector-pickButton";
  neTile.setAttribute("data-bind", "click: selectNE");
  const swTile = document.createElement("input");
  swTile.type = "button";
  swTile.value = "SW";
  swTile.className = "cesium-cesiumInspector-pickButton";
  swTile.setAttribute("data-bind", "click: selectSW");
  const seTile = document.createElement("input");
  seTile.type = "button";
  seTile.value = "SE";
  seTile.className = "cesium-cesiumInspector-pickButton";
  seTile.setAttribute("data-bind", "click: selectSE");

  const tileText = document.createElement("div");
  tileText.className = "cesium-cesiumInspector-tileText";
  tileInfo.className = "cesium-cesiumInspector-frustumStatistics";
  tileInfo.appendChild(tileText);
  tileInfo.setAttribute("data-bind", "visible: hasPickedTile");
  tileText.setAttribute("data-bind", "html: tileText");

  const relativeText = document.createElement("div");
  relativeText.className = "cesium-cesiumInspector-relativeText";
  relativeText.textContent = "Select relative:";
  tileInfo.appendChild(relativeText);

  const table = document.createElement("table");
  const tr1 = document.createElement("tr");
  const tr2 = document.createElement("tr");
  const td1 = document.createElement("td");
  td1.appendChild(parentTile);
  const td2 = document.createElement("td");
  td2.appendChild(nwTile);
  const td3 = document.createElement("td");
  td3.appendChild(neTile);
  tr1.appendChild(td1);
  tr1.appendChild(td2);
  tr1.appendChild(td3);
  const td4 = document.createElement("td");
  const td5 = document.createElement("td");
  td5.appendChild(swTile);
  const td6 = document.createElement("td");
  td6.appendChild(seTile);
  tr2.appendChild(td4);
  tr2.appendChild(td5);
  tr2.appendChild(td6);
  table.appendChild(tr1);
  table.appendChild(tr2);

  tileInfo.appendChild(table);

  pickTileRequired.appendChild(
    createCheckbox(
      "Show bounding volume",
      "tileBoundingSphere",
      "hasPickedTile"
    )
  );
  pickTileRequired.appendChild(
    createCheckbox("Show only selected", "filterTile", "hasPickedTile")
  );

  terrainSection.appendChild(createCheckbox("Wireframe", "wireframe"));
  terrainSection.appendChild(
    createCheckbox("Suspend LOD update", "suspendUpdates")
  );
  terrainSection.appendChild(
    createCheckbox("Show tile coordinates", "tileCoordinates")
  );

  knockout.applyBindings(viewModel, this._element);
}

Object.defineProperties(CesiumInspector.prototype, {
  /**
   * Gets the parent container.
   * @memberof CesiumInspector.prototype
   *
   * @type {Element}
   */
  container: {
    get: function () {
      return this._container;
    },
  },

  /**
   * Gets the view model.
   * @memberof CesiumInspector.prototype
   *
   * @type {CesiumInspectorViewModel}
   */
  viewModel: {
    get: function () {
      return this._viewModel;
    },
  },
});

/**
 * @returns {Boolean} true if the object has been destroyed, false otherwise.
 */
CesiumInspector.prototype.isDestroyed = function () {
  return false;
};

/**
 * Destroys the widget.  Should be called if permanently
 * removing the widget from layout.
 */
CesiumInspector.prototype.destroy = function () {
  knockout.cleanNode(this._element);
  this._container.removeChild(this._element);
  this.viewModel.destroy();

  return destroyObject(this);
};
export default CesiumInspector;
