/* $Id$
 *
 * Copyright (c) 1998 Xenonsoft Limited. All Rights Reserved.
 *
 * This software is protected by copyright. You are hereby notified from
 * now by reading this message. This software is also the confidential 
 * and proprietary information of Xenonsoft Limited.  ("Confidential
 * Information"). You are NOT permitted to publish or disclose such
 * Confidential Information, in anyway. Moreover, this software must be
 * used in accordance with, and in compliance of, the license agreement
 * you entered with Xenonsoft.
 */

// RowColumnLayout.java

// Description:
//	RowColumnLayout - custom layout style manager for the AWT.
//	Layouts widget (I mean components) in the style of OSF/Motif's
//	XmRowColumnManager widget. I find this concept of get layout in
//	components in a container easier to understand and to apply
//	than the GridBagLayout manager.
//
// Author:
//	Peter Pilgrim
//	Tue Aug 18 12:51:17 BST 1998
// 
// RCS HEADER ``RowColumnLayout.java''
// 
// $Author$
// $Date$
// $Source$
// $Revision$    $State$    $Locker$
//
// History 
// ================================================================================
//	$Log$

package xenon.swing;

import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.util.*;

// For Hashtable

public class RowColumnLayout implements LayoutManager {

    protected static boolean	debug = false;	// DEBUGGABLE FLAG


    /** layout the container vertically */
    public static final int VERTICAL	  = 1;
    /** layout the container horizontally */
    public static final int HORIZONTAL	  = 2;

    /** Pack horizontally in rows when orientation is VERTICAL */
    public static final int PACK_COLUMN	  = 0;
    /** Pack horizontally in rows when orientation is HORIZONTAL */
    public static final int PACK_ROW	  = 0;

    /** Pack tightly by orientation */
    public static final int PACK_TIGHT	  = 1;	
    /** No packing free dimension */
    public static final int PACK_NONE	  = 2;	

    /** resize the no columns if the layout is smaller than the container */
    public static final int RESIZE_NO_COLUMNS=0;
    /** resize the first columns if the layout is smaller than the container */
    public static final int RESIZE_FIRST_COLUMN=1;
    /** resize the last columns if the layout is smaller than the container */
    public static final int RESIZE_LAST_COLUMN=2;
    
    /* the resize column mode */
    protected int		resizeColumnMode=RESIZE_NO_COLUMNS;
    
    /* true that fit the layout to the container size */
    protected boolean		fitContainerSize = true;		// FIXME:

    protected Hashtable		comptable;
    protected RowColumnConstraints	defaultConstraints;
    
    protected Dimension		gridSize;	// Positional array grid size
    protected int		margin_width;
    protected int		margin_height;
    protected int		spacing;
    protected Dimension		prefSize;	// Preferred size of the form layout
    
    protected int		packing;	// packing style
    protected int		orientation;	// horizontal or vertical
    protected int		num_rowcols;	// number of a rows/columns depending on
						// the orientation of course.
    protected int		num_rows;	// number of rows for the layout
    protected int		num_columns;	// number of columns of layout
    protected int []		column_sizes;	// storage for greatest column sizes
    protected int []		row_sizes;	// storage for greatest column sizes


    /** Constructor 
     * @param orientation - sets layout to either HORIZONTAL or VERTICAL
     * @param num_rowcols - sets the number of columns when orientation is 
     * VERTICAL, sets the number of rows when orientation is HORIZONTAL.
     * @param packing - sets the packing style to PACK_NONE no packing,
     * PACK_TIGHT pack tightly, or PACK_COLUMN pack column or row size
     */
    public RowColumnLayout( int orientation, int num_rowcols, int packing )
    {
	this( orientation, num_rowcols, packing, 5, 5, 1 );	
    }

    /** Constructor 
     * @param orientation - sets layout to either HORIZONTAL or VERTICAL
     * @param num_rowcols - sets the number of columns when orientation is 
     * VERTICAL, sets the number of rows when orientation is HORIZONTAL.
     * @param packing - sets the packing style to PACK_NONE no packing,
     * PACK_TIGHT pack tightly, or PACK_COLUMN pack column or row size
     * @param spacing - sets the space between components
     */
    public RowColumnLayout( int orientation, int num_rowcols, int packing, 
			    int spacing )
    {
	this( orientation, num_rowcols, packing, 5, 5, spacing );	
    }

