System.register(["reactive-jsx", "src/client/graphics.js", "src/components/halo/lively-halo.js", "src/client/svg.js", "utils", "src/client/morphic/snapping.js", "src/client/morphic/event-helpers.js"], function (_export, _context) {
  "use strict";

  var _addSourceLocation, pt, Halo, SVG, debounce, Grid, events;

  return {
    setters: [function (_reactiveJsx) {
      _addSourceLocation = _reactiveJsx.addSourceLocation;
    }, function (_srcClientGraphicsJs) {
      pt = _srcClientGraphicsJs.pt;
    }, function (_srcComponentsHaloLivelyHaloJs) {
      Halo = _srcComponentsHaloLivelyHaloJs.default;
    }, function (_srcClientSvgJs) {
      SVG = _srcClientSvgJs.default;
    }, function (_utils) {
      debounce = _utils.debounce;
    }, function (_srcClientMorphicSnappingJs) {
      Grid = _srcClientMorphicSnappingJs.Grid;
    }, function (_srcClientMorphicEventHelpersJs) {
      events = _srcClientMorphicEventHelpersJs;
    }],
    execute: function () {
      _recorder_._src_client_graffle_js = _recorder_._src_client_graffle_js || {};
      _recorder_._src_client_graffle_js.pt = pt;
      _recorder_._src_client_graffle_js.Halo = Halo;
      _recorder_._src_client_graffle_js.SVG = SVG;
      _recorder_._src_client_graffle_js.debounce = debounce;
      _recorder_._src_client_graffle_js.Grid = Grid;
      _recorder_._src_client_graffle_js.events = events;
      class Graffle {

        // Graffle.keysDown 
        static load() {
          var _context2;

          lively.removeEventListener("Graffle", document.body);
          lively.removeEventListener("Graffle", document);
          lively.addEventListener("Graffle", document.body, "keydown", evt => {
            this.onKeyDown(evt);
          }, true);
          lively.addEventListener("Graffle", document.body, "keyup", evt => {
            this.onKeyUp(evt);
          }, true);
          lively.removeEventListener("GraffleMouse", document.documentElement);
          lively.addEventListener("GraffleMouse", document.documentElement, "pointerdown", evt => {
            this.onMouseDown(evt);
          }, true);
          lively.addEventListener("GraffleMouse", document.documentElement, "pointermove", evt => {
            this.onMouseMove(evt);
          });
          lively.addEventListener("GraffleMouse", document.documentElement, "pointerup", evt => {
            this.onMouseUp(evt);
          });
          lively.addEventListener("Graffle", document, "selectionchange", evt => {
            this.onSelectionHide(evt);
          });
          lively.addEventListener("Graffle", document, "selectionchange", (_context2 = evt => {
            this.onSelectionChange(evt);
          }, _recorder_._src_client_graffle_js.debounce).call(_context2, 600));
          this.keysDown = {};
        }

        static async showStyleBalloon(target) {
          if (!target) {
            return;
          }
          // console.log("show balloon " + target)
          // lively.showElement(target)
          if (!lively.styleBalloon) {
            lively.styleBalloon = await lively.openPart("formatting");
            lively.styleBalloon.style.zIndex = 500;
          }
          document.body.appendChild(lively.styleBalloon);
          // lively.showElement(lively.styleBalloon)

          // console.log("pos " + lively.getGlobalBounds(target).bottomLeft())
          lively.setGlobalPosition(lively.styleBalloon, lively.getGlobalBounds(target).bottomLeft());
        }

        static async hideStyleBalloon() {
          // console.log("hide balloon")
          if (lively.styleBalloon) {
            lively.styleBalloon.remove

            // lively.styleBalloon = null; // for developing
            ();
          }
        }

        static onSelectionHide(evt) {
          // var selection = window.getSelection()
          // if (!document.activeElement || !document.activeElement.isContentEditable) {
          //   if (document.activeElement === document.body) {
          //     this.hideStyleBalloon() 
          //   }
          // } else if (!selection.anchorNode || !selection.isCollapsed) {
          //   this.hideStyleBalloon() 
          // }
          this.hideStyleBalloon();
        }

        static onSelectionChange(evt) {
          var selection = window.getSelection();
          if (!document.activeElement || !document.activeElement.isContentEditable) {
            return;
          }
          if (document.activeElement.shadowRoot) {
            selection = document.activeElement.shadowRoot.getSelection();
          }
          if (selection.anchorNode && !selection.isCollapsed) {
            var element = selection.getRangeAt(0).endContainer.parentElement;
            while (["SPAN", "FONT", "A", "B", "I"].includes(element.tagName)) {
              element = element.parentElement;
            }
            this.showStyleBalloon(element);
          }
        }

        static async onKeyDown(evt) {
          if (!lively.preferences.get("GraffleMode")) return;

          if (!lively.isGlobalKeyboardFocusElement(evt.composedPath()[0])) return;
          var key = String.fromCharCode(evt.keyCode

          // console.log("" + Date.now() + " down " + key + " " +  evt.altKey)

          );this.keysDown[key] = true;
          if (this.specialKeyDown() && !(evt.ctrlKey || evt.metaKey)) {
            lively.selection.disabled = true;
            if (!evt.ctrlKey && !evt.altKey && !evt.altKey) {
              // console.log('disable ' + evt.keyCode)
              evt.stopPropagation();
              evt.preventDefault();
            }
            var hand = await lively.ensureHand();
            if (hand) {
              hand.style.visibility = "visible";
              var info = "";
              // #KeyboardShortcut HOLD-S+Drag create shape
              if (this.keysDown["S"]) {
                info = "shape";
              }
              // #KeyboardShortcut HOLD-C+Drag create connector
              if (this.keysDown["C"]) {
                info = "connect";
              }
              // #KeyboardShortcut HOLD-T+Drag create text
              if (this.keysDown["T"]) {
                info = "text";
              }
              // #KeyboardShortcut HOLD-D+Drag create svg path
              if (this.keysDown["D"]) {
                info = "draw";
              }
              // #KeyboardShortcut HOLD-F+Drag create freehand drawing
              if (this.keysDown["F"]) {
                info = "freehand";
              }

              if (hand.info) hand.info.textContent = info;
              hand.info.style.userSelect = "none";
            }
          }
        }

        static changeFontSize(element, factor) {
          if (element) {
            var fontSize = element.style.fontSize;
            if (!fontSize || !fontSize.match(/%$/)) {
              fontSize = "100%";
            }
            fontSize = "" + Math.round(Number(fontSize.replace(/%/, "")) * factor) + "%";
            element.style.fontSize = fontSize;
            // lively.notify("font size: " +  element.style.fontSize)
          }
        }

        static changeCurrentFontSize(factor) {
          var range = window.getSelection().getRangeAt(0);
          var element = range.commonAncestorContainer.parentElement;
          var oldSize = element.style.fontSize;

          // make a new region 
          document.execCommand("styleWithCSS", true, true);
          document.execCommand("fontSize", true, 1);
          element = window.getSelection().getRangeAt(0).commonAncestorContainer.parentElement;
          element.style.fontSize = oldSize.match("%$") ? oldSize : "100%";
          this.changeFontSize(element, factor);
        }

        static changeTextColor() {
          var color = "orange"; // #TODO make this interactive... 
          var element = window.getSelection().getRangeAt(0).startContainer.parentElement;
          if (element.style.color == color) {
            color = "black"; // TODO how can we unset a color? 
          }
          document.execCommand("styleWithCSS", true, true);
          document.execCommand("foreColor", true, color);
        }

        static changeHiliteColor() {
          var color = "yellow"; // #TODO make this interactive... 
          var element = window.getSelection().getRangeAt(0).startContainer.parentElement;
          if (element.style.color == color) {
            color = "transparent"; // TODO how can we unset a color? 
          }
          document.execCommand("styleWithCSS", true, true);
          document.execCommand("hiliteColor", true, color);
        }

        static async onKeyUp(evt) {
          var key = String.fromCharCode(evt.keyCode);
          this.keysDown[key] = false;

          // console.log("" + Date.now() + " up " + key + " " +  evt.altKey)

          if (key == "D" || key == "C") {
            this.currentPath = null;
            HaloService.showHaloItems();
          }

          lively.selection.disabled = false;

          var hand = await lively.ensureHand();
          if (hand) {
            hand.style.visibility = "hidden";
            if (hand.info) hand.info.textContent = "";
          }
          // if (this.lastElement)
          //   this.lastElement.focus(); // no, we can focus.... and continue typing

          if (evt.altKey && evt.keyCode == 187 /* + */) {
              this.changeCurrentFontSize(1.1);
            }

          if (evt.altKey && evt.keyCode == 189 /* - */) {
              this.changeCurrentFontSize(0.9);
            }

          if (evt.altKey && key == "C") {
            this.changeTextColor();
          }

          if (evt.altKey && key == "H") {
            this.changeHiliteColor();
          }
        }

        static specialKeyDown() {
          return this.keysDown["S"] || this.keysDown["T"] || this.keysDown["C"] || this.keysDown["D"] || this.keysDown["F"];
        }

        static eventPosition(evt) {
          return _recorder_._src_client_graffle_js.pt(evt.clientX, evt.clientY);
        }

        static async startShapeDrawing(evt) {
          var shape = _addSourceLocation(document.createElement("div"), {
            file: 'https://lively-kernel.org/lively4/lively4-stephelm/src/client/graffle.js',
            end: {
              column: 45,
              line: 234
            },
            start: {
              column: 16,
              line: 234
            }
          });
          shape.style.backgroundColor = "lightgray";
          shape.style.border = "1px solid gray";
          this.openAsLivelyContent(shape, evt);
          return shape;
        }

        static async startTextDrawing(evt) {
          var text = _addSourceLocation(document.createElement("div"), {
            file: 'https://lively-kernel.org/lively4/lively4-stephelm/src/client/graffle.js',
            end: {
              column: 44,
              line: 242
            },
            start: {
              column: 15,
              line: 242
            }
          });
          text.textContent = "";
          text.classList.add("lively-text"

          // #TODO move this to CSS as defaults?
          );text.style.width = "auto";
          text.style.height = "auto";
          text.style.whiteSpace = "nowrap";
          text.style.padding = "3px";

          text.contentEditable = true;
          this.openAsLivelyContent(text, evt);
          return text;
        }

        static async startConnectorDrawing(evt) {
          var connector = _addSourceLocation(document.createElement("lively-connector"), {
            file: 'https://lively-kernel.org/lively4/lively4-stephelm/src/client/graffle.js',
            end: {
              column: 62,
              line: 258
            },
            start: {
              column: 20,
              line: 258
            }
          });
          await lively.components.openIn(this.targetContainer, connector);
          lively.setGlobalPosition(connector, _recorder_._src_client_graffle_js.pt(evt.clientX, evt.clientY));
          window.that = connector;
          HaloService.showHalos(connector);
          let cp = lively.halo.ensureControlPoint(connector.getPath(), 1, true);
          this.currentControlPoint = cp;
          cp.setVerticePosition(_recorder_._src_client_graffle_js.pt(0, 0));
          cp.start(evt, connector);
          this.currentPath = connector;
          this.openAsLivelyContent(connector, evt);
          if (cp.targetElement) {
            connector.connectFrom(cp.targetElement);
          }
          connector.connectTo(lively.hand);
          return connector;
        }

        static async startFreehandDrawing(evt) {
          var freehand = await _addSourceLocation(lively.create("lively-drawboard"), {
            file: 'https://lively-kernel.org/lively4/lively4-stephelm/src/client/graffle.js',
            end: {
              column: 58,
              line: 277
            },
            start: {
              column: 25,
              line: 277
            }
          });
          freehand.freehand();
          this.currentFreehand = freehand;
          this.openAsLivelyContent(freehand, evt);
          lively.setExtent(freehand, _recorder_._src_client_graffle_js.pt(100, 100));
          freehand.onPointerDown(evt);
          return freehand;
        }

        static async startPathDrawing(evt) {
          var continueDrawing = true && this.currentPath;
          if (!this.currentPath) {
            var path = await lively.openPart("path", this.targetContainer);
            this.currentPath = path;
            window.that = path;
            this.openAsLivelyContent(path, evt
            // split position in global and local part to snap locally...
            );var offset = lively.getGlobalPosition(path.parentElement);
            var pos = _recorder_._src_client_graffle_js.pt(evt.clientX, evt.clientY).subPt(offset);

            if (!evt.ctrlKey) {
              pos = _recorder_._src_client_graffle_js.Grid.snapPt(pos, 10, 5);
            }
            HaloService.showHalos(path);
            lively.setPosition(path, pos);
          }
          var svgPath = this.currentPath.querySelector("path");
          var vertices = _recorder_._src_client_graffle_js.SVG.getPathVertices(svgPath);
          let cp = lively.halo.ensureControlPoint(svgPath, vertices.length - 1);
          this.currentControlPoint = cp;
          if (continueDrawing) {
            cp.addControlPoint();
          } else {
            cp.setVerticePosition(_recorder_._src_client_graffle_js.pt(0, 0));
          }
          cp.start(evt, this.currentPath);
          if (continueDrawing) {
            cp.eventOffset = this.lastMouseUpPos; // #ContinueHere 
          }
          return path;
        }

        static openAsLivelyContent(div, evt) {
          div.classList.add("lively-content");
          this.currentElement = div;
          this.targetContainer.appendChild(div);
          var pos = this.eventPosition(evt);

          lively.setGlobalPosition(div, pos);
          this.lastMouseDown = pos;
          return div;
        }

        static ensureTargetContainer(evt) {

          var targetContainer = evt.composedPath().find(ea => ea.localName == "lively-figure");
          if (!targetContainer) {
            targetContainer = evt.composedPath().find(ea => ea.tagName == "LIVELY-CONTAINER");
          }
          if (targetContainer) {
            lively.showElement(targetContainer);
            this.targetContainer = targetContainer;
          } else {
            this.targetContainer = document.body;
          }
        }

        static async onMouseDown(evt) {
          if (!this.specialKeyDown()) return;
          evt.stopPropagation();
          evt.preventDefault();
          document.documentElement.style.touchAction = "none";
          this.ensureTargetContainer(evt);
          if (this.keysDown["S"]) {
            await this.startShapeDrawing(evt);
          } else if (this.keysDown["T"]) {
            await this.startTextDrawing(evt);
          } else if (this.keysDown["C"]) {
            await this.startConnectorDrawing(evt);
          } else if (this.keysDown["D"]) {
            await this.startPathDrawing(evt);
          } else if (this.keysDown["F"]) {
            await this.startFreehandDrawing(evt);
          }
        }

        static onMouseMove(evt) {
          if (this.specialKeyDown()) {
            lively.setGlobalPosition(lively.hand, _recorder_._src_client_graffle_js.pt(evt.clientX - 2, evt.clientY - 2));
          }
          if (this.currentControlPoint) {
            this.currentControlPoint.move(evt);
          }
          if (this.currentFreehand) {
            this.currentFreehand.onPointerMove(evt);
          }

          if (!this.lastMouseDown || !this.currentElement) return;
          var extent = this.eventPosition(evt).subPt(this.lastMouseDown);
          if (!this.currentPath && !this.currentFreehand) {
            lively.setExtent(this.currentElement, extent);
          }
        }

        static onMouseUp(evt) {
          if (!evt) return;
          this.lastMouseUpPos = lively.getPosition(evt);
          if (this.currentControlPoint) {
            this.currentControlPoint.stop(evt);
            if (!this.keysDown["T"]) {
              HaloService.hideHaloItems();
            }
          }
          if (this.currentFreehand) {
            this.currentFreehand.onPointerUp(evt);
            var svg = this.currentFreehand.get("#svg");
            var path = svg.querySelector("path");

            var bounds = _recorder_._src_client_graffle_js.SVG.childBounds(svg);
            var p1 = lively.getGlobalPosition(this.currentFreehand);
            if (!bounds) return;

            var p2 = _recorder_._src_client_graffle_js.pt(bounds.x, bounds.y);
            var delta = p2.subPt(p1);

            lively.moveBy(this.currentFreehand, delta);
            lively.moveBy(path, delta.scaleBy(-1));
            lively.setExtent(this.currentFreehand, _recorder_._src_client_graffle_js.pt(bounds.width, bounds.height));

            this.currentFreehand = null;
            this.currentElement = null;
            // lively.showElement(svg)

            // lively.setGlobalPosition(this.currentFreehand, bounds.topLeft())
            // lively.setExtent(this.currentFreehand, pt(bounds.width, bounds.height))
          } else if (this.currentElement) {
            if (this.currentElement.classList.contains("lively-text")) {
              if (!this.keysDown["T"]) {
                this.currentElement.focus();
              }
            }
            this.lastMouseDown = null;
            this.currentElement = null;
            this.lastElement = this.currentElement;
            document.documentElement.style.touchAction = "";
          } else {
            this.lastElement = null;
          }
          this.currentControlPoint = null;
          this.currentConnectFrom = null;
        }
      }

      _export("default", Graffle);

      _recorder_._src_client_graffle_js.Graffle = Graffle;
      _recorder_._src_client_graffle_js.Graffle.load();
    }
  };
});