"use strict";

function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }

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

var Backbone = _interopRequireWildcard(require("backbone"));

var _namespace = _interopRequireDefault(require("../utils/namespace"));

var _collMeasures = _interopRequireDefault(require("../data/coll-measures"));

require("../mei/meiprocessing");

var _svgprocessing = _interopRequireDefault(require("../utils/svgprocessing"));

var _backboneEvents = _interopRequireDefault(require("../utils/backbone-events"));

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

function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }

function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { "default": obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj["default"] = obj; if (cache) { cache.set(obj, newObj); } return newObj; }

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }

function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }

function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }

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

function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }

function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } else if (call !== void 0) { throw new TypeError("Derived constructors may only return object or undefined"); } return _assertThisInitialized(self); }

function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }

function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }

function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }

var $ = require('jquery');

require('../../../lib/jquery-xpath/jquery.xpath');

// Note on Variable Prefixes
// $varname is a jQuery object
// XPvarname is an XPath object
var VerovioInteractionView = /*#__PURE__*/function (_Backbone$View) {
  _inherits(VerovioInteractionView, _Backbone$View);

  var _super = _createSuper(VerovioInteractionView);

  function VerovioInteractionView() {
    _classCallCheck(this, VerovioInteractionView);

    return _super.apply(this, arguments);
  }

  _createClass(VerovioInteractionView, [{
    key: "events",
    value: function events() {
      return {
        'mousedown svg': 'startSelect',
        'mousemove': 'areaSelect',
        'mouseup': 'stopSelect',
        'mousedown g.cnt-selectable': 'startSelect'
      };
    }
  }, {
    key: "initialize",
    value: function initialize() {
      this.$MEIdata = $(this.model.get("doc"));
      this.measures = new _collMeasures["default"](); // Flags for monitoring clicks and drags.

      this.selecting = false;
      this.dragging = false;
    }
  }, {
    key: "addMusEvent",
    value: function addMusEvent($svg_el) {
      var $mei_el = $svg_el.parent();
      var ev_id = $mei_el.attr("id");
      this.addMusEventFromId(ev_id);
      var XPevent = this.$MEIdata.xpath("//*[@xml:id='" + ev_id + "']");

      if (!$mei_el.hasClass("cnt-selected")) {
        $mei_el.addClass("cnt-selected");
        this.addMEIEvent(XPevent);
      }
    }
  }, {
    key: "addMusEventFromId",
    value: function addMusEventFromId(ev_id) {
      this.trigger("selectElement", ev_id);
      var XPevent = this.$MEIdata.xpath("//*[@xml:id='" + ev_id + "']"); // highlight it if it can be found.

      var $mei_el = this.$el.find('#' + ev_id);

      if ($mei_el.length > 0) {
        if (!$mei_el.hasClass("cnt-selected")) {
          $mei_el.addClass("cnt-selected");
        }
      }

      this.addMEIEvent(XPevent);
    }
  }, {
    key: "addMEIEvent",
    value: function addMEIEvent(XPevent) {
      var XPmeasure = XPevent.xpath("ancestor::mei:measure[1]", _namespace["default"]);
      var measure_id = XPmeasure.xpath('@xml:id').val();
      var XPstaff = XPevent.xpath("ancestor::mei:staff[1]", _namespace["default"]); // Make sure this is an event on staff, ie we can calculate its beat later.

      if (Object.keys(XPstaff).length === 0) return null;
      var staff_id = XPstaff.xpath('@xml:id').val();
      var measure_idx = XPmeasure.xpath("preceding::mei:measure[ancestor::mei:music]", _namespace["default"]).length + 1;
      var measure = this.measures.get(measure_id);

      if (!measure) {
        measure = this.measures.add({
          "measure": XPmeasure,
          "id": measure_id,
          "index": measure_idx
        });
      }

      var staves = measure.get("staves");
      var staff = staves.get(staff_id);
      var staff_idx = XPstaff.xpath("preceding-sibling::mei:staff", _namespace["default"]).length + 1;

      if (!staff) {
        staff = staves.add({
          "staff": XPstaff,
          "id": staff_id,
          "index": staff_idx
        });
      }

      var beats = staff.get("beats");
      var beat = XPevent.getEventBeat();
      var storedBeat = beats.filter(function (b) {
        return b.get("value") === beat;
      });

      if (storedBeat.length == 0) {
        beats.add({
          "event": XPevent.xpath('@xml:id').val(),
          "value": beat
        });
      }

      var emaExpr = this.measures.generateOptimizedEMAExpr();
      this.trigger('component:emaBox', emaExpr);
    }
  }, {
    key: "clearMusEvents",
    value: function clearMusEvents() {
      this.measures.reset();
      this.trigger('component:emaBox', "");
    }
  }, {
    key: "removeMusEvent",
    value: function removeMusEvent($mei_el) {
      $mei_el = $mei_el.parent();
      var ev_id = $mei_el.attr("id");
      this.trigger("deselectElement", ev_id);
      var XPevent = this.$MEIdata.xpath("//*[@xml:id='" + ev_id + "']");

      if ($mei_el.hasClass("cnt-selected")) {
        $mei_el.removeClass("cnt-selected");
        var event_id = XPevent.xpath('@xml:id').val();
        var XPmeasure = XPevent.xpath("ancestor::mei:measure[1]", _namespace["default"]);
        var measure_id = XPmeasure.xpath('@xml:id').val();
        var XPstaff = XPevent.xpath("ancestor::mei:staff[1]", _namespace["default"]);
        var staff_id = XPstaff.xpath('@xml:id').val();
        var beat = XPevent.getDurationToMeter();
        var measure = this.measures.get(measure_id);
        var staves = measure.get("staves");
        var staff = staves.get(staff_id);
        var beats = staff.get("beats");
        var storedBeat = beats.filter(function (b) {
          return b.get("event") === event_id;
        });

        if (storedBeat.length == 1) {
          beats.remove(storedBeat);
        } else {
          // not tested
          var _storedBeat = beats.filter(function (b) {
            return b.get("value") === beat;
          });

          beats.remove(_storedBeat);
        } // Remove staff if it contains no more beats


        if (beats.length == 0) {
          staves.remove(staff_id);
        } // Remove measure if it contains no more staves


        if (staves.length == 0) {
          this.measures.remove(measure_id);
        }

        var emaExpr = this.measures.generateOptimizedEMAExpr();
        this.trigger('component:emaBox', emaExpr);
      } else {//noop
      }
    }
  }, {
    key: "startSelect",
    value: function startSelect(e) {
      e.preventDefault();
      this.selecting = true;
      var $ct = $(e.currentTarget);

      if ($ct.is("g.cnt-selectable")) {
        // remove on Ctrl or ⌘.
        if (e.ctrlKey || e.metaKey) {
          this.removeMusEvent($ct);
        } else {
          this.addMusEvent($ct);
        }
      }
    }
  }, {
    key: "areaSelect",
    value: function areaSelect(e) {
      e.preventDefault();

      if (this.selecting) {
        this.dragging = true;

        var vrv_page = _svgprocessing["default"].getSVGRoot(e.target);

        var s = $(vrv_page).find(".cnt-areaSel");

        var loc = _svgprocessing["default"].getSVGCoordinates({
          "x": e.clientX,
          "y": e.clientY
        }, vrv_page);

        if (s.length > 0) {
          var d = {
            "x": parseInt(s.attr("x")),
            "y": parseInt(s.attr("y")),
            "width": parseInt(s.attr("width")),
            "height": parseInt(s.attr("height"))
          },
              move = {
            "x": loc.x - d.x,
            "y": loc.y - d.y
          };

          if (move.x < 1 || move.x * 2 < d.width) {
            d.x = loc.x;
            d.width -= move.x;
          } else {
            d.width = move.x;
          }

          if (move.y < 1 || move.y * 2 < d.height) {
            d.y = loc.y;
            d.height -= move.y;
          } else {
            d.height = move.y;
          }

          s.attr(d);
        } else {
          var rect_attrs = {
            "rx": 6,
            "ry": 6,
            "class": "cnt-areaSel",
            "x": loc.x,
            "y": loc.y,
            "width": 0,
            "height": 0
          };

          var rect = _svgprocessing["default"].makeSVGEl("rect", rect_attrs);

          vrv_page.appendChild(rect);
        }
      }
    }
  }, {
    key: "stopSelect",
    value: function stopSelect(e) {
      var _this = this;

      e.preventDefault();

      if (this.dragging) {
        var vrv_page = _svgprocessing["default"].getSVGRoot(e.target); // Find selectable elements intersecting the selection rectangle


        var s = $(vrv_page).find(".cnt-areaSel");
        var d = {
          "x": parseInt(s.attr("x")),
          "y": parseInt(s.attr("y")),
          "width": parseInt(s.attr("width")),
          "height": parseInt(s.attr("height"))
        };
        d.right = d.x + d.width;
        d.bottom = d.y + d.height;
        $(vrv_page).find("g.cnt-selectable").each(function (i, ev) {
          var bcr = ev.getBoundingClientRect();
          var ev_rect = {}; // We need to transform this according to the hosting SVG

          var pt_tl = _svgprocessing["default"].getSVGCoordinates({
            "x": bcr.left,
            "y": bcr.top
          }, vrv_page);

          ev_rect.left = pt_tl.x;
          ev_rect.top = pt_tl.y;

          var pt_br = _svgprocessing["default"].getSVGCoordinates({
            "x": bcr.right,
            "y": bcr.bottom
          }, vrv_page);

          ev_rect.right = pt_br.x;
          ev_rect.bottom = pt_br.y;

          if (ev_rect.left >= d.x && ev_rect.left <= d.right && ev_rect.top >= d.y && ev_rect.top <= d.bottom && ev_rect.right >= d.x && ev_rect.right <= d.right && ev_rect.bottom >= d.y && ev_rect.bottom <= d.bottom) {
            // remove on Ctrl or ⌘.
            if (e.ctrlKey || e.metaKey) {
              _this.removeMusEvent($(ev));
            } else {
              _this.addMusEvent($(ev));
            }
          }
        }); // Remove selection rectangle

        s.remove();
      } // Reset mouse flags.


      this.selecting = false;
      this.dragging = false;
    }
  }]);

  return VerovioInteractionView;
}(Backbone.View);

var _default = VerovioInteractionView;
exports["default"] = _default;