"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = void 0;

var _react = _interopRequireDefault(require("react"));

require("./H5j3dViewerWithBasicUI.css");

var _webH5jLoader = require("@janelia/web-h5j-loader");

var _TransferFunctions = require("./TransferFunctions");

var _Vol3dViewer = _interopRequireDefault(require("./Vol3dViewer"));

var _Obj = require("./Obj");

var _Swc = require("./Swc");

var _Utils = require("./Utils");

var _FileOrURLInput = _interopRequireDefault(require("./FileOrURLInput"));

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }

function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }

function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }

function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }

function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }

function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }

function _iterableToArrayLimit(arr, i) { var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"]; if (_i == null) return; var _arr = []; var _n = true; var _d = false; var _s, _e; try { for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; }

function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }

function H5j3dViewerWithBasicUI() {
  var alpha0 = 0;
  var peakDefault = 217;
  var dataGammaDefault = 0.5;
  var alpha1 = 255;

  var _React$useState = _react.default.useState(null),
      _React$useState2 = _slicedToArray(_React$useState, 2),
      fileH5J = _React$useState2[0],
      setFileH5J = _React$useState2[1];

  var _React$useState3 = _react.default.useState(null),
      _React$useState4 = _slicedToArray(_React$useState3, 2),
      filename = _React$useState4[0],
      setFilename = _React$useState4[1];

  var _React$useState5 = _react.default.useState(null),
      _React$useState6 = _slicedToArray(_React$useState5, 2),
      volumeSize = _React$useState6[0],
      setVolumeSize = _React$useState6[1];

  var _React$useState7 = _react.default.useState(null),
      _React$useState8 = _slicedToArray(_React$useState7, 2),
      voxelSize = _React$useState8[0],
      setVoxelSize = _React$useState8[1];

  var _React$useState9 = _react.default.useState(false),
      _React$useState10 = _slicedToArray(_React$useState9, 2),
      useVolumeMirrorX = _React$useState10[0],
      setUseVolumeMirrorX = _React$useState10[1];

  var _React$useState11 = _react.default.useState(''),
      _React$useState12 = _slicedToArray(_React$useState11, 2),
      units = _React$useState12[0],
      setUnits = _React$useState12[1];

  var _React$useState13 = _react.default.useState(null),
      _React$useState14 = _slicedToArray(_React$useState13, 2),
      channelSpecs = _React$useState14[0],
      setChannelSpecs = _React$useState14[1];

  var _React$useState15 = _react.default.useState(null),
      _React$useState16 = _slicedToArray(_React$useState15, 2),
      channel = _React$useState16[0],
      setChannel = _React$useState16[1];

  var _React$useState17 = _react.default.useState(0),
      _React$useState18 = _slicedToArray(_React$useState17, 2),
      loadingPercent = _React$useState18[0],
      setLoadingPercent = _React$useState18[1];

  var _React$useState19 = _react.default.useState(null),
      _React$useState20 = _slicedToArray(_React$useState19, 2),
      ffmpegWasm = _React$useState20[0],
      setFfmpegWasm = _React$useState20[1];

  var _React$useState21 = _react.default.useState(null),
      _React$useState22 = _slicedToArray(_React$useState21, 2),
      loadingError = _React$useState22[0],
      setLoadingError = _React$useState22[1];

  var _React$useState23 = _react.default.useState(null),
      _React$useState24 = _slicedToArray(_React$useState23, 2),
      dataUint8 = _React$useState24[0],
      setDataUint8 = _React$useState24[1];

  var _React$useState25 = _react.default.useState(true),
      _React$useState26 = _slicedToArray(_React$useState25, 2),
      useLighting = _React$useState26[0],
      setUseLighting = _React$useState26[1];

  var _React$useState27 = _react.default.useState('#ff00ff'),
      _React$useState28 = _slicedToArray(_React$useState27, 2),
      dataColor = _React$useState28[0],
      setDataColor = _React$useState28[1];

  var _React$useState29 = _react.default.useState(_Vol3dViewer.default.defaultProps.alphaScale),
      _React$useState30 = _slicedToArray(_React$useState29, 2),
      alphaScale = _React$useState30[0],
      setAlphaScale = _React$useState30[1];

  var _React$useState31 = _react.default.useState(_Vol3dViewer.default.defaultProps.dtScale),
      _React$useState32 = _slicedToArray(_React$useState31, 2),
      dtScale = _React$useState32[0],
      setDtScale = _React$useState32[1];

  var _React$useState33 = _react.default.useState(1),
      _React$useState34 = _slicedToArray(_React$useState33, 2),
      interactionSpeedup = _React$useState34[0],
      setInteractionSpeedup = _React$useState34[1];

  var _React$useState35 = _react.default.useState(peakDefault),
      _React$useState36 = _slicedToArray(_React$useState35, 2),
      peak = _React$useState36[0],
      setPeak = _React$useState36[1];

  var _React$useState37 = _react.default.useState(dataGammaDefault),
      _React$useState38 = _slicedToArray(_React$useState37, 2),
      dataGamma = _React$useState38[0],
      setDataGamma = _React$useState38[1];

  var _React$useState39 = _react.default.useState(_Vol3dViewer.default.defaultProps.finalGamma),
      _React$useState40 = _slicedToArray(_React$useState39, 2),
      finalGamma = _React$useState40[0],
      setFinalGamma = _React$useState40[1];

  var _React$useState41 = _react.default.useState(false),
      _React$useState42 = _slicedToArray(_React$useState41, 2),
      useSurface = _React$useState42[0],
      setUseSurface = _React$useState42[1];

  var _React$useState43 = _react.default.useState(null),
      _React$useState44 = _slicedToArray(_React$useState43, 2),
      swcSurfaceMesh = _React$useState44[0],
      setSwcSurfaceMesh = _React$useState44[1];

  var _React$useState45 = _react.default.useState('#00ff00'),
      _React$useState46 = _slicedToArray(_React$useState45, 2),
      surfaceColor = _React$useState46[0],
      setSurfaceColor = _React$useState46[1]; // Not `React.useState` so changes do not cause React to re-render.


  var allowThrottledEvent = _react.default.useRef(false);

  var transferFunctionTexRef = _react.default.useRef((0, _TransferFunctions.makeFluoTransferTex)(alpha0, peak, dataGamma, alpha1, dataColor));

  var onDataFileInputChange = /*#__PURE__*/function () {
    var _ref = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee(event) {
      var src, f, fH5J, attrs, _parseH5jAttrs, volSize, voxSize, chanSpecs;

      return regeneratorRuntime.wrap(function _callee$(_context) {
        while (1) {
          switch (_context.prev = _context.next) {
            case 0:
              src = null;

              if (event.target.files && event.target.files.length > 0) {
                // Local file
                f = event.target.files[0];
                setFilename(f.name);
                src = f;
              } else if (event.target.value && typeof event.target.value === 'string') {
                // URL
                setFilename(event.target.value);
                src = event.target.value;
              }

              if (!src) {
                _context.next = 24;
                break;
              }

              setLoadingError(null);
              setChannelSpecs(null);
              _context.prev = 5;
              _context.next = 8;
              return (0, _webH5jLoader.openH5J)(src);

            case 8:
              fH5J = _context.sent;
              attrs = (0, _webH5jLoader.getH5JAttrs)(fH5J);
              _parseH5jAttrs = (0, _Utils.parseH5jAttrs)(attrs), volSize = _parseH5jAttrs.volSize, voxSize = _parseH5jAttrs.voxSize, chanSpecs = _parseH5jAttrs.chanSpecs;
              setFileH5J(fH5J);
              setVolumeSize(volSize);
              setVoxelSize(voxSize);
              setUnits(attrs.unit);
              setChannelSpecs(chanSpecs); // When loading a dataset after the first time, this state resetting causes the
              // intermediate user interface to appear properly.

              setChannel(null);
              setLoadingPercent(0);
              setDataUint8(null);
              _context.next = 24;
              break;

            case 21:
              _context.prev = 21;
              _context.t0 = _context["catch"](5);
              setLoadingError(_context.t0);

            case 24:
            case "end":
              return _context.stop();
          }
        }
      }, _callee, null, [[5, 21]]);
    }));

    return function onDataFileInputChange(_x) {
      return _ref.apply(this, arguments);
    };
  }();

  var onLoadChannel = /*#__PURE__*/function () {
    var _ref2 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee2() {
      var radios, checked, i, ch, onProgress, ff, data, dUint8;
      return regeneratorRuntime.wrap(function _callee2$(_context2) {
        while (1) {
          switch (_context2.prev = _context2.next) {
            case 0:
              radios = document.getElementsByName("channels-radio-group");

              if (!radios) {
                _context2.next = 18;
                break;
              }

              for (i = 0; i < radios.length; i += 1) {
                if (radios[i].checked) {
                  checked = radios[i];
                }
              }

              if (!checked) {
                _context2.next = 18;
                break;
              }

              ch = checked.value;
              console.log("Loading 'Channels/".concat(ch, "'"));
              setChannel(ch);

              onProgress = function onProgress(_ref3) {
                var ratio = _ref3.ratio;
                setLoadingPercent(Math.round(ratio * 100));
              }; // The key code for loading the H.265 encoded volume data from one channel of the HDF5 container; 
              // similar code would be needed to use the `Vol3dViewer` component with another user interface.
              // Reuse the results of initializing ffpmeg.wasm once.  Doing so seems to save about a second
              // on any file reading after the first reading.


              ff = ffmpegWasm;

              if (ff) {
                _context2.next = 14;
                break;
              }

              _context2.next = 12;
              return (0, _webH5jLoader.createFFmpegForEnv)();

            case 12:
              ff = _context2.sent;
              setFfmpegWasm(ff);

            case 14:
              _context2.next = 16;
              return (0, _webH5jLoader.readH5JChannelUint8)(ch, fileH5J, onProgress, ff);

            case 16:
              data = _context2.sent;

              if (data) {
                console.log("Loaded ".concat(data.byteLength, " bytes"));
                setVolumeSize((0, _Utils.fixVolumeSize)(volumeSize, data)); // Treat the `ArrayBuffer` as an array of unsigned 8-bit integers.  Doing so should not
                // copy the underlying data, and is necessary to make the `THREE.DataTexture3D`.

                dUint8 = new Uint8Array(data.buffer);
                console.log("Converted ".concat(dUint8.length, " bytes"));
                setDataUint8(dUint8);
                setDtScale(_Vol3dViewer.default.defaultProps.dtScale);
                setAlphaScale(_Vol3dViewer.default.defaultProps.alphaScale);
                setPeak(peakDefault);
                setDataGamma(dataGammaDefault);
                setFinalGamma(_Vol3dViewer.default.defaultProps.finalGamma);
              }

            case 18:
            case "end":
              return _context2.stop();
          }
        }
      }, _callee2);
    }));

    return function onLoadChannel() {
      return _ref2.apply(this, arguments);
    };
  }();

  var onSurfaceFileInputChange = /*#__PURE__*/function () {
    var _ref4 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee3(event) {
      var src, f, text, mesh, json, _surfaceAlignmentFact, surfaceScale, surfaceTranslation;

      return regeneratorRuntime.wrap(function _callee3$(_context3) {
        while (1) {
          switch (_context3.prev = _context3.next) {
            case 0:
              src = null;

              if (event.target.files && event.target.files.length > 0) {
                // Local file
                f = event.target.files[0];
                src = f;
              } else if (event.target.value && typeof event.target.value === 'string') {
                // URL
                src = event.target.value;
              }

              if (!src) {
                _context3.next = 21;
                break;
              }

              setLoadingError(null);
              _context3.prev = 4;
              _context3.next = 7;
              return (0, _Utils.textFromFileOrURL)(src);

            case 7:
              text = _context3.sent;
              mesh = null;

              if ((0, _Obj.isObjSource)(src)) {
                mesh = (0, _Obj.makeObjSurface)(text, surfaceColor);
              } else {
                json = (0, _Swc.parseSwc)(text);
                mesh = (0, _Swc.makeSwcSurface)(json, surfaceColor);
              }

              _surfaceAlignmentFact = (0, _Utils.surfaceAlignmentFactors)(units, volumeSize, voxelSize), surfaceScale = _surfaceAlignmentFact.surfaceScale, surfaceTranslation = _surfaceAlignmentFact.surfaceTranslation;
              mesh.scale.set(surfaceScale, surfaceScale, surfaceScale);
              mesh.position.set(surfaceTranslation[0] * surfaceScale, surfaceTranslation[1] * surfaceScale, surfaceTranslation[2] * surfaceScale);
              setSwcSurfaceMesh(mesh);
              setUseSurface(true); // Relinquish keyboard focus, so pressing a key to toggle the surface visibility,
              // for example, does not instead trigger the file chooser again.

              if (event.target) {
                event.target.blur();
              }

              _context3.next = 21;
              break;

            case 18:
              _context3.prev = 18;
              _context3.t0 = _context3["catch"](4);
              setLoadingError(_context3.t0);

            case 21:
            case "end":
              return _context3.stop();
          }
        }
      }, _callee3, null, [[4, 18]]);
    }));

    return function onSurfaceFileInputChange(_x2) {
      return _ref4.apply(this, arguments);
    };
  }();

  var onAlphaScaleChange = function onAlphaScaleChange(event) {
    if (allowThrottledEvent.current) {
      allowThrottledEvent.current = false;
      setAlphaScale(event.target.valueAsNumber);
    }
  };

  var onDtScaleChange = function onDtScaleChange(event) {
    if (allowThrottledEvent.current) {
      allowThrottledEvent.current = false;
      setDtScale(event.target.valueAsNumber);
    }
  };

  var onPeakChange = function onPeakChange(event) {
    if (allowThrottledEvent.current) {
      allowThrottledEvent.current = false;
      setPeak(event.target.valueAsNumber);
      transferFunctionTexRef.current = (0, _TransferFunctions.makeFluoTransferTex)(alpha0, event.target.valueAsNumber, dataGamma, alpha1, dataColor);
    }
  };

  var onDataGammaChange = function onDataGammaChange(event) {
    if (allowThrottledEvent.current) {
      allowThrottledEvent.current = false;
      setDataGamma(event.target.valueAsNumber);
      transferFunctionTexRef.current = (0, _TransferFunctions.makeFluoTransferTex)(alpha0, peak, event.target.valueAsNumber, alpha1, dataColor);
    }
  };

  var onFinalGammaChange = function onFinalGammaChange(event) {
    if (allowThrottledEvent.current) {
      allowThrottledEvent.current = false;
      setFinalGamma(event.target.valueAsNumber);
    }
  };

  var onInteractionSpeedupChange = function onInteractionSpeedupChange(event) {
    if (allowThrottledEvent.current) {
      allowThrottledEvent.current = false;
      setInteractionSpeedup(event.target.valueAsNumber);
    }
  };

  var onDataColorInputChange = function onDataColorInputChange(event) {
    setDataColor(event.target.value);
    transferFunctionTexRef.current = (0, _TransferFunctions.makeFluoTransferTex)(alpha0, peak, dataGamma, alpha1, event.target.value);
  };

  var onSurfaceColorInputChange = function onSurfaceColorInputChange(event) {
    setSurfaceColor(event.target.value);
  };

  var onKeyPress = function onKeyPress(event) {
    if (event.key === 'l') {
      setUseLighting(!useLighting);
    } else if (event.key === 'm') {
      setUseVolumeMirrorX(!useVolumeMirrorX);
    } else if (swcSurfaceMesh) {
      setUseSurface(!useSurface);
    }
  }; // An example of how the `onCameraChange` prop could be used, with access to the
  // camera and the orbit controller.
  // It's best to make this function a memoized callback, to avoid repeated unncessary
  // `removeEventListener` / `addEventListener` calls in `Vol3dViewer`.


  var onCameraChangeTest = _react.default.useCallback(function (event) {
    if (event) {
      var orbitControls = event.target;
      var camera = event.target.object;
      /* eslint-disable no-unused-vars */

      var eye = camera.position;
      var center = orbitControls.target;
      var up = camera.up;
      /* eslint-enable no-unused-vars */
    }
  }, []);

  var onWebGLRender = _react.default.useCallback(function () {
    // Events generated by the spinners on the final-gamma control (and others) need to
    // be throttled, to avoid having a backlog of events that continue to be processed
    // after the user stops presssing the spinner.  Standard throttling techniques based
    // on time do not work well, but it does work to throttle so that no new event is
    // processed until the WebGL rendering triggered by the last event has been processed.
    allowThrottledEvent.current = true;
  }, []);

  var middle;

  var bottom = /*#__PURE__*/_react.default.createElement("div", {
    className: "Controls"
  }, "\xA0");

  if (loadingError) {
    middle = /*#__PURE__*/_react.default.createElement("div", null, "Error during loading: ".concat(loadingError.message));
  } else if (!filename) {
    middle = /*#__PURE__*/_react.default.createElement("div", null);
  } else if (!channelSpecs) {
    middle = /*#__PURE__*/_react.default.createElement("div", null, filename);
  } else if (!channel) {
    middle = /*#__PURE__*/_react.default.createElement("div", {
      className: "Channels"
    }, filename, /*#__PURE__*/_react.default.createElement("div", {
      style: {
        textAlign: "left",
        alignItems: "center"
      }
    }, channelSpecs.map(function (ch) {
      return /*#__PURE__*/_react.default.createElement("div", {
        key: ch.name
      }, /*#__PURE__*/_react.default.createElement("input", {
        type: "radio",
        name: "channels-radio-group",
        value: ch.name,
        id: ch.name,
        defaultChecked: ch === channelSpecs[0]
      }), /*#__PURE__*/_react.default.createElement("label", {
        htmlFor: ch
      }, ch.name, ": ", ch.content));
    })), /*#__PURE__*/_react.default.createElement("button", {
      type: "button",
      onClick: onLoadChannel
    }, "Load"));
  } else if (!dataUint8) {
    if (!loadingPercent) {
      middle = /*#__PURE__*/_react.default.createElement("div", null, "Loading...");
    } else {
      middle = /*#__PURE__*/_react.default.createElement("div", null, "Loading... (".concat(loadingPercent, "%)"));
    }
  } else {
    middle = /*#__PURE__*/_react.default.createElement(_Vol3dViewer.default, {
      volumeDataUint8: dataUint8,
      volumeSize: volumeSize,
      voxelSize: voxelSize,
      useVolumeMirrorX: useVolumeMirrorX,
      alphaScale: alphaScale,
      dtScale: dtScale,
      interactionSpeedup: interactionSpeedup,
      transferFunctionTex: transferFunctionTexRef.current,
      finalGamma: finalGamma,
      useLighting: useLighting,
      useSurface: useSurface,
      surfaceMesh: swcSurfaceMesh,
      surfaceColor: surfaceColor,
      onCameraChange: onCameraChangeTest,
      onWebGLRender: onWebGLRender
    });
    bottom = /*#__PURE__*/_react.default.createElement("div", {
      className: "Controls"
    }, "Data peak\xA0", /*#__PURE__*/_react.default.createElement("input", {
      className: "Control",
      type: "number",
      value: peak,
      min: "0",
      max: "255",
      step: "1",
      onChange: onPeakChange
    }), "\xA0 Data \u03B3\xA0", /*#__PURE__*/_react.default.createElement("input", {
      className: "Control",
      type: "number",
      value: dataGamma,
      min: "0",
      max: "6",
      step: "0.01",
      onChange: onDataGammaChange
    }), "Data \u03B1 scale\xA0", /*#__PURE__*/_react.default.createElement("input", {
      className: "Control",
      type: "number",
      value: alphaScale,
      min: "0.01",
      max: "1",
      step: "0.01",
      onChange: onAlphaScaleChange
    }), "\xA0 Sample spacing\xA0", /*#__PURE__*/_react.default.createElement("input", {
      className: "Control",
      type: "number",
      value: dtScale,
      min: "0.1",
      max: "10",
      step: "0.1",
      onChange: onDtScaleChange
    }), "\xA0 Interaction speedup\xA0", /*#__PURE__*/_react.default.createElement("input", {
      className: "Control",
      type: "number",
      value: interactionSpeedup,
      min: "1",
      max: "20",
      step: "1",
      onChange: onInteractionSpeedupChange
    }), "\xA0 Final \u03B3\xA0", /*#__PURE__*/_react.default.createElement("input", {
      className: "Control",
      type: "number",
      value: finalGamma,
      min: "0.1",
      max: "1000",
      step: "0.1",
      onChange: onFinalGammaChange
    }));
  }

  return /*#__PURE__*/_react.default.createElement("div", {
    className: "BasicUI"
  }, /*#__PURE__*/_react.default.createElement("div", {
    className: "Controls"
  }, /*#__PURE__*/_react.default.createElement("div", {
    className: "InputControl"
  }, "H5J\xA0", /*#__PURE__*/_react.default.createElement("input", {
    type: "color",
    value: dataColor,
    onChange: onDataColorInputChange
  }), "\xA0", /*#__PURE__*/_react.default.createElement(_FileOrURLInput.default, {
    accept: ".h5j",
    onChange: onDataFileInputChange
  })), "\xA0", /*#__PURE__*/_react.default.createElement("div", {
    className: "InputControl"
  }, "SWC\xA0", /*#__PURE__*/_react.default.createElement("input", {
    type: "color",
    value: surfaceColor,
    onChange: onSurfaceColorInputChange,
    disabled: !dataUint8
  }), "\xA0", /*#__PURE__*/_react.default.createElement(_FileOrURLInput.default, {
    accept: ".swc,.obj",
    onChange: onSurfaceFileInputChange,
    disabled: !dataUint8
  }))), /*#__PURE__*/_react.default.createElement("div", {
    className: "Middle",
    tabIndex: 0,
    onKeyPress: onKeyPress,
    role: "link"
  }, middle), bottom);
}

var _default = H5j3dViewerWithBasicUI;
exports.default = _default;