import java.awt.*;

/** StraightLayout lays out components in a single row or column,
 * according to the <B>layoutAxis</B> chosen at construction time:
 *
 * <dl>
 * <dt> VERTICAL
 * <dd> Lays out components in one column.
 * <B>crossOrientation</B> controls the width and positioning
 * of each component in this column,
 * and must be one of the following:
 * <dl>
 * <dt> LEFT
 * <dd> Each component will come left of any excess width,
 * <dt> FILL
 * <dd> Each component will fill available width,
 * <dt> CENTER (or not used by the constructor call)
 * <dd> Each component will be centered in any excess width,
 * <dt> RIGHT
 * <dd> Each component will come right of any excess width,
 * </dl>
 *
 * <dt> HORIZONTAL
 * <dd> Lays out components in one row.
 * <B>crossOrientation</B> controls the height and positioning
 * of each component in this row,
 * and must be one of the following:
 * <dl>
 * <dt> TOP
 * <dd> Each component will come above any excess height,
 * <dt> FILL 
 * <dd> Each component will fill available height,
 * <dt> CENTER (or not used by the constructor call)
 * <dd> Each component will be centered in any excess height,
 * <dt> BOTTOM
 * <dd> Each component will come below any excess height,
 * </dl>
 * </dl>
 *
 * The <B>alongAxis</B> distribution option controls either,
 * the height of each component in this VERTICAL column,
 * or the width of each component in this HORIZONTAL row,
 * and must be one of the following:
 * <dl>
 * <dt> NONE, LEFT, TOP (or not used by the constructor call)
 * <dd> Each component will get no more than their Preferred space
 * along the layout axis,
 * the components will be separated only the specified <B>gap</B>,
 * and the group of components will come before any excess space.
 * <dt> CENTER
 * <dd> Each component will get no more than their Preferred space
 * along the layout axis,
 * the components will be separated only the specified <B>gap</B>,
 * and the group of components will be centered in any excess space.
 * <dt> RIGHT, BOTTOM
 * <dd> Each component will get no more than their Preferred space
 * along the layout axis,
 * the components will be separated only the specified <B>gap</B>,
 * and the group of components will come after any excess space.
 * <dt> EQUALIZE
 * <dd> The entire available space will be filled.
 * All components will get equal space along the layout axis.
 * To ensure that no components get less than their Minimum,
 * the EQUALIZE option REQUIRES as total Minimum,
 * at least the largest Minimum times the number of components,
 * and REQUESTS as total Preferred,
 * at least the largest Preferred times the number of components.
 * <dt> DISTRIBUTE
 * <dd> The entire available space will be filled.
 * Excess space beyond the sum of Preferred sizes is distributed,
 * in proportion to the Preferred sizes of the components.
 * </dl>
 *
 * <P>
 * <B>Note:</B>
 * Only visible Components count in space requests and allocation,
 * therefore Components may be given different allocations,
 * according to the changed visibility of other Components.
 * The Container should be invalidated after any visibility changes.
 * <P>
 * This owes a lot to ColumnLayout and RowLayout,
 * from the GJT examples in D M Geary Graphic Java.
 * The DISTRIBUTE and EQUALIZE code is original here.
 *
 * @author Morris Hirsch IPD Inc
 */

public class StraightLayout implements LayoutManager {

    static public final int
    DEFAULT_GAP = 5,
    NONE = 0,
    LEFT = 1,
    CENTER = 2,
    RIGHT = 3,
    TOP = 4,
    BOTTOM = 5,
    FILL = 6,
    VERTICAL = 7,
    HORIZONTAL = 8,
    EQUALIZE = 9,
    DISTRIBUTE = 10;

    private int   gap;
    private int crossOrientation;
    private int layoutAxis;
    private int alongAxis;

    private int equal_step = 0;

/** Constructor with full parameters.
 * @param layoutAxis -- which axis, VERTICAL or HORIZONTAL,
 * @param alongAxis -- along Axis policy, NONE,
 * TOP, LEFT, CENTER, RIGHT, BOTTOM,
 * DISTRIBUTE or EQUALIZE,
 * @param crossOrient -- cross Orientation policy, LEFT, TOP, FILL, CENTER, BOTTOM, RIGHT,
 * @param gap -- Component separation in pixels.
 */

