"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports["default"] = exports.ImageColorPicker = void 0;
var _react = _interopRequireDefault(require("react"));
var _propTypes = _interopRequireDefault(require("prop-types"));
var _pointerEvent = require("../../../../../Utils/Events/pointerEvent");
var _ResizeDetect = require("../../../../../Shared/HOCs/ResizeDetect/ResizeDetect");
var _Selectors = require("../../../../Reducers/DesignArea/Selectors");
var _Progress = _interopRequireDefault(require("../../../../Shared/Components/Progress/Progress"));
function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _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(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t["return"] && (u = t["return"](), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
function _arrayWithHoles(r) { if (Array.isArray(r)) return r; }
function _classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }
function _defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, _toPropertyKey(o.key), o); } }
function _createClass(e, r, t) { return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; }
function _inherits(t, e) { if ("function" != typeof e && null !== e) throw new TypeError("Super expression must either be null or a function"); t.prototype = Object.create(e && e.prototype, { constructor: { value: t, writable: !0, configurable: !0 } }), Object.defineProperty(t, "prototype", { writable: !1 }), e && _setPrototypeOf(t, e); }
function _setPrototypeOf(t, e) { return _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function (t, e) { return t.__proto__ = e, t; }, _setPrototypeOf(t, e); }
function _createSuper(t) { var r = _isNativeReflectConstruct(); return function () { var e, o = _getPrototypeOf(t); if (r) { var s = _getPrototypeOf(this).constructor; e = Reflect.construct(o, arguments, s); } else e = o.apply(this, arguments); return _possibleConstructorReturn(this, e); }; }
function _possibleConstructorReturn(t, e) { if (e && ("object" == _typeof(e) || "function" == typeof e)) return e; if (void 0 !== e) throw new TypeError("Derived constructors may only return object or undefined"); return _assertThisInitialized(t); }
function _assertThisInitialized(e) { if (void 0 === e) throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); return e; }
function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); }
function _getPrototypeOf(t) { return _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function (t) { return t.__proto__ || Object.getPrototypeOf(t); }, _getPrototypeOf(t); }
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
function getColorAt(ctx, x, y) {
  var p = ctx.getImageData(x, y, 1, 1).data;
  return {
    rgba: {
      r: p[0],
      g: p[1],
      b: p[2],
      a: p[3]
    },
    hex: (0, _Selectors.rgbToHex)(p[0], p[1], p[2])
  };
}

/**
 * Saves the imageData of the source context, and returns a function which can clear the
 * given area and restore the original data.
 * @param sourceCtx
 * @returns {function(*, *=, *=, *=, *=)}
 */
var createAreaClearer = function createAreaClearer(sourceCtx) {
  var imageData;
  if (sourceCtx) {
    var _sourceCtx$canvas = sourceCtx.canvas,
      width = _sourceCtx$canvas.width,
      height = _sourceCtx$canvas.height;
    imageData = sourceCtx.getImageData(0, 0, width, height);
  }
  return function (ctx, x, y, w, h) {
    ctx.clearRect(x, y, w, h);
    imageData && ctx.putImageData(imageData, 0, 0, x, y, w + 1, h + 1);
  };
};

/**
 * By default the indicator is shown on the left side, but if the user moves the pointer close to it,
 * it jumps to the right side.
 * @param ctx
 * @param x
 * @param y
 * @returns {{size: number, offsetX: number, offsetY: number}}
 */
var getIndicatorPosition = function getIndicatorPosition(ctx, x, y) {
  var offsetX = 10;
  var offsetY = 10;
  var size = 50;
  var tolerance = 50;
  if (x < offsetX + size + tolerance && y < offsetY + size + tolerance) {
    offsetX = ctx.canvas.width - offsetX - size;
  }
  return {
    size: size,
    offsetX: offsetX,
    offsetY: offsetY
  };
};

/**
 * Draws the indicator on the given context depending on the mouse position (x, y).
 * It returns the dirty area as an array to clear: [x, y, size].
 * @param ctx
 * @param x
 * @param y
 * @returns {[number,number,number]}
 */
