/*
 * @(#)Figure.java 5.1
 *
 */

package de.renew.draw.storables.ontology;

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.io.Serializable;
import java.util.Vector;

import de.renew.draw.ui.ontology.DrawingView;
import de.renew.draw.ui.ontology.FigureDrawingContext;
import de.renew.draw.ui.ontology.FigureHandle;

/**
 * The interface of a graphical figure. A figure knows
 * its display box and can draw itself. A figure can be
 * composed of several figures. To interact and manipulate
 * with a figure it can provide Handles and Connectors.<p>
 * A figure has a set of handles to manipulate its shape or attributes.
 * A figure has one or more connectors that define how
 * to locate a connection point.<p>
 * Figures can have an open-ended set of attributes.
 * An attribute is identified by a string.<p>
 * Default implementations for the Figure interface are provided
 * by AbstractFigure.
 *
 * @see FigureHandle
 * @see Connector
 * @see CH.ifa.draw.standard.AbstractFigure
 */
public interface Figure extends Storable, Cloneable, Serializable {

    /**
     * Moves the Figure to a new location.
     * @param dx the x delta
     * @param dy the y delta
     */
    void moveBy(int dx, int dy);

    /**
     * Changes the display box of a figure. This method is
     * always implemented in figure subclasses.
     * It only changes
     * the displayBox and does not announce any changes. It
     * is usually not called by the client. Clients typically call
     * displayBox to change the display box.
     * @param origin the new origin
     * @param corner the new corner
     * @see #displayBox(Point,Point)
     */
    void basicDisplayBox(Point origin, Point corner);

    /**
     * Gets the display box of a figure.
     * The display box is usually the smallest rectangle
     * enclosing all points of the figure.
     * <p>
     * The figure's points can lie inside the display box
     * rectangle as well as on its bounds. This leads to a problem
     * when the rectangle's methods for intersection or
     * containment are used, because there all points lying
     * exactly on the lower or right bounds are treated as being
     * <i>outside</i> of the rectangle.
     * </p><p>
     * Note: With the release of Java 1.4, the behaviour of
     * {@link Rectangle#intersects} has been adopted to its
     * documentation commitment: It now returns
     * <code>false</code> if any of both rectangles is empty,
     * e.g. has zero width or height, even if the zero-sized
     * rectangle lies inside the other.
     * A zero-width display box is used by strictly vertical
     * line figures, for example.
     * So the result of this method should always be enlarged by
     * 1 unit into all directions before it is used to calculate
     * clipping effects with the <code>intersects</code> method.
     * </p>
     * @see #displayBox(Point,Point)
     * @return Display Box of this figure
     */
    Rectangle displayBox();

    /**
     * Changes the display box of a figure. This is a
     * convenience method. Implementors should only
     * have to override basicDisplayBox
     * @see #basicDisplayBox
     * @param r an instance of Rectangle
     */
    void displayBox(Rectangle r);

    /**
     * Changes the display box of a figure. Clients usually
     * invoke this method. It changes the display box
     * and announces the corresponding changes.
     * @param origin the new origin
     * @param corner the new corner
     * @see #displayBox()
     */
    void displayBox(Point origin, Point corner);

    /**
     * Draws the figure.
     * @param g the Graphics to draw into
     */
    void draw(Graphics g);

    /**
     * Draws the figure in an  appearance according to the DrawingContext.
     * @param g the Graphics to draw into
     * @param dc the FigureDrawingContext to obey
     */
    void draw(Graphics g, FigureDrawingContext dc);

    /**
     * Returns the handles used to manipulate
     * the figure. Handles is a Factory Method for
     * creating handle objects.
     *
     * @return a Vector of handles
     * @see FigureHandle
     */
    Vector<FigureHandle> handles();

    /**
     * Gets the size of the figure.
     * @return size of figure
     */
    Dimension size();

    /**
     * Gets the figure's center.
     * @return center of figure
     */
    Point center();

    /**
     * Checks if the Figure should be considered as empty.
     * @return boolean, {@code true} if considered empty
     */
    boolean isEmpty();

    /**
     * Returns an Enumeration of the figures contained in this figure.
     * @return enumeration of contained figures
     */
    FigureEnumeration figures();

    /**
     * Returns the figure that contains the given point.
     * @param x point on x-axis
     * @param y point on y-axis
     * @return figure that contains given point
     */
    Figure findFigureInside(int x, int y);

    /**
     * Checks if a point is inside the figure.
     * @param x point on x-axis
     * @param y point on y-axis
     * @return boolean, {@code true} if given point is inside figure
     */
    boolean containsPoint(int x, int y);

