/*
 * Copyright (c) 2000-2007 JetBrains s.r.o. All Rights Reserved.
 */

/*
 * User: anna
 * Date: 09-Jan-2007
 */
package com.intellij.codeInspection.actions;

import com.intellij.analysis.AnalysisScope;
import com.intellij.analysis.PerformAnalysisInBackgroundOption;
import com.intellij.codeHighlighting.HighlightDisplayLevel;
import com.intellij.codeInsight.daemon.HighlightDisplayKey;
import com.intellij.codeInspection.InspectionProfile;
import com.intellij.codeInspection.InspectionsBundle;
import com.intellij.codeInspection.InspectionManager;
import com.intellij.codeInspection.offline.OfflineProblemDescriptor;
import com.intellij.codeInspection.ex.*;
import com.intellij.codeInspection.offlineViewer.OfflineInspectionRVContentProvider;
import com.intellij.codeInspection.offlineViewer.OfflineViewParseUtil;
import com.intellij.codeInspection.reference.RefManagerImpl;
import com.intellij.codeInspection.ui.InspectionResultsView;
import com.intellij.ide.highlighter.XmlFileType;
import com.intellij.ide.util.BrowseFilesListener;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.fileChooser.FileChooser;
import com.intellij.openapi.fileEditor.impl.LoadTextUtil;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.profile.Profile;
import com.intellij.profile.codeInspection.InspectionProfileManager;
import com.intellij.profile.codeInspection.InspectionProjectProfileManager;
import com.intellij.util.ui.tree.TreeUtil;
import org.jetbrains.annotations.Nullable;