var drawIndicator = function drawIndicator(ctx, x, y) {
  var _getIndicatorPosition = getIndicatorPosition(ctx, x, y),
    offsetX = _getIndicatorPosition.offsetX,
    offsetY = _getIndicatorPosition.offsetY,
    size = _getIndicatorPosition.size;
  var lineWidth = 2;
  var shadowBlur = 1;
  ctx.fillStyle = "rgba(".concat(Object.values(getColorAt(ctx, x, y).rgba), ")");
  ctx.fillRect(offsetX, offsetY, size, size);
  ctx.lineWidth = lineWidth;
  ctx.strokeStyle = 'white';
  ctx.shadowColor = 'black';
  ctx.shadowBlur = shadowBlur;
  ctx.strokeRect(offsetX, offsetY, size, size);
  var padding = lineWidth + shadowBlur;
  return [offsetX - padding, offsetY - padding, size + 2 * padding];
};

/**
 * Draws the marker circle on the given context (from the center x and y).
 * It returns the dirty area as an array to clear: [x, y, size].
 * @param ctx
 * @param x
 * @param y
 * @returns {[number,number,number]}
 */
var drawMarker = function drawMarker(ctx, x, y) {
  var lineWidth = 2;
  var shadowBlur = 1;
  var size = 5;
  var posOffset = shadowBlur / 2;
  ctx.strokeStyle = 'white';
  ctx.lineWidth = lineWidth;
  ctx.shadowBlur = shadowBlur;
  ctx.shadowColor = 'black';
  ctx.beginPath();
  ctx.arc(x + posOffset, y + posOffset, size, 0, 2 * Math.PI);
  ctx.stroke();
  var padding = Math.ceil(lineWidth + shadowBlur + size);
  return [x - padding, y - padding, (padding + shadowBlur) * 2];
};
var ImageColorPicker = exports.ImageColorPicker = /*#__PURE__*/function (_React$Component) {
  _inherits(ImageColorPicker, _React$Component);
  var _super = _createSuper(ImageColorPicker);
  function ImageColorPicker() {
    var _this;
    _classCallCheck(this, ImageColorPicker);
    for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
      args[_key] = arguments[_key];
    }
    _this = _super.call.apply(_super, [this].concat(args));
    _defineProperty(_assertThisInitialized(_this), "state", {
      loadingImage: false
    });
    _defineProperty(_assertThisInitialized(_this), "canvasRef", /*#__PURE__*/_react["default"].createRef());
    _defineProperty(_assertThisInitialized(_this), "reportError", function (e) {
      // eslint-disable-next-line no-console
      console.error(e);
      var onError = _this.props.onError;
      onError && onError(e);
    });
    _defineProperty(_assertThisInitialized(_this), "redrawMarker", function (evt) {
      return setTimeout(function () {
        var _this$getRelativePosi = _this.getRelativePosition(evt),
          x = _this$getRelativePosi.x,
          y = _this$getRelativePosi.y;
        if (_this.indicatorPosition) {
          var _this$indicatorPositi = _slicedToArray(_this.indicatorPosition, 3),
            _x = _this$indicatorPositi[0],
            _y = _this$indicatorPositi[1],
            size = _this$indicatorPositi[2];
          _this.clearArea(_this.ctx, _x, _y, size, size);
        }
        if (_this.markerPosition) {
          var _this$markerPosition = _slicedToArray(_this.markerPosition, 3),
            _x2 = _this$markerPosition[0],
            _y2 = _this$markerPosition[1],
            _size = _this$markerPosition[2];
          _this.clearArea(_this.ctx, _x2, _y2, _size, _size);
        }
        _this.markerPosition = drawMarker(_this.ctx, x, y);
        _this.indicatorPosition = drawIndicator(_this.ctx, x, y);
      });
    });
    return _this;
  }
  _createClass(ImageColorPicker, [{
    key: "componentDidMount",
    value: function componentDidMount() {
      var _this2 = this;
      var src = this.props.src;
      if (src) {
        this.loadImage(src);
      }
      var canvas = this.canvasRef.current;
      this.ctx = canvas.getContext('2d');
      this.removeStartListener = (0, _pointerEvent.createPointerEventListener)(canvas, 'start', function (evt) {
        if (!_this2.props.enabled || !_this2.img) {
          return;
        }
        evt.preventDefault();
        _this2.redrawMarker(evt);
        var removeMoveListener = (0, _pointerEvent.createPointerEventListener)(canvas, 'move', _this2.redrawMarker);
        var removeEndListener = (0, _pointerEvent.createPointerEventListener)(canvas, 'end', function (evt) {
          removeMoveListener();
          removeEndListener();
          var onChange = _this2.props.onChange;
          var _this2$getRelativePos = _this2.getRelativePosition(evt),
            x = _this2$getRelativePos.x,
            y = _this2$getRelativePos.y;
          onChange && onChange(getColorAt(_this2.ctx, x, y));
        });
      });
    }
  }, {
    key: "componentWillUnmount",
    value: function componentWillUnmount() {
      this.removeStartListener();
    }
  }, {
    key: "componentDidUpdate",
    value: function componentDidUpdate(prevProps) {
      var _this$props = this.props,
        src = _this$props.src,
        size = _this$props.size;
      if (prevProps.src !== src) {
        src && this.loadImage(src);
      }
      if (prevProps.size !== size) {
        this.updateCanvas();
      }
    }
  }, {
    key: "loadImage",
    value: function loadImage(src) {
      var _this3 = this;
      this.currentSrc = src;
      this.setState({
        loadingImage: true
      });
      var img = document.createElement('img');
      img.crossOrigin = 'anonymous';
      img.onload = function () {
        // skip if the src is outdated
        if (_this3.currentSrc !== src) {
          return;
        }
        _this3.img = img;
        _this3.setState({
          loadingImage: false
        });
        _this3.updateCanvas();
      };
      img.onerror = function (e) {
        _this3.setState({
          loadingImage: false
        });
        _this3.reportError(e);
      };
      img.src = src;
    }
  }, {
    key: "updateCanvas",
    value: function updateCanvas() {
      var img = this.img;
      var canvas = this.canvasRef.current;
      if (!canvas || !img) {
        return;
      }
      var container = canvas.parentElement;
      var _container$getBoundin = container.getBoundingClientRect(),
        pw = _container$getBoundin.width,
        ph = _container$getBoundin.height;
      var ow = img.width,
        oh = img.height;
      if (ow / oh <= pw / ph) {
        var height = ph;
        var width = height * (ow / oh);
        this.updateCanvasDimensionsAndContent(canvas, img, width, height);
      } else {
        var _width = pw;
        var _height = _width * (oh / ow);
        this.updateCanvasDimensionsAndContent(canvas, img, _width, _height);
      }
      try {
        this.clearArea = createAreaClearer(this.ctx);
      } catch (e) {
        this.reportError(e);
      }
    }
  }, {
    key: "updateCanvasDimensionsAndContent",
    value: function updateCanvasDimensionsAndContent(canvas, img, width, height) {
      Object.assign(canvas, {
        width: width,
        height: height
      });
      this.ctx.clearRect(0, 0, width, height);
      this.ctx.drawImage(img, 0, 0, width, height);
    }
  }, {
    key: "getRelativePosition",
    value: function getRelativePosition(evt) {
      var canvas = this.canvasRef.current;
      var _canvas$getBoundingCl = canvas.getBoundingClientRect(),
        offsetX = _canvas$getBoundingCl.left,
        offsetY = _canvas$getBoundingCl.top;
      var _getPointFromPointerE = (0, _pointerEvent.getPointFromPointerEvent)(evt),
        eX = _getPointFromPointerE.x,
        eY = _getPointFromPointerE.y;
      var x = eX - offsetX;
      var y = eY - offsetY;
      return {
        x: x,
        y: y
      };
    }
  }, {
    key: "render",
    value: function render() {
      var className = this.props.className;
      var loadingImage = this.state.loadingImage;
      return /*#__PURE__*/_react["default"].createElement(_react["default"].Fragment, null, /*#__PURE__*/_react["default"].createElement(_Progress["default"], {
        loading: loadingImage
      }), /*#__PURE__*/_react["default"].createElement("canvas", {
        ref: this.canvasRef,
        className: className
      }));
    }
  }]);
  return ImageColorPicker;
}(_react["default"].Component);
_defineProperty(ImageColorPicker, "defaultProps", {
  enabled: true
});
var _default = exports["default"] = (0, _ResizeDetect.withResizeDetectWrapper)(ImageColorPicker);