text: 'use strict';var lang_1 = require('angular2/src/core/facade/lang');
  var exceptions_1 = require('angular2/src/core/facade/exceptions');
  var abstract_change_detector_1 = require('./abstract_change_detector');
  var change_detection_util_1 = require('./change_detection_util');
  var codegen_name_util_1 = require('./codegen_name_util');
  var codegen_logic_util_1 = require('./codegen_logic_util');
  var codegen_facade_1 = require('./codegen_facade');
  var proto_change_detector_1 = require('./proto_change_detector');
  /**
   * The code generator takes a list of proto records and creates a function/class
   * that "emulates" what the developer would write by hand to implement the same
   * kind of behaviour.
   *
   * This code should be kept in sync with the Dart transformer's
   * `angular2.transform.template_compiler.change_detector_codegen` library. If you make updates
   * here, please make equivalent changes there.
  */
  var IS_CHANGED_LOCAL = "isChanged";
  var CHANGES_LOCAL = "changes";
  var ChangeDetectorJITGenerator = (function () {
      function ChangeDetectorJITGenerator(definition, changeDetectionUtilVarName, abstractChangeDetectorVarName) {
          this.changeDetectionUtilVarName = changeDetectionUtilVarName;
          this.abstractChangeDetectorVarName = abstractChangeDetectorVarName;
          var propertyBindingRecords = proto_change_detector_1.createPropertyRecords(definition);
          var eventBindingRecords = proto_change_detector_1.createEventRecords(definition);
          var propertyBindingTargets = definition.bindingRecords.map(function (b) { return b.target; });
          this.id = definition.id;
          this.changeDetectionStrategy = definition.strategy;
          this.genConfig = definition.genConfig;
          this.records = propertyBindingRecords;
          this.propertyBindingTargets = propertyBindingTargets;
          this.eventBindings = eventBindingRecords;
          this.directiveRecords = definition.directiveRecords;
          this._names = new codegen_name_util_1.CodegenNameUtil(this.records, this.eventBindings, this.directiveRecords, this.changeDetectionUtilVarName);
          this._logic = new codegen_logic_util_1.CodegenLogicUtil(this._names, this.changeDetectionUtilVarName, this.changeDetectionStrategy);
          this.typeName = codegen_name_util_1.sanitizeName("ChangeDetector_" + this.id);
      }
      ChangeDetectorJITGenerator.prototype.generate = function () {
          var factorySource = "\n      " + this.generateSource() + "\n      return function(dispatcher) {\n        return new " + this.typeName + "(dispatcher);\n      }\n    ";
          return new Function(this.abstractChangeDetectorVarName, this.changeDetectionUtilVarName, factorySource)(abstract_change_detector_1.AbstractChangeDetector, change_detection_util_1.ChangeDetectionUtil);
      };
      ChangeDetectorJITGenerator.prototype.generateSource = function () {
          var _this = this;
          return "\n      var " + this.typeName + " = function " + this.typeName + "(dispatcher) {\n        " + this.abstractChangeDetectorVarName + ".call(\n            this, " + JSON.stringify(this.id) + ", dispatcher, " + this.records.length + ",\n            " + this.typeName + ".gen_propertyBindingTargets, " + this.typeName + ".gen_directiveIndices,\n            " + codegen_facade_1.codify(this.changeDetectionStrategy) + ");\n        this.dehydrateDirectives(false);\n      }\n\n      " + this.typeName + ".prototype = Object.create(" + this.abstractChangeDetectorVarName + ".prototype);\n\n      " + this.typeName + ".prototype.detectChangesInRecordsInternal = function(throwOnChange) {\n        " + this._names.genInitLocals() + "\n        var " + IS_CHANGED_LOCAL + " = false;\n        var " + CHANGES_LOCAL + " = null;\n\n        " + this.records.map(function (r) { return _this._genRecord(r); }).join("\n") + "\n      }\n\n      " + this._maybeGenHandleEventInternal() + "\n\n      " + this._genCheckNoChanges() + "\n\n      " + this._maybeGenAfterContentLifecycleCallbacks() + "\n\n      " + this._maybeGenAfterViewLifecycleCallbacks() + "\n\n      " + this._maybeGenHydrateDirectives() + "\n\n      " + this._maybeGenDehydrateDirectives() + "\n\n      " + this._genPropertyBindingTargets() + "\n\n      " + this._genDirectiveIndices() + "\n    ";
      };
      /** @internal */
      ChangeDetectorJITGenerator.prototype._genPropertyBindingTargets = function () {
          var targets = this._logic.genPropertyBindingTargets(this.propertyBindingTargets, this.genConfig.genDebugInfo);
          return this.typeName + ".gen_propertyBindingTargets = " + targets + ";";
      };
      /** @internal */
      ChangeDetectorJITGenerator.prototype._genDirectiveIndices = function () {
          var indices = this._logic.genDirectiveIndices(this.directiveRecords);
          return this.typeName + ".gen_directiveIndices = " + indices + ";";
      };
      /** @internal */
      ChangeDetectorJITGenerator.prototype._maybeGenHandleEventInternal = function () {
          var _this = this;
          if (this.eventBindings.length > 0) {
              var handlers = this.eventBindings.map(function (eb) { return _this._genEventBinding(eb); }).join("\n");
              return "\n        " + this.typeName + ".prototype.handleEventInternal = function(eventName, elIndex, locals) {\n          var " + this._names.getPreventDefaultAccesor() + " = false;\n          " + this._names.genInitEventLocals() + "\n          " + handlers + "\n          return " + this._names.getPreventDefaultAccesor() + ";\n        }\n      ";
          }
          else {
              return '';
          }
      };
      /** @internal */
      ChangeDetectorJITGenerator.prototype._genEventBinding = function (eb) {
          var _this = this;
          var recs = eb.records.map(function (r) { return _this._genEventBindingEval(eb, r); }).join("\n");
          return "\n    if (eventName === \"" + eb.eventName + "\" && elIndex === " + eb.elIndex + ") {\n      " + recs + "\n    }";
      };
      /** @internal */
      ChangeDetectorJITGenerator.prototype._genEventBindingEval = function (eb, r) {
          if (r.lastInBinding) {
              var evalRecord = this._logic.genEventBindingEvalValue(eb, r);
              var markPath = this._genMarkPathToRootAsCheckOnce(r);
              var prevDefault = this._genUpdatePreventDefault(eb, r);
              return evalRecord + "\n" + markPath + "\n" + prevDefault;
          }
          else {
              return this._logic.genEventBindingEvalValue(eb, r);
          }
      };
      /** @internal */
      ChangeDetectorJITGenerator.prototype._genMarkPathToRootAsCheckOnce = function (r) {
          var br = r.bindingRecord;
          if (br.isDefaultChangeDetection()) {
              return "";
          }
          else {
              return this._names.getDetectorName(br.directiveRecord.directiveIndex) + ".markPathToRootAsCheckOnce();";
          }
      };
      /** @internal */
      ChangeDetectorJITGenerator.prototype._genUpdatePreventDefault = function (eb, r) {
          var local = this._names.getEventLocalName(eb, r.selfIndex);
          return "if (" + local + " === false) { " + this._names.getPreventDefaultAccesor() + " = true};";
      };
      /** @internal */
      ChangeDetectorJITGenerator.prototype._maybeGenDehydrateDirectives = function () {
          var destroyPipesCode = this._names.genPipeOnDestroy();
          if (destroyPipesCode) {
              destroyPipesCode = "if (destroyPipes) { " + destroyPipesCode + " }";
          }
          var dehydrateFieldsCode = this._names.genDehydrateFields();
          if (!destroyPipesCode && !dehydrateFieldsCode)
              return '';
          return this.typeName + ".prototype.dehydrateDirectives = function(destroyPipes) {\n        " + destroyPipesCode + "\n        " + dehydrateFieldsCode + "\n    }";
      };
      /** @internal */
      ChangeDetectorJITGenerator.prototype._maybeGenHydrateDirectives = function () {
          var hydrateDirectivesCode = this._logic.genHydrateDirectives(this.directiveRecords);
          var hydrateDetectorsCode = this._logic.genHydrateDetectors(this.directiveRecords);
          if (!hydrateDirectivesCode && !hydrateDetectorsCode)
              return '';
          return this.typeName + ".prototype.hydrateDirectives = function(directives) {\n      " + hydrateDirectivesCode + "\n      " + hydrateDetectorsCode + "\n    }";
      };
      /** @internal */
      ChangeDetectorJITGenerator.prototype._maybeGenAfterContentLifecycleCallbacks = function () {
          var notifications = this._logic.genContentLifecycleCallbacks(this.directiveRecords);
          if (notifications.length > 0) {
              var directiveNotifications = notifications.join("\n");
              return "\n        " + this.typeName + ".prototype.afterContentLifecycleCallbacksInternal = function() {\n          " + directiveNotifications + "\n        }\n      ";
          }
          else {
              return '';
          }
      };
      /** @internal */
      ChangeDetectorJITGenerator.prototype._maybeGenAfterViewLifecycleCallbacks = function () {
          var notifications = this._logic.genViewLifecycleCallbacks(this.directiveRecords);
          if (notifications.length > 0) {
              var directiveNotifications = notifications.join("\n");
              return "\n        " + this.typeName + ".prototype.afterViewLifecycleCallbacksInternal = function() {\n          " + directiveNotifications + "\n        }\n      ";
          }
          else {
              return '';
          }
      };
      /** @internal */
      ChangeDetectorJITGenerator.prototype._genRecord = function (r) {
          var rec;
          if (r.isLifeCycleRecord()) {
              rec = this._genDirectiveLifecycle(r);
          }
          else if (r.isPipeRecord()) {
              rec = this._genPipeCheck(r);
          }
          else {
              rec = this._genReferenceCheck(r);
          }
          return "\n      " + this._maybeFirstInBinding(r) + "\n      " + rec + "\n      " + this._maybeGenLastInDirective(r) + "\n    ";
      };
      /** @internal */
      ChangeDetectorJITGenerator.prototype._genDirectiveLifecycle = function (r) {
          if (r.name === "DoCheck") {
              return this._genOnCheck(r);
          }
          else if (r.name === "OnInit") {
              return this._genOnInit(r);
          }
          else if (r.name === "OnChanges") {
              return this._genOnChange(r);
          }
          else {
              throw new exceptions_1.BaseException("Unknown lifecycle event '" + r.name + "'");
          }
      };
      /** @internal */
      ChangeDetectorJITGenerator.prototype._genPipeCheck = function (r) {
          var _this = this;
          var context = this._names.getLocalName(r.contextIndex);
          var argString = r.args.map(function (arg) { return _this._names.getLocalName(arg); }).join(", ");
          var oldValue = this._names.getFieldName(r.selfIndex);
          var newValue = this._names.getLocalName(r.selfIndex);
          var pipe = this._names.getPipeName(r.selfIndex);
          var pipeName = r.name;
          var init = "\n      if (" + pipe + " === " + this.changeDetectionUtilVarName + ".uninitialized) {\n        " + pipe + " = " + this._names.getPipesAccessorName() + ".get('" + pipeName + "');\n      }\n    ";
          var read = newValue + " = " + pipe + ".pipe.transform(" + context + ", [" + argString + "]);";
          var contexOrArgCheck = r.args.map(function (a) { return _this._names.getChangeName(a); });
          contexOrArgCheck.push(this._names.getChangeName(r.contextIndex));
          var condition = "!" + pipe + ".pure || (" + contexOrArgCheck.join(" || ") + ")";
          var check = "\n      if (" + oldValue + " !== " + newValue + ") {\n        " + newValue + " = " + this.changeDetectionUtilVarName + ".unwrapValue(" + newValue + ")\n        " + this._genChangeMarker(r) + "\n        " + this._genUpdateDirectiveOrElement(r) + "\n        " + this._genAddToChanges(r) + "\n        " + oldValue + " = " + newValue + ";\n      }\n    ";
          var genCode = r.shouldBeChecked() ? "" + read + check : read;
          if (r.isUsedByOtherRecord()) {
              return init + " if (" + condition + ") { " + genCode + " } else { " + newValue + " = " + oldValue + "; }";
          }
          else {
              return init + " if (" + condition + ") { " + genCode + " }";
          }
      };
      /** @internal */
      ChangeDetectorJITGenerator.prototype._genReferenceCheck = function (r) {
          var _this = this;
          var oldValue = this._names.getFieldName(r.selfIndex);
          var newValue = this._names.getLocalName(r.selfIndex);
          var read = "\n      " + this._logic.genPropertyBindingEvalValue(r) + "\n    ";
          var check = "\n      if (" + newValue + " !== " + oldValue + ") {\n        " + this._genChangeMarker(r) + "\n        " + this._genUpdateDirectiveOrElement(r) + "\n        " + this._genAddToChanges(r) + "\n        " + oldValue + " = " + newValue + ";\n      }\n    ";
          var genCode = r.shouldBeChecked() ? "" + read + check : read;
          if (r.isPureFunction()) {
              var condition = r.args.map(function (a) { return _this._names.getChangeName(a); }).join(" || ");
              if (r.isUsedByOtherRecord()) {
                  return "if (" + condition + ") { " + genCode + " } else { " + newValue + " = " + oldValue + "; }";
              }
              else {
                  return "if (" + condition + ") { " + genCode + " }";
              }
          }
          else {
              return genCode;
          }
      };
      /** @internal */
      ChangeDetectorJITGenerator.prototype._genChangeMarker = function (r) {
          return r.argumentToPureFunction ? this._names.getChangeName(r.selfIndex) + " = true" : "";
      };
      /** @internal */
      ChangeDetectorJITGenerator.prototype._genUpdateDirectiveOrElement = function (r) {
          if (!r.lastInBinding)
              return "";
          var newValue = this._names.getLocalName(r.selfIndex);
          var oldValue = this._names.getFieldName(r.selfIndex);
          var notifyDebug = this.genConfig.logBindingUpdate ? "this.logBindingUpdate(" + newValue + ");" : "";
          var br = r.bindingRecord;
          if (br.target.isDirective()) {
              var directiveProperty = this._names.getDirectiveName(br.directiveRecord.directiveIndex) + "." + br.target.name;
              return "\n        " + this._genThrowOnChangeCheck(oldValue, newValue) + "\n        " + directiveProperty + " = " + newValue + ";\n        " + notifyDebug + "\n        " + IS_CHANGED_LOCAL + " = true;\n      ";
          }
          else {
              return "\n        " + this._genThrowOnChangeCheck(oldValue, newValue) + "\n        this.notifyDispatcher(" + newValue + ");\n        " + notifyDebug + "\n      ";
          }
      };
      /** @internal */
      ChangeDetectorJITGenerator.prototype._genThrowOnChangeCheck = function (oldValue, newValue) {
          if (this.genConfig.genCheckNoChanges) {
              return "\n        if(throwOnChange) {\n          this.throwOnChangeError(" + oldValue + ", " + newValue + ");\n        }\n        ";
          }
          else {
              return '';
          }
      };
      /** @internal */
      ChangeDetectorJITGenerator.prototype._genCheckNoChanges = function () {
          if (this.genConfig.genCheckNoChanges) {
              return this.typeName + ".prototype.checkNoChanges = function() { this.runDetectChanges(true); }";
          }
          else {
              return '';
          }
      };
      /** @internal */
      ChangeDetectorJITGenerator.prototype._genAddToChanges = function (r) {
          var newValue = this._names.getLocalName(r.selfIndex);
          var oldValue = this._names.getFieldName(r.selfIndex);
          if (!r.bindingRecord.callOnChanges())
              return "";
          return CHANGES_LOCAL + " = this.addChange(" + CHANGES_LOCAL + ", " + oldValue + ", " + newValue + ");";
      };
      /** @internal */
      ChangeDetectorJITGenerator.prototype._maybeFirstInBinding = function (r) {
          var prev = change_detection_util_1.ChangeDetectionUtil.protoByIndex(this.records, r.selfIndex - 1);
          var firstInBindng = lang_1.isBlank(prev) || prev.bindingRecord !== r.bindingRecord;
          return firstInBindng && !r.bindingRecord.isDirectiveLifecycle() ?
              this._names.getPropertyBindingIndex() + " = " + r.propertyBindingIndex + ";" :
              '';
      };
      /** @internal */
      ChangeDetectorJITGenerator.prototype._maybeGenLastInDirective = function (r) {
          if (!r.lastInDirective)
              return "";
          return "\n      " + CHANGES_LOCAL + " = null;\n      " + this._genNotifyOnPushDetectors(r) + "\n      " + IS_CHANGED_LOCAL + " = false;\n    ";
      };
      /** @internal */
      ChangeDetectorJITGenerator.prototype._genOnCheck = function (r) {
          var br = r.bindingRecord;
          return "if (!throwOnChange) " + this._names.getDirectiveName(br.directiveRecord.directiveIndex) + ".doCheck();";
      };
      /** @internal */
      ChangeDetectorJITGenerator.prototype._genOnInit = function (r) {
          var br = r.bindingRecord;
          return "if (!throwOnChange && !" + this._names.getAlreadyCheckedName() + ") " + this._names.getDirectiveName(br.directiveRecord.directiveIndex) + ".onInit();";
      };
      /** @internal */
      ChangeDetectorJITGenerator.prototype._genOnChange = function (r) {
          var br = r.bindingRecord;
          return "if (!throwOnChange && " + CHANGES_LOCAL + ") " + this._names.getDirectiveName(br.directiveRecord.directiveIndex) + ".onChanges(" + CHANGES_LOCAL + ");";
      };
      /** @internal */
      ChangeDetectorJITGenerator.prototype._genNotifyOnPushDetectors = function (r) {
          var br = r.bindingRecord;
          if (!r.lastInDirective || br.isDefaultChangeDetection())
              return "";
          var retVal = "\n      if(" + IS_CHANGED_LOCAL + ") {\n        " + this._names.getDetectorName(br.directiveRecord.directiveIndex) + ".markAsCheckOnce();\n      }\n    ";
          return retVal;
      };
      return ChangeDetectorJITGenerator;
  })();
  exports.ChangeDetectorJITGenerator = ChangeDetectorJITGenerator;
  //# sourceMappingURL=change_detection_jit_generator.js.map