    /** Constructor 
     * @param orientation - sets layout to either HORIZONTAL or VERTICAL
     * @param num_rowcols - sets the number of columns when orientation is 
     * VERTICAL, sets the number of rows when orientation is HORIZONTAL.
     * @param packing - sets the packing style to PACK_NONE no packing,
     * PACK_TIGHT pack tightly, or PACK_COLUMN pack column or row size
     * @param margin_width - sets the margin width
     * @param margin_height - sets the margin height
     */
    public RowColumnLayout( int orientation, int num_rowcols, int packing,
			    int margin_width, int margin_height )
    {
	this( orientation, num_rowcols, packing, margin_width, margin_height, 1 );
    }
    
    
    /** Constructor 
     * @param orientation - sets layout to either HORIZONTAL or VERTICAL
     * @param num_rowcols - sets the number of columns when orientation is 
     * VERTICAL, sets the number of rows when orientation is HORIZONTAL.
     * @param packing - sets the packing style to PACK_NONE no packing,
     * PACK_TIGHT pack tightly, or PACK_COLUMN pack column or row size
     * @param margin_width - sets the margin width
     * @param margin_height - sets the margin height
     * @param spacing - sets the space between components
     */
    public RowColumnLayout( int orientation, int num_rowcols, int packing,
			    int margin_height, int margin_width, int spacing )
    {
	comptable = new Hashtable();
	defaultConstraints = new RowColumnConstraints();

	this.orientation = orientation;
	this.num_rowcols = num_rowcols;
	this.packing = packing;	
	this.margin_width = margin_width;
	this.margin_height = margin_height;
	this.spacing = spacing;
	gridSize = new Dimension( 100, 100 );
	prefSize = new Dimension( 0,0 );
    }

    /** sets the column resize mode */
    public void setColumnResizeMode( int mode )
    {
	if ( mode != RESIZE_FIRST_COLUMN &&
	     mode != RESIZE_LAST_COLUMN &&
	     mode != RESIZE_NO_COLUMNS )
	    throw new IllegalArgumentException(
		"unknown resize column mode:"+mode );
	resizeColumnMode = mode;
    }
    
    /** gets the column resize mode */
    public int getResizeColumnMode()
    {
	return (resizeColumnMode);
    }
    
    /** converts enumeration to a string 
     * @param aOrientation the orientation value
     */
    public static String orientationToString( int aOrientation )
    {
	switch (aOrientation) {
	  case HORIZONTAL: return "HORIZONTAL";
	  case VERTICAL: return "VERTICAL";
	}

	return "UNKNOWN";
    }
    
    /** converts enumeration to a string 
     * @param aPacking the packing value
     */
    public static String packingToString( int aPacking )
    {
	switch (aPacking) {
	  case PACK_NONE:   return "PACK_NONE";
	  case PACK_TIGHT:  return "PACK_TIGHT";
	  case PACK_COLUMN: return "PACK_COLUMN";
	}

	return "UNKNOWN";
    }
	      
    /**
     * Sets the fit all children inside container size flag
     * if the flag true the force the children to fit inside the containers size. 
     * @param newFit boolean flag
     */
    synchronized public RowColumnLayout setFitContainerSize( boolean  newFit  )
    {
	fitContainerSize = newFit;
	return (this);
    }

    /**
     * returns the boolean flag that fits all children inside container. 
     */
    synchronized public boolean isFitContainerSize()
    {
	return (fitContainerSize);
    }

    /** Sets the layout's grid size */
    synchronized public RowColumnLayout setGridSize( Dimension newSize )
    {
	this.gridSize = newSize;
	return (this);
    }
    
    /** Gets the layout's grid size */
    synchronized public Dimension getGridSize()
    {
	return (gridSize);
    }
    
    /**
     * Sets the constraints for the specified component.
     * @param comp the component to be modified
     * @param constraints the constraints to be applied
     */
    public void setConstraints(Component comp, RowColumnConstraints constraints)
    {
	comptable.put(comp, constraints.clone());
    }

    /**
     * Retrieves the constraints for the specified component. A copy of
     * the constraints is returned.
     * @param comp the component to be queried
     */
    public RowColumnConstraints getConstraints(Component comp) {
	RowColumnConstraints constraints = (RowColumnConstraints)comptable.get(comp);
	if (constraints == null) {
	    setConstraints(comp, defaultConstraints);
	    constraints = (RowColumnConstraints)comptable.get(comp);
	}
	return (RowColumnConstraints)constraints.clone();
    }

