/*
 * Copyright 2000-2014 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.jetbrains.python.configuration;

import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.projectRoots.impl.SdkConfigurationUtil;
import com.intellij.openapi.roots.ui.configuration.projectRoot.ProjectSdksModel;
import com.intellij.openapi.util.Comparing;
import com.jetbrains.python.psi.LanguageLevel;
import com.jetbrains.python.sdk.*;
import com.jetbrains.python.sdk.flavors.PythonSdkFlavor;
import com.jetbrains.python.sdk.flavors.VirtualEnvSdkFlavor;
import org.jetbrains.annotations.Nullable;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

/**
 * Manages the SDK model shared between PythonSdkConfigurable and PyActiveSdkConfigurable.
 *
 * @author yole
 */
public class PyConfigurableInterpreterList {
  private ProjectSdksModel myModel;

  public static PyConfigurableInterpreterList getInstance(Project project) {
    return ServiceManager.getService(project, PyConfigurableInterpreterList.class);
  }

  public ProjectSdksModel getModel() {
    if (myModel == null) {
      myModel = new ProjectSdksModel();
      myModel.reset(null);
    }
    return myModel;
  }

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

  public List<Sdk> getAllPythonSdks(@Nullable final Project project) {
    List<Sdk> result = new ArrayList<Sdk>();
    for (Sdk sdk : getModel().getSdks()) {
      if (sdk.getSdkType() instanceof PythonSdkType) {
        result.add(sdk);
      }
    }

    Collections.sort(result, new Comparator<Sdk>() {
      @Override
      public int compare(Sdk o1, Sdk o2) {
        if (!(o1.getSdkType() instanceof PythonSdkType) ||
            !(o2.getSdkType() instanceof PythonSdkType))
          return -Comparing.compare(o1.getName(), o2.getName());

        final boolean isVEnv1 = PythonSdkType.isVirtualEnv(o1);
        final boolean isVEnv2 = PythonSdkType.isVirtualEnv(o2);
        final boolean isRemote1 = PySdkUtil.isRemote(o1);
        final boolean isRemote2 = PySdkUtil.isRemote(o2);

        if (isVEnv1) {
          if (project != null && associatedWithCurrent(o1, project)) {
            if (associatedWithCurrent(o2, project)) return compareSdk(o1, o2);
            return -1;
          }
          if (isVEnv2) {
            return compareSdk(o1, o2);
          }
          return -1;
        }
        if (isVEnv2)   return 1;
        if (isRemote1) return 1;
        if (isRemote2) return -1;

        return compareSdk(o1, o2);
      }

      private int compareSdk(final Sdk o1, final Sdk o2) {
        final PythonSdkFlavor flavor1 = PythonSdkFlavor.getFlavor(o1);
        final PythonSdkFlavor flavor2 = PythonSdkFlavor.getFlavor(o2);
        final LanguageLevel level1 = flavor1 != null ? flavor1.getLanguageLevel(o1) : LanguageLevel.getDefault();
        final LanguageLevel level2 = flavor2 != null ? flavor2.getLanguageLevel(o2) : LanguageLevel.getDefault();
        final int compare = Comparing.compare(level1, level2);
        if (compare != 0) return -compare;
        return Comparing.compare(o1.getName(), o2.getName());
      }
    });

    final PySdkService sdkService = PySdkService.getInstance();
    final List<String> sdkHomes = new ArrayList<String>();
    sdkHomes.addAll(VirtualEnvSdkFlavor.INSTANCE.suggestHomePaths());
    for (PythonSdkFlavor flavor : PythonSdkFlavor.getApplicableFlavors()) {
      if (flavor instanceof VirtualEnvSdkFlavor) continue;
      sdkHomes.addAll(flavor.suggestHomePaths());
    }
    Collections.sort(sdkHomes);
    for (String sdkHome : SdkConfigurationUtil.filterExistingPaths(PythonSdkType.getInstance(), sdkHomes, getModel().getSdks())) {
      result.add(new PyDetectedSdk(sdkHome));
    }
    for (String sdkHome : SdkConfigurationUtil.filterExistingPaths(PythonSdkType.getInstance(), sdkService.getAddedSdks(), getModel().getSdks())) {
      result.add(new PyDetectedSdk(sdkHome));
    }
    Iterables.removeIf(result, new Predicate<Sdk>() {
      @Override
      public boolean apply(@Nullable Sdk input) {
        return input != null && sdkService.isRemoved(input);
      }
    });
    return result;
  }

  private static boolean associatedWithCurrent(Sdk o1, Project project) {
    final PythonSdkAdditionalData data = (PythonSdkAdditionalData)o1.getSdkAdditionalData();
    if (data != null) {
      final String path = data.getAssociatedProjectPath();
      final String projectBasePath = project.getBasePath();
      if (path != null && path.equals(projectBasePath)) {
        return true;
      }
    }
    return false;
  }

  public List<Sdk> getAllPythonSdks() {
    return getAllPythonSdks(null);
  }
}

@@ -2887,24 +2887,51 @@
 (isVEnv1) %7B%0A
+          if (isVEnv2) %7B%0A  
           if
@@ -2985,24 +2985,26 @@
 project)) %7B%0A
+  
             
@@ -3074,32 +3074,34 @@
 2);%0A            
+  
 return -1;%0A     
@@ -3109,34 +3109,11 @@
     
-%7D%0A          if (isVEnv2) %7B
+  %7D
 %0A   
@@ -3247,25 +3247,125 @@
 emote1) 
-return 1;
+%7B%0A          if (isRemote2) %7B%0A            return compareSdk(o1, o2);%0A          %7D%0A          return 1;%0A        %7D
 %0A       

Impose asymmetry and transitivity on SDK comparator