//[skeleton1.
package visual.statik;

import java.awt.*;
import java.awt.geom.*;
import java.util.*;

/**
 * A generic piece of static visual content that is a composition
 * of many component parts
 *
 * Note: The bounds are not stored in attributes to make this
 * class easier to understand.  To do so would require:
 * (1) Use of the isTransformationRequired() method in the parent;
 * and (2) Changes to the add() and remove() methods in 
 * this class.
 *
 * @author  Prof. David Bernstein, James Madison University
 * @version 1.0
 */
public abstract class 
                AbstractAggregateContent<C extends TransformableContent>
       extends  AbstractTransformableContent
{
    // A LinkedList is used to order the components.
    // Since we don't expect many components to be removed
    // this doesn't raise efficiency concerns.
    //
    // Alternatively, we could have a z-order.
    protected LinkedList<C>        components;
    


    /**
     * Default Constructor
     */
    public AbstractAggregateContent()
    {
       super();       
       components = new LinkedList<C>();
    }
//]skeleton1.
    

//[content1.

    /**
     * Add a TransformableContent
     *
     * @param component   The TransformableContent to add
     */
    public void add(C component)
    {
       components.add(component);
    }
//]content1.

//[bounds

    /**
     * Returns a high precision bounding box of the Content
     * either before or after it is transformed
     *
     * @param    ofTransformed    true to get the BB of the transformed content
     * @return   The bounding box
     */
    public Rectangle2D getBounds2D(boolean ofTransformed)
    {
       double                maxX, maxY, minX, minY, rx, ry;
       Iterator<C>           i;
       Rectangle2D           bounds;
       TransformableContent  component;

       maxX = Double.NEGATIVE_INFINITY;
       maxY = Double.NEGATIVE_INFINITY;
       minX = Double.POSITIVE_INFINITY;
       minY = Double.POSITIVE_INFINITY;
       
       
       i = components.iterator();
       while (i.hasNext())
       {
          component = i.next();

          bounds    = component.getBounds2D(ofTransformed);

          if (bounds != null)
          {
             rx = bounds.getX();
             ry = bounds.getY();
             if (rx < minX) minX = rx;
             if (ry < minY) minY = ry;
             
             rx = bounds.getX() + bounds.getWidth();
             ry = bounds.getY() + bounds.getHeight();
             if (rx > maxX) maxX = rx;
             if (ry > maxY) maxY = ry;
          }          
       }
       // We could use an object pool
       return new Rectangle2D.Double(minX, minY, maxX-minX, maxY-minY);
    }

//[content2.

    /**
     * Return an Iterator containing all of the TransformableContent
     * objects
     *
     * @return   The Iterator
     */
    public Iterator<C> iterator()
    {
       return components.iterator();       
    }
    

    /**
     * Remove a TransformableContent
     *
     * @param component   The TransformableContent to remove
     */
    public void remove(C component)
    {
       components.remove(component);
    }
//]content2.
//[render.

    /**
     * Render this AbstractAggregateContent
     * (required by TransformableContent)
     *
     * @param g   The rendering engine to use
     */
    public void render(Graphics g)
    {
       Iterator<C>   i;
       C             component;
       

       i = components.iterator();
       while (i.hasNext())
       {
          component = i.next();

          component.setLocation(x, y);
          component.setRotation(angle, xRotation, yRotation);
          component.setScale(xScale, yScale);

          component.render(g);          
       }
    }
//]render.
//[skeleton2.

}
//]skeleton2.
