/*
 * Created on Apr 12, 2003
 *
 * To change this generated comment go to 
 * Window>Preferences>Java>Code Generation>Code Template
 */
package jdraw.figures;

import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Color;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.Iterator;
import java.util.List;
import java.util.ArrayList;

import jdraw.framework.Figure;
import jdraw.framework.FigureListener;
import jdraw.framework.FigureEvent;

/**
 * Abstract class implementing some basics of figures.
 * This class can be used as convenience class for concrete Figure
 * implementations.
 *
 * @author  Christoph Denzler
 * @version 1.0  12.4.03
 */
public abstract class AbstractFigure implements Figure {
	protected static final int gravity = 5;
	private transient List listeners = new ArrayList();
	private boolean filled = false;
	private Color color = Color.BLACK;

	/**
	 * Tests whether the mouse coordinates are contained in the figure.
	 * contains is called when the mouse is pressed in the grafic in
	 * order to decide which figure has to be selected.
	 * Note: this default implementation may be to insensitive, as it
	 * returns true as soon as the given coordinates are contained in
	 * the bounding box. Finer grained definitions have to be
	 * implemented in extending classes.
	 * 
	 * @param x x-coordinate of mouse position
	 * @param y y-coordinate of mouse position
	 * @return <tt>true</tt>, if coordinates are contained in the figure, 
	 *         <tt>false</tt> otherwise
	 */
	public boolean contains(int x, int y) {
		Rectangle r = getBounds();
		return r.contains(x, y);
	}

	/**
	 * Returns the center of a figure. The center is usually the center
	 * of its bounds rectangle. More precise definitions have to be
	 * implemented in exdending classes
	 * 
	 * @return center of the figure
	 */
	public Point getCenter() {
		Rectangle r = getBounds();
		return new Point(r.x + r.width/2, r.y + r.height/2);
	}

	/**
	 * Returns a list of handles. Note this abstract default implementation
	 * does not support handles and therefore always returns null.
	 * 
	 * @return null, handles are not supported
	 * @see Handle
	 */
	public List getHandles() {
		return null;
	}

	/**
	 * Tests if the figure is empty. A figure is considered to be empty
	 * if its area is smaller than 4 square pixels.
	 *  
	 * @return <tt>true</tt>, if figure is "empty"
	 *         <tt>false</tt> otherwise
	 * @see DrawTool
	 */
	public boolean isEmpty() {
		Rectangle r = getBounds();
		return r.width*r.height >= 4;
	}

	/**
	 * Adds the specified figure listener to receive figure events from 
	 * this figure. If listener is null, no exception is thrown and no 
	 * action is performed.
	 * @param listener the figure listener.
	 * @see FigureListener
	 */
	public void addFigureListener(FigureListener listener) {
		if (listener != null) {
			this.listeners.add(listener);
		}
	}

	/**
	 * Removes the specified figure listener so that it no longer receives
	 * figure events from this figure. This method performs no function, 
	 * nor does it throw an exception, if the listener specified by the 
	 * argument was not previously added to this figure. 
	 * If listener is null, no exception is thrown and no action is performed.
	 * @param listener the figure listener.
	 * @see FigureListener
	 */
	public void removeFigureListener(FigureListener listener) {
		this.listeners.remove(listener);
	}
	
	/**
	 * Notify all FigureListeners of a FigureEvent.
	 */
	protected void notifyListeners(FigureEvent fe) {
		Iterator it = listeners.iterator();
		while (it.hasNext()) {
			((FigureListener)it.next()).figureChanged(fe);
		}
	}

	/**
	 * Copies the attributes filled and color.
	 * 
	 * @see java.lang.Object#clone()
	 */
	public Object clone() {
		AbstractFigure f = null;
		try {
			f = (AbstractFigure)super.clone();
			f.filled = filled;
			f.color = new Color(color.getRGB());
		} catch (CloneNotSupportedException cnse) {
			System.out.println("CloneNotSupportedException occured");
		}
		return f;
	}

	/**
	 * Sets the rectangle to filled. Listeners will only be notified if the
	 * invokation of this method causes a change.
	 * @param filled
	 */
	public void setFilled(boolean filled) {
		if (this.filled != filled) {
			this.filled = filled;
			notifyListeners(new FigureEvent(this));
		}
	}
	
	/**
	 * Returns the filled status of this figure.
	 * @return boolean
	 */
	public boolean isFilled() {
		return filled;
	}
	
	/**
	 * Sets the color of this figure. Listeners will only be notified if the
	 * invocation of this method cuases a change in color.
	 * @param c
	 */
	public void setColor(Color c) {
		if (!color.equals(c)) {
			color = c;
			notifyListeners(new FigureEvent(this));
		}
	}
	
	/**
	 * Returns the color of this Figure
	 * @return Color
	 */
	public Color getColor() {
		return color;
	}
	
	
	private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
		ois.defaultReadObject();
		
		listeners = new ArrayList();
	}
	
}
