/*
 * Created by IntelliJ IDEA.
 * User: mike
 * Date: Aug 23, 2002
 * Time: 8:15:58 PM
 * To change template for new class use 
 * Code Style | Class Templates options (Tools | IDE Options).
 */
package com.intellij.codeInsight.intention.impl.config;

import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.ide.ui.search.SearchUtil;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.components.ApplicationComponent;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.InvalidDataException;
import com.intellij.openapi.util.NamedJDOMExternalizable;
import com.intellij.openapi.util.WriteExternalException;
import com.intellij.util.ResourceUtil;
import org.jdom.Element;
import org.jetbrains.annotations.NonNls;

import java.io.IOException;
import java.net.URL;
import java.util.*;
import java.util.regex.Pattern;

public class IntentionManagerSettings implements ApplicationComponent, NamedJDOMExternalizable {
  private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.intention.impl.config.IntentionManagerSettings");

  private Set<String> myIgnoredActions = new LinkedHashSet<String>();

  private Map<String,IntentionActionMetaData> myMetaData = new LinkedHashMap<String, IntentionActionMetaData>();
  private static final @NonNls String IGNORE_ACTION_TAG = "ignoreAction";
  private static final @NonNls String NAME_ATT = "name";

  private HashMap<String, ArrayList<String>> myWords2DescriptorsMap;

  static final Pattern HTML_PATTERN = Pattern.compile("<[^<>]*>");

  public String getExternalFileName() {
    return "intentionSettings";
  }

  public static IntentionManagerSettings getInstance() {
    return ApplicationManager.getApplication().getComponent(IntentionManagerSettings.class);
  }

  public IntentionManagerSettings() {
    ApplicationManager.getApplication().invokeLater(new Runnable(){
      public void run() {
        new Thread(){
          public void run() {
            buildIndex();
          }
        }.start();
      }
    });
  }

  public String getComponentName() {
    return "IntentionManagerSettings";
  }

  public void initComponent() { }

  public void registerIntentionMetaData(IntentionAction intentionAction, String[] category) {
    registerIntentionMetaData(intentionAction, category, intentionAction.getFamilyName());
  }
  public void registerIntentionMetaData(IntentionAction intentionAction, String[] category, String descriptionDirectoryName) {
    registerMetaData(new IntentionActionMetaData(intentionAction.getFamilyName(), intentionAction.getClass().getClassLoader(), category, descriptionDirectoryName));
  }

  public void disposeComponent() {
  }

  public boolean isShowLightBulb(IntentionAction action) {
    return !myIgnoredActions.contains(action.getFamilyName());
  }

  public void setShowLightBulb(IntentionAction action, boolean show) {
    if (show) {
      myIgnoredActions.remove(action.getFamilyName());
    }
    else {
      myIgnoredActions.add(action.getFamilyName());
    }
  }

  public void readExternal(Element element) throws InvalidDataException {
    myIgnoredActions.clear();
    List children = element.getChildren(IGNORE_ACTION_TAG);
    for (final Object aChildren : children) {
      Element e = (Element)aChildren;
      myIgnoredActions.add(e.getAttributeValue(NAME_ATT));
    }
  }

  public void writeExternal(Element element) throws WriteExternalException {
    for (String name : myIgnoredActions) {
      element.addContent(new Element(IGNORE_ACTION_TAG).setAttribute(NAME_ATT, name));
    }
  }

  public List<IntentionActionMetaData> getMetaData() {
    return new ArrayList<IntentionActionMetaData>(myMetaData.values());
  }

  public boolean isEnabled(String family) {
    return !myIgnoredActions.contains(family);
  }
  public void setEnabled(String family, boolean enabled) {
    if (enabled) {
      myIgnoredActions.remove(family);
    }
    else {
      myIgnoredActions.add(family);
    }
  }

