package com.intellij.xdebugger.impl.settings;

import com.intellij.ide.DataManager;
import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.options.Configurable;
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.options.SearchableConfigurable;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.project.ProjectManagerAdapter;
import com.intellij.openapi.util.IconLoader;
import com.intellij.xdebugger.XDebuggerBundle;
import com.intellij.xdebugger.impl.DebuggerSupport;
import org.jetbrains.annotations.NonNls;

import javax.swing.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

/**
 * @author Eugene Belyaev & Eugene Zhuravlev
 */
public class DebuggerConfigurable implements SearchableConfigurable.Parent {
  private Configurable myRootConfigurable;
  private Configurable[] myChildren;
  private String myProjectLocationHash;
  public static final String DISPLAY_NAME = XDebuggerBundle.message("debugger.configurable.display.name");

  public DebuggerConfigurable(ProjectManager pm) {
    pm.addProjectManagerListener(new ProjectManagerAdapter() {
      public void projectClosed(final Project project) {
        myChildren = null;
        myRootConfigurable = null;
      }
    });
  }

  public Icon getIcon() {
    return IconLoader.getIcon("/general/configurableDebugger.png");
  }

  public String getDisplayName() {
    return DISPLAY_NAME;
  }

  public String getHelpTopic() {
    return myRootConfigurable != null? myRootConfigurable.getHelpTopic() : null;
  }

  public Configurable[] getConfigurables() {
    Project project = PlatformDataKeys.PROJECT.getData(DataManager.getInstance().getDataContext());
    if(project == null) {
      project = ProjectManager.getInstance().getDefaultProject();
    }

    final String locationHash = project.getLocationHash();
    if (!locationHash.equals(myProjectLocationHash)) {
      // clear data (if any) built for the previous projects 
      myChildren = null;
      myRootConfigurable = null;
      myProjectLocationHash = locationHash;
    }

    if (myChildren == null) {
      final ArrayList<Configurable> configurables = new ArrayList<Configurable>();
      final List<DebuggerSettingsPanelProvider> providers = new ArrayList<DebuggerSettingsPanelProvider>();
      for (DebuggerSupport support : DebuggerSupport.getDebuggerSupports()) {
        providers.add(support.getSettingsPanelProvider());
      }
      Collections.sort(providers, new Comparator<DebuggerSettingsPanelProvider>() {
        public int compare(final DebuggerSettingsPanelProvider o1, final DebuggerSettingsPanelProvider o2) {
          return o2.getPriority() - o1.getPriority();
        }
      });
      for (DebuggerSettingsPanelProvider provider : providers) {
        configurables.addAll(provider.getConfigurables(project));
        final Configurable rootConfigurable = provider.getRootConfigurable();
        if (rootConfigurable != null) {
          if (myRootConfigurable != null) {
            configurables.add(rootConfigurable);
          }
          else {
            myRootConfigurable = rootConfigurable;
          }
        }
      }
      myChildren = configurables.toArray(new Configurable[configurables.size()]);
    }
    return myChildren;
  }

  public void apply() throws ConfigurationException {
    for (DebuggerSupport support : DebuggerSupport.getDebuggerSupports()) {
      support.getSettingsPanelProvider().apply();
    }
    if (myRootConfigurable != null) {
      myRootConfigurable.apply();
    }
  }

  public boolean hasOwnContent() {
    return myRootConfigurable != null;
  }

  public boolean isVisible() {
    return true;
  }

  public Runnable enableSearch(final String option) {
    return null;
  }

  public JComponent createComponent() {
    return myRootConfigurable != null ? myRootConfigurable.createComponent() : null;
  }

  public boolean isModified() {
    return myRootConfigurable != null && myRootConfigurable.isModified();
  }

  public void reset() {
    if (myRootConfigurable != null) {
      myRootConfigurable.reset();
    }
  }

  public void disposeUIResources() {
    if (myRootConfigurable != null) {
      myRootConfigurable.disposeUIResources();
    }
  }

  @NonNls
  public String getId() {
    return "project.propDebugger";
  }
}
@@ -670,16 +670,52 @@
 wing.*;%0A
+import java.lang.ref.WeakReference;%0A
 import j
@@ -1041,37 +1041,49 @@
 ate 
-String myProjectLocationHash;
+WeakReference%3CProject%3E myContextProject;%0A
 %0A  p
@@ -1976,114 +1976,73 @@
     
-final String locationHash = project.getLocationHash();%0A    if (!locationHash.equals(myProjectLocationHash)
+if (myContextProject == null %7C%7C myContextProject.get() != project
 ) %7B%0A
@@ -2060,21 +2060,19 @@
 ear 
-data (if any)
+cached data
  bui
@@ -2171,42 +2171,60 @@
   my
-ProjectLocationHash = locationHash
+ContextProject = new WeakReference%3CProject%3E(project)
 ;%0A  

use weak reference on a project instead of location hash