    public StraightLayout (int layoutAxis,
      int alongAxis,
      int crossOrient, 
      int gap) {

        if (!(gap >= 0))
	    throw new IllegalArgumentException ("gap");

        if (!(
          layoutAxis == VERTICAL ||
          layoutAxis == HORIZONTAL))
	      throw new IllegalArgumentException ("layoutAxis");

        if (!(
          alongAxis == NONE ||
          alongAxis == LEFT   ||
          alongAxis == TOP ||
          alongAxis == CENTER ||
          alongAxis == BOTTOM ||
          alongAxis == RIGHT ||
          alongAxis == DISTRIBUTE ||
          alongAxis == EQUALIZE))
	      throw new IllegalArgumentException ("alongAxis");

        if (!(
          crossOrient == LEFT   ||
          crossOrient == TOP ||
          crossOrient == FILL ||
          crossOrient == CENTER ||
          crossOrient == BOTTOM ||
          crossOrient == RIGHT))
	      throw new IllegalArgumentException ("crossOrient");

        this.layoutAxis    = layoutAxis;
        this.alongAxis    = alongAxis;
        this.crossOrientation   = crossOrient;
        this.gap       = gap;
    }

/** Short constructor.
 * @param layoutAxis -- which axis, VERTICAL or HORIZONTAL,
 * @param alongAxis -- along Axis policy, NONE,
 * TOP, LEFT, CENTER, RIGHT, BOTTOM,
 * DISTRIBUTE or EQUALIZE,
 * @param gap -- Component separation in pixels.
 */

    public StraightLayout (int layoutAxis, int alongAxis, int gap) {
        this (layoutAxis, alongAxis, CENTER, gap);
    }

/** Short constructor.
 * @param layoutAxis -- which axis, VERTICAL or HORIZONTAL,
 * @param alongAxis -- along Axis policy, NONE,
 * TOP, LEFT, CENTER, RIGHT, BOTTOM,
 * DISTRIBUTE or EQUALIZE,
 */

    public StraightLayout (int layoutAxis, int alongAxis) {
        this (layoutAxis, alongAxis, CENTER, DEFAULT_GAP);
    }

/** Short constructor.
 * @param layoutAxis -- which axis, VERTICAL or HORIZONTAL,
 */

    public StraightLayout (int layoutAxis) {
        this (layoutAxis, NONE, CENTER, DEFAULT_GAP);
    }

/** Default constructor */

    public StraightLayout () {
        this (VERTICAL, NONE, CENTER, DEFAULT_GAP);
    }

/** Set an alongAxis dimension to step each component,
 * regardless of their PreferredSize.
 * This distance includes the gap if any.
 * It is the distance from the start (left or top) of one component,
 * to the start of the next.
 * Any excess alongAxis space will not be used.
 * This setting is used only with the EQUALIZE mode,
 * and is otherwise ignored.
 * <P>
 * This method can ensure that components of different types,
 * or even in different containers,
 * will use the same spacing.
 * @param step -- the alongAxis dimension,
 * or zero (the default) to not use this feature. */

    public void setEqualSteps (int step) {
	equal_step = step;
    }

/** Required by LayoutManager interface but not used. **/

    public void addLayoutComponent (String name, Component comp) { 
    }

/** Required by LayoutManager interface but not used. **/

    public void removeLayoutComponent (Component comp) { 
    }

/** Compute the Preferred Layout Size request.
 * <dl>
 * <dt> VERTICAL:
 * <dd> Preferred height is sum of all Preferred heights,
 * unless EQUALIZE,
 * where Preferred height is the largest of all Preferred heights,
 * times the number of components.
 * Preferred width is max of all preferred widths.
 * <dt> HORIZONTAL:
 * <dd> Preferred width is sum of all Preferred widths,
 * unless EQUALIZE,
 * where Preferred width is the largest of all Preferred widths,
 * times the number of components.
 * Preferred height is max of all preferred heights.
 * </dl>
 * Both are padded by <B>gaps</B> between Components,
 * and by <B>insets</B> specified for the Container.
 * We call the deprecated &quot;insets ()&quot; form for portability.
 * @param target -- The Container this layout controls.
 */