    /**
     * Returns a Clone of this figure
     * @return clone of figure
     */
    Object clone();

    /**
     * Checks whether the given figure is contained in this figure.
     * @param figure figure to be checked
     * @return boolean, {@code true} if contained
     */
    boolean includes(Figure figure);

    /**
     * Decomposes a figure into its parts. A figure is considered
     * as a part of itself.
     * @return decomposed figure
     */
    FigureEnumeration decompose();

    /**
     * Sets the Figure's container and registers the container
     * as a figure change listener. A figure's container can be
     * any kind of FigureChangeListener. A figure is not restricted
     * to have a single container.
     * @param c the listener that is added to the container
     */
    void addToContainer(FigureChangeListener c);

    /**
     * Removes a figure from the given container and unregisters
     * it as a change listener.
     * @param c the listener that is unregistered
     */
    void removeFromContainer(FigureChangeListener c);

    /**
     * Gets the Figure's listeners.
     * @return all listeners of figure
     */
    FigureChangeListener listener();

    /**
     * Adds a listener for this figure.
     * @param l listener to be added
     */
    void addFigureChangeListener(FigureChangeListener l);

    /**
     * Removes a listener for this figure.
     * @param l listener to be removed
     */
    void removeFigureChangeListener(FigureChangeListener l);

    /**
     * Releases a figure's resources. Release is called when
     * a figure is removed from a drawing. Informs the listeners that
     * the figure is removed by calling figureRemoved.
     */
    void release();

    /**
     * Invalidates the figure. This method informs its listeners
     * that its current display box is invalid and should be
     * refreshed.
     */
    void invalidate();

    /**
     * Informs that a figure is about to change such that its
     * display box is affected.
     * Here is an example of how it is used together with changed()
     * <pre>
     * public void move(int x, int y) {
     *      willChange();
     *      // change the figure's location
     *      changed();
     *  }
     * </pre>
     * @see #invalidate
     * @see #changed
     */
    void willChange();

    /**
     * Informs that a figure has changed its display box.
     * This method also triggers an update call for its
     * registered observers.
     * @see #invalidate
     * @see #willChange
     *
     */
    void changed();

    /**
     * Checks if this figure can be connected.
     * @return boolean, {@code true} if figure can be connected
     */
    boolean canConnect();

    /**
     * Gets a connector for this figure at the given location.
     * A figure can have different connectors at different locations.
     * @param x point on x-axis
     * @param y point on y-axis
     * @return connector for figure at given location
     */
    Connector connectorAt(int x, int y);

    /**
     * Gets a connector for this figure at the given location.
     * A figure can have different connectors at different locations.
     * @param p given point
     * @return connector for figure at given location
     */
    Connector connectorAt(Point p);

    /**
     * Sets whether the connectors should be visible.
     * Connectors can be optionally visible. Implement
     * this method and react on isVisible to turn the
     * connectors on or off.
     * @param isVisible boolean, {@code true} if should be visible
     */
    void connectorVisibility(boolean isVisible);

    /**
     * Returns the connection insets. This is only a hint that
     * connectors can use to determine the connection location.
     * The insets define the area where the display box of a
     * figure should not be connected.
     * @return connection insets
     *
     */
    Insets connectionInsets();

    /**
     * Returns the locator used to located connected text.
     * @param text connected text
     * @return locator used to locate connected text
     */
    Locator connectedTextLocator(Figure text);

    /**
     * Returns the named attribute or null if
     * a figure doesn't have an attribute.
     * All figures support the attribute names
     * FillColor and FrameColor
     * @param name name of attribute
     * @return attribute names (or null if none set)
     */
    Object getAttribute(String name);

    /**
     * Sets the named attribute to the new value.
     * @param name name attribute
     * @param value new value of given named attribute
     */
    void setAttribute(String name, Object value);

    /**
     * This event is issued when the figure is asked
     * by the user to perform some default action.
     * @param alternate the figure is asked to perform some alternate action (usually right mouse-click)
     * @param view an instance of DrawingView
     * @return tells whether the event was consumed.
     */
    boolean inspect(DrawingView view, boolean alternate);

    /** Returns whether this figure is visible.
     * @return boolean, {@code true} if visible
     */
    boolean isVisible();

    /** Sets the visibility of this figure.
     * @param visible boolean, {@code true} if visible
     */
    void setVisible(boolean visible);

    /** Returns whether this figure can be selected.
     * @return boolean, {@code true} if figure can be selected
     */
    boolean isSelectable();
}