System.register(["reactive-jsx", "src/external/rasterizeHTML.js", "src/client/graphics.js"], function (_export, _context) {
  "use strict";

  var _addSourceLocation, rasterizeHTML, pt;

  return {
    setters: [function (_reactiveJsx) {
      _addSourceLocation = _reactiveJsx.addSourceLocation;
    }, function (_srcExternalRasterizeHTMLJs) {
      rasterizeHTML = _srcExternalRasterizeHTMLJs.default;
    }, function (_srcClientGraphicsJs) {
      pt = _srcClientGraphicsJs.pt;
    }],
    execute: function () {
      const __SystemJSRewritingHack = {};
      _recorder_._src_client_rasterize_js = _recorder_._src_client_rasterize_js || {};
      Object.defineProperty(_recorder_._src_client_rasterize_js, "rasterizeHTML", {
        get() {
          return rasterizeHTML;
        },

        set(thisIsVererySecretVariableName) {
          rasterizeHTML = thisIsVererySecretVariableName;
          return true;
        },

        enumerable: true,
        configurable: true
      });
      Object.defineProperty(_recorder_._src_client_rasterize_js, "pt", {
        get() {
          return pt;
        },

        set(thisIsVererySecretVariableName) {
          pt = thisIsVererySecretVariableName;
          return true;
        },

        enumerable: true,
        configurable: true
      });


      /* ## Workspace Snipped for interactive Testing
      
      ```
        import {CloneDeepHTML} from "src/client/rasterize.js"
      
        $morph("Cloned").innerHTML = ""
        var cloned = CloneDeepHTML.deepCopyAsHTML($morph("Original"))
        $morph("Cloned").appendChild(cloned)
      ```
      */

      // the rasterization code expects only plain HTML and cannot deal with shadow dom, so we flatten it away
      class CloneDeepHTML {

        // computes the styles of a and b and prints the difference CSS
        static diffCSS(a, b) {
          var astyle = getComputedStyle(a);
          var bstyle = getComputedStyle(b);
          var css = "";
          for (var i = 0; i < astyle.length; i++) {
            var name = astyle.item(i);
            if (!name.match("-webkit")) {
              if (astyle.getPropertyValue(name) != bstyle.getPropertyValue(name)) {
                css += name + ": " + astyle.getPropertyValue(name) + ";\n";
              }
            }
          }
          return css;
        }

        static shallowClone(obj, parent, root) {
          if (!obj) return;
          var node;
          if (obj.constructor.name == "Text") {
            if (obj.parentElement && obj.parentElement.tagName == "STYLE") {
              // #Hack hot fix font-awesome styles...
              node = document.createTextNode(obj.textContent.replace(/url\('\.\.\/fonts\/fontawesome-webfont/g, `url('${lively4url}/src/external/font-awesome/fonts/fontawesome-webfont`));
            } else {
              node = document.createTextNode(obj.textContent);
            }
          } else if (obj.tagName == "CONTENT") {
            node = _addSourceLocation(document.createElement("div"), {
              file: 'https://lively-kernel.org/lively4/composed-offset/src/client/rasterize.js',
              end: {
                column: 42,
                line: 47
              },
              start: {
                column: 13,
                line: 47
              }
            });
            node.id = "CONTENTNODE";
            if (root) {
              root._shadowRootContentNode = node;
            }
            return node;
          } else if (obj.tagName == "STYLE") {
            node = _addSourceLocation(document.createElement("style"), {
              file: 'https://lively-kernel.org/lively4/composed-offset/src/client/rasterize.js',
              end: {
                column: 44,
                line: 54
              },
              start: {
                column: 13,
                line: 54
              }
            });

            return node;
          } else if (obj instanceof SVGElement) {
            // console.log("svg element " + obj)
            node = document.createElementNS("http://www.w3.org/2000/svg", obj.tagName);
            Array.from(obj.attributes).forEach(ea => {
              try {
                // console.log("attr " + ea.name + " " + ea.value)
                node.setAttribute(ea.name, ea.value);
              } catch (e) {
                console.log('rasterize: could not write attribute ' + ea.name + " from " + obj);
              }
            });
            return node;
          } else if (obj.shadowRoot) {
            node = _addSourceLocation(document.createElement("div"), {
              file: 'https://lively-kernel.org/lively4/composed-offset/src/client/rasterize.js',
              end: {
                column: 42,
                line: 70
              },
              start: {
                column: 13,
                line: 70
              }
            });
          } else {
            if (!obj.tagName) {
              // comments...
            } else {
              node = _addSourceLocation(document.createElement(obj.tagName), {
                file: 'https://lively-kernel.org/lively4/composed-offset/src/client/rasterize.js',
                end: {
                  column: 50,
                  line: 75
                },
                start: {
                  column: 15,
                  line: 75
                }
              });
            }
          }
          if (obj.tagName == "H1") {
            lively.showElement(obj);
          }

          if (obj.attributes) {
            Array.from(obj.attributes).forEach(ea => {
              if (ea.name == "style") return;
              try {
                node[ea.name] = "" + ea.value;
              } catch (e) {
                console.log('rasterize: could not write attribute ' + ea.name + " from " + obj);
              }
            });
            if (obj.style) {
              node.style = this.diffCSS(obj, node);
            }

            var beforeElementStyle = getComputedStyle(obj, ':before');
            var beforeContent = beforeElementStyle.content;
            if (beforeContent && beforeContent.length > 0 && beforeContent !== 'none') {
              var text = _addSourceLocation(document.createElement("span"), {
                file: 'https://lively-kernel.org/lively4/composed-offset/src/client/rasterize.js',
                end: {
                  column: 49,
                  line: 98
                },
                start: {
                  column: 19,
                  line: 98
                }
              });

              try {
                text.textContent = "" + JSON.parse(beforeContent);
              } catch (e) {
                lively.warn('could not parse ' + beforeContent, e);
              }
              text.style = beforeContent.cssText;
              node.appendChild(text);
            }
          }
          if (obj.tagName == "INPUT") {
            // weired... why are they not connected?
            node.value = obj.value;
            node.setAttribute("value", obj.value);
          }

          return node;
        }

        static deepCopyAsHTML(obj) {
          var to = this.shallowClone(obj);
          this.deepCopyAsHTMLFromTo(obj, to, undefined);
          return to;
        }

        static deepCopyAsHTMLFromTo(from, to, root) {
          var target = to;

          if (from.shadowRoot) {
            this.deepCopyAsHTMLFromTo(from.shadowRoot, to, from);

            var contentNode = from._shadowRootContentNode;
            if (contentNode) {
              target = contentNode;
            }
          }

          from.childNodes.forEach(fromChild => {
            var toChild = this.shallowClone(fromChild, target, root);
            if (toChild) {
              target.appendChild(toChild);
              this.deepCopyAsHTMLFromTo(fromChild, toChild, root);
            }
          });
        }
      }

      // var clone = CloneDeepHTML.deepCopyAsHTML(that)
      // $morph("result").innerHTML = ""
      // $morph("result").appendChild(clone)
      // $morph("showResult").inspect(clone)

      _export("CloneDeepHTML", CloneDeepHTML);

      Object.defineProperty(_recorder_._src_client_rasterize_js, "CloneDeepHTML", {
        get() {
          return CloneDeepHTML;
        },

        set(thisIsVererySecretVariableName) {
          _export("CloneDeepHTML", CloneDeepHTML = thisIsVererySecretVariableName);

          return true;
        },

        enumerable: true,
        configurable: true
      });
      class Rasterize {
        // from: https://gist.github.com/timdown/021d9c8f2aabc7092df564996f5afbbf
        static trimCanvas(canvas) {
          function rowBlank(imageData, width, y) {
            for (var x = 0; x < width; ++x) {
              if (imageData.data[y * width * 4 + x * 4 + 3] !== 0) return false;
            }
            return true;
          }

          function columnBlank(imageData, width, x, top, bottom) {
            for (var y = top; y < bottom; ++y) {
              if (imageData.data[y * width * 4 + x * 4 + 3] !== 0) return false;
            }
            return true;
          }

          var ctx = canvas.getContext("2d");
          var width = canvas.width;
          var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
          var top = 0,
              bottom = imageData.height,
              left = 0,
              right = imageData.width;

          while (top < bottom && rowBlank(imageData, width, top)) ++top;
          while (bottom - 1 > top && rowBlank(imageData, width, bottom - 1)) --bottom;
          while (left < right && columnBlank(imageData, width, left, top, bottom)) ++left;
          while (right - 1 > left && columnBlank(imageData, width, right - 1, top, bottom)) --right;

          var trimmed = ctx.getImageData(left, top, right - left, bottom - top);
          var copy = canvas.ownerDocument.createElement("canvas");
          var copyCtx = copy.getContext("2d");
          copy.width = trimmed.width;
          copy.height = trimmed.height;
          copyCtx.putImageData(trimmed, 0, 0);

          return copy;
        }

        static async elementToCanvas(element, zoom = 1) {
          // zoom = 2; // see   tmp.style.transform = "scale(2)" in (rc/client/html.js)
          var bounds = lively.getTotalGlobalBounds(element);
          var extent = pt(bounds.width, bounds.height);

          await lively.sleep(100); // give the element some time to render...

          var cloned = CloneDeepHTML.deepCopyAsHTML(element);

          var h = _addSourceLocation(document.createElement("html"), {
            file: 'https://lively-kernel.org/lively4/composed-offset/src/client/rasterize.js',
            end: {
              column: 42,
              line: 198
            },
            start: {
              column: 12,
              line: 198
            }
          });
          h.appendChild(_addSourceLocation(document.createElement("body"), {
            file: 'https://lively-kernel.org/lively4/composed-offset/src/client/rasterize.js',
            end: {
              column: 48,
              line: 199
            },
            start: {
              column: 18,
              line: 199
            }
          }));
          // var style = document.createElement("style")
          // style.textContent = await fetch(lively4url + "/src/external/font-awesome/css/font-awesome.css").then(r => r.text())
          // h.appendChild(document.createElement("head"))
          // h.querySelector("head").appendChild(style)
          h.querySelector("body").appendChild(cloned);

          lively.setPosition(cloned, pt(0, 0));
          var canvas = _addSourceLocation(document.createElement("canvas"), {
            file: 'https://lively-kernel.org/lively4/composed-offset/src/client/rasterize.js',
            end: {
              column: 49,
              line: 207
            },
            start: {
              column: 17,
              line: 207
            }
          });
          var minExtent = pt(1, 1);
          canvas.width = Math.max(extent.x * zoom, minExtent.x);
          canvas.height = Math.max(extent.y * zoom, minExtent.y);
          await rasterizeHTML.drawHTML(h.outerHTML, canvas);

          canvas = this.trimCanvas(canvas);
          return canvas;
        }

        static async elementToDataURL(element, zoom) {
          var canvas = await this.elementToCanvas(element, zoom);
          return canvas.toDataURL("image/png");
        }

        static async elementToURL(element, url, zoom) {
          var dataURL = await this.elementToDataURL(element, zoom);
          return lively.files.copyURLtoURL(dataURL, url);
        }

        static async asImage(element) {
          var dataURL = await this.elementToDataURL(element);
          var img = _addSourceLocation(document.createElement("img"), {
            file: 'https://lively-kernel.org/lively4/composed-offset/src/client/rasterize.js',
            end: {
              column: 43,
              line: 230
            },
            start: {
              column: 14,
              line: 230
            }
          });
          img.src = dataURL;
          return img;
        }

        static async openAsImage(element) {
          var img = await this.asImage(element);
          document.body.appendChild(img);
          return img;
        }
      }

      _export("default", Rasterize);

      Object.defineProperty(_recorder_._src_client_rasterize_js, "Rasterize", {
        get() {
          return Rasterize;
        },

        set(thisIsVererySecretVariableName) {
          _export("default", Rasterize = thisIsVererySecretVariableName);

          return true;
        },

        enumerable: true,
        configurable: true
      });
      class TemplatePreview {

        static async createPreview(url, templateName) {
          if (!url) throw new Error("url argument missing");
          if (!templateName) throw new Error("templateName argument missing");
          console.log("PREVIEW work on:" + templateName);
          try {
            var comp = await Promise.race([lively.openComponentInWindow(templateName), new Promise(r => setTimeout(r, 4000))]);
            if (!comp) {
              console.log("could not load component in time: " + templateName);
              return;
            }

            if (comp.livelyExample) {
              await comp.livelyExample();
            }

            var a = $morph("RasterImg");if (a) a.remove();
            var img = await Rasterize.openAsImage(comp.windowTitle ? comp.parentElement : comp).then(img => {
              img.id = "RasterImg";
              img.style.width = img.width * 1 + "px";
              img.style.position = "fixed";
              img.style.top = "0px";
              img.style.right = "0px";

              return img;
            }
            // img.remove()

            );var imgData = await fetch(img.src).then(r => r.blob());
            var imgURL = url + templateName + ".png";
            await fetch(imgURL, { method: "PUT", body: imgData });
            console.log("PREVIEW wrote " + imgURL);
          } catch (e) {
            console.error(e);
          } finally {
            if (comp && comp.parentElement) {
              comp.parentElement.remove();
            }
          }
          return imgURL;
        }

        static async generate(dry) {
          let urls = lively.components.getTemplatePaths();
          for (let url of urls) {
            console.log("generate preview in: " + url);
            let dir = await fetch(url, {
              method: "OPTIONS"
            }).then(r => r.json());
            let templates = dir.contents.filter(ea => ea.name.match(/\.html$/));
            for (let ea of templates) {
              let name = ea.name.replace(/\.html$/, "");
              let previewUrl = url + name + ".png";
              try {
                console.log("next " + previewUrl);
                if (!(await lively.files.existFile(previewUrl))) {
                  if (TemplatePreview.stoped) return;
                  if (dry) {
                    console.warn("would generate " + url);
                  } else {
                    try {
                      await Promise.race([this.createPreview(url, name), new Promise(r => setTimeout(r, 6000))]);
                    } catch (e) {
                      console.warn("GeneratePreview Errro: " + e);
                    }
                  }
                } else {
                  console.warn("Preview exists: " + previewUrl);
                }
              } catch (e) {
                console.warn("Error when generating preview: " + e);
              }
            }
          }
        }
      }

      // TemplatePreview.generate()

      // Rasterize.openAsImage(that)

      _export("TemplatePreview", TemplatePreview);

      Object.defineProperty(_recorder_._src_client_rasterize_js, "TemplatePreview", {
        get() {
          return TemplatePreview;
        },

        set(thisIsVererySecretVariableName) {
          _export("TemplatePreview", TemplatePreview = thisIsVererySecretVariableName);

          return true;
        },

        enumerable: true,
        configurable: true
      });
    }
  };
});