/*
 * @(#)PackerLayout.java    1.0 12/19/95 Henry Wong
 *
 * Copyright (c) 1995 Sun Microsystems, Inc. All Rights Reserved.
 *
 * Permission to use, copy, modify, and distribute this software
 * and its documentation for NON-COMMERCIAL purposes and without
 * fee is hereby granted provided that this copyright notice
 * appears in all copies. Please refer to the file "copyright.html"
 * for further important copyright and licensing information.
 *
 * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
 * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
 * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
 * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
 * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
 * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
 */

package awt;
import java.awt.*;
import java.util.Vector;

/**
 * A layout manager for a container that lays out in packer format
 *
 *
 * @version 1.8, 10/05/95
 * @author 
 */
public class PackerLayout implements LayoutManager {
	private PackerInfo defaultPackerInfo;
	private Vector infoTable;
        private boolean debug = true;

        /**
         *      Creates the packer layout
         */
        public PackerLayout() {
		if ( debug )
			System.out.println("PackerLayout() called");
		defaultPackerInfo = new PackerInfo();
		infoTable = new Vector();
	}
        /**
         *      Layout info added sequentially
         *      @param info the Packerinfo for the component
         */
	public synchronized void addLayoutInfo(PackerInfo info) {
		if ( debug )
                        System.out.println("addLayoutInfo() called");
		infoTable.addElement(info.clone());	
	}
        /**
         *      Remove the layout info for the given component
         */
	public synchronized void removeLayoutInfo(Component comp) {
		if ( debug )
                        System.out.println("removeLautoutInfo() called");
		for (int i = 0; i < infoTable.size(); i++) {
			if (((PackerInfo)infoTable.elementAt(i)).widget == comp)
				infoTable.removeElementAt(i);
		}
	}
        /**
         *      Return the packer info for the given component
         *      @param comp the componenet
         */
        public synchronized PackerInfo getLayoutInfo(Component comp) {
		if ( debug )
                        System.out.println("getLayoutInfo() called");
		for (int i = 0; i < infoTable.size(); i++) {
			if (((PackerInfo)infoTable.elementAt(i)).widget == comp)
				return (PackerInfo)infoTable.elementAt(i);
		}
		return defaultPackerInfo;
	}
        /**
         * Adds the specified component with the specified name to the layout.
         * @param name the name of the component
         * @param comp the component to be added
         * Does not apply
         */
 	public void addLayoutComponent(String name, Component comp) {
		if ( debug )
                        System.out.println("addLayoutComponent() called");
	}
         /**
         * Adds the specified component with the specified name to the layout.
         * @param comp the component to be removed
         * Does not apply
         */
	public void removeLayoutComponent(Component comp) {
		if ( debug )
                        System.out.println("removeLayoutComponent() called");
	}

	private Dimension getSizeComponent(Component component, boolean preferred) {
		if ( debug )
                        System.out.println("getSizeComponent() called");
		if (preferred)
			return component.preferredSize();
		else
			return component.minimumSize();
	}

	private Dimension getSizeContainer(Container parent, boolean preferred) {
	    Dimension dim = new Dimension(0, 0);
	    Dimension max = new Dimension(0, 0);
	    int ncomponents = parent.countComponents();
		if ( debug )
                        System.out.println("getSizeContainer() called");

	    Insets ins = parent.insets();
	    dim.width = ins.left + ins.right; max.width = dim.width;
	    dim.height = ins.top + ins.bottom; max.height = dim.height;

	    for (int i = 0; i < ncomponents; i++) {
		Component c = parent.getComponent(i);
		if (c.isVisible() == false) continue;
		PackerInfo winfo = getLayoutInfo(c);
		Dimension widget = getSizeComponent(c, preferred);

		if ((winfo.side == PackerInfo.TOP) ||
		    (winfo.side == PackerInfo.BOTTOM)) {
			dim.height += widget.height+(2*winfo.pady);
			max.width =
			    Math.max(widget.width+dim.width+(2*winfo.padx),max.width);
		} else {
			dim.width += widget.width+(2*winfo.padx);
			max.height =
			    Math.max(widget.height+dim.height+(2*winfo.pady),max.height);
		}
	    }

	    dim.height = Math.max(dim.height, max.height);
	    dim.width = Math.max(dim.width, max.width);
	    return dim;
        }

