/*
 * 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.bulenkov.darcula.ui;

import com.bulenkov.iconloader.util.*;

import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.border.CompoundBorder;
import javax.swing.border.EmptyBorder;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.UIResource;
import javax.swing.plaf.basic.BasicArrowButton;
import javax.swing.plaf.basic.BasicSpinnerUI;
import java.awt.*;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;

/**
 * @author Konstantin Bulenkov
 */
public class DarculaSpinnerUI extends BasicSpinnerUI {
  private final FocusAdapter myFocusListener = new FocusAdapter() {
    @Override
    public void focusGained(FocusEvent e) {
      spinner.repaint();
    }

    @Override
    public void focusLost(FocusEvent e) {
      spinner.repaint();
    }
  };

  @SuppressWarnings({"MethodOverridesStaticMethodOfSuperclass", "UnusedDeclaration"})
  public static ComponentUI createUI(JComponent c) {
    return new DarculaSpinnerUI();
  }

  @Override
  protected void replaceEditor(JComponent oldEditor, JComponent newEditor) {
      super.replaceEditor(oldEditor, newEditor);
      if (oldEditor != null && oldEditor.getComponents().length > 0) {
          oldEditor.getComponents()[0].removeFocusListener(myFocusListener);
      }
      if (newEditor.getComponents().length > 0) {
          newEditor.getComponents()[0].addFocusListener(myFocusListener);
      }
  }

  @Override
  protected JComponent createEditor() {
    final JComponent editor = super.createEditor();
    editor.getComponents()[0].addFocusListener(myFocusListener);
    return editor;
  }

  @Override
  public void paint(Graphics g, JComponent c) {
    super.paint(g, c);
    final Border border = spinner.getBorder();
    if (border != null) {
      border.paintBorder(c, g, 0, 0, spinner.getWidth(), spinner.getHeight());
    }
  }

  @Override
  protected Component createPreviousButton() {
    JButton button = createArrow(SwingConstants.SOUTH);
    button.setName("Spinner.previousButton");
    button.setBorder(new EmptyBorder(1, 1, 1, 1));
    installPreviousButtonListeners(button);
    return button;
  }

  @Override
  protected Component createNextButton() {
    JButton button = createArrow(SwingConstants.NORTH);
    button.setName("Spinner.nextButton");
    button.setBorder(new EmptyBorder(1, 1, 1, 1));
    installNextButtonListeners(button);
    return button;
  }


  @Override
  protected LayoutManager createLayout() {
    return new LayoutManagerDelegate(super.createLayout()) {
      @Override
      public void layoutContainer(Container parent) {
        super.layoutContainer(parent);
        final JComponent editor = spinner.getEditor();
        if (editor != null) {
          final Rectangle bounds = editor.getBounds();
          editor.setBounds(bounds.x, bounds.y, bounds.width - 6, bounds.height);
        }
      }
    };
  }

  private JButton createArrow(int direction) {
    final Color shadow = UIUtil.getPanelBackground();
    final Color enabledColor = new DoubleColor(Gray._255, UIUtil.getLabelForeground());
    final Color disabledColor = new DoubleColor(Gray._200, UIUtil.getLabelForeground().darker());
    JButton b = new BasicArrowButton(direction, shadow, shadow, enabledColor, shadow) {
      @Override
      public void paint(Graphics g) {
        int y = direction == NORTH ? getHeight() - 6 : 2;
        paintTriangle(g, (getWidth() - 8)/2 - 1, y, 0, direction, DarculaSpinnerUI.this.spinner.isEnabled());
      }

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

      @Override
      public void paintTriangle(Graphics g, int x, int y, int size, int direction, boolean isEnabled) {
        final GraphicsConfig config = GraphicsUtil.setupAAPainting(g);
        int mid;
        final int w = 8;
        final int h = 6;
        mid = w  / 2;

        g.setColor(isEnabled ? enabledColor : disabledColor);

        g.translate(x, y);
        switch (direction) {
          case SOUTH:
            g.fillPolygon(new int[]{0, w, mid}, new int[]{1, 1, h}, 3);
            break;
          case NORTH:
            g.fillPolygon(new int[]{0, w, mid}, new int[]{h - 1, h - 1, 0}, 3);
            break;
          case WEST:
          case EAST:
        }
        g.translate(-x, -y);
        config.restore();
      }
    };
    Border buttonBorder = UIManager.getBorder("Spinner.arrowButtonBorder");
    if (buttonBorder instanceof UIResource) {
      // Wrap the border to avoid having the UIResource be replaced by
      // the ButtonUI. This is the opposite of using BorderUIResource.
      b.setBorder(new CompoundBorder(buttonBorder, null));
    }
    else {
      b.setBorder(buttonBorder);
    }
    b.setInheritsPopupMenu(true);
    return b;
  }

  static class LayoutManagerDelegate implements LayoutManager {
    protected final LayoutManager myDelegate;

    LayoutManagerDelegate(LayoutManager delegate) {
      myDelegate = delegate;
    }

    @Override
    public void addLayoutComponent(String name, Component comp) {
      myDelegate.addLayoutComponent(name, comp);
    }

    @Override
    public void removeLayoutComponent(Component comp) {
      myDelegate.removeLayoutComponent(comp);
    }

    @Override
    public Dimension preferredLayoutSize(Container parent) {
      return myDelegate.preferredLayoutSize(parent);
    }

    @Override
    public Dimension minimumLayoutSize(Container parent) {
      return myDelegate.minimumLayoutSize(parent);
    }

    @Override
    public void layoutContainer(Container parent) {
      myDelegate.layoutContainer(parent);
    }
  }
}
