package com.mindprod.layout;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.LayoutManager2;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * Arrange Components in a star shaped pattern, using a radial co-ordinate
 * system, with angle and distance from the center of the Container.
 * Requires the use of StarConstraints on each object added.
 *
 * @author Roedy Green
 * @version 1.0
 * @since 2003-06-01
 */
public class StarLayout implements LayoutManager2
   {
   /**
    * Constructor
    *
    * @param width  width of box you want generated start to live in.
    * @param height height of box you want generated start to live in.
    */
   public StarLayout ( int width, int height )
      {
      this.starWidth = width;
      this.starHeight = height;
      h = new HashMap();
      }

   /**
    * Width of the Container in pixels. This is fixed.
    */
   private int starWidth;
   /**
    * Height of the Container in pixels. This is fixed.
    */
   private int starHeight;

   /**
    * HashMap to associate components with their constraints,
    * array [ angle, radius, tweak x, tweak y ]
    * converted internally to radians and doubles.
    */
   private HashMap h;
   /**
   * If the layout manager uses a per-component string,
   * adds the component <code>comp</code> to the layout,
   * associating it
   * with the string specified by <code>name</code>.
   *
   * @param name the string to be associated with the component
   * @param comp the component to be added
   */
   public void addLayoutComponent(String name, Component comp)
      {
      return;
      }
   /**
    * Removes the specified component from the layout.
    * @param comp the component to be removed
    */
   public void removeLayoutComponent(Component comp)
      {
      h.remove ( comp );
      }
   /**
    * Calculates the preferred size dimensions for the specified
    * container, given the components it contains.
    * @param parent the container to be laid out
    *
    * @see #minimumLayoutSize
    */
   public Dimension preferredLayoutSize(Container parent)
      {
      return new Dimension ( starWidth, starHeight );
      }
   /**
    * Calculates the minimum size dimensions for the specified
    * container, given the components it contains.
    * @param parent the component to be laid out
    * @see #preferredLayoutSize
    */
   public Dimension minimumLayoutSize(Container parent)
      {
      return new Dimension ( starWidth, starHeight );
      }
   /**
    * Lays out the specified container.
    * @param parent the container to be laid out
    */
   public void layoutContainer(Container parent)
      {
      int pwidth =   parent.getWidth();
      int pheight =  parent.getHeight();
      int cx = pwidth / 2;
      int cy = pheight / 2;
      // Iterate over all components in this container.
      for ( Iterator iter = h.entrySet().iterator(); iter.hasNext(); )
         {
         Map.Entry pair = ( Map.Entry ) iter.next();
         Component comp = ( Component ) pair.getKey();
         StarConstraint constr = ( StarConstraint ) pair.getValue();

         Dimension compSize = comp.getPreferredSize();
         double width = compSize.width;
         double height = compSize.height;
         // centre object at requested angle/radius, then apply tweaks.
         int x = (int) (cx + Math.cos( constr.angleInRadians ) * constr.radius - width/2 + constr.tweakx);
         int y = (int) (cy + Math.sin( constr.angleInRadians ) * constr.radius - height/2 + constr.tweaky);
         comp.setLocation( x, y );
         comp.setSize( compSize );
         }
      }

   /**
    * 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.
    *
    * @param target Container containing this Star.
    * @return .5 to center.
    */
   public float getLayoutAlignmentX(Container target)
      {
      return .5F;
      }

   /**
    * 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 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.
    *
    * @param target Container containing this Star.
    * @return .5 to center.
    */
   public float getLayoutAlignmentY(Container target)
      {
      return .5F;
      }
   /**
    * Adds the specified component to the layout, using the specified
    * constraint object which must be a StarConstraint.
    *
    * @param comp   the component to be added
    * @param constraints
    *               where/how the component is added to the layout.
    *               Must be a StarConstraint object.
    */
   public void addLayoutComponent(Component comp, Object constraints)
      {
      if ( constraints == null || !(constraints instanceof StarConstraint) )
         {
         throw new IllegalArgumentException ("constraints must be a StarConstraint object");
         }
      h.put( comp, constraints );
      }
   /**
    * Calculates the maximum size dimensions for the specified container,
    * given the components it contains.
    *
    * @param target Container where this Component will be placed.
    * @return Dimensions of the Component
    * @see java.awt.Component#getMaximumSize
    * @see LayoutManager
    */
   public Dimension maximumLayoutSize( Container target )
      {
      return new Dimension ( starWidth, starHeight );
      }
   /**
    * Invalidates the layout, indicating that if the layout manager
    * has cached information it should be discarded.
    *
    * @param target Container containing this Star.
    */
   public void invalidateLayout(Container target)
      {
      return;
      }
   }