package com.jetbrains.python.inspections;

import com.intellij.codeInspection.LocalQuickFix;
import com.intellij.codeInspection.ProblemsHolder;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiElementVisitor;
import com.jetbrains.python.PyBundle;
import com.jetbrains.python.psi.LanguageLevel;
import com.jetbrains.python.validation.CompatibilityVisitor;
import com.jetbrains.python.validation.UnsupportedFeaturesUtil;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;

/**
 * User: catherine
 *
 * Inspection to detect code incompatibility with python versions
 */
public class PyCompatibilityInspection extends PyInspection {
  public String fromVersion = LanguageLevel.PYTHON24.toString();
  public String toVersion = LanguageLevel.PYTHON27.toString();

  private List<LanguageLevel> myVersionsToProcess;

  public PyCompatibilityInspection () {
    super();
    if (ApplicationManager.getApplication().isUnitTestMode()) toVersion = LanguageLevel.PYTHON31.toString();
    myVersionsToProcess = new ArrayList<LanguageLevel>();
    updateVersionsToProcess();
  }

  @Override
  public boolean isEnabledByDefault() {
    return false;
  }

  private void updateVersionsToProcess() {
    myVersionsToProcess.clear();

    boolean add = false;
    for (String version : UnsupportedFeaturesUtil.ALL_LANGUAGE_LEVELS) {
      LanguageLevel level = LanguageLevel.fromPythonVersion(version);
      if (version.equals(fromVersion))
        add = true;
      if (version.equals(toVersion)) {
        myVersionsToProcess.add(level);
        add = false;
      }
      if (add)
        myVersionsToProcess.add(level);
    }
  }

  @Nls
  @NotNull
  @Override
  public String getDisplayName() {
    return PyBundle.message("INSP.NAME.compatibility");
  }

  @Override
  public JComponent createOptionsPanel() {
    final JPanel versionPanel = new JPanel();

    final JComboBox fromComboBox = new JComboBox(UnsupportedFeaturesUtil.ALL_LANGUAGE_LEVELS);
    fromComboBox.setSelectedItem(fromVersion);
    final JComboBox toComboBox = new JComboBox(UnsupportedFeaturesUtil.ALL_LANGUAGE_LEVELS);
    toComboBox.setSelectedItem(toVersion);

    fromComboBox.addActionListener(new ActionListener() {
      @Override
      public void actionPerformed(ActionEvent e) {
        JComboBox cb = (JComboBox)e.getSource();
        fromVersion = (String)cb.getSelectedItem();
      }
    });

    toComboBox.addActionListener(new ActionListener() {
      @Override
      public void actionPerformed(ActionEvent e) {
        JComboBox cb = (JComboBox)e.getSource();
        toVersion = (String)cb.getSelectedItem();
      }
    });

    versionPanel.add(new JLabel("Check for compatibility with python from"), BorderLayout.WEST);
    versionPanel.add(fromComboBox);
    versionPanel.add(new JLabel("to"));
    versionPanel.add(toComboBox);
    return versionPanel;
  }

  @NotNull
  @Override
  public PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly) {
    updateVersionsToProcess();
    return new Visitor(holder, myVersionsToProcess);
  }

  private static class Visitor extends CompatibilityVisitor {
    private final ProblemsHolder myHolder;
    public Visitor(ProblemsHolder holder, List<LanguageLevel> versionsToProcess) {
      super(versionsToProcess);
      myHolder = holder;
    }

    protected final void registerProblem(@Nullable final PsiElement element,
                                       @NotNull final String message,
                                       final LocalQuickFix quickFix, boolean asError){
      if (element == null || element.getTextLength() == 0){
          return;
      }
      if (quickFix != null)
        myHolder.registerProblem(element, message, quickFix);
      else
        myHolder.registerProblem(element, message);
    }
  }
}

@@ -1067,60 +1067,8 @@
 );%0A%0A
-  private List%3CLanguageLevel%3E myVersionsToProcess;%0A%0A
   pu
@@ -1229,97 +1229,8 @@
 ();%0A
-    myVersionsToProcess = new ArrayList%3CLanguageLevel%3E();%0A    updateVersionsToProcess();%0A
   %7D%0A
@@ -1315,20 +1315,35 @@
 private 
-void
+List%3CLanguageLevel%3E
  updateV
@@ -1371,33 +1371,65 @@
     
-myVersionsToProcess.clear
+List%3CLanguageLevel%3E result = new ArrayList%3CLanguageLevel%3E
 ();%0A
@@ -1703,35 +1703,22 @@
         
-myVersionsToProcess
+result
 .add(lev
@@ -1778,45 +1778,51 @@
     
-myVersionsToProcess.add(level);%0A    %7D
+result.add(level);%0A    %7D%0A    return result;
 %0A  %7D
@@ -3170,39 +3170,8 @@
 ) %7B%0A
-    updateVersionsToProcess();%0A
     
@@ -3197,18 +3197,22 @@
 holder, 
-my
+update
 Versions
@@ -3216,24 +3216,26 @@
 onsToProcess
+()
 );%0A  %7D%0A%0A  pr

fix race condition in updateVersionsToProcess() (no caching is needed here)