System.register(['src/components/widgets/lively-morph.js', 'src/client/morphic/node-helpers.js', 'src/client/morphic/event-helpers.js', 'src/client/morphic/selecting.js', 'src/client/graphics.js', 'src/client/preferences.js', 'src/client/morphic/snapping.js', 'src/client/morphic/dragbehavior.js', 'src/client/svg.js'], function (_export, _context) {
  "use strict";

  var Morph, nodes, events, selecting, pt, rect, Rectangle, preferences, Grid, DragBehavior, svg;
  return {
    setters: [function (_srcComponentsWidgetsLivelyMorphJs) {
      Morph = _srcComponentsWidgetsLivelyMorphJs.default;
    }, function (_srcClientMorphicNodeHelpersJs) {
      nodes = _srcClientMorphicNodeHelpersJs;
    }, function (_srcClientMorphicEventHelpersJs) {
      events = _srcClientMorphicEventHelpersJs;
    }, function (_srcClientMorphicSelectingJs) {
      selecting = _srcClientMorphicSelectingJs.default;
    }, function (_srcClientGraphicsJs) {
      pt = _srcClientGraphicsJs.pt;
      rect = _srcClientGraphicsJs.rect;
      Rectangle = _srcClientGraphicsJs.Rectangle;
    }, function (_srcClientPreferencesJs) {
      preferences = _srcClientPreferencesJs.default;
    }, function (_srcClientMorphicSnappingJs) {
      Grid = _srcClientMorphicSnappingJs.Grid;
    }, function (_srcClientMorphicDragbehaviorJs) {
      DragBehavior = _srcClientMorphicDragbehaviorJs.default;
    }, function (_srcClientSvgJs) {
      svg = _srcClientSvgJs.default;
    }],
    execute: function () {
      _recorder_._src_components_halo_lively_halo_js = _recorder_._src_components_halo_lively_halo_js || {};
      _recorder_._src_components_halo_lively_halo_js.Morph = Morph;
      _recorder_._src_components_halo_lively_halo_js.nodes = nodes;
      _recorder_._src_components_halo_lively_halo_js.events = events;
      _recorder_._src_components_halo_lively_halo_js.selecting = selecting;
      _recorder_._src_components_halo_lively_halo_js.Rectangle = Rectangle;
      _recorder_._src_components_halo_lively_halo_js.rect = rect;
      _recorder_._src_components_halo_lively_halo_js.pt = pt;
      _recorder_._src_components_halo_lively_halo_js.preferences = preferences;
      _recorder_._src_components_halo_lively_halo_js.Grid = Grid;
      _recorder_._src_components_halo_lively_halo_js.DragBehavior = DragBehavior;
      _recorder_._src_components_halo_lively_halo_js.svg = svg;


      /* globals Halo, that, HaloService */

      let svgStrategy = {
        match(target) {
          return target instanceof SVGSVGElement || target instanceof SVGElement;
        },

        configureHalo(halo) {
          halo.setHandleVisibility(true);

          this.querySelectorAll(':not(marker)>path').forEach(ea => {
            _recorder_._src_components_halo_lively_halo_js.svg.getPathVertices(ea).forEach((p, index) => {
              halo.ensureControlPoint(ea, index);
              if (p.c == 'Q') {
                halo.ensureControlPoint(ea, index, false, 2);
              }
            });
          });
        },

        dragBehaviorStart(halo, evt, pos) {
          evt.preventDefault();
          evt.stopPropagation();
        },
        dragBehaviorMove(halo, evt, pos) {}
      };

      _recorder_._src_components_halo_lively_halo_js.svgStrategy = svgStrategy;
      let defaultStrategy = {
        match(target) {
          return true;
        },

        configureHalo(halo) {},

        dragBehaviorStart(halo, evt, pos) {
          halo.dragOffset = lively.getPosition(this).subPt(pos);
          halo.alignHaloToBounds(this);
        },
        dragBehaviorMove(halo, evt, pos) {
          lively.setPosition(this, pos.addPt(halo.dragOffset));
          halo.alignHaloToBounds(this);
        }
      };

      _recorder_._src_components_halo_lively_halo_js.defaultStrategy = defaultStrategy;
      let fallbackStrategies = [_recorder_._src_components_halo_lively_halo_js.svgStrategy, _recorder_._src_components_halo_lively_halo_js.defaultStrategy];

      /*
       * Halo, the container for HaloItems
       */
      _recorder_._src_components_halo_lively_halo_js.fallbackStrategies = fallbackStrategies;
      class Halo extends _recorder_._src_components_halo_lively_halo_js.Morph {

        get isMetaNode() {
          return true;
        }
        get haloItems() {
          return this.shadowRoot.querySelectorAll('.halo');
        }

        initialize() {
          this.shadowRoot.querySelectorAll('*').forEach(ea => {
            if (ea.isMetaNode === undefined) ea.isMetaNode = true;
          }
          // #TODO Refeactor away jQuery in Halo
          );_recorder_._src_components_halo_lively_halo_js.Halo.instance = this;
          this.hidden = true;
          window.HaloService = _recorder_._src_components_halo_lively_halo_js.Halo;
          var targetContext = document.body.parentElement;

          lively.removeEventListener('Halo', document.body);
          lively.addEventListener('Halo', document.body, 'pointerdown', evt => this.onBodyMouseDown(evt, targetContext));

          this.haloItems.forEach(ea => ea.halo = this);
          _recorder_._src_components_halo_lively_halo_js.DragBehavior.on(this);
        }

        onBodyMouseDown(evt, targetContext) {
          this.targetContext = targetContext;
          evt.stopPropagation();
          var whitelistNodes = lively.html.findAllNodes // #TODO only find nodes of subelement
          ().filter(ea => ea.tagName == 'INPUT' || ea.tagName == 'LI' || ea.tagName == 'TD' || ea.tagName == 'P' || ea.tagName == 'PRE').filter(ea => {
            var b = ea.getBoundingClientRect();
            var bounds = new _recorder_._src_components_halo_lively_halo_js.Rectangle(b.left, b.top, b.width, b.height);
            var pos = _recorder_._src_components_halo_lively_halo_js.events.globalPosition(evt);
            // lively.showPoint(bounds.topLeft())
            // lively.showPoint(pos)
            return bounds.containsPoint(pos);
          });
          // inputFields.forEach( ea => lively.showElement(ea))
          if (whitelistNodes.length > 0) {
            // evt.preventDefault();
            // evt.stopPropagation();
            document.body.draggable = false;
            return false;
          }
          document.body.draggable = true;
        }

        setHandleVisibility(shouldHide) {
          let visibility = shouldHide ? 'hidden' : null;
          this.shadowRoot.querySelectorAll('lively-halo-handle-item').forEach(ea => {
            ea.style.visibility = visibility;
          });
        }

        resetHaloControlPointItem() {
          this.shadowRoot.querySelectorAll('lively-halo-control-point-item').forEach(ea => ea.remove());
        }

        resetHaloConfig() {
          this.resetHaloControlPointItem();

          this.get('#default-items').style.display = null;
          this.get('#vivide-items').style.display = null;

          this.setHandleVisibility(false);

          this.get('#vivide-outport-connection-items').innerHTML = '';
          this.get('#vivide-inport-connection-items').innerHTML = '';
        }

        ensureControlPoint(path, index, isConnector, curveIndex) {
          var id = 'controlPoint' + index + (curveIndex ? '-' + curveIndex : '');
          var controlPoint = this.shadowRoot.querySelector('#' + id);
          if (!controlPoint) {
            controlPoint = document.createElement('lively-halo-control-point-item');
            controlPoint.id = id;
            this.shadowRoot.appendChild(controlPoint);
          }
          controlPoint.isConnector = isConnector;
          controlPoint.curveIndex = curveIndex;
          controlPoint.setup(this, path, index);
          controlPoint.style.visibility = '';
          return controlPoint;
        }

        showHalo(target, path) {
          document.body.appendChild(this);
          lively.html.registerKeys(document.body, 'HaloKeys', this);
          this.hidden = false;
          this.style.display = "";

          if (!target || !target.getBoundingClientRect) {
            return;
          }
          lively.globalFocus();

          this.alignHaloToBounds(target);

          this.resetHaloConfig();
          this.dispatch(target, 'configureHalo');
          this.haloItems.forEach(ea => {
            if (ea.updateTarget) {
              ea.updateTarget(target);
            }
          });
        }

        dispatch(target, methodName, ...args) {
          if (!target) {
            return;
          }

          // instance-specific handling
          if (target && target.livelyHalo) {
            let haloStrategy = target.livelyHalo();
            if (haloStrategy[methodName]) {
              haloStrategy[methodName].call(target, this, ...args);
              return;
            }
          }

          // fallback to generic handlers
          let fallbackStrategy = _recorder_._src_components_halo_lively_halo_js.fallbackStrategies.find(strategy => strategy[methodName] && strategy.match(target));
          if (fallbackStrategy) {
            fallbackStrategy[methodName].call(target, this, ...args);
          } else {
            lively.warn('no halo handler found for ' + methodName);
          }
        }

        alignHaloToBounds(target) {
          const margin = 30;
          var bounds = lively.getGlobalBounds(target);

          var offset = {
            top: bounds.top() + window.scrollY,
            left: bounds.left() + window.scrollX
          };

          // viewport coordinates
          var scrollTop = Math.abs(window.scrollY);
          var scrollLeft = Math.abs(window.scrollX);

          // make sure halo respects left and top viewport boundary
          var offsetTop = Math.max(offset.top - margin, scrollTop);
          var offsetLeft = Math.max(offset.left - margin, scrollLeft);
          var offsetTopDiff = offsetTop - offset.top;
          var offsetLeftDiff = offsetLeft - offset.left;
          offset.top = offsetTop;
          offset.left = offsetLeft;

          // make sure halo respects right and bottom viewport boundary
          var width = bounds.width - offsetLeftDiff + margin;
          var height = bounds.height - offsetTopDiff + margin;
          var offsetBottom = Math.min(offset.top + height, scrollTop + window.innerHeight);
          var offsetRight = Math.min(offset.left + width, scrollLeft + window.innerWidth);
          width = offsetRight - offsetLeft;
          height = offsetBottom - offsetTop;

          lively.setGlobalPosition(this, _recorder_._src_components_halo_lively_halo_js.pt(offset.left - scrollLeft, offset.top - scrollTop));
          lively.setExtent(this, _recorder_._src_components_halo_lively_halo_js.pt(width, height));

          var boundsRect = lively.getGlobalBounds(that);
          ['topLeft', 'bottomLeft', 'bottomRight', 'topRight'].forEach(ea => {
            lively.setGlobalPosition(this.get('#' + ea), boundsRect[ea]());
          });
        }

        static showHalos(target, path) {
          this.target = target;
          this.instance.showHalo(target, path);
        }

        static hideHalos() {
          if (this.instance.info) {
            this.instance.info.stop();
          }
          lively.removeEventListener('HaloKeys', document.body);
          if (HaloService.lastIndicator) HaloService.lastIndicator.remove();
          if (this.areHalosActive()) this.halosHidden = Date.now();
          lively.setPosition(this.instance, _recorder_._src_components_halo_lively_halo_js.pt(0, 0));
          this.instance.hidden = true;
        }

        static hideHaloItems() {
          this.instance.haloItems.forEach(ea => ea.style.visibility = 'hidden');
        }

        static showHaloItems() {
          this.instance.haloItems.forEach(ea => ea.style.visibility = null);

          // #TODO: this usually called updateHandles
          //this.instance.showHalo(window.that);
        }

        // 
        // Positioning of Elments with arrow keys
        //

        /*
         * Arrow Keys     .... move halo target
         * holding SHIFT  .... resize halo target
         * holding ALT    .... align to in bigger steps to grid (resize and move)
         */
        moveTargetOnEventWithKey(evt, delta) {
          var gridSize = lively.preferences.get('GridSize') * 0.25;
          if (evt.altKey) {
            delta = delta.scaleBy(gridSize);
          }

          if (evt.shiftKey) {
            var newExtent = lively.getExtent(that).addPt(delta);
            lively.setExtent(that, newExtent);

            if (evt.altKey) {
              lively.setExtent(that, _recorder_._src_components_halo_lively_halo_js.Grid.snapPt(lively.getExtent(that), gridSize, gridSize / 2));
            }
          } else {
            lively.moveBy(that, delta);
            if (evt.altKey) {
              lively.setPosition(that, _recorder_._src_components_halo_lively_halo_js.Grid.snapPt(lively.getPosition(that), gridSize, gridSize * 0.5));
            }
          }
          evt.preventDefault();
          evt.stopPropagation();
          this.alignHaloToBounds(that);

          if (this.info) {
            this.info.stop();
          }
          this.info = lively.showInfoBox(that);

          if (that) {
            this.info.innerHTML = `x=${lively.getPosition(that).x} y=${lively.getPosition(that).y} w=${lively.getExtent(that).x} h=${lively.getExtent(that).y}`;
          }
        }

        onLeftDown(evt) {
          this.moveTargetOnEventWithKey(evt, _recorder_._src_components_halo_lively_halo_js.pt(-1, 0));
        }

        onRightDown(evt) {
          this.moveTargetOnEventWithKey(evt, _recorder_._src_components_halo_lively_halo_js.pt(1, 0));
        }

        onUpDown(evt) {
          this.moveTargetOnEventWithKey(evt, _recorder_._src_components_halo_lively_halo_js.pt(0, -1));
        }

        onDownDown(evt) {
          this.moveTargetOnEventWithKey(evt, _recorder_._src_components_halo_lively_halo_js.pt(0, 1));
        }

        // onKeyUp(evt) {
        //   if(this.info) this.info.stop()
        // }

        // Override defdault DragBehavior
        dragBehaviorStart(evt, pos) {
          this.dispatch(that, 'dragBehaviorStart', evt, pos);
        }

        dragBehaviorMove(evt, pos) {
          this.dispatch(that, 'dragBehaviorMove', evt, pos);
        }

        static areHalosActive() {

          return _recorder_._src_components_halo_lively_halo_js.Halo.instance && !_recorder_._src_components_halo_lively_halo_js.Halo.instance.hidden && _recorder_._src_components_halo_lively_halo_js.Halo.instance.style.display !== "none";
        }

        static migrate() {
          var old = document.querySelector('lively-halo');
          if (old) {
            old.remove();
            lively.initializeHalos();
          }
        }
      }

      _export('default', Halo);

      _recorder_._src_components_halo_lively_halo_js.Halo = Halo;
      _recorder_._src_components_halo_lively_halo_js.Halo.migrate();
    }
  };
});