text: "use strict";
  var collection_1 = require('angular2/src/facade/collection');
  var provider_1 = require('./provider');
  var exceptions_1 = require('./exceptions');
  var lang_1 = require('angular2/src/facade/lang');
  var exceptions_2 = require('angular2/src/facade/exceptions');
  var key_1 = require('./key');
  var metadata_1 = require('./metadata');
  // Threshold for the dynamic version
  var _MAX_CONSTRUCTION_COUNTER = 10;
  exports.UNDEFINED = lang_1.CONST_EXPR(new Object());
  /**
   * Visibility of a {@link Provider}.
   */
  (function (Visibility) {
      /**
       * A `Public` {@link Provider} is only visible to regular (as opposed to host) child injectors.
       */
      Visibility[Visibility["Public"] = 0] = "Public";
      /**
       * A `Private` {@link Provider} is only visible to host (as opposed to regular) child injectors.
       */
      Visibility[Visibility["Private"] = 1] = "Private";
      /**
       * A `PublicAndPrivate` {@link Provider} is visible to both host and regular child injectors.
       */
      Visibility[Visibility["PublicAndPrivate"] = 2] = "PublicAndPrivate";
  })(exports.Visibility || (exports.Visibility = {}));
  var Visibility = exports.Visibility;
  function canSee(src, dst) {
      return (src === dst) ||
          (dst === Visibility.PublicAndPrivate || src === Visibility.PublicAndPrivate);
  }
  var ProtoInjectorInlineStrategy = (function () {
      function ProtoInjectorInlineStrategy(protoEI, bwv) {
          this.provider0 = null;
          this.provider1 = null;
          this.provider2 = null;
          this.provider3 = null;
          this.provider4 = null;
          this.provider5 = null;
          this.provider6 = null;
          this.provider7 = null;
          this.provider8 = null;
          this.provider9 = null;
          this.keyId0 = null;
          this.keyId1 = null;
          this.keyId2 = null;
          this.keyId3 = null;
          this.keyId4 = null;
          this.keyId5 = null;
          this.keyId6 = null;
          this.keyId7 = null;
          this.keyId8 = null;
          this.keyId9 = null;
          this.visibility0 = null;
          this.visibility1 = null;
          this.visibility2 = null;
          this.visibility3 = null;
          this.visibility4 = null;
          this.visibility5 = null;
          this.visibility6 = null;
          this.visibility7 = null;
          this.visibility8 = null;
          this.visibility9 = null;
          var length = bwv.length;
          if (length > 0) {
              this.provider0 = bwv[0].provider;
              this.keyId0 = bwv[0].getKeyId();
              this.visibility0 = bwv[0].visibility;
          }
          if (length > 1) {
              this.provider1 = bwv[1].provider;
              this.keyId1 = bwv[1].getKeyId();
              this.visibility1 = bwv[1].visibility;
          }
          if (length > 2) {
              this.provider2 = bwv[2].provider;
              this.keyId2 = bwv[2].getKeyId();
              this.visibility2 = bwv[2].visibility;
          }
          if (length > 3) {
              this.provider3 = bwv[3].provider;
              this.keyId3 = bwv[3].getKeyId();
              this.visibility3 = bwv[3].visibility;
          }
          if (length > 4) {
              this.provider4 = bwv[4].provider;
              this.keyId4 = bwv[4].getKeyId();
              this.visibility4 = bwv[4].visibility;
          }
          if (length > 5) {
              this.provider5 = bwv[5].provider;
              this.keyId5 = bwv[5].getKeyId();
              this.visibility5 = bwv[5].visibility;
          }
          if (length > 6) {
              this.provider6 = bwv[6].provider;
              this.keyId6 = bwv[6].getKeyId();
              this.visibility6 = bwv[6].visibility;
          }
          if (length > 7) {
              this.provider7 = bwv[7].provider;
              this.keyId7 = bwv[7].getKeyId();
              this.visibility7 = bwv[7].visibility;
          }
          if (length > 8) {
              this.provider8 = bwv[8].provider;
              this.keyId8 = bwv[8].getKeyId();
              this.visibility8 = bwv[8].visibility;
          }
          if (length > 9) {
              this.provider9 = bwv[9].provider;
              this.keyId9 = bwv[9].getKeyId();
              this.visibility9 = bwv[9].visibility;
          }
      }
      ProtoInjectorInlineStrategy.prototype.getProviderAtIndex = function (index) {
          if (index == 0)
              return this.provider0;
          if (index == 1)
              return this.provider1;
          if (index == 2)
              return this.provider2;
          if (index == 3)
              return this.provider3;
          if (index == 4)
              return this.provider4;
          if (index == 5)
              return this.provider5;
          if (index == 6)
              return this.provider6;
          if (index == 7)
              return this.provider7;
          if (index == 8)
              return this.provider8;
          if (index == 9)
              return this.provider9;
          throw new exceptions_1.OutOfBoundsError(index);
      };
      ProtoInjectorInlineStrategy.prototype.createInjectorStrategy = function (injector) {
          return new InjectorInlineStrategy(injector, this);
      };
      return ProtoInjectorInlineStrategy;
  }());
  exports.ProtoInjectorInlineStrategy = ProtoInjectorInlineStrategy;
  var ProtoInjectorDynamicStrategy = (function () {
      function ProtoInjectorDynamicStrategy(protoInj, bwv) {
          var len = bwv.length;
          this.providers = collection_1.ListWrapper.createFixedSize(len);
          this.keyIds = collection_1.ListWrapper.createFixedSize(len);
          this.visibilities = collection_1.ListWrapper.createFixedSize(len);
          for (var i = 0; i < len; i++) {
              this.providers[i] = bwv[i].provider;
              this.keyIds[i] = bwv[i].getKeyId();
              this.visibilities[i] = bwv[i].visibility;
          }
      }
      ProtoInjectorDynamicStrategy.prototype.getProviderAtIndex = function (index) {
          if (index < 0 || index >= this.providers.length) {
              throw new exceptions_1.OutOfBoundsError(index);
          }
          return this.providers[index];
      };
      ProtoInjectorDynamicStrategy.prototype.createInjectorStrategy = function (ei) {
          return new InjectorDynamicStrategy(this, ei);
      };
      return ProtoInjectorDynamicStrategy;
  }());
  exports.ProtoInjectorDynamicStrategy = ProtoInjectorDynamicStrategy;
  var ProtoInjector = (function () {
      function ProtoInjector(bwv) {
          this.numberOfProviders = bwv.length;
          this._strategy = bwv.length > _MAX_CONSTRUCTION_COUNTER ?
              new ProtoInjectorDynamicStrategy(this, bwv) :
              new ProtoInjectorInlineStrategy(this, bwv);
      }
      ProtoInjector.fromResolvedProviders = function (providers) {
          var bd = providers.map(function (b) { return new ProviderWithVisibility(b, Visibility.Public); });
          return new ProtoInjector(bd);
      };
      ProtoInjector.prototype.getProviderAtIndex = function (index) {
          return this._strategy.getProviderAtIndex(index);
      };
      return ProtoInjector;
  }());
  exports.ProtoInjector = ProtoInjector;
  var InjectorInlineStrategy = (function () {
      function InjectorInlineStrategy(injector, protoStrategy) {
          this.injector = injector;
          this.protoStrategy = protoStrategy;
          this.obj0 = exports.UNDEFINED;
          this.obj1 = exports.UNDEFINED;
          this.obj2 = exports.UNDEFINED;
          this.obj3 = exports.UNDEFINED;
          this.obj4 = exports.UNDEFINED;
          this.obj5 = exports.UNDEFINED;
          this.obj6 = exports.UNDEFINED;
          this.obj7 = exports.UNDEFINED;
          this.obj8 = exports.UNDEFINED;
          this.obj9 = exports.UNDEFINED;
      }
      InjectorInlineStrategy.prototype.resetConstructionCounter = function () { this.injector._constructionCounter = 0; };
      InjectorInlineStrategy.prototype.instantiateProvider = function (provider, visibility) {
          return this.injector._new(provider, visibility);
      };
      InjectorInlineStrategy.prototype.getObjByKeyId = function (keyId, visibility) {
          var p = this.protoStrategy;
          var inj = this.injector;
          if (p.keyId0 === keyId && canSee(p.visibility0, visibility)) {
              if (this.obj0 === exports.UNDEFINED) {
                  this.obj0 = inj._new(p.provider0, p.visibility0);
              }
              return this.obj0;
          }
          if (p.keyId1 === keyId && canSee(p.visibility1, visibility)) {
              if (this.obj1 === exports.UNDEFINED) {
                  this.obj1 = inj._new(p.provider1, p.visibility1);
              }
              return this.obj1;
          }
          if (p.keyId2 === keyId && canSee(p.visibility2, visibility)) {
              if (this.obj2 === exports.UNDEFINED) {
                  this.obj2 = inj._new(p.provider2, p.visibility2);
              }
              return this.obj2;
          }
          if (p.keyId3 === keyId && canSee(p.visibility3, visibility)) {
              if (this.obj3 === exports.UNDEFINED) {
                  this.obj3 = inj._new(p.provider3, p.visibility3);
              }
              return this.obj3;
          }
          if (p.keyId4 === keyId && canSee(p.visibility4, visibility)) {
              if (this.obj4 === exports.UNDEFINED) {
                  this.obj4 = inj._new(p.provider4, p.visibility4);
              }
              return this.obj4;
          }
          if (p.keyId5 === keyId && canSee(p.visibility5, visibility)) {
              if (this.obj5 === exports.UNDEFINED) {
                  this.obj5 = inj._new(p.provider5, p.visibility5);
              }
              return this.obj5;
          }
          if (p.keyId6 === keyId && canSee(p.visibility6, visibility)) {
              if (this.obj6 === exports.UNDEFINED) {
                  this.obj6 = inj._new(p.provider6, p.visibility6);
              }
              return this.obj6;
          }
          if (p.keyId7 === keyId && canSee(p.visibility7, visibility)) {
              if (this.obj7 === exports.UNDEFINED) {
                  this.obj7 = inj._new(p.provider7, p.visibility7);
              }
              return this.obj7;
          }
          if (p.keyId8 === keyId && canSee(p.visibility8, visibility)) {
              if (this.obj8 === exports.UNDEFINED) {
                  this.obj8 = inj._new(p.provider8, p.visibility8);
              }
              return this.obj8;
          }
          if (p.keyId9 === keyId && canSee(p.visibility9, visibility)) {
              if (this.obj9 === exports.UNDEFINED) {
                  this.obj9 = inj._new(p.provider9, p.visibility9);
              }
              return this.obj9;
          }
          return exports.UNDEFINED;
      };
      InjectorInlineStrategy.prototype.getObjAtIndex = function (index) {
          if (index == 0)
              return this.obj0;
          if (index == 1)
              return this.obj1;
          if (index == 2)
              return this.obj2;
          if (index == 3)
              return this.obj3;
          if (index == 4)
              return this.obj4;
          if (index == 5)
              return this.obj5;
          if (index == 6)
              return this.obj6;
          if (index == 7)
              return this.obj7;
          if (index == 8)
              return this.obj8;
          if (index == 9)
              return this.obj9;
          throw new exceptions_1.OutOfBoundsError(index);
      };
      InjectorInlineStrategy.prototype.getMaxNumberOfObjects = function () { return _MAX_CONSTRUCTION_COUNTER; };
      return InjectorInlineStrategy;
  }());
  exports.InjectorInlineStrategy = InjectorInlineStrategy;
  var InjectorDynamicStrategy = (function () {
      function InjectorDynamicStrategy(protoStrategy, injector) {
          this.protoStrategy = protoStrategy;
          this.injector = injector;
          this.objs = collection_1.ListWrapper.createFixedSize(protoStrategy.providers.length);
          collection_1.ListWrapper.fill(this.objs, exports.UNDEFINED);
      }
      InjectorDynamicStrategy.prototype.resetConstructionCounter = function () { this.injector._constructionCounter = 0; };
      InjectorDynamicStrategy.prototype.instantiateProvider = function (provider, visibility) {
          return this.injector._new(provider, visibility);
      };
      InjectorDynamicStrategy.prototype.getObjByKeyId = function (keyId, visibility) {
          var p = this.protoStrategy;
          for (var i = 0; i < p.keyIds.length; i++) {
              if (p.keyIds[i] === keyId && canSee(p.visibilities[i], visibility)) {
                  if (this.objs[i] === exports.UNDEFINED) {
                      this.objs[i] = this.injector._new(p.providers[i], p.visibilities[i]);
                  }
                  return this.objs[i];
              }
          }
          return exports.UNDEFINED;
      };
      InjectorDynamicStrategy.prototype.getObjAtIndex = function (index) {
          if (index < 0 || index >= this.objs.length) {
              throw new exceptions_1.OutOfBoundsError(index);
          }
          return this.objs[index];
      };
      InjectorDynamicStrategy.prototype.getMaxNumberOfObjects = function () { return this.objs.length; };
      return InjectorDynamicStrategy;
  }());
  exports.InjectorDynamicStrategy = InjectorDynamicStrategy;
  var ProviderWithVisibility = (function () {
      function ProviderWithVisibility(provider, visibility) {
          this.provider = provider;
          this.visibility = visibility;
      }
      ;
      ProviderWithVisibility.prototype.getKeyId = function () { return this.provider.key.id; };
      return ProviderWithVisibility;
  }());
  exports.ProviderWithVisibility = ProviderWithVisibility;
  /**
   * A dependency injection container used for instantiating objects and resolving dependencies.
   *
   * An `Injector` is a replacement for a `new` operator, which can automatically resolve the
   * constructor dependencies.
   *
   * In typical use, application code asks for the dependencies in the constructor and they are
   * resolved by the `Injector`.
   *
   * ### Example ([live demo](http://plnkr.co/edit/jzjec0?p=preview))
   *
   * The following example creates an `Injector` configured to create `Engine` and `Car`.
   *
   * ```typescript
   * @Injectable()
   * class Engine {
   * }
   *
   * @Injectable()
   * class Car {
   *   constructor(public engine:Engine) {}
   * }
   *
   * var injector = Injector.resolveAndCreate([Car, Engine]);
   * var car = injector.get(Car);
   * expect(car instanceof Car).toBe(true);
   * expect(car.engine instanceof Engine).toBe(true);
   * ```
   *
   * Notice, we don't use the `new` operator because we explicitly want to have the `Injector`
   * resolve all of the object's dependencies automatically.
   */
  var Injector = (function () {
      /**
       * Private
       */
      function Injector(_proto /* ProtoInjector */, _parent, _isHostBoundary, _depProvider, _debugContext) {
          if (_parent === void 0) { _parent = null; }
          if (_isHostBoundary === void 0) { _isHostBoundary = false; }
          if (_depProvider === void 0) { _depProvider = null; }
          if (_debugContext === void 0) { _debugContext = null; }
          this._isHostBoundary = _isHostBoundary;
          this._depProvider = _depProvider;
          this._debugContext = _debugContext;
          /** @internal */
          this._constructionCounter = 0;
          this._proto = _proto;
          this._parent = _parent;
          this._strategy = _proto._strategy.createInjectorStrategy(this);
      }
      /**
       * Turns an array of provider definitions into an array of resolved providers.
       *
       * A resolution is a process of flattening multiple nested arrays and converting individual
       * providers into an array of {@link ResolvedProvider}s.
       *
       * ### Example ([live demo](http://plnkr.co/edit/AiXTHi?p=preview))
       *
       * ```typescript
       * @Injectable()
       * class Engine {
       * }
       *
       * @Injectable()
       * class Car {
       *   constructor(public engine:Engine) {}
       * }
       *
       * var providers = Injector.resolve([Car, [[Engine]]]);
       *
       * expect(providers.length).toEqual(2);
       *
       * expect(providers[0] instanceof ResolvedProvider).toBe(true);
       * expect(providers[0].key.displayName).toBe("Car");
       * expect(providers[0].dependencies.length).toEqual(1);
       * expect(providers[0].factory).toBeDefined();
       *
       * expect(providers[1].key.displayName).toBe("Engine");
       * });
       * ```
       *
       * See {@link Injector#fromResolvedProviders} for more info.
       */
      Injector.resolve = function (providers) {
          return provider_1.resolveProviders(providers);
      };
      /**
       * Resolves an array of providers and creates an injector from those providers.
       *
       * The passed-in providers can be an array of `Type`, {@link Provider},
       * or a recursive array of more providers.
       *
       * ### Example ([live demo](http://plnkr.co/edit/ePOccA?p=preview))
       *
       * ```typescript
       * @Injectable()
       * class Engine {
       * }
       *
       * @Injectable()
       * class Car {
       *   constructor(public engine:Engine) {}
       * }
       *
       * var injector = Injector.resolveAndCreate([Car, Engine]);
       * expect(injector.get(Car) instanceof Car).toBe(true);
       * ```
       *
       * This function is slower than the corresponding `fromResolvedProviders`
       * because it needs to resolve the passed-in providers first.
       * See {@link Injector#resolve} and {@link Injector#fromResolvedProviders}.
       */
      Injector.resolveAndCreate = function (providers) {
          var resolvedProviders = Injector.resolve(providers);
          return Injector.fromResolvedProviders(resolvedProviders);
      };
      /**
       * Creates an injector from previously resolved providers.
       *
       * This API is the recommended way to construct injectors in performance-sensitive parts.
       *
       * ### Example ([live demo](http://plnkr.co/edit/KrSMci?p=preview))
       *
       * ```typescript
       * @Injectable()
       * class Engine {
       * }
       *
       * @Injectable()
       * class Car {
       *   constructor(public engine:Engine) {}
       * }
       *
       * var providers = Injector.resolve([Car, Engine]);
       * var injector = Injector.fromResolvedProviders(providers);
       * expect(injector.get(Car) instanceof Car).toBe(true);
       * ```
       */
      Injector.fromResolvedProviders = function (providers) {
          return new Injector(ProtoInjector.fromResolvedProviders(providers));
      };
      /**
       * @deprecated
       */
      Injector.fromResolvedBindings = function (providers) {
          return Injector.fromResolvedProviders(providers);
      };
      Object.defineProperty(Injector.prototype, "hostBoundary", {
          /**
           * Whether this injector is a boundary to a host.
           * @internal
           */
          get: function () { return this._isHostBoundary; },
          enumerable: true,
          configurable: true
      });
      /**
       * @internal
       */
      Injector.prototype.debugContext = function () { return this._debugContext(); };
      /**
       * Retrieves an instance from the injector based on the provided token.
       * Throws {@link NoProviderError} if not found.
       *
       * ### Example ([live demo](http://plnkr.co/edit/HeXSHg?p=preview))
       *
       * ```typescript
       * var injector = Injector.resolveAndCreate([
       *   provide("validToken", {useValue: "Value"})
       * ]);
       * expect(injector.get("validToken")).toEqual("Value");
       * expect(() => injector.get("invalidToken")).toThrowError();
       * ```
       *
       * `Injector` returns itself when given `Injector` as a token.
       *
       * ```typescript
       * var injector = Injector.resolveAndCreate([]);
       * expect(injector.get(Injector)).toBe(injector);
       * ```
       */
      Injector.prototype.get = function (token) {
          return this._getByKey(key_1.Key.get(token), null, null, false, Visibility.PublicAndPrivate);
      };
      /**
       * Retrieves an instance from the injector based on the provided token.
       * Returns null if not found.
       *
       * ### Example ([live demo](http://plnkr.co/edit/tpEbEy?p=preview))
       *
       * ```typescript
       * var injector = Injector.resolveAndCreate([
       *   provide("validToken", {useValue: "Value"})
       * ]);
       * expect(injector.getOptional("validToken")).toEqual("Value");
       * expect(injector.getOptional("invalidToken")).toBe(null);
       * ```
       *
       * `Injector` returns itself when given `Injector` as a token.
       *
       * ```typescript
       * var injector = Injector.resolveAndCreate([]);
       * expect(injector.getOptional(Injector)).toBe(injector);
       * ```
       */
      Injector.prototype.getOptional = function (token) {
          return this._getByKey(key_1.Key.get(token), null, null, true, Visibility.PublicAndPrivate);
      };
      /**
       * @internal
       */
      Injector.prototype.getAt = function (index) { return this._strategy.getObjAtIndex(index); };
      Object.defineProperty(Injector.prototype, "parent", {
          /**
           * Parent of this injector.
           *
           * <!-- TODO: Add a link to the section of the user guide talking about hierarchical injection.
           * -->
           *
           * ### Example ([live demo](http://plnkr.co/edit/eosMGo?p=preview))
           *
           * ```typescript
           * var parent = Injector.resolveAndCreate([]);
           * var child = parent.resolveAndCreateChild([]);
           * expect(child.parent).toBe(parent);
           * ```
           */
          get: function () { return this._parent; },
          enumerable: true,
          configurable: true
      });
      Object.defineProperty(Injector.prototype, "internalStrategy", {
          /**
           * @internal
           * Internal. Do not use.
           * We return `any` not to export the InjectorStrategy type.
           */
          get: function () { return this._strategy; },
          enumerable: true,
          configurable: true
      });
      /**
       * Resolves an array of providers and creates a child injector from those providers.
       *
       * <!-- TODO: Add a link to the section of the user guide talking about hierarchical injection.
       * -->
       *
       * The passed-in providers can be an array of `Type`, {@link Provider},
       * or a recursive array of more providers.
       *
       * ### Example ([live demo](http://plnkr.co/edit/opB3T4?p=preview))
       *
       * ```typescript
       * class ParentProvider {}
       * class ChildProvider {}
       *
       * var parent = Injector.resolveAndCreate([ParentProvider]);
       * var child = parent.resolveAndCreateChild([ChildProvider]);
       *
       * expect(child.get(ParentProvider) instanceof ParentProvider).toBe(true);
       * expect(child.get(ChildProvider) instanceof ChildProvider).toBe(true);
       * expect(child.get(ParentProvider)).toBe(parent.get(ParentProvider));
       * ```
       *
       * This function is slower than the corresponding `createChildFromResolved`
       * because it needs to resolve the passed-in providers first.
       * See {@link Injector#resolve} and {@link Injector#createChildFromResolved}.
       */
      Injector.prototype.resolveAndCreateChild = function (providers) {
          var resolvedProviders = Injector.resolve(providers);
          return this.createChildFromResolved(resolvedProviders);
      };
      /**
       * Creates a child injector from previously resolved providers.
       *
       * <!-- TODO: Add a link to the section of the user guide talking about hierarchical injection.
       * -->
       *
       * This API is the recommended way to construct injectors in performance-sensitive parts.
       *
       * ### Example ([live demo](http://plnkr.co/edit/VhyfjN?p=preview))
       *
       * ```typescript
       * class ParentProvider {}
       * class ChildProvider {}
       *
       * var parentProviders = Injector.resolve([ParentProvider]);
       * var childProviders = Injector.resolve([ChildProvider]);
       *
       * var parent = Injector.fromResolvedProviders(parentProviders);
       * var child = parent.createChildFromResolved(childProviders);
       *
       * expect(child.get(ParentProvider) instanceof ParentProvider).toBe(true);
       * expect(child.get(ChildProvider) instanceof ChildProvider).toBe(true);
       * expect(child.get(ParentProvider)).toBe(parent.get(ParentProvider));
       * ```
       */
      Injector.prototype.createChildFromResolved = function (providers) {
          var bd = providers.map(function (b) { return new ProviderWithVisibility(b, Visibility.Public); });
          var proto = new ProtoInjector(bd);
          var inj = new Injector(proto);
          inj._parent = this;
          return inj;
      };
      /**
       * Resolves a provider and instantiates an object in the context of the injector.
       *
       * The created object does not get cached by the injector.
       *
       * ### Example ([live demo](http://plnkr.co/edit/yvVXoB?p=preview))
       *
       * ```typescript
       * @Injectable()
       * class Engine {
       * }
       *
       * @Injectable()
       * class Car {
       *   constructor(public engine:Engine) {}
       * }
       *
       * var injector = Injector.resolveAndCreate([Engine]);
       *
       * var car = injector.resolveAndInstantiate(Car);
       * expect(car.engine).toBe(injector.get(Engine));
       * expect(car).not.toBe(injector.resolveAndInstantiate(Car));
       * ```
       */
      Injector.prototype.resolveAndInstantiate = function (provider) {
          return this.instantiateResolved(Injector.resolve([provider])[0]);
      };
      /**
       * Instantiates an object using a resolved provider in the context of the injector.
       *
       * The created object does not get cached by the injector.
       *
       * ### Example ([live demo](http://plnkr.co/edit/ptCImQ?p=preview))
       *
       * ```typescript
       * @Injectable()
       * class Engine {
       * }
       *
       * @Injectable()
       * class Car {
       *   constructor(public engine:Engine) {}
       * }
       *
       * var injector = Injector.resolveAndCreate([Engine]);
       * var carProvider = Injector.resolve([Car])[0];
       * var car = injector.instantiateResolved(carProvider);
       * expect(car.engine).toBe(injector.get(Engine));
       * expect(car).not.toBe(injector.instantiateResolved(carProvider));
       * ```
       */
      Injector.prototype.instantiateResolved = function (provider) {
          return this._instantiateProvider(provider, Visibility.PublicAndPrivate);
      };
      /** @internal */
      Injector.prototype._new = function (provider, visibility) {
          if (this._constructionCounter++ > this._strategy.getMaxNumberOfObjects()) {
              throw new exceptions_1.CyclicDependencyError(this, provider.key);
          }
          return this._instantiateProvider(provider, visibility);
      };
      Injector.prototype._instantiateProvider = function (provider, visibility) {
          if (provider.multiProvider) {
              var res = collection_1.ListWrapper.createFixedSize(provider.resolvedFactories.length);
              for (var i = 0; i < provider.resolvedFactories.length; ++i) {
                  res[i] = this._instantiate(provider, provider.resolvedFactories[i], visibility);
              }
              return res;
          }
          else {
              return this._instantiate(provider, provider.resolvedFactories[0], visibility);
          }
      };
      Injector.prototype._instantiate = function (provider, resolvedFactory, visibility) {
          var factory = resolvedFactory.factory;
          var deps = resolvedFactory.dependencies;
          var length = deps.length;
          var d0;
          var d1;
          var d2;
          var d3;
          var d4;
          var d5;
          var d6;
          var d7;
          var d8;
          var d9;
          var d10;
          var d11;
          var d12;
          var d13;
          var d14;
          var d15;
          var d16;
          var d17;
          var d18;
          var d19;
          try {
              d0 = length > 0 ? this._getByDependency(provider, deps[0], visibility) : null;
              d1 = length > 1 ? this._getByDependency(provider, deps[1], visibility) : null;
              d2 = length > 2 ? this._getByDependency(provider, deps[2], visibility) : null;
              d3 = length > 3 ? this._getByDependency(provider, deps[3], visibility) : null;
              d4 = length > 4 ? this._getByDependency(provider, deps[4], visibility) : null;
              d5 = length > 5 ? this._getByDependency(provider, deps[5], visibility) : null;
              d6 = length > 6 ? this._getByDependency(provider, deps[6], visibility) : null;
              d7 = length > 7 ? this._getByDependency(provider, deps[7], visibility) : null;
              d8 = length > 8 ? this._getByDependency(provider, deps[8], visibility) : null;
              d9 = length > 9 ? this._getByDependency(provider, deps[9], visibility) : null;
              d10 = length > 10 ? this._getByDependency(provider, deps[10], visibility) : null;
              d11 = length > 11 ? this._getByDependency(provider, deps[11], visibility) : null;
              d12 = length > 12 ? this._getByDependency(provider, deps[12], visibility) : null;
              d13 = length > 13 ? this._getByDependency(provider, deps[13], visibility) : null;
              d14 = length > 14 ? this._getByDependency(provider, deps[14], visibility) : null;
              d15 = length > 15 ? this._getByDependency(provider, deps[15], visibility) : null;
              d16 = length > 16 ? this._getByDependency(provider, deps[16], visibility) : null;
              d17 = length > 17 ? this._getByDependency(provider, deps[17], visibility) : null;
              d18 = length > 18 ? this._getByDependency(provider, deps[18], visibility) : null;
              d19 = length > 19 ? this._getByDependency(provider, deps[19], visibility) : null;
          }
          catch (e) {
              if (e instanceof exceptions_1.AbstractProviderError || e instanceof exceptions_1.InstantiationError) {
                  e.addKey(this, provider.key);
              }
              throw e;
          }
          var obj;
          try {
              switch (length) {
                  case 0:
                      obj = factory();
                      break;
                  case 1:
                      obj = factory(d0);
                      break;
                  case 2:
                      obj = factory(d0, d1);
                      break;
                  case 3:
                      obj = factory(d0, d1, d2);
                      break;
                  case 4:
                      obj = factory(d0, d1, d2, d3);
                      break;
                  case 5:
                      obj = factory(d0, d1, d2, d3, d4);
                      break;
                  case 6:
                      obj = factory(d0, d1, d2, d3, d4, d5);
                      break;
                  case 7:
                      obj = factory(d0, d1, d2, d3, d4, d5, d6);
                      break;
                  case 8:
                      obj = factory(d0, d1, d2, d3, d4, d5, d6, d7);
                      break;
                  case 9:
                      obj = factory(d0, d1, d2, d3, d4, d5, d6, d7, d8);
                      break;
                  case 10:
                      obj = factory(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9);
                      break;
                  case 11:
                      obj = factory(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10);
                      break;
                  case 12:
                      obj = factory(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11);
                      break;
                  case 13:
                      obj = factory(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11, d12);
                      break;
                  case 14:
                      obj = factory(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11, d12, d13);
                      break;
                  case 15:
                      obj = factory(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11, d12, d13, d14);
                      break;
                  case 16:
                      obj = factory(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11, d12, d13, d14, d15);
                      break;
                  case 17:
                      obj = factory(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11, d12, d13, d14, d15, d16);
                      break;
                  case 18:
                      obj = factory(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11, d12, d13, d14, d15, d16, d17);
                      break;
                  case 19:
                      obj = factory(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11, d12, d13, d14, d15, d16, d17, d18);
                      break;
                  case 20:
                      obj = factory(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11, d12, d13, d14, d15, d16, d17, d18, d19);
                      break;
                  default:
                      throw new exceptions_2.BaseException("Cannot instantiate '" + provider.key.displayName + "' because it has more than 20 dependencies");
              }
          }
          catch (e) {
              throw new exceptions_1.InstantiationError(this, e, e.stack, provider.key);
          }
          return obj;
      };
      Injector.prototype._getByDependency = function (provider, dep, providerVisibility) {
          var special = lang_1.isPresent(this._depProvider) ?
              this._depProvider.getDependency(this, provider, dep) :
              exports.UNDEFINED;
          if (special !== exports.UNDEFINED) {
              return special;
          }
          else {
              return this._getByKey(dep.key, dep.lowerBoundVisibility, dep.upperBoundVisibility, dep.optional, providerVisibility);
          }
      };
      Injector.prototype._getByKey = function (key, lowerBoundVisibility, upperBoundVisibility, optional, providerVisibility) {
          if (key === INJECTOR_KEY) {
              return this;
          }
          if (upperBoundVisibility instanceof metadata_1.SelfMetadata) {
              return this._getByKeySelf(key, optional, providerVisibility);
          }
          else if (upperBoundVisibility instanceof metadata_1.HostMetadata) {
              return this._getByKeyHost(key, optional, providerVisibility, lowerBoundVisibility);
          }
          else {
              return this._getByKeyDefault(key, optional, providerVisibility, lowerBoundVisibility);
          }
      };
      /** @internal */
      Injector.prototype._throwOrNull = function (key, optional) {
          if (optional) {
              return null;
          }
          else {
              throw new exceptions_1.NoProviderError(this, key);
          }
      };
      /** @internal */
      Injector.prototype._getByKeySelf = function (key, optional, providerVisibility) {
          var obj = this._strategy.getObjByKeyId(key.id, providerVisibility);
          return (obj !== exports.UNDEFINED) ? obj : this._throwOrNull(key, optional);
      };
      /** @internal */
      Injector.prototype._getByKeyHost = function (key, optional, providerVisibility, lowerBoundVisibility) {
          var inj = this;
          if (lowerBoundVisibility instanceof metadata_1.SkipSelfMetadata) {
              if (inj._isHostBoundary) {
                  return this._getPrivateDependency(key, optional, inj);
              }
              else {
                  inj = inj._parent;
              }
          }
          while (inj != null) {
              var obj = inj._strategy.getObjByKeyId(key.id, providerVisibility);
              if (obj !== exports.UNDEFINED)
                  return obj;
              if (lang_1.isPresent(inj._parent) && inj._isHostBoundary) {
                  return this._getPrivateDependency(key, optional, inj);
              }
              else {
                  inj = inj._parent;
              }
          }
          return this._throwOrNull(key, optional);
      };
      /** @internal */
      Injector.prototype._getPrivateDependency = function (key, optional, inj) {
          var obj = inj._parent._strategy.getObjByKeyId(key.id, Visibility.Private);
          return (obj !== exports.UNDEFINED) ? obj : this._throwOrNull(key, optional);
      };
      /** @internal */
      Injector.prototype._getByKeyDefault = function (key, optional, providerVisibility, lowerBoundVisibility) {
          var inj = this;
          if (lowerBoundVisibility instanceof metadata_1.SkipSelfMetadata) {
              providerVisibility = inj._isHostBoundary ? Visibility.PublicAndPrivate : Visibility.Public;
              inj = inj._parent;
          }
          while (inj != null) {
              var obj = inj._strategy.getObjByKeyId(key.id, providerVisibility);
              if (obj !== exports.UNDEFINED)
                  return obj;
              providerVisibility = inj._isHostBoundary ? Visibility.PublicAndPrivate : Visibility.Public;
              inj = inj._parent;
          }
          return this._throwOrNull(key, optional);
      };
      Object.defineProperty(Injector.prototype, "displayName", {
          get: function () {
              return "Injector(providers: [" + _mapProviders(this, function (b) { return (" \"" + b.key.displayName + "\" "); }).join(", ") + "])";
          },
          enumerable: true,
          configurable: true
      });
      Injector.prototype.toString = function () { return this.displayName; };
      return Injector;
  }());
  exports.Injector = Injector;
  var INJECTOR_KEY = key_1.Key.get(Injector);
  function _mapProviders(injector, fn) {
      var res = [];
      for (var i = 0; i < injector._proto.numberOfProviders; ++i) {
          res.push(fn(injector._proto.getProviderAtIndex(i)));
      }
      return res;
  }
  //# sourceMappingURL=injector.js.map