/*
 * Copyright 2018 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.template.soy.passes;

import com.google.template.soy.base.internal.IdGenerator;
import com.google.template.soy.error.ErrorReporter;
import com.google.template.soy.error.SoyErrorKind;
import com.google.template.soy.soytree.HtmlOpenTagNode;
import com.google.template.soy.soytree.KeyNode;
import com.google.template.soy.soytree.SoyFileNode;
import com.google.template.soy.soytree.SoyTreeUtils;

/**
 * Validates restrictions on DOM nodes with key commands (e.g. {@code <div {key 'foo'}></div>}).
 * Note that while these restrictions are applied due to how Soy handles incremental dom keys, this
 * pass runs in every backend for consistency.
 */
final class KeyCommandPass extends CompilerFilePass {

  private static final SoyErrorKind KEY_ATTR_DIRECT_CHILD_OF_OPEN_TAG =
      SoyErrorKind.of(
          "The `key` command must be directly nested within an HTML open tag "
              + "(e.g. `<div '{'key 'foo''}'></div>`).");

  private final ErrorReporter errorReporter;

  KeyCommandPass(ErrorReporter errorReporter) {
    this.errorReporter = errorReporter;
  }

  @Override
  public void run(SoyFileNode file, IdGenerator nodeIdGen) {
    for (KeyNode node : SoyTreeUtils.getAllNodesOfType(file, KeyNode.class)) {
      checkNodeIsOpenTagNodeChild(node);
    }
  }

  private void checkNodeIsOpenTagNodeChild(KeyNode node) {
    if (!(node.getParent() instanceof HtmlOpenTagNode)) {
      errorReporter.report(node.getSourceLocation(), KEY_ATTR_DIRECT_CHILD_OF_OPEN_TAG);
    }
  }
}

@@ -791,16 +791,74 @@
 orKind;%0A
+import com.google.template.soy.soytree.HtmlAttributeNode;%0A
 import c
@@ -901,24 +901,24 @@
 penTagNode;%0A
-
 import com.g
@@ -1001,24 +1001,72 @@
 oyFileNode;%0A
+import com.google.template.soy.soytree.SoyNode;%0A
 import com.g
@@ -1647,16 +1647,169 @@
 %60).%22);%0A%0A
+  private static final SoyErrorKind DUPLICATE_KEY_ATTR =%0A      SoyErrorKind.of(%22The key attribute is deprecated. Instead, use the '%7B'key'%7D' command.%22);%0A%0A
   privat
@@ -2132,16 +2132,58 @@
 (node);%0A
+      checkNoDuplicateKeyAttribute(node);%0A
     %7D%0A  
@@ -2298,24 +2298,24 @@
 TagNode)) %7B%0A
-
       errorR
@@ -2400,11 +2400,505 @@
    %7D%0A  %7D
+%0A%0A  //  TODO(b/119309461): Remove after migration is complete.%0A  private void checkNoDuplicateKeyAttribute(KeyNode node) %7B%0A    SoyNode parentNode = node.getParent();%0A    if (!(parentNode instanceof HtmlOpenTagNode)) %7B%0A      // Error thrown before this.%0A      return;%0A    %7D%0A%0A    HtmlAttributeNode keyAttrNode = ((HtmlOpenTagNode) parentNode).getDirectAttributeNamed(%22key%22);%0A    if (keyAttrNode != null) %7B%0A      errorReporter.report(keyAttrNode.getSourceLocation(), DUPLICATE_KEY_ATTR);%0A    %7D%0A  %7D
 %0A%7D%0A

Raise an error for a key command and key attribute on the same node. This will simplify assumptions for the codegen.