    public Dimension preferredLayoutSize (Container target) {
        //Insets  insets  = target.getInsets ();
        Insets  insets  = target.insets ();
        Dimension dim   = new Dimension (0,0);
        int   ncomponents = target.getComponentCount ();
        Component comp;
        Dimension d;
        int countVis = 0, biggest = 0;

        for (int i = 0 ; i < ncomponents ; i++) {
            comp = target.getComponent(i);

            if (comp.isVisible()) {
		countVis++;
                d = comp.getPreferredSize ();

                if (VERTICAL == layoutAxis) {
                    if (i > 0) dim.height += gap;

                    dim.height += d.height;
                    dim.width   = Math.max (d.width, dim.width);

                    if (biggest < d.height)
                        biggest = d.height;
                }
                else {
                    dim.width  += d.width;
                    dim.height  = Math.max (d.height, dim.height);

                    if (i > 0) dim.width += gap;

                    if (biggest < d.width)
                        biggest = d.width;
                }
            }
        }

        if ((0 < countVis)
	 && (EQUALIZE == alongAxis)) {
            if (VERTICAL == layoutAxis)
                dim.height = (countVis * biggest) + ((countVis-1) * gap);
            else
                dim.width = (countVis * biggest) + ((countVis-1) * gap);
        }

        dim.width  += insets.left + insets.right;
        dim.height += insets.top  + insets.bottom;

        return dim;
    }

/** Compute the Minimum Layout Size requirement.
 * <dl>
 * <dt> VERTICAL:
 * <dd> Minimum height is sum of all Minimum heights,
 * unless EQUALIZE,
 * where Minimum height is the largest of all Minimum heights,
 * times the number of components.
 * Minimum width is max of all minimum widths.
 * <dt> HORIZONTAL:
 * <dd> Minimum width is sum of all Minimum widths,
 * unless EQUALIZE,
 * where Minimum width is the largest of all Minimum widths,
 * times the number of components.
 * Minimum height is max of all Minimum heights.
 * </dl>
 * Both are padded by <B>gaps</B> between Components,
 * and by <B>insets</B> specified for the Container.
 * We call the deprecated &quot;insets ()&quot; form for portability.
 * @param target -- The Container this layout controls.
 */

    public Dimension minimumLayoutSize (Container target) {
        //Insets  insets  = target.getInsets ();
        Insets  insets  = target.insets ();
        Dimension dim   = new Dimension (0,0);
        int   ncomponents = target.getComponentCount ();
        Component comp;
        Dimension d;
        int countVis = 0, biggest = 0;

        for (int i = 0 ; i < ncomponents ; i++) {
            comp = target.getComponent (i);

            if (comp.isVisible ()) {
		countVis++;
                d = comp.getMinimumSize ();

                if (VERTICAL == layoutAxis) {
                    dim.width  = Math.max (d.width, dim.width);
                    dim.height += d.height;

                    if (i > 0) dim.height += gap;

                    if (biggest < d.height)
                        biggest = d.height;
                }
                else {
                    dim.width  += d.width;
                    dim.height  = Math.max (d.height, dim.height);

                    if (i > 0) dim.width += gap;

                    if (biggest < d.width)
                        biggest = d.width;
                }
            }
        }

        if ((0 < countVis)
	 && (EQUALIZE == alongAxis)) {
            if (VERTICAL == layoutAxis)
                dim.height = (countVis * biggest) + ((countVis-1) * gap);
            else
                dim.width = (countVis * biggest) + ((countVis-1) * gap);
        }

        dim.width  += insets.left + insets.right;
        dim.height += insets.top  + insets.bottom;

        return dim;
    }

/** Set each Component where it belongs in the available space.
 * @param target -- The Container this layout controls.
 * <P>
 * To distribute available space in EQUALIZE mode,
 * either by extra pixel in some gaps or in some components,
 * the difference is less visible in the components,
 * although EQUALIZE implies they should all be exactly alike.
 * <P>
 * To distribute available space in DISTRIBUTE mode,
 * use ratio of actual over preferred space (both less insets and gaps)
 * times the preferred size of each component.
 * The ratio could be more or less than one.
 * We call the deprecated &quot;insets ()&quot; form for portability.
 */

