package jetbrains.mps.editor.contextActionsTool.pluginSolution.plugin;

/*Generated by MPS */

import javax.swing.JComponent;
import javax.swing.JPanel;
import java.util.List;
import jetbrains.mps.ide.tools.BaseTool;
import java.awt.BorderLayout;
import javax.swing.BoxLayout;
import javax.swing.JScrollPane;
import javax.swing.BorderFactory;
import jetbrains.mps.ide.ThreadUtils;
import jetbrains.mps.internal.collections.runtime.ListSequence;
import java.util.ArrayList;
import java.util.Map;
import java.util.TreeMap;
import jetbrains.mps.internal.collections.runtime.CollectionSequence;
import javax.swing.JLabel;
import java.awt.dnd.InvalidDnDOperationException;
import java.awt.HeadlessException;
import java.awt.Font;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.Icon;
import org.jetbrains.annotations.NotNull;
import jetbrains.mps.openapi.editor.menus.transformation.CommandPolicy;
import com.intellij.openapi.wm.ToolWindow;

public class ToolComponent extends JComponent {
  private ViewType myViewType = ViewType.LIST;
  private JPanel myItemPanel = new JPanel();
  private String myFilterString = "";
  private SearchField mySearchField = new SearchField() {
    @Override
    public void executeSearch(boolean next) {
      myFilterString = mySearchField.getText().toLowerCase();
      reloadItems();
    }
  };
  private List<IItem> myLoadedItems;
  private BaseTool myTool;
  private ItemExecutor myItemExecutor;

  public ToolComponent(BaseTool tool) {
    myTool = tool;

    initComponents();
  }

  public void setItemExecutor(ItemExecutor itemExecutor) {
    myItemExecutor = itemExecutor;
  }

  protected void initComponents() {
    setLayout(new BorderLayout());

    myItemPanel.setLayout(new BoxLayout(myItemPanel, BoxLayout.Y_AXIS));

    JComponent viewport = new JPanel();
    viewport.setLayout(new BorderLayout());
    viewport.add(myItemPanel, BorderLayout.NORTH);
    JScrollPane scrollPane = new JScrollPane(viewport);
    scrollPane.setBorder(BorderFactory.createEmptyBorder());
    scrollPane.getVerticalScrollBar().setUnitIncrement(16);
    scrollPane.getHorizontalScrollBar().setUnitIncrement(8);
    add(scrollPane, BorderLayout.CENTER);
    add(mySearchField, BorderLayout.NORTH);

    myItemPanel.setOpaque(false);
    viewport.setOpaque(true);
  }

  @Override
  public void setBounds(int x, int y, int w, int h) {
    // Relayout the folders after resizing the tool

    boolean widthChanged = w != getSize().width;
    super.setBounds(x, y, w, h);
    if (widthChanged) {
      ThreadUtils.runInUIThreadNoWait(() -> reloadItems());
    }
  }

  public boolean isToolVisible() {
    return check_cnbxua_a0a61(myTool.getToolWindow());
  }

  /**
   * Creates Swing components for each item
   * 
   * @param items the items to show
   */
  protected void loadItems(List<IItem> items) {
    if (items == null) {
      items = ListSequence.fromList(new ArrayList<IItem>());
    }
    myLoadedItems = items;
    myItemPanel.removeAll();

    Map<String, Folder> folders = new TreeMap<String, Folder>();

    for (IItem item : ListSequence.fromList(items)) {
      if (!(matchesFilter(item))) {
        continue;
      }
      getOrCreateFolder(item.getFolderName(), folders).addItem(createLabel(item));
    }

    for (Folder folder : CollectionSequence.fromCollection(folders.values())) {
      myItemPanel.add(folder.getComponent());
    }

    doLayout();
    invalidate();
    revalidate();
    repaint();
  }

  private boolean matchesFilter(IItem item) {
    if ((myFilterString == null || myFilterString.length() == 0)) {
      return true;
    }

    if (item.getLabel().toLowerCase().contains(myFilterString)) {
      return true;
    }

    if (isNotEmptyString(item.getFolderName()) && item.getFolderName().toLowerCase().contains(myFilterString)) {
      return true;
    }

    return false;
  }

  private JLabel createLabel(final IItem item) throws InvalidDnDOperationException, HeadlessException {
    final JLabel jlabel = new HoverLabel((myViewType == ViewType.LIST ? item.getLabel() : abbreviate(item.getLabel(), 15)));

    if (myViewType == ViewType.SYMBOLS) {
      Font font = jlabel.getFont();
      jlabel.setFont(font.deriveFont(0.7f * font.getSize()));
      jlabel.setHorizontalAlignment(JLabel.CENTER);
    }

    jlabel.setToolTipText(item.getTooltip());

    jlabel.addMouseListener(new MouseAdapter() {
      @Override
      public void mouseClicked(MouseEvent event) {
        if (event.getClickCount() > 1) {
          return;
        }
        if (myItemExecutor == null) {
          return;
        }

        myItemExecutor.execute(item);
      }
    });

    Icon itemIcon = item.getIcon();
    if (itemIcon != null) {
      jlabel.setIcon((myViewType == ViewType.SYMBOLS ? itemIcon : ScaledIcon.scaleIfNeeded(16, itemIcon)));
    }
    if (myViewType == ViewType.SYMBOLS) {
      jlabel.setHorizontalTextPosition(JLabel.CENTER);
      jlabel.setVerticalTextPosition(JLabel.BOTTOM);
    }
    return jlabel;
  }

  private static String abbreviate(String str, int maxWidth) {
    if (str == null) {
      return null;
    }
    if (str.length() <= maxWidth) {
      return str;
    }
    return str.substring(0, maxWidth - 3) + "...";
  }

  public void reloadItems() {
    loadItems(myLoadedItems);
  }

  private Folder getOrCreateFolder(String folderName, Map<String, Folder> folders) {
    if (folderName == null) {
      folderName = "";
    }
    Folder folder = folders.get(folderName);
    if (folder == null) {
      folder = new Folder(folderName, myViewType);
      folders.put(folderName, folder);
    }
    return folder;
  }


  public void setViewType(ViewType type) {
    myViewType = type;
    reloadItems();
  }

  public ViewType getViewType() {
    return myViewType;
  }

  public interface IItem {
    String getLabel();
    Icon getIcon();
    String getFolderName();
    String getTooltip();

    boolean isVisible();
    @NotNull
    CommandPolicy getCommandPolicy();
    void execute();
  }
  private static boolean check_cnbxua_a0a61(ToolWindow checkedDotOperand) {
    if (null != checkedDotOperand) {
      return checkedDotOperand.isVisible();
    }
    return false;
  }
  private static boolean isNotEmptyString(String str) {
    return str != null && str.length() > 0;
  }
}
