import _regeneratorRuntime from "@babel/runtime/regenerator";

function _createForOfIteratorHelperLoose(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (it) return (it = it.call(o)).next.bind(it); if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; return function () { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }; } throw new TypeError("Invalid attempt to iterate 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 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 _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }

function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; _setPrototypeOf(subClass, superClass); }

function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }

function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }

function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }

import PipeHolistic from '@mediapipe/holistic';
import { drawLandmarks, drawConnectors, lerp } from '@mediapipe/drawing_utils';
import { Camera } from '@mediapipe/camera_utils';
import { HolisticAngleCalculator, HolisticPoseValidator } from "./index";

var Holistic = PipeHolistic.Holistic,
    mpHolistic = _objectWithoutPropertiesLoose(PipeHolistic, ["Holistic"]);

var activeEffect = 'mask';

var MediaPipeHolistic = /*#__PURE__*/function (_HolisticAngleCalcula) {
  _inheritsLoose(MediaPipeHolistic, _HolisticAngleCalcula);

  function MediaPipeHolistic(videoRef, canvasRef, props) {
    var _this;

    _this = _HolisticAngleCalcula.call(this) || this;

    _defineProperty(_assertThisInitialized(_this), "angleValue", 0);

    _this.video = videoRef;
    _this.canvas = canvasRef;
    _this.props = props;
    _this.holisticPoseValidator = new HolisticPoseValidator();

    if (!MediaPipeHolistic._instance) {
      _this.setup();

      MediaPipeHolistic._instance = _assertThisInitialized(_this);
    }

    return MediaPipeHolistic._instance || _assertThisInitialized(_this);
  }

  MediaPipeHolistic.getInstance = function getInstance() {
    return this._instance;
  };

  var _proto = MediaPipeHolistic.prototype;

  _proto.updateProps = function updateProps(newProps) {
    this.props = newProps;
  };

  _proto.setup = function setup() {
    this.holistic = new Holistic({
      locateFile: function locateFile(file) {
        return "https://cdn.jsdelivr.net/npm/@mediapipe/holistic/" + file;
      },
      prefix: false
    });
    this.holistic.setOptions({
      enableFaceGeometry: false,
      selfieMode: false,
      modelComplexity: 1,
      smoothLandmarks: true,
      enableSegmentation: false,
      smoothSegmentation: true,
      minDetectionConfidence: 0.5,
      minTrackingConfidence: 0.5
    });
    this.holistic.onResults(this.__onResults.bind(this));
    this.setupCamera();
  };

  _proto.setupCamera = function setupCamera() {
    var _this2 = this;

    var camera = new Camera(this.video, {
      onFrame: function () {
        var _onFrame = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
          return _regeneratorRuntime.wrap(function _callee$(_context) {
            while (1) {
              switch (_context.prev = _context.next) {
                case 0:
                  _context.next = 2;
                  return _this2.holistic.send({
                    image: _this2.video
                  });

                case 2:
                case "end":
                  return _context.stop();
              }
            }
          }, _callee);
        }));

        function onFrame() {
          return _onFrame.apply(this, arguments);
        }

        return onFrame;
      }(),
      width: 1280,
      height: 720
    });
    camera.start().then(function () {
      if (_this2.props.loading) _this2.props.onLoading();
    });
  };

  _proto.connect = function connect(ctx, connectors) {
    var canvas = ctx.canvas;

    for (var _iterator = _createForOfIteratorHelperLoose(connectors), _step; !(_step = _iterator()).done;) {
      var connector = _step.value;
      var from = connector[0];
      var to = connector[1];

      if (from && to) {
        if (from.visibility && to.visibility && (from.visibility < 0.1 || to.visibility < 0.1)) {
          continue;
        }

        ctx.beginPath();
        ctx.moveTo(from.x * canvas.width, from.y * canvas.height);
        ctx.lineTo(to.x * canvas.width, to.y * canvas.height);
        ctx.stroke();
      }
    }
  };

  _proto.removeElements = function removeElements(landmarks, elements) {
    for (var _iterator2 = _createForOfIteratorHelperLoose(elements), _step2; !(_step2 = _iterator2()).done;) {
      var element = _step2.value;
      delete landmarks[element];
    }
  };

  _proto.removeLandmarks = function removeLandmarks(results) {
    if (results.poseLandmarks) {
      this.removeElements(results.poseLandmarks, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 16, 17, 18, 19, 20, 21, 22]);
    }
  };

  _proto.__onResults = function __onResults(results) {
    // document.body.classList.add('loaded');
    var canvasCtx = this.canvas.getContext('2d'); // Remove landmarks we don't want to draw.

    if (results.poseLandmarks) {
      this.removeLandmarks(results);
    } // Update the frame rate.
    // fpsControl.tick();
    // this.canvas.width, this.canvas.height
    // Draw the overlays.


    var width = this.canvas.width;
    var height = this.canvas.height;
    canvasCtx.save();
    canvasCtx.clearRect(0, 0, width, height);

    if (results.segmentationMask) {
      canvasCtx.drawImage(results.segmentationMask, 0, 0, width, height); // Only overwrite existing pixels.

      if (activeEffect === 'mask' || activeEffect === 'both') {
        canvasCtx.globalCompositeOperation = 'source-in'; // This can be a color or a texture or whatever...

        canvasCtx.fillStyle = '#00FF007F';
        canvasCtx.fillRect(0, 0, width, height);
      } else {
        canvasCtx.globalCompositeOperation = 'source-out';
        canvasCtx.fillStyle = '#0000FF7F';
        canvasCtx.fillRect(0, 0, width, height);
      } // Only overwrite missing pixels.


      canvasCtx.globalCompositeOperation = 'destination-atop';
      canvasCtx.drawImage(results.image, 0, 0, width, height);
      canvasCtx.globalCompositeOperation = 'source-over';
    } else {
      canvasCtx.drawImage(results.image, 0, 0, width, height);
    } // Connect elbows to hands. Do this first so that the other graphics will draw
    // on top of these marks.


    canvasCtx.lineWidth = 5;

    if (results.poseLandmarks) {
      var _this$props$currentEx;

      if (results.rightHandLandmarks) {
        canvasCtx.strokeStyle = 'white';
        this.connect(canvasCtx, [[results.poseLandmarks[mpHolistic.POSE_LANDMARKS.RIGHT_ELBOW], results.rightHandLandmarks[0]]]);
      }

      if (results.leftHandLandmarks) {
        canvasCtx.strokeStyle = 'white';
        this.connect(canvasCtx, [[results.poseLandmarks[mpHolistic.POSE_LANDMARKS.LEFT_ELBOW], results.leftHandLandmarks[0]]]);
      }

      if ((_this$props$currentEx = this.props.currentExercise) === null || _this$props$currentEx === void 0 ? void 0 : _this$props$currentEx.key) {
        var _this$props$currentEx2;

        var resultObject = this.holisticPoseValidator.visiblePoints((_this$props$currentEx2 = this.props.currentExercise) === null || _this$props$currentEx2 === void 0 ? void 0 : _this$props$currentEx2.key, results);
        this.props.onBodyPartNotVisible(resultObject);
        this.angleValue = this.calculate(this.props.currentExercise.key, results);
        this.props.onExerciseValue(this.angleValue.toFixed(2));
      } // Pose...


      drawConnectors(canvasCtx, results.poseLandmarks, mpHolistic.POSE_CONNECTIONS, {
        color: 'white'
      });
      drawLandmarks(canvasCtx, Object.values(mpHolistic.POSE_LANDMARKS_LEFT).map(function (index) {
        return results.poseLandmarks[index];
      }), {
        visibilityMin: 0.65,
        color: 'white',
        fillColor: 'rgb(255,138,0)'
      });
      drawLandmarks(canvasCtx, Object.values(mpHolistic.POSE_LANDMARKS_RIGHT).map(function (index) {
        return results.poseLandmarks[index];
      }), {
        visibilityMin: 0.65,
        color: 'white',
        fillColor: 'rgb(0,217,231)'
      }); // Hands...

      drawConnectors(canvasCtx, results.rightHandLandmarks, mpHolistic.HAND_CONNECTIONS, {
        color: 'white'
      });
      drawLandmarks(canvasCtx, results.rightHandLandmarks, {
        color: 'white',
        fillColor: 'rgb(0,217,231)',
        lineWidth: 2,
        radius: function radius(data) {
          return lerp(data.from.z, -0.15, 0.1, 10, 1);
        }
      });
      drawConnectors(canvasCtx, results.leftHandLandmarks, mpHolistic.HAND_CONNECTIONS, {
        color: 'white'
      });
      drawLandmarks(canvasCtx, results.leftHandLandmarks, {
        color: 'white',
        fillColor: 'rgb(255,138,0)',
        lineWidth: 2,
        radius: function radius(data) {
          return lerp(data.from.z, -0.15, 0.1, 10, 1);
        }
      });
    }

    canvasCtx.restore(); // Face...
    // drawConnectors(
    //   canvasCtx,
    //   results.faceLandmarks,
    //   mpHolistic.FACEMESH_TESSELATION,
    //   { color: '#C0C0C070', lineWidth: 1 }
    // );
    // drawConnectors(
    //   canvasCtx,
    //   results.faceLandmarks,
    //   mpHolistic.FACEMESH_RIGHT_EYE,
    //   { color: 'rgb(0,217,231)' }
    // );
    // drawConnectors(
    //   canvasCtx,
    //   results.faceLandmarks,
    //   mpHolistic.FACEMESH_RIGHT_EYEBROW,
    //   { color: 'rgb(0,217,231)' }
    // );
    // drawConnectors(
    //   canvasCtx,
    //   results.faceLandmarks,
    //   mpHolistic.FACEMESH_LEFT_EYE,
    //   { color: 'rgb(255,138,0)' }
    // );
    // drawConnectors(
    //   canvasCtx,
    //   results.faceLandmarks,
    //   mpHolistic.FACEMESH_LEFT_EYEBROW,
    //   { color: 'rgb(255,138,0)' }
    // );
    // drawConnectors(
    //   canvasCtx,
    //   results.faceLandmarks,
    //   mpHolistic.FACEMESH_FACE_OVAL,
    //   { color: '#E0E0E0', lineWidth: 5 }
    // );
    // drawConnectors(canvasCtx, results.faceLandmarks, mpHolistic.FACEMESH_LIPS, {
    //   color: '#E0E0E0',
    //   lineWidth: 5,
    // });
  };

  return MediaPipeHolistic;
}(HolisticAngleCalculator);

export default MediaPipeHolistic;