/*
 * Copyright (c) 2009 Kathryn Huxtable and Kenneth Orr.
 *
 * This file is part of the SeaGlass Pluggable Look and Feel.
 *
 * 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.
 *
 * $Id$
 */
package com.seaglasslookandfeel.component;

import java.awt.Component;
import java.awt.Container;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.LayoutManager;
import java.awt.Rectangle;

import java.beans.PropertyChangeEvent;

import javax.swing.JButton;
import javax.swing.JSplitPane;
import javax.swing.SwingConstants;
import javax.swing.plaf.basic.BasicSplitPaneDivider;
import javax.swing.plaf.basic.BasicSplitPaneUI;
import javax.swing.plaf.synth.Region;

import com.seaglasslookandfeel.SeaGlassContext;
import com.seaglasslookandfeel.SeaGlassLookAndFeel;
import com.seaglasslookandfeel.ui.SeaGlassSplitPaneUI;

import sun.swing.DefaultLookup;

/**
 * SeaGlassSplitPaneDivider implementation.
 *
 * <p>Based on Synth's divider.</p>
 *
 * @see javax.swing.plaf.synth.SynthSplitPaneDivider
 */
public class SeaGlassSplitPaneDivider extends BasicSplitPaneDivider {
    private static final long serialVersionUID = 5876267823818018895L;

    /**
     * Width or height of the divider based on orientation BasicSplitPaneUI adds
     * two to this.
     */
    protected static final int ONE_TOUCH_SIZE = 6;

    /** The offset for the one-touch buttons. */
    protected static final int ONE_TOUCH_OFFSET = 2;

    private int oneTouchSize;
    private int oneTouchOffset;

    /** If true the one touch buttons are centered on the divider. */
    private boolean centerOneTouchButtons;

    int oneTouchVOffset;

    /**
     * Creates a new SeaGlassSplitPaneDivider object.
     *
     * @param ui the parent UI delegate.
     */
    public SeaGlassSplitPaneDivider(BasicSplitPaneUI ui) {
        super(ui);
        oneTouchSize          = DefaultLookup.getInt(ui.getSplitPane(), ui, "SplitPane.oneTouchButtonSize", ONE_TOUCH_SIZE);
        oneTouchOffset        = DefaultLookup.getInt(ui.getSplitPane(), ui, "SplitPane.oneTouchButtonOffset", ONE_TOUCH_OFFSET);
        centerOneTouchButtons = DefaultLookup.getBoolean(ui.getSplitPane(), ui, "SplitPane.centerOneTouchButtons", true);
        oneTouchVOffset       = DefaultLookup.getInt(ui.getSplitPane(), ui, "SplitPane.oneTouchButtonVOffset", 0);
        setLayout(new DividerLayout());
    }

    /**
     * @see javax.swing.plaf.basic.BasicSplitPaneDivider#setMouseOver(boolean)
     */
    protected void setMouseOver(boolean mouseOver) {
        if (isMouseOver() != mouseOver) {
            repaint();
        }

        super.setMouseOver(mouseOver);
    }

    /**
     * @see javax.swing.plaf.basic.BasicSplitPaneDivider#propertyChange(java.beans.PropertyChangeEvent)
     */
    public void propertyChange(PropertyChangeEvent e) {
        super.propertyChange(e);

        if (e.getSource() == splitPane) {

            if (e.getPropertyName() == JSplitPane.ORIENTATION_PROPERTY) {

                if (leftButton instanceof SeaGlassArrowButton) {
                    ((SeaGlassArrowButton) leftButton).setDirection(mapDirection(true));
                }

                if (rightButton instanceof SeaGlassArrowButton) {
                    ((SeaGlassArrowButton) rightButton).setDirection(mapDirection(false));
                }
            }
        }
    }