  public void registerMetaData(IntentionActionMetaData metaData) {
    //LOG.assertTrue(!myMetaData.containsKey(metaData.myFamily), "Action '"+metaData.myFamily+"' already registered");
    if (!myMetaData.containsKey(metaData.myFamily) && isIndexBuild()){
      try {
        processMetaData(metaData);
      }
      catch (IOException e) {
        LOG.error(e);
      }
    }
    myMetaData.put(metaData.myFamily, metaData);
  }

  public boolean isIndexBuild(){
    return myWords2DescriptorsMap != null && !myWords2DescriptorsMap.isEmpty();
  }

  public synchronized void buildIndex(){
    if (myWords2DescriptorsMap == null) {
      myWords2DescriptorsMap = new HashMap<String, ArrayList<String>>();
      try {
        final List<IntentionActionMetaData> list = IntentionManagerSettings.getInstance().getMetaData();
        for (IntentionActionMetaData metaData : list) {
          processMetaData(metaData);
        }
      }
      catch (IOException e) {
        LOG.error(e);
      }
    }
  }

  private void processMetaData(final IntentionActionMetaData metaData) throws IOException {
    final URL description = metaData.getDescription();
    if (description != null) {
      @NonNls String descriptionText = ResourceUtil.loadText(description).toLowerCase();
      descriptionText = HTML_PATTERN.matcher(descriptionText).replaceAll(" ");
      final Set<String> words = SearchUtil.getProcessedWords(descriptionText);
      words.addAll(SearchUtil.getProcessedWords(metaData.myFamily));      
      for (String word : words) {
        ArrayList<String> descriptors = myWords2DescriptorsMap.get(word);
        if (descriptors == null) {
          descriptors = new ArrayList<String>();
          myWords2DescriptorsMap.put(word, descriptors);
        }
        descriptors.add(metaData.myFamily);
      }
    }
  }

  public ArrayList<String> getIntentionNames(final String filtString) {
    return myWords2DescriptorsMap.get(filtString);
  }

  public Set<String> getIntentionWords() {
    return myWords2DescriptorsMap.keySet();
  }

  public List<String> getFilteredIntentionNames(final String word) {
    return myWords2DescriptorsMap.get(word);
  }
}

@@ -1510,16 +1510,59 @@
 ptorsMap
+ = new HashMap%3CString, ArrayList%3CString%3E%3E()
 ;%0A%0A  sta
@@ -1860,270 +1860,8 @@
  %7D%0A%0A
-  public IntentionManagerSettings() %7B%0A    ApplicationManager.getApplication().invokeLater(new Runnable()%7B%0A      public void run() %7B%0A        new Thread()%7B%0A          public void run() %7B%0A            buildIndex();%0A          %7D%0A        %7D.start();%0A      %7D%0A    %7D);%0A  %7D%0A%0A
   pu
@@ -4031,26 +4031,8 @@
 ily)
- && isIndexBuild()
 )%7B%0A 
@@ -4209,284 +4209,37 @@
  %7D%0A%0A
-  public boolean isIndexBuild()%7B%0A    return myWords2DescriptorsMap != null && !myWords2DescriptorsMap.isEmpty();%0A  %7D%0A%0A  public synchronized void buildIndex()%7B%0A    if (myWords2DescriptorsMap == null) %7B%0A      myWords2DescriptorsMap = new HashMap%3CString, ArrayList%3CString%3E%3E();%0A  
+%0A  public void buildIndex()%7B%0A
     
@@ -4240,26 +4240,24 @@
 %7B%0A    try %7B%0A
-  
       final 
@@ -4349,26 +4349,24 @@
 ta();%0A      
-  
 for (Intenti
@@ -4397,26 +4397,24 @@
 a : list) %7B%0A
-  
         proc
@@ -4446,22 +4446,16 @@
     
-  
 %7D%0A    
- 
- 
 %7D%0A
-  
     
@@ -4470,34 +4470,32 @@
 OException e) %7B%0A
-  
       LOG.error(
@@ -4494,32 +4494,24 @@
 G.error(e);%0A
-      %7D%0A
     %7D%0A  %7D%0A%0A 

remove threading