/*
 * Copyright 2000-2016 JetBrains s.r.o.
 *
 * 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.intellij.codeInspection.defaultFileTemplateUsage;

import com.intellij.codeInsight.CodeInsightUtil;
import com.intellij.codeInspection.*;
import com.intellij.ide.fileTemplates.FileTemplate;
import com.intellij.ide.fileTemplates.FileTemplateManager;
import com.intellij.ide.fileTemplates.FileTemplateUtil;
import com.intellij.ide.highlighter.JavaFileType;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiComment;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiFileFactory;
import com.intellij.psi.util.PsiTreeUtil;
import gnu.trove.TIntObjectHashMap;
import org.jetbrains.annotations.NotNull;

import java.io.IOException;
import java.util.Arrays;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author cdr
 */
public class FileHeaderChecker {
  private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.defaultFileTemplateUsage.FileHeaderChecker");

  static ProblemDescriptor checkFileHeader(@NotNull PsiFile file, @NotNull InspectionManager manager, boolean onTheFly) {
    TIntObjectHashMap<String> offsetToProperty = new TIntObjectHashMap<String>();
    FileTemplate defaultTemplate = FileTemplateManager.getInstance(file.getProject()).getDefaultTemplate(FileTemplateManager.FILE_HEADER_TEMPLATE_NAME);
    Pattern pattern = FileTemplateUtil.getTemplatePattern(defaultTemplate, file.getProject(), offsetToProperty);
    Matcher matcher = pattern.matcher(file.getViewProvider().getContents());
    if (!matcher.matches()) {
      return null;
    }

    PsiComment element = PsiTreeUtil.findElementOfClassAtRange(file, matcher.start(1), matcher.end(1), PsiComment.class);
    if (element == null) {
      return null;
    }

    LocalQuickFix[] fixes = createQuickFix(matcher, offsetToProperty, file.getProject());
    String description = InspectionsBundle.message("default.file.template.description");
    return manager.createProblemDescriptor(element, description, onTheFly, fixes, ProblemHighlightType.GENERIC_ERROR_OR_WARNING);
  }


  private static Properties computeProperties(final Matcher matcher, final TIntObjectHashMap<String> offsetToProperty, Project project) {
    Properties properties = new Properties(FileTemplateManager.getInstance(project).getDefaultProperties());

    int[] offsets = offsetToProperty.keys();
    Arrays.sort(offsets);
    for (int i = 0; i < offsets.length; i++) {
      final int offset = offsets[i];
      String propName = offsetToProperty.get(offset);
      int groupNum = i + 2; // first group is whole doc comment
      String propValue = matcher.group(groupNum);
      properties.setProperty(propName, propValue);
    }

    return properties;
  }

  private static LocalQuickFix[] createQuickFix(final Matcher matcher, final TIntObjectHashMap<String> offsetToProperty, Project project) {
    final FileTemplate template = FileTemplateManager.getInstance(project).getPattern(FileTemplateManager.FILE_HEADER_TEMPLATE_NAME);

    ReplaceWithFileTemplateFix replaceTemplateFix = new ReplaceWithFileTemplateFix() {
      @Override
      public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
        PsiElement element = descriptor.getPsiElement();
        if (element == null || !element.isValid()) return;
        if (!CodeInsightUtil.preparePsiElementsForWrite(element)) return;

        String newText;
        try {
          newText = template.getText(computeProperties(matcher, offsetToProperty, project)).trim();
        }
        catch (IOException e) {
          LOG.error(e);
          return;
        }

        if (!newText.isEmpty()) {
          PsiElement parent = element.getParent();
          PsiFile tempFile = PsiFileFactory.getInstance(project).createFileFromText("template.java", JavaFileType.INSTANCE, newText);
          for (PsiElement child : tempFile.getChildren()) {
            if (child.getTextLength() > 0) {
              parent.addBefore(child, element);
            }
          }
        }

        element.delete();
      }
    };

    LocalQuickFix editFileTemplateFix = DefaultFileTemplateUsageInspection.createEditFileTemplateFix(template, replaceTemplateFix);
    return template.isDefault() ? new LocalQuickFix[]{editFileTemplateFix} : new LocalQuickFix[]{replaceTemplateFix, editFileTemplateFix};
  }
}

@@ -2519,19 +2519,29 @@
 roject()
+, onTheFly
 );%0A
-
     Stri
@@ -3476,32 +3476,80 @@
 Matcher matcher,
+%0A                                               
  final TIntObjec
@@ -3582,32 +3582,146 @@
 roperty,
- Project project
+%0A                                                Project project,%0A                                                boolean onTheFly
 ) %7B%0A    
@@ -4923,16 +4923,38 @@
     %7D;%0A%0A
+    if (onTheFly) %7B%0A  
     Loca
@@ -5077,24 +5077,26 @@
 teFix);%0A    
+  
 return templ
@@ -5218,14 +5218,103 @@
 teFix%7D;%0A
+    %7D%0A    return template.isDefault() ? null : new LocalQuickFix%5B%5D %7BreplaceTemplateFix%7D;%0A
   %7D%0A%7D%0A

disable template editing during batch mode (IDEA-155795)