System.register(['src/components/widgets/lively-morph.js', 'src/client/bound-eval.js', 'src/external/lodash/lodash.js', 'utils', 'src/components/widgets/lively-code-mirror.js'], function (_export, _context) {
  "use strict";

  var Morph, boundEval, _, generateUuid, waitForDeepProperty, stripErrorString;

  return {
    setters: [function (_srcComponentsWidgetsLivelyMorphJs) {
      Morph = _srcComponentsWidgetsLivelyMorphJs.default;
    }, function (_srcClientBoundEvalJs) {
      boundEval = _srcClientBoundEvalJs.default;
    }, function (_srcExternalLodashLodashJs) {
      _ = _srcExternalLodashLodashJs.default;
    }, function (_utils) {
      generateUuid = _utils.uuid;
      waitForDeepProperty = _utils.waitForDeepProperty;
    }, function (_srcComponentsWidgetsLivelyCodeMirrorJs) {
      stripErrorString = _srcComponentsWidgetsLivelyCodeMirrorJs.stripErrorString;
    }],
    execute: function () {
      const __SystemJSRewritingHack = {};
      _recorder_._src_components_widgets_lively_script_js = _recorder_._src_components_widgets_lively_script_js || {};
      Object.defineProperty(_recorder_._src_components_widgets_lively_script_js, 'Morph', {
        get() {
          return Morph;
        },

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

        enumerable: true,
        configurable: true
      });
      Object.defineProperty(_recorder_._src_components_widgets_lively_script_js, 'boundEval', {
        get() {
          return boundEval;
        },

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

        enumerable: true,
        configurable: true
      });
      Object.defineProperty(_recorder_._src_components_widgets_lively_script_js, '_', {
        get() {
          return _;
        },

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

        enumerable: true,
        configurable: true
      });
      Object.defineProperty(_recorder_._src_components_widgets_lively_script_js, 'waitForDeepProperty', {
        get() {
          return waitForDeepProperty;
        },

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

        enumerable: true,
        configurable: true
      });
      Object.defineProperty(_recorder_._src_components_widgets_lively_script_js, 'generateUuid', {
        get() {
          return generateUuid;
        },

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

        enumerable: true,
        configurable: true
      });
      Object.defineProperty(_recorder_._src_components_widgets_lively_script_js, 'stripErrorString', {
        get() {
          return stripErrorString;
        },

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

        enumerable: true,
        configurable: true
      });


      /* Replacement for "script" tag, that supports
       *  - import module statements
       *  - extended syntax 
       * by going through or own "boundEval" that uses babel incl. our plugins
       *
       * #TODO coordinate evaluation of multiple script tags
       *
       */

      var currentScriptPromises = [];

      _export('currentScriptPromises', currentScriptPromises);

      Object.defineProperty(_recorder_._src_components_widgets_lively_script_js, 'currentScriptPromises', {
        get() {
          return currentScriptPromises;
        },

        set(thisIsVererySecretVariableName) {
          _export('currentScriptPromises', currentScriptPromises = thisIsVererySecretVariableName);

          return true;
        },

        enumerable: true,
        configurable: true
      });
      var moduleMap = new Map();

      _export('moduleMap', moduleMap);

      Object.defineProperty(_recorder_._src_components_widgets_lively_script_js, 'moduleMap', {
        get() {
          return moduleMap;
        },

        set(thisIsVererySecretVariableName) {
          _export('moduleMap', moduleMap = thisIsVererySecretVariableName);

          return true;
        },

        enumerable: true,
        configurable: true
      });
      class LivelyScript extends Morph {

        async initialize() {
          this.evaluated = new Promise(resolve => {
            this.resolveEvaluated = resolve;
          });
        }

        // evalute script not when the component is initialized, but when it is actually in the DOM
        async attachedCallback() {

          // we get exectuted to often?
          if (this.lastParentElement == this.parentElement) return;
          this.lastParentElement = this.parentElement;
          // lively.notify("execute " + this.textContent)


          // console.log("SCRIPT attached ", lively.findWorldContext(this))
          var src = this.textContent;
          // console.log("LivelyScript>>initialize " + src)

          this.get("#result").innerHTML = `[pending exec script${this.id ? " " + this.id : ""}]`;
          var result = await this.boundEval(src);
          if (result.isError) {
            this.get("#result").innerHTML = "<lively-error><pre>" + stripErrorString(result.value).replace(/</g, "&lt;") + "</pre></lively-error>";
            return;
          }

          if (result.value && result.value.then) {
            result.value = await result.value;
          }

          if (result.value instanceof HTMLElement && result.value !== this) {
            this.get("#result").innerHTML = "";
            this.get("#result").appendChild(result.value);
          } else if (result.value !== undefined) {
            this.get("#result").innerHTML = "" + result.value;
          } else {
            this.get("#result").innerHTML = "";
          }
          if (this.resolveEvaluated) {
            // lively.notify("[script] evaluated " + this)
            this.resolveEvaluated();
            this.resolveEvaluated = null; // don't do it twice...
          } else {
            console.log("[script] evaluated AGAIN");
          }
        }

        cleanModuleURL(url) {
          return url.toString().replace(/[^A-Za-z0-9\-_:\/.]/g, "" // #TODO this is important, maybe we should blacklist instead of whitelist
          );
        }

        async moduleFor(obj) {
          var moduleName = moduleMap.get(obj);
          if (!moduleName) {
            // first check if we are part of a markdonw 
            var markdown = lively.query(this, "lively-markdown");
            if (markdown) {
              var url = markdown.getAttribute("url") || markdown.getAttribute("src");
              if (url) {
                moduleName = url.replace(/[^/]*$/, "livelyscript_" + generateUuid());
              }
            }
            // check if for a container...
            if (!moduleName) {
              var container = lively.query(this, "lively-container");
              if (container) {

                await waitForDeepProperty(container, "getURL");
                container.livelyScriptContainerId = container.livelyScriptContainerId || generateUuid

                // all scripts in one container share the same module... but a second container will get a different module
                ();moduleName = (this.cleanModuleURL(container.getURL()) || lively4url).toString() + "_" + container.livelyScriptContainerId;
              }
            }

            // no markdown, no container, so we assume lively4 as root
            if (!moduleName) {
              moduleName = lively4url + "/livelyscript_" + generateUuid // so that some relative urls work...
              ();
            }
            moduleMap.set(obj, moduleName);
          }
          return moduleName;
        }

        async boundEval(str) {
          //console.log("" + this.id + ">>boundEval " + str )
          var worldContext = lively.findWorldContext(this

          // log("world context " + worldContext)

          );if (worldContext) {
            // #Bug we are not yet in a body or shadow-root
            console.warn("Executing lively-script without world context", this);
          }

          var targetModule = await this.moduleFor(worldContext // all scripts in one container should share scope? 

          // console.log("[lively-script] worldContext: " + worldContext + " targetModule: ", targetModule)

          );var resolveMe;
          if (currentScriptPromises.length > 0) {
            // console.log("script wait on " + currentScriptPromise)
            var last = _.last(currentScriptPromises); // wait on each other... scripts can only be executed sequencitally?
          }
          var myPromise = new Promise(resolve => {
            resolveMe = resolve;
          });
          currentScriptPromises.push(myPromise);
          if (last) {
            // console.log("wait on last: " + last)
            await last;
          }
          // console.log("[lively-script] " + this.id + ">>boundEval " + "targetModule: " + targetModule + "\n exec: \"" + str + '"', )
          var myPromisedResult = boundEval(str, this, targetModule);
          myPromisedResult.then(() => {
            var first = currentScriptPromises.shift();
            if (first !== myPromise) {
              _recorder_._src_components_widgets_lively_script_js.currentScriptPromises = [];
              throw new Error("LivelyScript execution order broken, resetting it...");
            }
            resolveMe();
          });
          return myPromisedResult;
        }

        toString() {
          return "[LivelyScript]";
        }

        livelyExample() {
          this.textContent = "3 + 4";
          this.initialize();
        }

      }

      _export('default', LivelyScript);

      Object.defineProperty(_recorder_._src_components_widgets_lively_script_js, 'LivelyScript', {
        get() {
          return LivelyScript;
        },

        set(thisIsVererySecretVariableName) {
          _export('default', LivelyScript = thisIsVererySecretVariableName);

          return true;
        },

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