        /**
         * Returns the preferred dimensions for this layout given the components
         * int the specified panel.
         * @param parent the component which needs to be laid out 
         * @see #minimumSize
         */

	public Dimension preferredLayoutSize(Container parent) {
		if ( debug )
                        System.out.println("preferredLayoutSize() called");
	    return getSizeContainer(parent, true);
	}

        /**
         * Returns the minimum dimensions needed to layout the components 
         * contained in the specified panel.
         * @param parent the component which needs to be laid out 
         * @see #preferredSize
         */
    	public Dimension minimumLayoutSize(Container parent) {
		if ( debug )
                        System.out.println("minimumLayoutSize() called");
	    return getSizeContainer(parent, false);
	}

        /** 
         * Lays out the container in the specified panel.
         * @param parent the specified component being laid out
         * @see Container
         */
	public void layoutContainer(Container parent) {
	    boolean preferred = false;
	    int ncomponents = parent.countComponents();
	    Dimension dim = parent.size();
	    Dimension chk = preferredLayoutSize(parent);
		if ( debug )
                        System.out.println("layoutContainer() called");
	    if ((dim.height >= chk.height) || (dim.width >= chk.width)) {
		preferred = true;
	    } else {
		chk = minimumLayoutSize(parent);
		dim.width = Math.max(dim.width, chk.width);
		dim.height = Math.max(dim.height, chk.height);
	    }

	    Rectangle frees = new Rectangle(dim);
	    Insets ins = parent.insets();
	    frees.x += ins.left; frees.y += ins.top;
	    frees.width -= ins.left + ins.right;
	    frees.height -= ins.top + ins.bottom;

	    for (int i = 0; i < ncomponents; i++) {
		Component c = parent.getComponent(i);
		if (c.isVisible() == false) continue;
		PackerInfo winfo = getLayoutInfo(c);
		Dimension widget = getSizeComponent(c, preferred);
		Rectangle shape = new Rectangle();

		// Calculate the Width and Height of the widget
		switch (winfo.side) {
		    case PackerInfo.TOP:
		    case PackerInfo.BOTTOM:
			if (winfo.fillx)
				shape.width = frees.width - (2*winfo.padx);
			else
				shape.width = widget.width;
			if ((winfo.filly) && ((i+1) == ncomponents))
				shape.height = frees.height - (2*winfo.pady);
			else
				shape.height = widget.height;
			break;
		    case PackerInfo.LEFT:
		    case PackerInfo.RIGHT:
			if ((winfo.fillx) && ((i+1) == ncomponents))
				shape.width = frees.width - (2*winfo.padx);
			else
				shape.width = widget.width;
			if (winfo.filly)
				shape.height = frees.height - (2*winfo.pady);
			else
				shape.height = widget.height;
			break;
		}
		// Calculate the X and Y of the widget
		switch (winfo.side) {
		    case PackerInfo.TOP:
			shape.x = frees.x + ((frees.width - shape.width)/2);
			shape.y = frees.y + winfo.pady;

			frees.y += shape.height + (2*winfo.pady);
			frees.height -= shape.height + (2*winfo.pady);
			break;
		    case PackerInfo.BOTTOM:
			shape.x = frees.x + ((frees.width - shape.width)/2);
			shape.y = frees.y + frees.height - shape.height - winfo.pady;

			frees.height -= shape.height + (2*winfo.pady);
			break;
		    case PackerInfo.LEFT:
			shape.x = frees.x + winfo.padx;
			shape.y = frees.y + ((frees.height - shape.height)/2);

			frees.x += shape.width + (2*winfo.padx);
			frees.width -= shape.width + (2*winfo.padx);
			break;
		    case PackerInfo.RIGHT:
			shape.x = frees.x + frees.width - shape.width - winfo.padx;
			shape.y = frees.y + ((frees.height - shape.height)/2);

			frees.width -= shape.width + (2*winfo.padx);
			break;
		}
		c.reshape(shape.x, shape.y, shape.width, shape.height);
	    }
	}
}


