text: "use strict";
  var platform_browser_1 = require('@angular/platform-browser');
  var core_1 = require('@angular/core');
  var http_1 = require('@angular/http');
  var node_1 = require('./platform/node');
  var document_1 = require('./platform/document');
  var ng_preboot_1 = require('./ng_preboot');
  var platform_server_1 = require('@angular/platform-server');
  platform_server_1.Parse5DomAdapter.makeCurrent(); // ensure Parse5DomAdapter is used
  var dom_adapter_1 = require('@angular/platform-browser/src/dom/dom_adapter');
  var DOM = dom_adapter_1.getDOM();
  var Bootloader = (function () {
      function Bootloader(config) {
          this._config = { async: true, preboot: false };
          Object.assign(this._config, config || {});
          this.platformRef = this.platform();
          // this.applicationRef = this.application();
      }
      Bootloader.create = function (config) {
          if (config instanceof Bootloader) {
              return config;
          }
          return new Bootloader(config);
      };
      Bootloader.applicationRefToString = function (applicationRefs) {
          var injector = applicationRefs.injector;
          if (Array.isArray(applicationRefs)) {
              injector = applicationRefs[0].injector;
          }
          var document = injector.get(platform_browser_1.DOCUMENT);
          var rendered = Bootloader.serializeDocument(document);
          return rendered;
      };
      Bootloader.parseFragment = function (document) { return document_1.parseFragment(document); };
      Bootloader.parseDocument = function (document) { return document_1.parseDocument(document); };
      Bootloader.serializeDocument = function (document) { return document_1.serializeDocument(document); };
      Bootloader.prototype.document = function (document) {
          if (document === void 0) { document = null; }
          var doc = document || this._config.template || this._config.document;
          if (typeof doc === 'string') {
              return Bootloader.parseDocument(doc);
          }
          return doc;
      };
      Bootloader.prototype.platform = function (providers) {
          var pro = providers || this._config.platformProviders;
          var customProviders = core_1.ReflectiveInjector.resolveAndCreate(node_1.buildNodeProviders(pro));
          return core_1.createPlatform(customProviders);
      };
      Bootloader.prototype.application = function (document, providers) {
          var doc = this.document(document);
          var pro = providers || this._config.providers;
          var customProviders = node_1.buildNodeAppProviders(doc, pro);
          var appinjector = core_1.ReflectiveInjector.resolveAndCreate(customProviders, this.platformRef.injector);
          return appinjector;
      };
      Bootloader.prototype.bootstrap = function (Component) {
          var component = Component || this._config.component;
          if (component) {
              // .then(waitRouter)); // fixed by checkStable()
              return core_1.coreLoadAndBootstrap(this.application(), component);
          }
          else {
              return this._bootstrapAll(component);
          }
      };
      Bootloader.prototype.serialize = function (Component) {
          return this.bootstrap(Component)
              .then(Bootloader.applicationRefToString);
      };
      Bootloader.prototype.serializeApplication = function (Component, componentProviders) {
          var _this = this;
          var component = Component || this._config.component;
          var providers = componentProviders || this._config.componentProviders || [];
          // let customProviders = ReflectiveInjector.resolveAndCreate(providers);
          var ngDoCheck = this._config.ngDoCheck || null;
          var maxZoneTurns = Math.max(this._config.maxZoneTurns || 2000, 1);
          return this._applicationAll(component, providers)
              .then(function (configRefs) {
              if ('ngOnInit' in _this._config) {
                  if (!_this._config.ngOnInit) {
                      return configRefs;
                  }
                  var document_2 = configRefs[0].applicationRef.injector.get(platform_browser_1.DOCUMENT);
                  return Promise.resolve(_this._config.ngOnInit(configRefs, document_2)).then(function () { return configRefs; });
              }
              return configRefs;
          })
              .catch(function (err) {
              console.log('ngOnInit Error:', err);
              throw err;
          })
              .then(function (configRefs) {
              if ('async' in _this._config) {
                  if (!_this._config.async) {
                      return configRefs;
                  }
                  var apps = configRefs.map(function (config, i) {
                      // app injector
                      var ngZone = config.applicationRef.injector.get(core_1.NgZone);
                      // component injector
                      var http = config.componentRef.injector.get(http_1.Http, http_1.Http);
                      var promise = new Promise(function (resolve) {
                          ngZone.runOutsideAngular(function () {
                              var checkAmount = 0;
                              var checkCount = 0;
                              function checkStable() {
                                  // we setTimeout 10 after the first 20 turns
                                  checkCount++;
                                  if (checkCount === maxZoneTurns) {
                                      console.warn('\nWARNING: your application is taking longer than ' + maxZoneTurns + ' Zone turns. \n');
                                      return resolve(config);
                                  }
                                  if (checkCount === 20) {
                                      checkAmount = 10;
                                  }
                                  setTimeout(function () {
                                      if (ngZone.hasPendingMicrotasks) {
                                          return checkStable();
                                      }
                                      if (ngZone.hasPendingMacrotasks) {
                                          return checkStable();
                                      }
                                      if (http && http._async > 0) {
                                          return checkStable();
                                      }
                                      if (ngZone._isStable && typeof ngDoCheck === 'function') {
                                          var isStable = ngDoCheck(config);
                                          if (isStable === true) {
                                          }
                                          else if (typeof isStable !== 'boolean') {
                                              console.warn('\nWARNING: ngDoCheck must return a boolean value of either true or false\n');
                                          }
                                          else {
                                              return checkStable();
                                          }
                                      }
                                      if (ngZone._isStable) {
                                          return resolve(config);
                                      }
                                      return checkStable();
                                  }, checkAmount);
                              }
                              return checkStable();
                          });
                      });
                      return promise;
                  });
                  return Promise.all(apps);
              }
              return configRefs;
          })
              .catch(function (err) {
              console.log('Async Error:', err);
              throw err;
          })
              .then(function (configRefs) {
              if ('ngOnStable' in _this._config) {
                  if (!_this._config.ngOnStable) {
                      return configRefs;
                  }
                  var document_3 = configRefs[0].applicationRef.injector.get(platform_browser_1.DOCUMENT);
                  return Promise.resolve(_this._config.ngOnStable(configRefs, document_3)).then(function () { return configRefs; });
              }
              return configRefs;
          })
              .catch(function (err) {
              console.log('ngOnStable Error:', err);
              throw err;
          })
              .then(function (configRefs) {
              if ('preboot' in _this._config) {
                  if (!_this._config.preboot) {
                      return configRefs;
                  }
                  var prebootCode = ng_preboot_1.createPrebootCode(_this._config.directives, _this._config.preboot);
                  return prebootCode
                      .then(function (code) {
                      // TODO(gdi2290): manage the codegen better after preboot supports multiple appRoot
                      var lastRef = configRefs[configRefs.length - 1];
                      var el = lastRef.componentRef.location.nativeElement;
                      var script = document_1.parseFragment(code);
                      var prebootEl = DOM.createElement('div');
                      DOM.setInnerHTML(prebootEl, code);
                      DOM.insertAfter(el, prebootEl);
                      return configRefs;
                  });
              }
              return configRefs;
          })
              .catch(function (err) {
              console.log('preboot Error:', err);
              throw err;
          })
              .then(function (configRefs) {
              var document = configRefs[0].applicationRef.injector.get(platform_browser_1.DOCUMENT);
              var rendered = Bootloader.serializeDocument(document);
              // dispose;
              for (var i = 0; i < configRefs.length; i++) {
                  var config = configRefs[i];
                  config.componentRef.destroy();
                  config.applicationRef.dispose();
              }
              return rendered;
          })
              .catch(function (err) {
              console.log('Rendering Document Error:', err);
              throw err;
          })
              .then(function (rendered) {
              if ('beautify' in _this._config) {
                  if (!_this._config.beautify) {
                      return rendered;
                  }
                  var beautify = require('js-beautify');
                  return beautify.html(rendered, { indent_size: 2 });
              }
              return rendered;
          })
              .then(function (rendered) {
              if ('ngOnRendered' in _this._config) {
                  if (!_this._config.ngOnRendered) {
                      return rendered;
                  }
                  return Promise.resolve(_this._config.ngOnRendered(rendered)).then(function () { return rendered; });
              }
              return rendered;
          })
              .catch(function (err) {
              console.log('ngOnRendered Error:', err);
              throw err;
          });
      };
      Bootloader.prototype._bootstrapAll = function (Components, componentProviders) {
          var _this = this;
          var components = Components || this._config.directives;
          var providers = componentProviders || this._config.componentProviders;
          // .then(waitRouter)); // fixed by checkStable()
          var directives = components.map(function (component) { return _this.application().bootstrap(component); });
          return Promise.all(directives);
      };
      Bootloader.prototype._applicationAll = function (Components, providers) {
          var _this = this;
          var components = Components || this._config.directives;
          var doc = this.document(this._config.template || this._config.document);
          var directives = components.map(function (component) {
              // var applicationRef = this.application(doc, providers);
              // .then(waitRouter)); // fixed by checkStable()
              var appInjector = _this.application(doc, providers);
              var compRef = core_1.coreLoadAndBootstrap(appInjector, component);
              // let compRef = Promise.resolve(applicationRef.bootstrap(component));
              return compRef.then(function (componentRef) { return ({
                  applicationRef: appInjector.get(core_1.ApplicationRef),
                  componentRef: componentRef
              }); });
          });
          return Promise.all(directives);
      };
      Bootloader.prototype.dispose = function () {
          this.platformRef.dispose();
          this._config = null;
          this.platformRef = null;
      };
      return Bootloader;
  }());
  exports.Bootloader = Bootloader;
  function bootloader(config) {
      if (config === void 0) { config = {}; }
      return new Bootloader(config);
  }
  exports.bootloader = bootloader;
  //# sourceMappingURL=bootloader.js.map