System.register(['src/client/bound-eval.js', 'utils', 'src/client/vivide/utils.js', 'src/client/vivide/vividescriptstep.js', 'src/client/vivide/vivideobject.js', 'src/client/reactive/utils/annotations.js'], function (_export, _context) {
  "use strict";

  var boundEval, uuid, stepFolder, ScriptStep, VivideObject, Annotations;
  return {
    setters: [function (_srcClientBoundEvalJs) {
      boundEval = _srcClientBoundEvalJs.default;
    }, function (_utils) {
      uuid = _utils.uuid;
    }, function (_srcClientVivideUtilsJs) {
      stepFolder = _srcClientVivideUtilsJs.stepFolder;
    }, function (_srcClientVivideVividescriptstepJs) {
      ScriptStep = _srcClientVivideVividescriptstepJs.default;
    }, function (_srcClientVivideVivideobjectJs) {
      VivideObject = _srcClientVivideVivideobjectJs.default;
    }, function (_srcClientReactiveUtilsAnnotationsJs) {
      Annotations = _srcClientReactiveUtilsAnnotationsJs.default;
    }],
    execute: function () {
      _recorder_._src_client_vivide_vividescript_js = _recorder_._src_client_vivide_vividescript_js || {};
      _recorder_._src_client_vivide_vividescript_js.boundEval = boundEval;
      _recorder_._src_client_vivide_vividescript_js.uuid = uuid;
      _recorder_._src_client_vivide_vividescript_js.stepFolder = stepFolder;
      _recorder_._src_client_vivide_vividescript_js.ScriptStep = ScriptStep;
      _recorder_._src_client_vivide_vividescript_js.VivideObject = VivideObject;
      _recorder_._src_client_vivide_vividescript_js.Annotations = Annotations;
      class Script {
        constructor(view) {
          this.setView(view);
        }

        setView(view) {
          this._view = view;
        }

        /**
         * Access
         */
        setInitialStep(step) {
          return this.initialStep = step;
        }
        getInitialStep() {
          return this.initialStep;
        }

        getLastStep() {
          const firstStep = this.getInitialStep();
          return firstStep && firstStep.getLastStep();
        }

        getLoopStartStep() {
          const lastStep = this.getLastStep();
          return lastStep && lastStep.getNextExecutionStep();
        }

        numberOfSteps() {
          let length = 0;
          this.getInitialStep().iterateLinear(() => length++);
          return length;
        }

        getPrevStep(step) {
          return this.getInitialStep().find(s => s.getNextExecutionStep() === step);
        }

        async forEachStepAsync(cb) {
          await this.getInitialStep().iterateLinearAsync(cb);
        }

        stepsAsArray() {
          const arr = [];
          this.getInitialStep().iterateLinear(step => arr.push(step));

          return arr;
        }

        /**
         * Modify
         */
        async insertStepAfter(stepType, prevStep) {
          const newStep = await _recorder_._src_client_vivide_vividescript_js.ScriptStep.newFromTemplate(stepType);
          newStep.setScript(this);

          prevStep.insertAfter(newStep);

          return newStep;
        }

        removeStep(stepToBeRemoved) {
          if (stepToBeRemoved === this.getLoopStartStep()) {
            this.removeLoop();
          }

          if (stepToBeRemoved === this.getInitialStep()) {
            // First script was removed
            this.setInitialStep(stepToBeRemoved.getNextExecutionStep());
          }

          stepToBeRemoved.remove();
        }

        removeLoop() {
          const lastStep = this.getLastStep();
          lastStep.removeLoopTargetStep();
        }

        setLoopStart(step) {
          const lastStep = step.getLastStep();
          lastStep.setLoopTargetStep(step);
        }

        /**
         * Handling script execution
         */
        gotUpdated() {
          lively.notify('VivideScript::gotIpdated');
          this._view.scriptGotUpdated();
        }

        /**
         * Script execution
         */
        async getViewConfig() {
          const viewConfig = new _recorder_._src_client_vivide_vividescript_js.Annotations();
          const steps = this.stepsAsArray();

          for (let step of steps) {
            // #TODO: just say 'await step.getConfig()' (make it lazy and memoize later)
            const [fn, config] = await step.getExecutable();
            viewConfig.add(config);
          }

          return viewConfig;
        }

        /**
         * Serialization
         */
        static async createDefaultScript(view) {
          const transform = await _recorder_._src_client_vivide_vividescript_js.ScriptStep.newFromTemplate('transform');
          const extract = await _recorder_._src_client_vivide_vividescript_js.ScriptStep.newFromTemplate('extract');
          const descent = await _recorder_._src_client_vivide_vividescript_js.ScriptStep.newFromTemplate('descent');

          transform.insertAfter(extract);
          extract.insertAfter(descent);

          const script = new _recorder_._src_client_vivide_vividescript_js.Script(view);
          script.setInitialStep(transform);
          transform.setScript(script);
          extract.setScript(script);
          descent.setScript(script);

          return script;
        }

        toJSO() {
          const jsonContainer = {};

          this.stepsAsArray().forEach(step => {
            jsonContainer[step.id] = step.toJSO();
          });

          return jsonContainer;
        }

        toJSON() {
          return JSON.stringify(this.toJSO());
        }

        static async fromJSON(json, view) {
          // this is deserialization of a script
          let jsonScripts = JSON.parse(json);
          let scripts = {};

          var firstScriptStep;
          var lastScriptStep;

          const script = new _recorder_._src_client_vivide_vividescript_js.Script(view);
          for (let scriptId in jsonScripts) {
            let step = new _recorder_._src_client_vivide_vividescript_js.ScriptStep(jsonScripts[scriptId].source, jsonScripts[scriptId].type, scriptId);
            step.setScript(script);
            scripts[scriptId] = step;
            if (!firstScriptStep) firstScriptStep = step;
            if (lastScriptStep) {
              lastScriptStep.insertAfter(step);
            }
            lastScriptStep = step;
          }

          script.setInitialStep(firstScriptStep);
          return script;
        }
      }

      _export('default', Script);

      _recorder_._src_client_vivide_vividescript_js.Script = Script;
      // #UPDATE_INSTANCES
      // #TODO: idea: using a list of all object, we can make them become anew
      // go through all object reachable from window
      document.querySelectorAll("vivide-view").forEach(vv => {
        const script = vv.myCurrentScript;

        if (script) {
          // evil live programming
          script.constructor === _recorder_._src_client_vivide_vividescript_js.Script;

          // we can fix this, so we can do live development again....
          script.__proto__ = _recorder_._src_client_vivide_vividescript_js.Script.prototype;
        }
      });
    }
  };
});