/*
 * $Id$
 *
 * Copyright 2009 Sun Microsystems, Inc., 4150 Network Circle,
 * Santa Clara, California 95054, U.S.A. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 */
package org.jdesktop.swingx;

import javax.swing.JComponent;
import javax.swing.JViewport;
import javax.swing.SwingConstants;

import org.jdesktop.swingx.util.Contract;

/**
 * Sizing hints for layout, useful f.i. in a Scrollable implementation.<p>
 * 
 * Inspired by <a href=
 * http://tips4java.wordpress.com/2009/12/20/scrollable-panel/> Rob Camick</a>.
 * <p>
 * PENDING JW: naming... suggestions?<br>
 * KS: I'd go with TrackingHint or ScrollableTrackingHint, since it is used in getScrollableTracksViewportXXX.
 * 
 * 
 * @author Jeanette Winzenburg
 * @author Karl Schaefer
 */
public enum ScrollableSizeHint {
    /**
     * Size should be unchanged.
     */
    NONE {
        /**
         * {@inheritDoc}
         */
        @Override
        boolean getTracksParentSizeImpl(JComponent component, int orientation) {
            return false;
        }
    }, 
    
    /**
     * Size should be adjusted to parent size. 
     */
    FIT {
        /**
         * {@inheritDoc}
         */
        @Override
        boolean getTracksParentSizeImpl(JComponent component, int orientation) {
            return true;
        }
    }, 
    
    /**
     * Stretches the component when its parent is larger than its minimum size.
     */
    MINIMUM_STRETCH {
        /**
         * {@inheritDoc}
         */
        @Override
        boolean getTracksParentSizeImpl(JComponent component, int orientation) {
            switch (orientation) {
            case SwingConstants.HORIZONTAL:
                return component.getParent() instanceof JViewport
                        && component.getParent().getWidth() > component.getMinimumSize().width
                        && component.getParent().getWidth() < component.getMaximumSize().width;
            case SwingConstants.VERTICAL:
                return component.getParent() instanceof JViewport
                        && component.getParent().getHeight() > component.getMinimumSize().height
                        && component.getParent().getHeight() < component.getMaximumSize().height;
            default:
                throw new IllegalArgumentException("invalid orientation");
            }
        }
    },
    
    /**
     * Stretches the component when its parent is larger than its preferred size.
     */
    PREFERRED_STRETCH {
        /**
         * {@inheritDoc}
         */
        @Override
        boolean getTracksParentSizeImpl(JComponent component, int orientation) {
            switch (orientation) {
            case SwingConstants.HORIZONTAL:
                return component.getParent() instanceof JViewport
                        && component.getParent().getWidth() > component.getPreferredSize().width
                        && component.getParent().getWidth() < component.getMaximumSize().width;
            case SwingConstants.VERTICAL:
                return component.getParent() instanceof JViewport
                        && component.getParent().getHeight() > component.getPreferredSize().height
                        && component.getParent().getHeight() < component.getMaximumSize().height;
            default:
                throw new IllegalArgumentException("invalid orientation");
            }
        }
    },
    
    /**
     * Width should be stretched to parent width if smaller, unchanged otherwise.
     */
    @Deprecated
    HORIZONTAL_STRETCH {
        /**
         * {@inheritDoc}
         * <p>
         * Returns {@code false}.
         */
        @Override
        @Deprecated
        public boolean isVerticalCompatible() {
            return false;
        }
        
        /**
         * {@inheritDoc}
         */
        @Override
        boolean getTracksParentSizeImpl(JComponent component, int orientation) {
            if (orientation != SwingConstants.HORIZONTAL) {
                throw new IllegalArgumentException();
            }
            
            if (component.getParent() != null) {
                return component.getParent().getWidth() > component.getPreferredSize().width
                    && component.getParent().getWidth() < component.getMaximumSize().width;
            }

            return false;
        }
    },
    
    /**
     * Width should be stretched to parent height if smaller, unchanged otherwise.
     */
    @Deprecated
    VERTICAL_STRETCH {
        /**
         * {@inheritDoc}
         * <p>
         * Returns {@code false}.
         */
        @Override
        @Deprecated
        public boolean isHorizontalCompatible() {
            return false;
        }
        
        /**
         * {@inheritDoc}
         */
        @Override
        boolean getTracksParentSizeImpl(JComponent component, int orientation) {
            if (orientation != SwingConstants.VERTICAL) {
                throw new IllegalArgumentException();
            }
            
            if (component.getParent() != null) {
                return component.getParent().getHeight() > component.getPreferredSize().height
                        && component.getParent().getWidth() < component.getMaximumSize().height;
            }

            return false;
        }
    };
    
    /**
     * Returns a boolean indicating whether the component's size should be
     * adjusted to parent.
     *  
     * @param component the component resize, must not be null
     * @return a boolean indicating whether the component's size should be
     *    adjusted to parent
     *    
     * @throws NullPointerException if component is null   
     */
    @Deprecated
    public boolean getTracksParentSize(JComponent component) {
        return getTracksParentSize(component, 0);
    }
    
    /**
     * Returns a boolean indicating whether the component's size should be
     * adjusted to parent.
     *  
     * @param component the component resize, must not be null
     * @return a boolean indicating whether the component's size should be
     *    adjusted to parent
     *    
     * @throws NullPointerException if component is null
     * @throws IllegalArgumentException if orientation is invalid
     */
    public boolean getTracksParentSize(JComponent component, int orientation) {
        Contract.asNotNull(component, "component must be not-null");
        
        return getTracksParentSizeImpl(component, orientation);
    }

    /**
     * Returns a boolean indicating whether the hint can be used in 
     * horizontal orientation.
     * 
     * @return a boolean indicating whether the hint can be used in horizontal
     *   orientation. 
     */
    @Deprecated
    public boolean isHorizontalCompatible() {
        return true;
    }
    
    /**
     * Returns a boolean indicating whether the hint can be used in 
     * vertical orientation.
     * 
     * @return a boolean indicating whether the hint can be used in vertical
     *   orientation. 
     */
    @Deprecated
    public boolean isVerticalCompatible() {
        return true;
    }

    /**
     * Determines whether the supplied component is smaller than its parent; used to determine
     * whether to track with the parents size.
     * 
     * @param component
     *            the component to test
     * @param orientation
     *            the orientation to test
     * @return {@code true} to track; {@code false} otherwise
     */
    abstract boolean getTracksParentSizeImpl(JComponent component, int orientation);
}