    /**
     * Retrieves the constraints for the specified component. The return
     * value is not a copy, but is the actual constraints class used by the
     * layout mechanism.
     * @param comp the component to be queried
     */
    protected RowColumnConstraints lookupConstraints(Component comp) {
	RowColumnConstraints constraints = (RowColumnConstraints)comptable.get(comp);
	if (constraints == null) {
	    setConstraints(comp, defaultConstraints);
	    constraints = (RowColumnConstraints)comptable.get(comp);
	}
	return constraints;
    }

  public void addLayoutComponent(String name,
				 Component comp)
    {	
    }
    
  public void removeLayoutComponent(Component comp)
    {
	// Removes the specified component from the layout. 
	//
	// Parameters: 
        //      comp - the component ot be removed 
	//
	// preferredLayoutSize 
    }
    
  public Dimension preferredLayoutSize(Container parent)
    {
	// Calculates the preferred size dimensions for the specified
	// panel given the components in the specified parent
	// container. 
	// 
	// Parameters: 
	// 	 parent - the component to be laid out 
	// See Also: 
	// 	 minimumLayoutSize 

	Dimension pref = performLayout(parent, false, 1);
	return (pref);
    }
    
  public Dimension minimumLayoutSize(Container parent)
    {
	// Calculates the minimum size dimensions for the specified
	// panel given the components in the specified parent
	// container. 
	// 
	// Parameters: 
	// 	 parent - the component to be laid out 
	// See Also: 
	// 	 preferredLayoutSize 

	Dimension pref = performLayout(parent, false, 2);
	return (pref);
    }
    
  public Dimension maximumLayoutSize(Container target)
    {
	// Returns the maximum size of this component. 
	//
	// See Also: 
	// getMinimumSize, getPreferredSize, LayoutManager 
	
	Dimension pref = performLayout(target, false, 3);
	return (pref);
    }

  public void layoutContainer(Container parent)
    {
	// Lays out the container in the specified panel. 
	// 
	// Parameters: 
	// 	 parent - the component which needs to be laid out

	performLayout(parent, true, 1 /* GetPreferredSize */ );

    }
    


  public  void addLayoutComponent(Component comp,
				  Object constraints)
    {
	// Adds the specified component to the layout, using the
	// specified constraint object.
	//
	// Parameters: 
	// 	 comp - the component to be added 
	// 	 constraints - where/how the component is added to the layout. 
	
	if (constraints instanceof RowColumnConstraints) {
	    setConstraints(comp, (RowColumnConstraints)constraints);
	}
	else if (constraints != null) {
	    throw new IllegalArgumentException("cannot add to layout: constraint must be a RowColumnConstraint");
	}
    }
        
  public  float getLayoutAlignmentX(Container target)
    {
	// Returns the alignment along the x axis. This specifies how
	// the component would like to be aligned relative to other
	// components. The value should be a number between 0 and 1
	// where 0 represents alignment along the
        // origin, 1 is aligned the furthest away from the origin,
	// 0.5 is centered, etc.

	return (0.5f);
    }

  public  float getLayoutAlignmentY(Container target)
    {
	// Returns the alignment along the y axis. This specifies how
	// the component would like to be aligned relative to
	// other components. The value should be a n
	// umber between 0 and 1 where 0 represents alignment along the
	// origin, 1 is aligned the furthest away from
	// the origin, 0.5 is centered, etc. 

	return (0.5f);
      }

    public void invalidateLayout(Container target)
    {
	
	// Invalidates the layout, indicating that if the layout
	// manager has cached inRowColumnation it should be discarded.
    }

