import java.awt.* ;
import java.util.* ;

/**
Author Jean-Claude Dufourd
Version 2
Date 17.11.95
Title RelativeLayout 

This is for placing components relatively to each other or to the parent
panel with an offset. The offset direction depends intuitively on the
relative position required. 

Relative positions are :
- RelativeLayout.above
- RelativeLayout.under
- RelativeLayout.left
- RelativeLayout.right
- RelativeLayout.aboveRight
- RelativeLayout.underRight
- RelativeLayout.leftBottom
- RelativeLayout.rightBottom
- RelativeLayout.upperLeftCorner
- RelativeLayout.upperRightCorner
- RelativeLayout.lowerRightCorner
- RelativeLayout.lowerLeftCorner
- RelativeLayout.insideUpperLeft
- RelativeLayout.insideUpperRight
- RelativeLayout.insideLowerRight
- RelativeLayout.insideLowerLeft
- RelativeLayout.aboveLeft
- RelativeLayout.underLeft
- RelativeLayout.leftTop
- RelativeLayout.rightTop
- RelativeLayout.insideTop
- RelativeLayout.insideBottom
- RelativeLayout.insideRight
- RelativeLayout.insideLeft
all of which are named after what they implement. Above is centered above the
reference, aboveLeft is same left-aligned...

*/

class RelativeConstraint {
    Component reference;
    int position, dx, dy;
    
    RelativeConstraint( Component ref, char where, int x, int y ) {
	reference = ref;
	position = where;
	dx = x;
	dy = y;
    }

}

public class RelativeLayout implements LayoutManager {

    public final static char above = 'A';
    public final static char under = 'B';
    public final static char left = 'C';
    public final static char right = 'D';
    public final static char aboveRight = 'E';
    public final static char underRight = 'F';
    public final static char leftBottom = 'G';
    public final static char rightBottom = 'H';
    public final static char upperLeftCorner = 'I';
    public final static char upperRightCorner = 'J';
    public final static char lowerRightCorner = 'K';
    public final static char lowerLeftCorner = 'L';
    public final static char insideUpperLeft = 'M';
    public final static char insideUpperRight = 'N';
    public final static char insideLowerRight = 'O';
    public final static char insideLowerLeft = 'P';
    public final static char aboveLeft = 'Q';
    public final static char underLeft = 'R';
    public final static char leftTop = 'S';
    public final static char rightTop = 'T';
    public final static char insideTop = 'U';
    public final static char insideBottom = 'V';
    public final static char insideRight = 'W';
    public final static char insideLeft = 'X';

    Dimension d;
    Vector components = new Vector(10,10);
    Vector constraints = new Vector(10,10);

    /* RelativeLayout has a fixed size */
    public RelativeLayout(Dimension dim) {
	d = dim;
    }

    public void addLayoutComponent(String name, Component comp) {
	components.addElement( comp );
	constraints.addElement( null );
    }

    public void removeLayoutComponent(Component comp) {
	int i = components.indexOf( comp );
	if (i != -1) {
	    components.removeElementAt( i );
	    constraints.removeElementAt( i );
	}
    }

    public Dimension minimumLayoutSize(Container target) {
	return d;
    }
    
    public Dimension preferredLayoutSize(Container target) {
	return d;
    }

    public void setConstraint( Component self, Component ref, char where, int dx, int dy ) {
	int i = components.indexOf( self );
	// ignore unknown components
	if (i != -1) {
	    RelativeConstraint c = new RelativeConstraint( ref, where, dx, dy );
	    constraints.setElementAt( c, i );
	}
    }

