/*
 * Copyright 2006 Sascha Weinreuter
 *
 * 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 org.intellij.plugins.intelliLang.inject.config.ui;

import com.intellij.lang.LanguageAnnotators;
import com.intellij.lang.annotation.AnnotationHolder;
import com.intellij.lang.annotation.Annotator;
import com.intellij.lang.annotation.HighlightSeverity;
import com.intellij.openapi.util.Key;
import com.intellij.psi.PsiElement;
import org.intellij.lang.regexp.RegExpFile;
import org.intellij.lang.regexp.RegExpLanguage;
import org.intellij.lang.regexp.psi.RegExpBranch;
import org.intellij.lang.regexp.psi.RegExpGroup;
import org.intellij.lang.regexp.psi.RegExpPattern;
import org.intellij.lang.regexp.psi.RegExpRecursiveElementVisitor;
import org.intellij.plugins.intelliLang.IntelliLangBundle;
import org.jetbrains.annotations.NotNull;

/**
 * Annotator that is used to validate the "Value-Pattern" textfield: The regex entered there should contain exactly
 * one capturing group that determines the text-range the configured language will be injected into.
 */
public final class ValueRegExpAnnotator implements Annotator {
  public static final Key<Boolean> KEY = Key.create("IS_VALUE_REGEXP");

  static {
    // inject annotator one the class is referenced
    LanguageAnnotators.INSTANCE.addExplicitExtension(RegExpLanguage.INSTANCE, new ValueRegExpAnnotator());
  }

  public ValueRegExpAnnotator() {
  }

  @Override
  public void annotate(@NotNull PsiElement psiElement, @NotNull AnnotationHolder holder) {
    if (psiElement instanceof RegExpFile && psiElement.getCopyableUserData(KEY) == Boolean.TRUE) {
      final PsiElement pattern = psiElement.getFirstChild();
      if (!(pattern instanceof RegExpPattern)) {
        return;
      }

      final RegExpBranch[] branches = ((RegExpPattern)pattern).getBranches();
      if (branches.length == 1 && branches[0].getAtoms().length == 0) {
        return;
      }

      for (RegExpBranch branch : branches) {
        final int[] count = new int[1];
        branch.accept(new RegExpRecursiveElementVisitor() {
          @Override
          public void visitRegExpGroup(RegExpGroup group) {
            if (group.isCapturing()) {
              count[0]++;
            }
            super.visitRegExpGroup(group);
          }
        });

        if (count[0] != 1) {
          holder.newAnnotation(HighlightSeverity.WARNING, IntelliLangBundle.message("annotation.message.the.pattern")).range(branch)
            .create();
        }
      }
    }
  }
}