    /** performs the layout of the RowColumn */ 
    protected Dimension	performLayout( Container parent,
				       boolean doit, int sizetype )
    {
	int		compindex;	
	Component	kid;
	RowColumnConstraints	constraints;	
	Dimension	parentSize;
	Insets		parentInsets = parent.getInsets();
	Dimension	RowColumnSize;	
	Component	components[] = parent.getComponents();

	if (debug) 
	    System.out.println("performLayout("+parent.getName() + ")" ); // FIXME:
	
	parentSize = parent.getSize();
	if (debug)
	    System.out.println(" parentSize:" + parentSize.width + "," + 
			       parentSize.height );


	// if (parentSize.width == 0) parentSize.width = 400;
	// if (parentSize.height == 0) parentSize.height = 300;
	// parent.setSize( parentSize );



	//
	// Part #1 
	//
	// Reset the visit count of each component and get the preferred
	// size of each visible component.
	//
	for (compindex = 0 ; compindex < components.length ; compindex++)
	{
	    kid = components[compindex];
	    if (!kid.isVisible())
		continue;
	    constraints = lookupConstraints(kid);

	    // Reset the visited count to zero!
	    constraints.visited = 0;
	    
	    if (constraints.insets == null)
		// Prevent the almighty Null pointer object exception!!
		constraints.insets = new Insets( 0, 0, 0, 0 ); 

	    // Get the preferred size
	    Rectangle rect = kid.getBounds();
	    Dimension pref;
	    if (sizetype == 1)
		pref = kid.getPreferredSize();
	    else if (sizetype == 2)
		pref = kid.getMinimumSize();
	    else
		pref = kid.getMaximumSize();

	    if (debug)
		System.out.println("     pref[" + kid.getName()+ "]   sizetype:" + sizetype + "  rec:" + pref.width + "," + pref.height );
	    
	    // Add the inset dimensions
	    pref.width  += constraints.insets.left + constraints.insets.right;
	    pref.height += constraints.insets.top + constraints.insets.bottom;
	    
	    // Store in temporary area
	    constraints.prefWidth = pref.width;
	    constraints.prefHeight = pref.height;
	    constraints.tempX = rect.x;
	    constraints.tempY = rect.y;
	    constraints.tempWidth = pref.width;
	    constraints.tempHeight = pref.height;
	}

	//
	// Part #2
	//
	// Visit each visible component and lay it out
	//
	internalLayoutComponent( parent );

	if (parentSize.width < 2 || parentSize.height < 2 ) {
	    //
	    // Find the greastest dimension of the RowColumn.
	    //


	    Point	  smallestOrigin = new Point( 9999999, 9999999 );

	    parentInsets = parent.getInsets();
	    if (debug)
		System.out.println("**** Finding smallest origin.");
	    
	    for (compindex = 0 ; compindex < components.length ; compindex++)
	    {
		kid = components[compindex];
		constraints = lookupConstraints(kid);

		if (!kid.isVisible())
		    continue;
		if (smallestOrigin.x > constraints.tempX)
		    smallestOrigin.x = constraints.tempX;
		if (smallestOrigin.y > constraints.tempY)
		    smallestOrigin.y = constraints.tempY;
	    }
	    if (debug) {
		System.out.println("smallestOrigin:" + smallestOrigin );
		System.out.println("**** Translating coordinates of kids now.");
	    }
	    
	    for (compindex = 0 ; compindex < components.length ; compindex++)
	    {
		kid = components[compindex];
		constraints = lookupConstraints(kid);

		if (!kid.isVisible())
		    continue;
		constraints.tempX += -smallestOrigin.x + parentInsets.left;
		constraints.tempY += -smallestOrigin.y + parentInsets.top;
		// Reset the kid's preferred dimensions for next attempt
		// at layout.
		constraints.tempWidth = constraints.prefWidth;
		constraints.tempHeight = constraints.prefHeight;
	    }
	    

	    Dimension greatestSize = new Dimension( 0, 0 );
	    if (debug)
		System.out.println("**** Finding greatest size.");
	    
	    for (compindex = 0 ; compindex < components.length ; compindex++)
	    {
		kid = components[compindex];
		constraints = lookupConstraints(kid);

		if (!kid.isVisible())
		    continue;
		if (greatestSize.width < constraints.tempX + constraints.tempWidth )
		    greatestSize.width = constraints.tempX + constraints.tempWidth;
		if (greatestSize.height < constraints.tempY + constraints.tempHeight )
		    greatestSize.height = constraints.tempY + constraints.tempHeight;

		// *FIX ME!!*
		if (debug) {
		    System.out.print( "kid:" + kid.getName() );
		    System.out.print( " ( x:" + constraints.tempX + 
				      " y:" + constraints.tempY );
		    System.out.print( " w:" + constraints.tempWidth + 
				      " h:" + constraints.tempHeight + " )" );
		    System.out.println( "  greatestSize:[" + greatestSize.width +
					"," + greatestSize.height + "]" );
		}
	    }

	    // Take into account the parent RowColumn insets, and margins!
	    // greatestSize.width += parentInsets.left + 2*spacing + 2*margin_width ; // + parentInsets.right;
	    // greatestSize.height += parentInsets.top + 2*spacing + 2*margin_height + parentInsets.bottom;
	    greatestSize.width +=  2*spacing + 2*margin_width + parentInsets.right;
	    if (orientation == HORIZONTAL)
		greatestSize.width += parentInsets.left;
	    greatestSize.height += 2*spacing + 2*margin_height + parentInsets.bottom;
	    // Set the parent's size.
	    parent.setSize( greatestSize );
	    parentSize = greatestSize;
	    
	    if (debug)
		System.out.println( "***** greatest width:" + parentSize.width + ", height:" + parentSize.height );
	    
	    internalLayoutComponent( parent);

	}
	
	if (doit == true) {
	    //
	    // Part #3
	    //
	    // Set each visible component to it's layed-out size.
	    for (compindex = 0 ; compindex < components.length ; compindex++)
	    {
		kid = components[compindex];
		if (!kid.isVisible())
		    continue;
		constraints = lookupConstraints(kid);
		kid.setBounds( constraints.tempX, constraints.tempY,
			       constraints.tempWidth, constraints.tempHeight );

		kid.validate();
		
		if (debug) {		    
		    System.out.print( "kid:" + kid.getName() );
		    System.out.print( " ( x:" + constraints.tempX + 
				      " y:" + constraints.tempY );
		    System.out.println( " w:" + constraints.tempWidth + 
					" h:" + constraints.tempHeight + " )" );
		}
	    }	    
	}
	
	if (debug) System.out.println("\n" );

	// return proper preferred geometry.
	return (parentSize);
    }