    public void layoutContainer (Container target) {
        //Insets  insets  = target.getInsets ();
        Insets  insets  = target.insets ();
        int   top = 0;
        int   left = 0;
        int   ncomponents   = target.getComponentCount ();
        Dimension preferredSize = target.getPreferredSize ();
        Dimension targetSize  = target.getSize ();
        Component comp;
        Dimension ps;
        int full = 0;
        float feach = 0;
        float fstep = 0;
        float fratio = 0;
        float ftop = 0;
        float fleft = 0;

        int countVis = 0;

        for (int i = 0 ; i < ncomponents ; i++)
            if (target.getComponent (i).isVisible ())
		countVis++;

        if (VERTICAL == layoutAxis) {
            top = insets.top;

            if ((0 < countVis)
	     && (EQUALIZE == alongAxis)) {
                feach = (float)(targetSize.height
                  - insets.top
                  - insets.bottom
                  - ((countVis-1) * gap));
                feach /= countVis;
		fstep = feach + gap;
                ftop = (float)top;
            }

            else if ((0 < countVis)
	     && (DISTRIBUTE == alongAxis)) {
                fratio = (float)(targetSize.height
		- insets.top
		- insets.bottom
		- ((countVis-1) * gap))
		  / (float)(preferredSize.height
		  - insets.top
		  - insets.bottom
		  - ((countVis-1) * gap));
                ftop = (float)top;
            }

            else if (alongAxis == CENTER)
                top += (targetSize.height/2) - 
                  (preferredSize.height/2);

            else if (alongAxis == BOTTOM)
                top = targetSize.height - preferredSize.height + 
                  insets.top;

            full = targetSize.width - insets.left - insets.right;
        }

        else {
            left = insets.left;

            if ((0 < countVis)
	     && (EQUALIZE == alongAxis)) {
                feach = (float)(targetSize.width
                  - insets.left
                  - insets.right
                  - ((countVis-1) * gap));
                feach /= countVis;
		fstep = feach + gap;
                fleft = (float)left;
            }

            else if ((0 < countVis)
	     && (DISTRIBUTE == alongAxis)) {
                fratio = (float)(targetSize.width
		- insets.left
		- insets.right
		- ((countVis-1) * gap))
		  / (float)(preferredSize.width
		  - insets.left
		  - insets.right
		  - ((countVis-1) * gap));
                fleft = (float)left;
            }

            else if (alongAxis == CENTER)
                left = left + (targetSize.width/2) - (preferredSize.width/2);

            else if (alongAxis == RIGHT)
                left = left + targetSize.width - preferredSize.width;

            full  = targetSize.height - insets.top - insets.bottom;
        }

/** If setEqualSteps () set a positive (valid) alongAxis dimension,
 * and it is less than the EQUALIZE share plus gap,
 * use it instead to leave empty space at the end. */

	if ((0 < equal_step) && (equal_step < fstep)) {
	    fstep = equal_step;
	    feach = fstep - gap;
	}

        for (int i = 0 ; i < ncomponents ; i++) {
            comp = target.getComponent (i);

            if (comp.isVisible ()) {
                ps = comp.getPreferredSize ();

                if (VERTICAL == layoutAxis) {
                    if (EQUALIZE == alongAxis) {
                        int itop = (int)ftop;
                        int ibot = (int)(ftop + feach);
                        int ih = ibot - itop;
                        comp.setBounds (left,itop,full,ih);
                        //ftop += feach; ftop += gap;
			ftop += fstep;
                    }

                    else if (DISTRIBUTE == alongAxis) {
			int itop = (int)(top * fratio);
			int ih = (int)(ps.height * fratio);
			comp.setBounds (left,itop,full,ih);
			top += ps.height;
			top += gap;
                    }

                    else {
                        if (crossOrientation == CENTER)
                            left = (targetSize.width/2) - (ps.width/2);
                        else if (crossOrientation == RIGHT)
                            left = targetSize.width
			       - ps.width - insets.right;
                        else
                            left = insets.left;

                        if (crossOrientation == FILL)
                            comp.setBounds (left,top,full,ps.height);
			else
                            comp.setBounds (left,top,ps.width,ps.height);
                        top += ps.height + gap;
                    }
                }

                else {
                    if (EQUALIZE == alongAxis) {
                        int ileft = (int)fleft;
                        int iright = (int)(fleft + feach);
                        int iw = iright - ileft;
                        comp.setBounds (ileft,top,iw,full);
                        //fleft += feach; fleft += gap;
			fleft += fstep;
                    }

                    else if (DISTRIBUTE == alongAxis) {
			int ileft = (int)(left * fratio);
			int iw = (int)(ps.width * fratio);
                        comp.setBounds (ileft,top,iw,full);
			left += ps.width;
			left += gap;
                    }

                    else {
                        if (crossOrientation == CENTER)
                            top = (targetSize.height/2) - (ps.height/2);
                        else if (crossOrientation == TOP)
                            top = insets.top;
                        else if (crossOrientation == BOTTOM)
                            top = targetSize.height - 
                              ps.height - insets.bottom;

                        if (crossOrientation == FILL)
                            comp.setBounds (left,top,ps.width,full);
			else
                            comp.setBounds (left,top,ps.width,ps.height);
                        left += ps.width + gap;
                    }
                }
            }

/* The Container should not paint or print this Component,
 * but it seems that some methods do not test and try to anyway,
 * so we do this to prevent it. */

	    else
		comp.setBounds (0, 0, 0, 0);
        }
    }

}
/* <IMG SRC="/cgi-bin/counter">*/