    /**
     * @see javax.swing.plaf.basic.BasicSplitPaneDivider#paint(java.awt.Graphics)
     */
    public void paint(Graphics g) {
        Graphics g2 = g.create();

        SeaGlassContext context = ((SeaGlassSplitPaneUI) splitPaneUI).getContext(splitPane, Region.SPLIT_PANE_DIVIDER);
        Rectangle       bounds  = getBounds();

        bounds.x = bounds.y = 0;
        SeaGlassLookAndFeel.updateSubregion(context, g, bounds);
        context.getPainter().paintSplitPaneDividerBackground(context, g, 0, 0, bounds.width, bounds.height, splitPane.getOrientation());

        context.getPainter().paintSplitPaneDividerForeground(context, g, 0, 0, getWidth(), getHeight(), splitPane.getOrientation());
        context.dispose();

        // super.paint(g2);
        for (int counter = 0; counter < getComponentCount(); counter++) {
            Component child       = getComponent(counter);
            Rectangle childBounds = child.getBounds();
            Graphics  childG      = g.create(childBounds.x, childBounds.y, childBounds.width, childBounds.height);

            child.paint(childG);
            childG.dispose();
        }

        g2.dispose();
    }

    /**
     * Convert the orientation of the pane into compass points based on the pane
     * orientation and the left-right orientation of the containter.
     *
     * @param  isLeft {@code true} if the component's container is laid out
     *                left-to-right, otherwise {@code false}.
     *
     * @return the compass direction for increasing the divider.
     */
    private int mapDirection(boolean isLeft) {
        if (isLeft) {

            if (splitPane.getOrientation() == JSplitPane.HORIZONTAL_SPLIT) {
                return SwingConstants.WEST;
            }

            return SwingConstants.NORTH;
        }

        if (splitPane.getOrientation() == JSplitPane.HORIZONTAL_SPLIT) {
            return SwingConstants.EAST;
        }

        return SwingConstants.SOUTH;
    }

    /**
     * Creates and return an instance of JButton that can be used to collapse
     * the left/top component in the split pane.
     *
     * @return a one-touch button.
     */
    protected JButton createLeftOneTouchButton() {
        SeaGlassArrowButton b            = new SeaGlassArrowButton(SwingConstants.NORTH);
        int                 oneTouchSize = lookupOneTouchSize();

        b.setName("SplitPaneDivider.leftOneTouchButton");
        b.setMinimumSize(new Dimension(oneTouchSize, oneTouchSize));
        b.setCursor(Cursor.getPredefinedCursor(
            splitPane.getOrientation() == 
                JSplitPane.HORIZONTAL_SPLIT ? 
                        Cursor.W_RESIZE_CURSOR:Cursor.N_RESIZE_CURSOR));
        b.setFocusPainted(false);
        b.setBorderPainted(false);
        b.setRequestFocusEnabled(false);
        b.setDirection(mapDirection(true));

        return b;
    }

    /**
     * Get the size of the one-touch button.
     *
     * @return the button size.
     */
    private int lookupOneTouchSize() {
        return DefaultLookup.getInt(splitPaneUI.getSplitPane(), splitPaneUI, "SplitPaneDivider.oneTouchButtonSize", ONE_TOUCH_SIZE);
    }

    /**
     * Creates and return an instance of JButton that can be used to collapse
     * the right component in the split pane.
     *
     * @return a one-touch button
     */
    protected JButton createRightOneTouchButton() {
        SeaGlassArrowButton b            = new SeaGlassArrowButton(SwingConstants.NORTH);
        int                 oneTouchSize = lookupOneTouchSize();

        b.setName("SplitPaneDivider.rightOneTouchButton");
        b.setMinimumSize(new Dimension(oneTouchSize, oneTouchSize));
        // Rossi: Change cursors on "one touch" buttons. Better would be an mouse over effect
        b.setCursor(Cursor.getPredefinedCursor(
            splitPane.getOrientation() == 
                JSplitPane.HORIZONTAL_SPLIT ? 
                        Cursor.E_RESIZE_CURSOR:Cursor.S_RESIZE_CURSOR));
        b.setFocusPainted(false);
        b.setBorderPainted(false);
        b.setRequestFocusEnabled(false);
        b.setDirection(mapDirection(false));

        return b;
    }

