package slides;

import java.awt.*;
import java.util.*;

/**
 * A LayoutManager that can be used for slide
 * presentations and outlines
 *
 * @author  Prof. David Bernstein, James Madison University
 * @version 1.0
 */
public class SlideLayout implements LayoutManager
{
    private Font[]        fonts;
    private Hashtable     constraints;
    private int           numLevels;
    private int[]         indents, vSpaces;

    private static final int indentWidthInPixels = 40;
    private static final int lineHeightInPixels  = 50;


    public static final String CENTER = "CENTER";
    public static final String LEVEL0 = "LEVEL0";
    public static final String LEVEL1 = "LEVEL1";
    public static final String LEVEL2 = "LEVEL2";


    /**
     * Default constructor
     */
    public SlideLayout()
    {
	int             i, iSize, fSize;

	constraints = new Hashtable();

	numLevels = 5;

	indents = new int[numLevels];
	vSpaces = new int[numLevels];
	fonts   = new Font[numLevels];
	

	fSize = 24;
	iSize = 0;
	for (i=0; i < numLevels; i++) 
        {
	    indents[i] = iSize;
	    fonts[i]   = new Font("Sans Serif", Font.PLAIN, fSize);
	    vSpaces[i] = lineHeightInPixels / 5;
	    fSize -= 3;
	    iSize += indentWidthInPixels;
	}
	vSpaces[0] = lineHeightInPixels;
    }




    /**
     * Adds the specified component with the specified "constraint"
     * to the layout (Required by LayoutManager)
     *
     * @param constraint The constraint (e.g., "LEVEL0" or "CENTER")
     * @param comp       The component
     */
    public void addLayoutComponent(String constraint, Component comp)
    {
	synchronized (comp.getTreeLock()) 
        {
	    constraints.put(comp, constraint);
	}
    }






    /**
     * Lays out the container in the specified panel
     * (Required by LayoutManager)
     *
     * @param The Container to layout
     */
    public void layoutContainer(Container parent)
    {
	Component[]       e;
	Component         comp;
	Dimension         dComp, dParent;
	int               i, level, x, y;
	String            constraint;


	synchronized (parent.getTreeLock()) 
        {
	    dParent = parent.getSize();
	    y = 0;

	    e = parent.getComponents();
	    for (i=0; i < e.length; i++) 
            {
		comp   = e[i];
		constraint = (String)constraints.get(comp);

		if (constraint.equals(CENTER)) 
                {
		    y += vSpaces[2];
		    dComp = comp.getSize();
		    x = dParent.width/2 - dComp.width/2;
		} 
                else 
                {
		    if      (constraint.equals(LEVEL0)) level = 0;
		    else if (constraint.equals(LEVEL1)) level = 1;
		    else if (constraint.equals(LEVEL2)) level = 2;
		    else                                level = 2;
		    
		
		    x = indents[level];
		    y += vSpaces[level];
		    comp.setFont(fonts[level]);
		}

		locateComponent(comp, x, y);
		
		// Update the vertical position
		dComp = comp.getSize();
		y     += dComp.height;
		
	    }
	}
    }


    /**
     * Set the location of a component
     *
     * @param comp   The component
     * @param x      The horizontal location
     * @param y      The vertical location
     */
    protected void locateComponent(Component comp, int x, int y)
    {
	Dimension         dComp;

	
	// Set the width of the Component
	dComp = comp.getPreferredSize();
	comp.setSize(dComp);
	
	// Invalidate any cached information used to layout 
	// the Component
	comp.invalidate();
	
	
	// Set the location of the Component
	comp.setLocation(x, y);
	
	// Validate the component (i.e., layout the component)
	comp.validate();
    }




    /**
     * Calculates the minimum size dimensions for the specified 
     * panel given the components in the specified parent container
     * (Required by LayoutManager)
     *
     * @param parent  The Container
     * @return        The minimum size
     */
    public Dimension minimumLayoutSize(Container parent)
    {
	return preferredLayoutSize(parent);
    }




    /**
     * Calculates the preferred size dimensions for the specified 
     * panel given the components in the specified parent container
     * (Required by LayoutManager)
     *
     * @param parent  The Container
     * @return        The preferred size
     */
    public Dimension preferredLayoutSize(Container parent)
    {
	Component[]      components;
	Dimension        d, parentD;


	synchronized (parent.getTreeLock()) 
        {
	    // Note: Should worry about insets
	    d = new Dimension(0,0);
	    
	    components = parent.getComponents();
	    if ((components != null) && (components.length != 0)) 
            {
		parentD  = parent.getSize();
		d.width  = parentD.width;
		d.height = components.length * lineHeightInPixels;
		if (d.height < parentD.height) d.height = parentD.height;
	    }
	    
	    return d;
	}
    }




    /**
     * Removes the specified component from the layout
     * (Required by LayoutManager)
     *
     * @param comp    The Component to remove
     */
    public void removeLayoutComponent(Component comp)
    {
	constraints.remove(comp);
    }



}
