/*
 * @(#)ZoomableViewportLayout.java  1.0  2008-09-21
 * 
 * Copyright (c) 2008 Werner Randelshofer, Immensee, Switzerland.
 * All rights reserved.
 *
 * You may not use, copy or modify this file, except in compliance with the
 * license agreement you entered into with Werner Randelshofer.
 * For details see accompanying license terms.
 */
package ch.randelshofer.pdf;

import java.awt.*;
import javax.swing.*;

/**
 * A ViewportLayout which centers the view, if there is more space available
 * than the view needs.
 *
 * @author Werner Randelshofer
 * @version 1.0 2008-09-21 Created.
 */
public class ZoomableViewportLayout extends ViewportLayout {

    public final static String ZOOM_POLICY_PROPERTY = "zoomPolicy";
     private ZoomPolicy zoomPolicy = ZoomPolicy.FIXED_SIZE;

    public void setZoomPolicy(ZoomPolicy newValue) {
        ZoomPolicy oldValue = zoomPolicy;
        zoomPolicy = newValue;
    //firePropertyChange(ZOOM_POLICY_PROPERTY, oldValue, newValue);
    }

    public ZoomPolicy getZoomPolicy() {
        return zoomPolicy;
    }

    /**
     * Called by the AWT when the specified container needs to be laid out.
     *
     * @param parent  the container to lay out
     *
     * @exception AWTError  if the target isn't the container specified to the
     *                      <code>BoxLayout</code> constructor
     */
    @Override
    public void layoutContainer(Container parent) {
        // layout must be done in two passes, due to interaction of the
        // scrollpane with the viewport.
        doLayoutContainer(parent);
        doLayoutContainer(parent);
    }
    private void doLayoutContainer(Container parent) {
        JViewport vp = (JViewport) parent;
        Component view = vp.getView();
        Scrollable scrollableView = null;

        if (view == null) {
            return;
        } else if (view instanceof Scrollable) {
            scrollableView = (Scrollable) view;
        }

        /* All of the dimensions below are in view coordinates, except
         * vpSize which we're converting.
         */

        Insets insets = vp.getInsets();
        Dimension viewPrefSize = view.getPreferredSize();
        Dimension vpSize = vp.getSize();
        Dimension extentSize = vp.toViewCoordinates(vpSize);
        Dimension viewSize = new Dimension(viewPrefSize);

        Point viewPosition = vp.getViewPosition();

        switch (zoomPolicy) {
            case FIT_PAGE: {
                viewSize.width = vpSize.width - insets.left - insets.right;
                viewSize.height = vpSize.height - insets.top - insets.bottom;
                viewPosition.x = insets.left;
                viewPosition.y = insets.top;
                break;
            }
            case FIT_WIDTH: {
                viewSize.width = vpSize.width - insets.left - insets.right;
                viewSize.height = (int) (viewSize.width / (float) viewPrefSize.width * viewPrefSize.height);
                viewPosition.x = insets.left;
                if (viewSize.height < vpSize.height) {
                viewPosition.y = insets.top - (vpSize.height - insets.top - insets.bottom - viewSize.height) / 2;
                    }
                break;
            }
            case FIT_HEIGHT: {
                viewSize.height = vpSize.height - insets.top - insets.bottom;
                viewSize.width = (int) (viewSize.height / (float) viewPrefSize.height * viewPrefSize.width);
                viewPosition.y = insets.top;
                if (viewSize.width < vpSize.width) {
                viewPosition.x = insets.left - (vpSize.width - insets.left - insets.right - viewSize.width) / 2;
              }
                break;
            }
            case FIXED_SIZE: {
                if (scrollableView != null) {
                    if (scrollableView.getScrollableTracksViewportWidth()) {
                        viewSize.width = vpSize.width;
                    }
                    if (scrollableView.getScrollableTracksViewportHeight()) {
                        viewSize.height = vpSize.height;
                    }
                }

                /* If the new viewport size would leave empty space to the
                 * right or the left of the view, center
                 * the view when the width of the view is smaller than the
                 * container.
                 */
                if (scrollableView == null ||
                        vp.getParent() == null ||
                        vp.getParent().getComponentOrientation().isLeftToRight()) {
                    if ((viewPosition.x + extentSize.width) > viewSize.width) {
                        //viewPosition.x = Math.max(0, viewSize.width - extentSize.width);
                        viewPosition.x = (viewSize.width - extentSize.width) / 2;
                    }
                } else {
                    if (extentSize.width > viewSize.width) {
                        viewPosition.x = (viewSize.width - extentSize.width) / 2;
                    } else {
                        //viewPosition.x = Math.max(0, Math.min(viewSize.width - extentSize.width, viewPosition.x));
                        viewPosition.x = (viewSize.width - extentSize.width) / 2;
                    }
                }

                /* If the new viewport size would leave empty space below the
                 * view, bottom justify the view or top justify the view when
                 * the height of the view is smaller than the container.
                 */
                if ((viewPosition.y + extentSize.height) > viewSize.height) {
                    // viewPosition.y = Math.max(0, viewSize.height - extentSize.height);
                    viewPosition.y = (viewSize.height - extentSize.height) / 2;
                }

                /* If we haven't been advised about how the viewports size 
                 * should change wrt to the viewport, i.e. if the view isn't
                 * an instance of Scrollable, then adjust the views size as follows.
                 * 
                 * If the origin of the view is showing and the viewport is
                 * bigger than the views preferred size, then make the view
                 * the same size as the viewport.
                 */
                if (scrollableView == null) {
                    if ((viewPosition.x == 0) && (vpSize.width > viewPrefSize.width)) {
                        viewSize.width = vpSize.width;
                    }
                    if ((viewPosition.y == 0) && (vpSize.height > viewPrefSize.height)) {
                        viewSize.height = vpSize.height;
                    }
                }
                break;
            }
        }
        vp.setViewPosition(viewPosition);
        vp.setViewSize(viewSize);
    }
}