    /**
     * Used to layout a <code>BasicSplitPaneDivider</code>. Layout for the
     * divider involves appropriately moving the left/right buttons around.
     */
    protected class DividerLayout implements LayoutManager {

        /**
         * @see java.awt.LayoutManager#layoutContainer(java.awt.Container)
         */
        public void layoutContainer(Container c) {
            if (leftButton != null && rightButton != null && c == SeaGlassSplitPaneDivider.this) {

                if (splitPane.isOneTouchExpandable()) {
                    Insets insets = getInsets();

                    if (orientation == JSplitPane.VERTICAL_SPLIT) {
                        int extraX    = (insets != null) ? insets.left : 0;
                        int blockSize = getHeight();

                        if (insets != null) {
                            blockSize -= (insets.top + insets.bottom);
                            blockSize = Math.max(blockSize, 0);
                        }

                        blockSize = Math.min(blockSize, oneTouchSize);

                        int y = (c.getSize().height - blockSize) / 2;

                        if (!centerOneTouchButtons) {
                            y      = (insets != null) ? insets.top : 0;
                            extraX = 0;
                        }

                        leftButton.setBounds(extraX + oneTouchOffset, y - oneTouchVOffset, blockSize * 2, blockSize);
                        rightButton.setBounds(extraX + oneTouchOffset, y + oneTouchVOffset + 1, blockSize * 2, blockSize);
                    } else {
                        int extraY    = (insets != null) ? insets.top : 0;
                        int blockSize = getWidth();

                        if (insets != null) {
                            blockSize -= (insets.left + insets.right);
                            blockSize = Math.max(blockSize, 0);
                        }

                        blockSize = Math.min(blockSize, oneTouchSize);

                        int x = (c.getSize().width - blockSize) / 2;

                        if (!centerOneTouchButtons) {
                            x      = (insets != null) ? insets.left : 0;
                            extraY = 0;
                        }

                        leftButton.setBounds(x - oneTouchVOffset, extraY + oneTouchOffset, blockSize, blockSize * 2);
                        rightButton.setBounds(x + oneTouchVOffset + 1, extraY + oneTouchOffset, blockSize, blockSize * 2);
                    }
                } else {
                    leftButton.setBounds(-5, -5, 1, 1);
                    rightButton.setBounds(-5, -5, 1, 1);
                }
            }
        }

        /**
         * @see java.awt.LayoutManager#minimumLayoutSize(java.awt.Container)
         */
        public Dimension minimumLayoutSize(Container c) {
            // NOTE: This isn't really used, refer to
            // BasicSplitPaneDivider.getPreferredSize for the reason.
            // I leave it in hopes of having this used at some point.
            if (c != SeaGlassSplitPaneDivider.this || splitPane == null) {
                return new Dimension(0, 0);
            }

            Dimension buttonMinSize = null;

            if (splitPane.isOneTouchExpandable() && leftButton != null) {
                buttonMinSize = leftButton.getMinimumSize();
            }

            Insets insets = getInsets();
            int    width  = getDividerSize();
            int    height = width;

            if (orientation == JSplitPane.VERTICAL_SPLIT) {

                if (buttonMinSize != null) {
                    int size = buttonMinSize.height;

                    if (insets != null) {
                        size += insets.top + insets.bottom;
                    }

                    height = Math.max(height, size);
                }

                width = 1;
            } else {

                if (buttonMinSize != null) {
                    int size = buttonMinSize.width;

                    if (insets != null) {
                        size += insets.left + insets.right;
                    }

                    width = Math.max(width, size);
                }

                height = 1;
            }

            return new Dimension(width, height);
        }

        /**
         * @see java.awt.LayoutManager#preferredLayoutSize(java.awt.Container)
         */
        public Dimension preferredLayoutSize(Container c) {
            return minimumLayoutSize(c);
        }

        /**
         * @see java.awt.LayoutManager#removeLayoutComponent(java.awt.Component)
         */
        public void removeLayoutComponent(Component c) {
        }

        /**
         * @see java.awt.LayoutManager#addLayoutComponent(java.lang.String, java.awt.Component)
         */
        public void addLayoutComponent(String string, Component c) {
        }
    }
}