    public void layoutContainer(Container target) {
	Enumeration e = components.elements();
	Rectangle oneBounds, referenceBounds;
	RelativeConstraint constr;
	Dimension d;
	Component c;
	int i = -1;
	while (e.hasMoreElements()) {
	    i = i + 1;
	    constr = (RelativeConstraint)constraints.elementAt( i );
	    c = (Component)e.nextElement();
	    d = c.preferredSize();
	    oneBounds = c.bounds();
	    if (constr.reference == null) referenceBounds = target.bounds();
	    else referenceBounds = constr.reference.bounds();
	    switch (constr.position) {
	      case RelativeLayout.above:
		c.reshape( referenceBounds.x + referenceBounds.width/2 - oneBounds.width/2 + constr.dx, 
			  referenceBounds.y - constr.dy - oneBounds.height,
			  d.width, d.height ); 
		break;
	      case RelativeLayout.under:
		c.reshape( referenceBounds.x + referenceBounds.width/2 - oneBounds.width/2 + constr.dx, 
			  referenceBounds.y + constr.dy + referenceBounds.height,
			  d.width, d.height ); 
		break;
	      case RelativeLayout.left:
		c.reshape( referenceBounds.x - constr.dx - oneBounds.width, 
			  referenceBounds.y + referenceBounds.height/2 - oneBounds.height/2 + constr.dy,
			  d.width, d.height ); 
		break;
	      case RelativeLayout.right:
		c.reshape( referenceBounds.x + constr.dx + referenceBounds.width, 
			  referenceBounds.y + referenceBounds.height/2 - oneBounds.height/2 + constr.dy,
			  d.width, d.height ); 
		break;
	      case RelativeLayout.aboveRight:
		c.reshape( referenceBounds.x + referenceBounds.width - oneBounds.width - constr.dx, 
			  referenceBounds.y - constr.dy - oneBounds.height,
			  d.width, d.height );
		break;
	      case RelativeLayout.underRight:
		c.reshape( referenceBounds.x + referenceBounds.width - oneBounds.width - constr.dx, 
			  referenceBounds.y + constr.dy + referenceBounds.height,
			  d.width, d.height );
		break;
	      case RelativeLayout.leftBottom:
		c.reshape( referenceBounds.x - constr.dx - oneBounds.width, 
			  referenceBounds.y + referenceBounds.height - oneBounds.height - constr.dy,
			  d.width, d.height ); 
		break;
	      case RelativeLayout.rightBottom:
		c.reshape( referenceBounds.x + constr.dx + referenceBounds.width, 
			  referenceBounds.y + referenceBounds.height - oneBounds.height - constr.dy,
			  d.width, d.height ); 
		break;
	      case RelativeLayout.upperLeftCorner:
		c.reshape( referenceBounds.x - constr.dx - oneBounds.width, 
			  referenceBounds.y - constr.dy - oneBounds.height,
			  d.width, d.height );
		break;
	      case RelativeLayout.upperRightCorner:
		c.reshape( referenceBounds.x + referenceBounds.width + constr.dx, 
			  referenceBounds.y - constr.dy - oneBounds.height,
			  d.width, d.height );
		break;
	      case RelativeLayout.lowerRightCorner:
		c.reshape( referenceBounds.x + referenceBounds.width + constr.dx, 
			  referenceBounds.y + constr.dy + referenceBounds.height,
			  d.width, d.height );
		break;
	      case RelativeLayout.lowerLeftCorner:
		c.reshape( referenceBounds.x - oneBounds.width - constr.dx, 
			  referenceBounds.y + constr.dy + referenceBounds.height,
			  d.width, d.height );
		break;
	      case RelativeLayout.insideUpperLeft:
		c.reshape( referenceBounds.x + constr.dx,
			  referenceBounds.y + constr.dy,
			  d.width, d.height ); 
		break;
	      case RelativeLayout.insideUpperRight:
		c.reshape( referenceBounds.x + referenceBounds.width - oneBounds.width - constr.dx,
			  referenceBounds.y + constr.dy,
			  d.width, d.height );
		break;
	      case RelativeLayout.insideLowerRight:
		c.reshape( referenceBounds.x + referenceBounds.width - oneBounds.width - constr.dx,
			  referenceBounds.y + referenceBounds.height - oneBounds.height - constr.dy,
			  d.width, d.height ); 
		break;
	      case RelativeLayout.insideLowerLeft:
		c.reshape( referenceBounds.x + constr.dx,
			  referenceBounds.y + referenceBounds.height - oneBounds.height - constr.dy,
			  d.width, d.height ); 
		break;
	      case RelativeLayout.aboveLeft:
		c.reshape( referenceBounds.x + constr.dx, 
			  referenceBounds.y - constr.dy - oneBounds.height,
			  d.width, d.height ); 
		break;
	      case RelativeLayout.underLeft:
		c.reshape( referenceBounds.x + constr.dx,
			  referenceBounds.y + constr.dy + referenceBounds.height,
			  d.width, d.height ); 
		break;
	      case RelativeLayout.leftTop:
		c.reshape( referenceBounds.x - constr.dx - oneBounds.width,
			  referenceBounds.y + constr.dy,
			  d.width, d.height ); 
		break;
	      case RelativeLayout.rightTop:
		c.reshape( referenceBounds.x + constr.dx + referenceBounds.width,
			  referenceBounds.y + constr.dy,
			  d.width, d.height ); 
		break;
	      case RelativeLayout.insideTop:
		c.reshape( referenceBounds.x + referenceBounds.width/2 - oneBounds.width/2 + constr.dx, 
			  referenceBounds.y + constr.dy,
			  d.width, d.height ); 
		break;
	      case RelativeLayout.insideBottom:
		c.reshape( referenceBounds.x + referenceBounds.width/2 - oneBounds.width/2 + constr.dx, 
			  referenceBounds.y - constr.dy + referenceBounds.height - oneBounds.height,
			  d.width, d.height ); 
		break;
	      case RelativeLayout.insideLeft:
		c.reshape( referenceBounds.x + constr.dx, 
			  referenceBounds.y + referenceBounds.height/2 - oneBounds.height/2 + constr.dy,
			  d.width, d.height ); 
		break;
	      case RelativeLayout.insideRight:
		c.reshape( referenceBounds.x - constr.dx + referenceBounds.width - oneBounds.width, 
			  referenceBounds.y + referenceBounds.height/2 - oneBounds.height/2 + constr.dy,
			  d.width, d.height ); 
		break;
	      default:
		c.reshape( 0, 0, d.width, d.height );
		break;
	    }
	}
    }
}


