text: /**
   * @license
   * Copyright Google Inc. All Rights Reserved.
   *
   * Use of this source code is governed by an MIT-style license that can be
   * found in the LICENSE file at https://angular.io/license
   */
  "use strict";
  var collection_1 = require('../facade/collection');
  var exceptions_1 = require('../facade/exceptions');
  var lang_1 = require('../facade/lang');
  var html_ast_1 = require('../html_ast');
  var html_parser_1 = require('../html_parser');
  var interpolation_config_1 = require('../interpolation_config');
  var expander_1 = require('./expander');
  var message_1 = require('./message');
  var shared_1 = require('./shared');
  var _PLACEHOLDER_ELEMENT = 'ph';
  var _NAME_ATTR = 'name';
  var _PLACEHOLDER_EXPANDED_REGEXP = /<ph(\s)+name=("(\w)+")><\/ph>/gi;
  /**
   * Creates an i18n-ed version of the parsed template.
   *
   * Algorithm:
   *
   * See `message_extractor.ts` for details on the partitioning algorithm.
   *
   * This is how the merging works:
   *
   * 1. Use the stringify function to get the message id. Look up the message in the map.
   * 2. Get the translated message. At this point we have two trees: the original tree
   * and the translated tree, where all the elements are replaced with placeholders.
   * 3. Use the original tree to create a mapping Index:number -> HtmlAst.
   * 4. Walk the translated tree.
   * 5. If we encounter a placeholder element, get its name property.
   * 6. Get the type and the index of the node using the name property.
   * 7. If the type is 'e', which means element, then:
   *     - translate the attributes of the original element
   *     - recurse to merge the children
   *     - create a new element using the original element name, original position,
   *     and translated children and attributes
   * 8. If the type if 't', which means text, then:
   *     - get the list of expressions from the original node.
   *     - get the string version of the interpolation subtree
   *     - find all the placeholders in the translated message, and replace them with the
   *     corresponding original expressions
   */
  var I18nHtmlParser = (function () {
      function I18nHtmlParser(_htmlParser, _parser, _messagesContent, _messages, _implicitTags, _implicitAttrs) {
          this._htmlParser = _htmlParser;
          this._parser = _parser;
          this._messagesContent = _messagesContent;
          this._messages = _messages;
          this._implicitTags = _implicitTags;
          this._implicitAttrs = _implicitAttrs;
      }
      I18nHtmlParser.prototype.parse = function (sourceContent, sourceUrl, parseExpansionForms, interpolationConfig) {
          if (parseExpansionForms === void 0) { parseExpansionForms = false; }
          if (interpolationConfig === void 0) { interpolationConfig = interpolation_config_1.DEFAULT_INTERPOLATION_CONFIG; }
          this.errors = [];
          this._interpolationConfig = interpolationConfig;
          var res = this._htmlParser.parse(sourceContent, sourceUrl, true);
          if (res.errors.length > 0) {
              return res;
          }
          else {
              var expanded = expander_1.expandNodes(res.rootNodes);
              var nodes = this._recurse(expanded.nodes);
              (_a = this.errors).push.apply(_a, expanded.errors);
              return this.errors.length > 0 ? new html_parser_1.HtmlParseTreeResult([], this.errors) :
                  new html_parser_1.HtmlParseTreeResult(nodes, []);
          }
          var _a;
      };
      I18nHtmlParser.prototype._processI18nPart = function (part) {
          try {
              return part.hasI18n ? this._mergeI18Part(part) : this._recurseIntoI18nPart(part);
          }
          catch (e) {
              if (e instanceof shared_1.I18nError) {
                  this.errors.push(e);
                  return [];
              }
              else {
                  throw e;
              }
          }
      };
      I18nHtmlParser.prototype._mergeI18Part = function (part) {
          var message = part.createMessage(this._parser, this._interpolationConfig);
          var messageId = message_1.id(message);
          if (!collection_1.StringMapWrapper.contains(this._messages, messageId)) {
              throw new shared_1.I18nError(part.sourceSpan, "Cannot find message for id '" + messageId + "', content '" + message.content + "'.");
          }
          var parsedMessage = this._messages[messageId];
          return this._mergeTrees(part, parsedMessage, part.children);
      };
      I18nHtmlParser.prototype._recurseIntoI18nPart = function (p) {
          // we found an element without an i18n attribute
          // we need to recurse in cause its children may have i18n set
          // we also need to translate its attributes
          if (lang_1.isPresent(p.rootElement)) {
              var root = p.rootElement;
              var children = this._recurse(p.children);
              var attrs = this._i18nAttributes(root);
              return [new html_ast_1.HtmlElementAst(root.name, attrs, children, root.sourceSpan, root.startSourceSpan, root.endSourceSpan)];
          }
          else if (lang_1.isPresent(p.rootTextNode)) {
              return [p.rootTextNode];
          }
          else {
              return this._recurse(p.children);
          }
      };
      I18nHtmlParser.prototype._recurse = function (nodes) {
          var _this = this;
          var parts = shared_1.partition(nodes, this.errors, this._implicitTags);
          return collection_1.ListWrapper.flatten(parts.map(function (p) { return _this._processI18nPart(p); }));
      };
      I18nHtmlParser.prototype._mergeTrees = function (p, translated, original) {
          var l = new _CreateNodeMapping();
          html_ast_1.htmlVisitAll(l, original);
          // merge the translated tree with the original tree.
          // we do it by preserving the source code position of the original tree
          var merged = this._mergeTreesHelper(translated, l.mapping);
          // if the root element is present, we need to create a new root element with its attributes
          // translated
          if (lang_1.isPresent(p.rootElement)) {
              var root = p.rootElement;
              var attrs = this._i18nAttributes(root);
              return [new html_ast_1.HtmlElementAst(root.name, attrs, merged, root.sourceSpan, root.startSourceSpan, root.endSourceSpan)];
          }
          else if (lang_1.isPresent(p.rootTextNode)) {
              throw new exceptions_1.BaseException('should not be reached');
          }
          else {
              return merged;
          }
      };
      I18nHtmlParser.prototype._mergeTreesHelper = function (translated, mapping) {
          var _this = this;
          return translated.map(function (t) {
              if (t instanceof html_ast_1.HtmlElementAst) {
                  return _this._mergeElementOrInterpolation(t, translated, mapping);
              }
              else if (t instanceof html_ast_1.HtmlTextAst) {
                  return t;
              }
              else {
                  throw new exceptions_1.BaseException('should not be reached');
              }
          });
      };
      I18nHtmlParser.prototype._mergeElementOrInterpolation = function (t, translated, mapping) {
          var name = this._getName(t);
          var type = name[0];
          var index = lang_1.NumberWrapper.parseInt(name.substring(1), 10);
          var originalNode = mapping[index];
          if (type == 't') {
              return this._mergeTextInterpolation(t, originalNode);
          }
          else if (type == 'e') {
              return this._mergeElement(t, originalNode, mapping);
          }
          else {
              throw new exceptions_1.BaseException('should not be reached');
          }
      };
      I18nHtmlParser.prototype._getName = function (t) {
          if (t.name != _PLACEHOLDER_ELEMENT) {
              throw new shared_1.I18nError(t.sourceSpan, "Unexpected tag \"" + t.name + "\". Only \"" + _PLACEHOLDER_ELEMENT + "\" tags are allowed.");
          }
          var names = t.attrs.filter(function (a) { return a.name == _NAME_ATTR; });
          if (names.length == 0) {
              throw new shared_1.I18nError(t.sourceSpan, "Missing \"" + _NAME_ATTR + "\" attribute.");
          }
          return names[0].value;
      };
      I18nHtmlParser.prototype._mergeTextInterpolation = function (t, originalNode) {
          var split = this._parser.splitInterpolation(originalNode.value, originalNode.sourceSpan.toString(), this._interpolationConfig);
          var exps = lang_1.isPresent(split) ? split.expressions : [];
          var messageSubstring = this._messagesContent.substring(t.startSourceSpan.end.offset, t.endSourceSpan.start.offset);
          var translated = this._replacePlaceholdersWithExpressions(messageSubstring, exps, originalNode.sourceSpan);
          return new html_ast_1.HtmlTextAst(translated, originalNode.sourceSpan);
      };
      I18nHtmlParser.prototype._mergeElement = function (t, originalNode, mapping) {
          var children = this._mergeTreesHelper(t.children, mapping);
          return new html_ast_1.HtmlElementAst(originalNode.name, this._i18nAttributes(originalNode), children, originalNode.sourceSpan, originalNode.startSourceSpan, originalNode.endSourceSpan);
      };
      I18nHtmlParser.prototype._i18nAttributes = function (el) {
          var _this = this;
          var res = [];
          var implicitAttrs = lang_1.isPresent(this._implicitAttrs[el.name]) ? this._implicitAttrs[el.name] : [];
          el.attrs.forEach(function (attr) {
              if (attr.name.startsWith(shared_1.I18N_ATTR_PREFIX) || attr.name == shared_1.I18N_ATTR)
                  return;
              var message;
              var i18ns = el.attrs.filter(function (a) { return a.name == "" + shared_1.I18N_ATTR_PREFIX + attr.name; });
              if (i18ns.length == 0) {
                  if (implicitAttrs.indexOf(attr.name) == -1) {
                      res.push(attr);
                      return;
                  }
                  message = shared_1.messageFromAttribute(_this._parser, _this._interpolationConfig, attr);
              }
              else {
                  message = shared_1.messageFromI18nAttribute(_this._parser, _this._interpolationConfig, el, i18ns[0]);
              }
              var messageId = message_1.id(message);
              if (collection_1.StringMapWrapper.contains(_this._messages, messageId)) {
                  var updatedMessage = _this._replaceInterpolationInAttr(attr, _this._messages[messageId]);
                  res.push(new html_ast_1.HtmlAttrAst(attr.name, updatedMessage, attr.sourceSpan));
              }
              else {
                  throw new shared_1.I18nError(attr.sourceSpan, "Cannot find message for id '" + messageId + "', content '" + message.content + "'.");
              }
          });
          return res;
      };
      I18nHtmlParser.prototype._replaceInterpolationInAttr = function (attr, msg) {
          var split = this._parser.splitInterpolation(attr.value, attr.sourceSpan.toString(), this._interpolationConfig);
          var exps = lang_1.isPresent(split) ? split.expressions : [];
          var first = msg[0];
          var last = msg[msg.length - 1];
          var start = first.sourceSpan.start.offset;
          var end = last instanceof html_ast_1.HtmlElementAst ? last.endSourceSpan.end.offset : last.sourceSpan.end.offset;
          var messageSubstring = this._messagesContent.substring(start, end);
          return this._replacePlaceholdersWithExpressions(messageSubstring, exps, attr.sourceSpan);
      };
      ;
      I18nHtmlParser.prototype._replacePlaceholdersWithExpressions = function (message, exps, sourceSpan) {
          var _this = this;
          var expMap = this._buildExprMap(exps);
          return lang_1.RegExpWrapper.replaceAll(_PLACEHOLDER_EXPANDED_REGEXP, message, function (match) {
              var nameWithQuotes = match[2];
              var name = nameWithQuotes.substring(1, nameWithQuotes.length - 1);
              return _this._convertIntoExpression(name, expMap, sourceSpan);
          });
      };
      I18nHtmlParser.prototype._buildExprMap = function (exps) {
          var expMap = new Map();
          var usedNames = new Map();
          for (var i = 0; i < exps.length; i++) {
              var phName = shared_1.getPhNameFromBinding(exps[i], i);
              expMap.set(shared_1.dedupePhName(usedNames, phName), exps[i]);
          }
          return expMap;
      };
      I18nHtmlParser.prototype._convertIntoExpression = function (name, expMap, sourceSpan) {
          if (expMap.has(name)) {
              return "" + this._interpolationConfig.start + expMap.get(name) + this._interpolationConfig.end;
          }
          else {
              throw new shared_1.I18nError(sourceSpan, "Invalid interpolation name '" + name + "'");
          }
      };
      return I18nHtmlParser;
  }());
  exports.I18nHtmlParser = I18nHtmlParser;
  var _CreateNodeMapping = (function () {
      function _CreateNodeMapping() {
          this.mapping = [];
      }
      _CreateNodeMapping.prototype.visitElement = function (ast, context) {
          this.mapping.push(ast);
          html_ast_1.htmlVisitAll(this, ast.children);
          return null;
      };
      _CreateNodeMapping.prototype.visitAttr = function (ast, context) { return null; };
      _CreateNodeMapping.prototype.visitText = function (ast, context) {
          this.mapping.push(ast);
          return null;
      };
      _CreateNodeMapping.prototype.visitExpansion = function (ast, context) { return null; };
      _CreateNodeMapping.prototype.visitExpansionCase = function (ast, context) { return null; };
      _CreateNodeMapping.prototype.visitComment = function (ast, context) { return ''; };
      return _CreateNodeMapping;
  }());
  //# sourceMappingURL=i18n_html_parser.js.map