    /** Calculate the array index for a component at a particular row 
     * column
     */
    protected int  indexOf( int row, int column )
    {
	return ( row * num_columns + column  );	
    }
    
    /** Internal method lays out a container's components in 
     * to rows and columns 
     */
    protected void internalLayoutComponent( Container parent )
    {
	int			compindex;	
	Dimension		RowColumnSize;
	Component		kid;
	Component		components[] = parent.getComponents();
	int			row,col;
	int			biggest_width;	// greatest component width
	int			biggest_height;	// greatest component height
	int			total;		// total width/height
	RowColumnConstraints	constraints;	// any kid's constraints

	// Get the container parent's dimensions and it's insets
	Dimension		parentSize = parent.getSize();
	Insets			parentInsets = parent.getInsets();
	
	int			forcedWidth, forcedHeight;

	//
	// Calculate the boundaries of the frame where to place
	// components.
	//
	int lowerX = margin_width + spacing + parentInsets.left;
	int upperX = parentSize.width - margin_width - spacing - parentInsets.right;
	int lowerY = margin_height + spacing + parentInsets.top;
	int upperY = parentSize.height - margin_height - spacing - parentInsets.bottom;

	// Calculate the parent
	Dimension areaSize = new Dimension( upperX - lowerX, upperY - lowerY );	

	
	boolean allowFitContainerSize = fitContainerSize;
	if (parentSize.width <= 2 || parentSize.height <= 2 )
	    // Forbid containment when container itself is indeterminant!!
	    allowFitContainerSize = false;

	if ( num_rowcols < 0 )
	    throw new ImpossibleLayoutException( "num_rowcols must be greater than zero." );
	if ( components.length == 0 )
	    throw new ImpossibleLayoutException( "no components to layout." );
	    
	switch (orientation) {
	  case HORIZONTAL: 
	  {
	      // HORIZONTAL LAYOUT: The row (height) size is fixed to
	      // the component of the greatest height in a row, the
	      // column (width) size can vary or be fixed to largest
	      // component's width in the entire matrix.

	      int child_counter=0;
	      
	      // Get the row size to find the number of columns
	      num_rows = num_rowcols;
	      num_columns = components.length / num_rows;

	      // Calculate the forced sizes
	      forcedWidth = (upperX - lowerX) / num_columns;
	      forcedHeight = (upperY - lowerY) / num_rows;

	      if (debug)
		  System.out.println( "  num_rows=" +num_rows+"  num_columns=" +num_columns+ "  num_rowcols=" + num_rowcols );

	      if ( column_sizes == null) 
		  column_sizes = new int[num_columns+1];
	      if ( row_sizes == null) 
		  row_sizes = new int[num_rows+1];

	      //
	      // Find the biggest height for each row of components
	      //
	      biggest_width = 0;
	      
	    horizontalLayout1:
	      for (child_counter=0,row=0; row<num_rows ; ++row )
	      {
		  row_sizes[row] = 0;
		  total = 0;

		  int saved_child_counter = child_counter; // KEEP A COPY
		  
		  for (col=0; col<num_columns; ++col, ++child_counter ) 
		  {
		      if (child_counter >= components.length )
			  break horizontalLayout1;

		      compindex = indexOf( row, col );
		      kid = components[compindex];
		      if (!kid.isVisible())
			  continue;
		      constraints = lookupConstraints(kid);
		      if ( row_sizes[row] < constraints.prefHeight )
			  row_sizes[row] = constraints.prefHeight;
		      if ( biggest_width < constraints.prefWidth )
			  biggest_width = constraints.prefWidth;
		      total = total + constraints.prefWidth;
		  }
		  if (debug) {
		      System.out.println( "    row_sizes["+ row +"] = " + row_sizes[row] );
		      System.out.println( "    biggest_width = " + biggest_width );
		  }

		  if ( allowFitContainerSize ) {
		      //
		      // Fit the children in the container. 
		      //
		      // We are packing horizontally so we want
		      // squeeze if the total `ideal' size of the
		      // column is bigger than the parent container's
		      // width.
		      //
		      // Cases
		      // i) PACK_COLUMN easy just resize the components
		      // in to regular boxes.
		      //
		      // ii) PACK_TIGHT only when the acculumated total
		      // width exceeds the limits should we pack regular
		      // box of each row in the grid.
		      //
		      if (packing == PACK_COLUMN  && 
		          (( biggest_width * num_columns ) != ( upperX- lowerX ))) 
		      {
			  if (debug) 
			      System.out.println( "PACK_COLUMN:" +
						  ( biggest_width * num_columns )+
						  " , "+( upperX - lowerX ) );
			  biggest_width = (upperX - lowerX) / num_columns;
			  int counter = saved_child_counter;	/*!!!*/
			  for (col=0; col<num_columns; ++col, ++counter ) 
			  {
			      if (counter >= components.length ) {
				  // Make sure we keep within child array bounds
				  counter = num_columns;
				  continue;
			      }
			      
			      compindex = indexOf( row, col );
			      kid = components[compindex];
			      if (!kid.isVisible())
				  continue;
			      constraints = lookupConstraints(kid);
			      constraints.prefWidth = biggest_width;
			      constraints.tempWidth = biggest_width;
			  }
		      }
		      else if (packing == PACK_TIGHT && 
			       total > (upperX - lowerX) ) 
		      {
			  if (debug)
			      System.out.println( "PACK_TIGHT:" +
						  ( biggest_width * num_columns ) + " , " +
						  ( upperX - lowerX ) );
			  int ruggedWidth = (upperX - lowerX) / num_columns;
			  
			horizontalLayout33:
			  
			  int counter = saved_child_counter;	/*!!!*/
			  for (col=0; col<num_columns; ++col, ++counter ) 
			  {
			      if (counter >= components.length ) {
				  // Make sure we keep within child array bounds
				  counter = num_columns;
				  continue;
			      }
			      

			      compindex = indexOf( row, col );
			      kid = components[compindex];
			      if (!kid.isVisible())
				  continue;
			      constraints = lookupConstraints(kid);
			      constraints.prefWidth = ruggedWidth;
			      constraints.tempWidth = ruggedWidth;
			  }
		      }
		  }
	      }

	      //
	      // Resize the row size if the container is bigger than
	      // the over layout.
	      //
	      int temp=0;
	      for ( row=0; row<num_rows; ++row )
		  temp += spacing + row_sizes[row];
	      if ( temp < (upperY - lowerY) ) {
		  switch ( resizeColumnMode ) {
		    case RESIZE_FIRST_COLUMN:
			// Resize the first row 
			temp=0;
			for ( row=1; row<num_rows; ++row )
			    temp += spacing + row_sizes[row];
			row_sizes[0] = (upperY - lowerY) - temp;
			break;
			
		    case RESIZE_LAST_COLUMN:
			// Resize the last row 
			temp=0;
			for ( row=0; row<num_rows-1; ++row )
			    temp += spacing + row_sizes[row];
			row_sizes[num_rows-1] = (upperY - lowerY) - temp;
			break;
		  }
	      }
	      
	      //
	      // Layout components for HORIZONTAL orientation.
	      //
	      int xpos, ypos;
	      
	      ypos = lowerY;

	    horizontalLayout2:
		  
	      for (child_counter=0,row=0; row<num_rows ; ++row )
	      {
		  xpos = lowerX;
		  for (col=0; col<num_columns; ++col, ++child_counter ) 
		  {
		      if (child_counter >= components.length )
			  break horizontalLayout2;

		      compindex = indexOf( row, col );
		      kid = components[compindex];
		      if (!kid.isVisible())
			  continue;
		      constraints = lookupConstraints(kid);
		      constraints.tempX = xpos;
		      constraints.tempY = ypos;
		      constraints.tempHeight = row_sizes[row];

		      if (packing == PACK_COLUMN)
			  // PACK_COLUMN/PACK_ROW
			  constraints.tempWidth = biggest_width;
		      else if (packing == PACK_NONE || packing == PACK_TIGHT )
			  // PACK_NONE 
			  constraints.tempWidth = constraints.prefWidth;
		      if (packing == PACK_TIGHT)
			  // PACK_TIGHT
			  xpos += spacing + constraints.prefWidth;
		      else
			  xpos += spacing + biggest_width;


		      if (debug) {
			  System.out.print( "\t(" + kid.getName() + ", v:" + 
					    constraints.visited + ")  ");
			  System.out.println( "constraints = " + 
					      constraints.tempX + "," + constraints.tempY + "," + 
					      constraints.tempWidth + "," + constraints.tempHeight);
		      }

		  }
		  ypos += spacing + row_sizes[row];
	      }
	  }
	  break;
	  
	  case VERTICAL:
	  {
	      // VERTICAL LAYOUT: The column (width) size is fixed to
	      // the component of the greatest width in a column, the
	      // row (height) size can vary or be fixed to largest
	      // component's height in the entire matrix.


	      int child_counter=0;
	      
	      // Get the column size to find the number of rows
	      num_columns = num_rowcols;
	      num_rows = components.length / num_columns;

	      // Calculate the forced sizes
	      forcedWidth = (upperX - lowerX) / num_columns;
	      forcedHeight = (upperY - lowerY) / num_rows;

	      if (debug)
		  System.out.println( "  num_rows=" +num_rows+"  num_columns=" +num_columns+
				      "  num_rowcols=" + num_rowcols );

	      if ( column_sizes == null) 
		  column_sizes = new int[num_columns+1];
	      if ( row_sizes == null) 
		  row_sizes = new int[num_rows+1];

	      
	      //
	      // Find the biggest height for each column of components
	      //
	      biggest_height = 0;

	    verticalLayout1:
	      for (child_counter=0,col=0; col<num_columns ; ++col )
	      {
		  column_sizes[col] = 0;
		  total = 0;

		  int saved_child_counter = child_counter; // KEEP A COPY
		  
		  for (row=0; row<num_rows; ++row, ++child_counter ) 
		  {
		      if (child_counter >= components.length )
			  break verticalLayout1;

		      compindex = indexOf( row, col );
		      kid = components[compindex];
		      if (!kid.isVisible())
			  continue;
		      constraints = lookupConstraints(kid);
		      if ( column_sizes[col] < constraints.prefWidth )
			  column_sizes[col] = constraints.prefWidth;
		      if ( biggest_height < constraints.prefHeight )
			  biggest_height = constraints.prefHeight;
		      total = total + constraints.prefHeight;
		  }
		  if (debug) {
		      System.out.println( "    column_sizes["+ col +"] = " + column_sizes[col] );
		      System.out.println( "    biggest_height = " + biggest_height );
		  }


		  if ( allowFitContainerSize ) {
		      //
		      // Fit the children in the container. 
		      //
		      // We are packing vertically so we want
		      // squeeze if the total `ideal' size of the
		      // height is bigger than the parent container's
		      // height.
		      //
		      // Cases
		      // i) PACK_COLUMN easy just resize the components
		      // in to regular boxes.
		      //
		      // ii) PACK_TIGHT only when the acculumated total
		      // height exceeds the limits should we pack regular
		      // box of each column in the grid.
		      //
		      if (packing == PACK_COLUMN )
		      {
			  if  (( biggest_height * num_rows ) != ( upperY - lowerY )) {
			      if (debug) 
				  System.out.println( "PACK_COLUMN:"+
						      ( biggest_height * num_rows )+ 
						      " , "+( upperY - lowerY ) );
			      biggest_height = (upperY - lowerY) / num_rows;
			      int counter = saved_child_counter;	/*!!!*/
			      for (row=0; row<num_rows; ++row, ++counter ) 
			      {
				  if (counter >= components.length ) 
				      // Make sure we keep within child array bounds
				      break;
				  
				  compindex = indexOf( row, col );
				  kid = components[compindex];
				  if (!kid.isVisible())
				      continue;
				  constraints = lookupConstraints(kid);
				  constraints.prefHeight = biggest_height;
				  constraints.tempHeight = biggest_height;
			      }
			  }
		      }
		      else if (packing == PACK_TIGHT && 
			       total > (upperY - lowerY) ) {
			  if (debug) 
			      System.out.println( "PACK_TIGHT:" +
						  ( biggest_height * num_rows ) + " , " +
						  ( upperY - lowerY ) );
			  int ruggedHeight = (upperY - lowerY) / num_rows;

			  int counter = saved_child_counter;	/*!!!*/
			  for (row=0; row<num_rows; ++row, ++counter ) 
			  {
			      if (counter >= components.length ) 
				  // Make sure we keep within child array bounds
				  break;
				  
			      compindex = indexOf( row, col );
			      kid = components[compindex];
			      if (!kid.isVisible())
				  continue;
			      constraints = lookupConstraints(kid);
			      constraints.prefHeight = ruggedHeight;
			      constraints.tempHeight = ruggedHeight;
			  }
		      }
		  }
	      }
	      
	      //
	      // Resize the column size if the container is bigger than
	      // the over layout.
	      //
	      int temp=0;
	      for ( col=0; col<num_columns; ++col )
		  temp += spacing + column_sizes[col];
	      if ( temp < (upperX - lowerX) ) {
		  switch ( resizeColumnMode ) {
		    case RESIZE_FIRST_COLUMN:
			// Resize the first col 
			temp=0;
			for ( col=1; col<num_columns; ++col )
			    temp += spacing + column_sizes[col];
			column_sizes[0] = (upperX - lowerX) - temp;
			break;
			
		    case RESIZE_LAST_COLUMN:
			// Resize the last col 
			temp=0;
			for ( col=0; col<num_columns-1; ++col )
			    temp += spacing + column_sizes[col];
			column_sizes[num_columns-1] = (upperX - lowerX) - temp;
			break;
		  }
	      }
	      

	      //
	      // Layout components for VERTICAL orientation.
	      //
	      int xpos, ypos;
	      
	      xpos = lowerX;

	    verticalLayout2:
	      for (child_counter=0,col=0; col<num_columns ; ++col )
	      {
		  ypos = lowerY;
		  for (row=0; row<num_rows; ++row, ++child_counter ) 
		  {
		      if (child_counter >= components.length )
			  break verticalLayout2;

		      compindex = indexOf( row, col );
		      kid = components[compindex];
		      if (!kid.isVisible())
			  continue;
		      constraints = lookupConstraints(kid);
		      constraints.tempX = xpos;
		      constraints.tempY = ypos;
		      constraints.tempWidth = column_sizes[col];

		      if (packing == PACK_COLUMN)
			  // PACK_COLUMN/PACK_ROW
			  constraints.tempHeight = biggest_height;
		      else if (packing == PACK_NONE || packing == PACK_TIGHT )
			  // PACK_NONE 
			  constraints.tempHeight = constraints.prefHeight;
		      if (packing == PACK_TIGHT)
			  // PACK_TIGHT
			  ypos += spacing + constraints.prefHeight;
		      else
			  ypos += spacing + biggest_height;

		      if (debug) {
			  System.out.print( "\t(" + kid.getName() + ", v:" + 
					    constraints.visited + ")  ");
			  System.out.println( "constraints = " + 
					      constraints.tempX + "," + constraints.tempY + "," + 
					      constraints.tempWidth + "," + constraints.tempHeight);
		      }

		  }
		  xpos += spacing + column_sizes[col];
	      }
	  }
	  break;

	  default:
	      throw new ImpossibleLayoutException( "orientation must be horizontal or vertical" );
	}

    }
}

// fini
