package com.intellij.ide.util.gotoByName;

import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.psi.codeStyle.NameUtil;
import com.intellij.util.ArrayUtil;
import com.intellij.util.ui.UIUtil;
import org.apache.oro.text.regex.MalformedPatternException;
import org.apache.oro.text.regex.Pattern;
import org.apache.oro.text.regex.Perl5Compiler;
import org.apache.oro.text.regex.Perl5Matcher;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import javax.swing.*;
import javax.swing.border.EmptyBorder;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;

/**
 * Model allowing to show a fixed list of items, each having a name and description, in Choose by Name popup.
 */
public class ListChooseByNameModel<T extends ChooseByNameItem> extends SimpleChooseByNameModel {

  private static final int MAX_DESC_LENGTH = 80;
  private static final String ELLIPSIS_SUFFIX = "...";

  private Pattern myCompiledPattern;
  private String myPattern;
  private final List<T> myItems;
  private final String myNotInMessage;

  public ListChooseByNameModel(@NotNull final Project project,
                               final String prompt,
                               final String notInMessage,
                               List<T> items) {
    super(project, prompt, null);

    myItems = items;
    myNotInMessage = notInMessage;
  }

  @Override
  public String[] getNames() {
    final ArrayList<String> taskFullCmds = new ArrayList<String>();
    for (T item : myItems) {
      taskFullCmds.add(item.getName());
    }

    return ArrayUtil.toStringArray(taskFullCmds);
  }

  @Override
  protected Object[] getElementsByName(String name, String pattern) {
    for (T item : myItems) {
      if (item.getName().equals(name)) {
        return new Object[] { item };
      }
    }
    return ArrayUtil.EMPTY_OBJECT_ARRAY;
  }

  @Override
  public String getNotInMessage() {
    return myNotInMessage;
  }

  @Override
  public String getNotFoundMessage() {
    return myNotInMessage;
  }

  // from ruby plugin
  @Override
  public ListCellRenderer getListCellRenderer() {
    return new DefaultListCellRenderer() {
      @Override
      public Component getListCellRendererComponent(final JList list,
                                                    final Object value,
                                                    final int index, final boolean isSelected, final boolean cellHasFocus) {

        final JPanel panel = new JPanel(new BorderLayout());
        panel.setOpaque(true);
        panel.setBorder(new EmptyBorder(0, 0, 0, 5));

        final Color bg = isSelected ? UIUtil.getListSelectionBackground() : UIUtil.getListBackground();
        panel.setBackground(bg);

        if (value instanceof ChooseByNameItem) {
          final ChooseByNameItem item = (ChooseByNameItem) value;

          final Color fg = isSelected ? UIUtil.getListSelectionForeground() : UIUtil.getListForeground();

          final JLabel actionLabel = new JLabel(item.getName(), null, LEFT);
          actionLabel.setBackground(bg);
          actionLabel.setForeground(fg);
          actionLabel.setFont(actionLabel.getFont().deriveFont(Font.BOLD));
          actionLabel.setBorder(BorderFactory.createEmptyBorder(0, 4, 0, 0));

          panel.add(actionLabel, BorderLayout.WEST);

          String description = item.getDescription();
          if (description != null) {
            // truncate long descriptions
            final String normalizedDesc;
            if (description.length() > MAX_DESC_LENGTH) {
              normalizedDesc = description.substring(0, MAX_DESC_LENGTH) + ELLIPSIS_SUFFIX;
            }
            else {
              normalizedDesc = description;
            }
            final JLabel descriptionLabel = new JLabel(normalizedDesc);
            descriptionLabel.setBackground(bg);
            descriptionLabel.setForeground(fg);
            descriptionLabel.setBorder(new EmptyBorder(0, 15, 0, 0));

            panel.add(descriptionLabel, BorderLayout.EAST);
          }
        }
        else {
          // E.g. "..." item
          final JLabel actionLabel = new JLabel(value.toString(), null, LEFT);
          actionLabel.setBackground(bg);
          actionLabel.setForeground(UIUtil.getListForeground());
          actionLabel.setFont(actionLabel.getFont().deriveFont(Font.PLAIN));
          actionLabel.setBorder(BorderFactory.createEmptyBorder(0, 4, 0, 0));
          panel.add(actionLabel, BorderLayout.WEST);
        }
        return panel;
      }
    };
  }

  @Override
  public String getElementName(final Object element) {
    if (!(element instanceof ChooseByNameItem)) return null;
    return ((ChooseByNameItem)element).getName();
  }

  public boolean matches(@NotNull final String name, @NotNull final String pattern) {
    final Pattern compiledPattern = getTaskPattern(pattern);
    if (compiledPattern == null) {
      return false;
    }

    return new Perl5Matcher().matches(name, compiledPattern);
  }

  @Nullable
  private Pattern getTaskPattern(String pattern) {
    if (!Comparing.strEqual(pattern, myPattern)) {
      myCompiledPattern = null;
      myPattern = pattern;
    }
    if (myCompiledPattern == null) {
      final String regex = "^.*" + NameUtil.buildRegexp(pattern, 0, true, true);

      final Perl5Compiler compiler = new Perl5Compiler();
      try {
        myCompiledPattern = compiler.compile(regex);
      }
      catch (MalformedPatternException ignored) {
      }
    }
    return myCompiledPattern;
  }
}

@@ -1,8 +1,609 @@
+/*%0A * Copyright 2000-2016 JetBrains s.r.o.%0A *%0A * Licensed under the Apache License, Version 2.0 (the %22License%22);%0A * you may not use this file except in compliance with the License.%0A * You may obtain a copy of the License at%0A *%0A * http://www.apache.org/licenses/LICENSE-2.0%0A *%0A * Unless required by applicable law or agreed to in writing, software%0A * distributed under the License is distributed on an %22AS IS%22 BASIS,%0A * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.%0A * See the License for the specific language governing permissions and%0A * limitations under the License.%0A */%0A
 package 
@@ -802,24 +802,58 @@
 .ArrayUtil;%0A
+import com.intellij.util.ui.JBUI;%0A
 import com.i
@@ -1185,47 +1185,8 @@
 .*;%0A
-import javax.swing.border.EmptyBorder;%0A
 impo
@@ -3214,33 +3214,32 @@
 der(
-new EmptyBorder(0, 0, 0, 
+JBUI.Borders.emptyRight(
 5));
@@ -3872,50 +3872,32 @@
 der(
+JBUI.
 Border
-Factory.createEmptyBorder(0, 4, 0, 0
+s.emptyLeft(4
 ));%0A
@@ -4577,35 +4577,33 @@
 der(
-new EmptyBorder(0, 15, 0, 0
+JBUI.Borders.emptyLeft(15
 ));%0A
@@ -5027,50 +5027,32 @@
 der(
+JBUI.
 Border
-Factory.createEmptyBorder(0, 4, 0, 0
+s.emptyLeft(4
 ));%0A

fix scaling for empty border