import javax.swing.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class ViewOfflineResultsAction extends AnAction {
  private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.actions.ViewOfflineResultsAction");

  public void update(AnActionEvent event) {
    final Presentation presentation = event.getPresentation();
    final Project project = event.getData(DataKeys.PROJECT);
    presentation.setEnabled(project != null);
    presentation.setVisible(ActionPlaces.MAIN_MENU.equals(event.getPlace()));
  }

  public void actionPerformed(AnActionEvent event) {
    final Project project = event.getData(DataKeys.PROJECT);

    LOG.assertTrue(project != null);

    final VirtualFile[] virtualFiles = FileChooser.chooseFiles(project, BrowseFilesListener.SINGLE_DIRECTORY_DESCRIPTOR);
    if (virtualFiles.length == 0) return;
    if (!virtualFiles[0].isDirectory()) return;

    final Map<String, Map<String, Set<OfflineProblemDescriptor>>> resMap =
      new HashMap<String, Map<String, Set<OfflineProblemDescriptor>>>();
    final String [] profileName = new String[1];
    final Runnable process = new Runnable() {
      public void run() {
        final VirtualFile[] files = virtualFiles[0].getChildren();
        try {
          for (final VirtualFile inspectionFile : files) {
            if (inspectionFile.isDirectory()) continue;
            final String shortName = inspectionFile.getNameWithoutExtension();
            if (shortName.equals(InspectionApplication.DESCRIPTIONS)) {
              profileName[0] = ApplicationManager.getApplication().runReadAction(
                  new Computable<String>() {
                    @Nullable
                    public String compute() {
                      return OfflineViewParseUtil.parseProfileName(LoadTextUtil.loadText(inspectionFile).toString());
                    }
                  }
              );
            }
            else if (inspectionFile.getFileType() instanceof XmlFileType) {
              resMap.put(shortName, ApplicationManager.getApplication().runReadAction(
                  new Computable<Map<String, Set<OfflineProblemDescriptor>>>() {
                    public Map<String, Set<OfflineProblemDescriptor>> compute() {
                      return OfflineViewParseUtil.parse(LoadTextUtil.loadText(inspectionFile).toString());
                    }
                  }
              ));
            }
          }
        }
        catch (final Exception e) {  //all parse exceptions
          SwingUtilities.invokeLater(new Runnable() {
            public void run() {
              Messages.showInfoMessage(e.getMessage(), InspectionsBundle.message("offline.view.parse.exception.title"));
            }
          });
          throw new ProcessCanceledException(); //cancel process
        }
      }
    };
    ProgressManager.getInstance().runProcessWithProgressAsynchronously(project, InspectionsBundle.message("parsing.inspections.dump.progress.title"), process, new Runnable() {
      public void run() {
        SwingUtilities.invokeLater(new Runnable(){
          public void run() {
            final String name = profileName[0];
            showOfflineView(project, name, resMap,
                            InspectionsBundle.message("offline.view.title") +
                            " (" + (name != null ? name : InspectionsBundle.message("offline.view.editor.settings.title")) +")");
          }
        });
      }
    }, null, new PerformAnalysisInBackgroundOption(project));
  }

  @SuppressWarnings({"UnusedDeclaration", "WeakerAccess", "UnusedReturnValue"}) //used in TeamCity
  public static InspectionResultsView showOfflineView(final Project project,
                                                      @Nullable
                                                      final String profileName,
                                                      final Map<String, Map<String, Set<OfflineProblemDescriptor>>> resMap,
                                                      final String title) {
    Profile profile;
    if (profileName != null) {
      profile = InspectionProjectProfileManager.getInstance(project).getProfile(profileName);
      if (profile == null) {
        profile = InspectionProfileManager.getInstance().getProfiles().get(profileName);
      }
    }
    else {
      profile = null;
    }
    final InspectionProfile inspectionProfile;
    if (profile != null) {
      inspectionProfile = (InspectionProfile)profile;
    }
    else {
      inspectionProfile = new InspectionProfileImpl("Server Side") {
        public boolean isToolEnabled(final HighlightDisplayKey key) {
          return resMap.containsKey(key.toString());
        }

        public HighlightDisplayLevel getErrorLevel(final HighlightDisplayKey key) {
          return ((InspectionProfile)InspectionProfileManager.getInstance().getRootProfile()).getErrorLevel(key);
        }

        public boolean isEditable() {
          return false;
        }
      };
    }
    return showOfflineView(project, resMap, inspectionProfile, title);
  }

  public static InspectionResultsView showOfflineView(final Project project,
                                                      final Map<String, Map<String, Set<OfflineProblemDescriptor>>> resMap,
                                                      final InspectionProfile inspectionProfile,
                                                      final String title) {
    final AnalysisScope scope = new AnalysisScope(project);
    final InspectionManagerEx managerEx = (InspectionManagerEx)InspectionManager.getInstance(project);
    final GlobalInspectionContextImpl inspectionContext = managerEx.createNewGlobalContext(false);
    inspectionContext.setExternalProfile(inspectionProfile);
    inspectionContext.setCurrentScope(scope);
    inspectionContext.initializeTools(scope, new HashMap<String, Set<InspectionTool>>(), new HashMap<String, Set<InspectionTool>>());
    final InspectionResultsView view = new InspectionResultsView(project, inspectionProfile, scope, inspectionContext,
                                                                 new OfflineInspectionRVContentProvider(resMap, project));
    ((RefManagerImpl)inspectionContext.getRefManager()).inspectionReadActionStarted();
    try {
      view.update();
      TreeUtil.selectFirstNode(view.getTree());
      if (inspectionContext.getContentManager() != null) { //test
        inspectionContext.addView(view, title);
      }
      return view;
    }
    finally {
      ((RefManagerImpl)inspectionContext.getRefManager()).inspectionReadActionFinished();
    }
  }
}

@@ -8166,28 +8166,16 @@
 rted();%0A
-    try %7B%0A  
     view
@@ -8181,26 +8181,24 @@
 w.update();%0A
-  
     TreeUtil
@@ -8231,26 +8231,24 @@
 ree());%0A    
-  
 if (inspecti
@@ -8295,18 +8295,16 @@
  //test%0A
-  
       in
@@ -8341,30 +8341,26 @@
 title);%0A    
-  %7D%0A  
+%7D%0A
     return v
@@ -8368,124 +8368,8 @@
 ew;%0A
-    %7D%0A    finally %7B%0A      ((RefManagerImpl)inspectionContext.getRefManager()).inspectionReadActionFinished();%0A    %7D%0A
   %7D%0A

make offline view lazy enough