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

package CH.ifa.draw.standard;

import java.awt.Graphics;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serial;
import java.util.Vector;

import de.renew.draw.storables.api.StorableApi;
import de.renew.draw.storables.ontology.Connector;
import de.renew.draw.storables.ontology.Figure;
import de.renew.draw.storables.ontology.FigureChangeEvent;
import de.renew.draw.storables.ontology.FigureChangeListener;
import de.renew.draw.storables.ontology.FigureEnumeration;
import de.renew.draw.storables.ontology.Locator;
import de.renew.draw.storables.ontology.StorableInput;
import de.renew.draw.storables.ontology.StorableOutput;
import de.renew.draw.ui.ontology.FigureHandle;

/**
 * DecoratorFigure can be used to decorate other figures with
 * decorations like borders. Decorator forwards all the
 * methods to their contained figure. Subclasses can selectively
 * override these methods to extend and filter their behavior.
 * <hr>
 * <b>Design Patterns</b><P>
 * <img src="images/red-ball-small.gif" width=6 height=6 alt=" o ">
 * <b><a href=../pattlets/sld014.htm>Decorator</a></b><br>
 * DecoratorFigure is a decorator.
 *
 * See {@link Figure}.
 * @deprecated This class is not to be used externally and will later be hidden.
 */
@Deprecated(since = "5.0", forRemoval = true)
public abstract class DecoratorFigure extends AbstractFigure implements FigureChangeListener {
    /*
     * Serialization support.
     */
    @Serial
    private static final long serialVersionUID = 8993011151564573288L;
    private final int _decoratorFigureSerializedDataVersion = 1;

    /**
     * The decorated figure.
     * @serial
     */
    protected Figure fComponent;

    public DecoratorFigure() {}

    /**
     * Constructs a DecoratorFigure and decorates the passed in figure.
     */
    public DecoratorFigure(Figure figure) {
        decorate(figure);
    }

    /**
     * Forwards the connection insets to its contained figure.
     */
    @Override
    public Insets connectionInsets() {
        return fComponent.connectionInsets();
    }

    /**
     * Forwards the canConnect to its contained figure.
     */
    @Override
    public boolean canConnect() {
        return fComponent.canConnect();
    }

    /**
     * Forwards containsPoint to its contained figure.
     */
    @Override
    public boolean containsPoint(int x, int y) {
        return fComponent.containsPoint(x, y);
    }

    /**
     * Decorates the given figure.
     */
    public void decorate(Figure figure) {
        fComponent = figure;
        fComponent.addToContainer(this);
    }

    /**
     * Removes the decoration from the contained figure.
     */
    public Figure peelDecoration() {
        fComponent.removeFromContainer(this); //??? set the container to the listener()?
        return fComponent;
    }

    /**
     * Forwards displayBox to its contained figure.
     */
    @Override
    public Rectangle displayBox() {
        return fComponent.displayBox();
    }

    /**
     * Forwards basicDisplayBox to its contained figure.
     */
    @Override
    public void basicDisplayBox(Point origin, Point corner) {
        fComponent.basicDisplayBox(origin, corner);
    }

    /**
     * Forwards draw to its contained figure.
     */
    @Override
    public void draw(Graphics g) {
        fComponent.draw(g);
    }

    /**
     * Forwards findFigureInside to its contained figure.
     */
    @Override
    public Figure findFigureInside(int x, int y) {
        return fComponent.findFigureInside(x, y);
    }

    /**
     * Forwards handles to its contained figure.
     */
    @Override
    public Vector<FigureHandle> handles() {
        return fComponent.handles();
    }

    /**
     * Forwards includes to its contained figure.
     */
    @Override
    public boolean includes(Figure figure) {
        return (super.includes(figure) || fComponent.includes(figure));
    }

    /**
     * Forwards moveBy to its contained figure.
     */
    @Override
    public void moveBy(int x, int y) {
        fComponent.moveBy(x, y);
    }

    /**
     * Forwards basicMoveBy to its contained figure.
     */
    @Override
    protected void basicMoveBy(int x, int y) {
        // this will never be called
    }

    /**
     * Releases itself and the contained figure.
     */
    @Override
    public void release() {
        super.release();
        fComponent.removeFromContainer(this);
        fComponent.release();
    }

    /**
     * Propagates invalidate up the container chain.
     * @see FigureChangeListener
     */
    @Override
    public void figureInvalidated(FigureChangeEvent e) {
        if (listener() != null) {
            listener().figureInvalidated(e);
        }
    }

    @Override
    public void figureChanged(FigureChangeEvent e) {}

    @Override
    public void figureHandlesChanged(FigureChangeEvent e) {}

    @Override
    public void figureRemoved(FigureChangeEvent e) {}

    /**
     * Propagates figureRequestUpdate up the container chain.
     * @see FigureChangeListener
     */
    @Override
    public void figureRequestUpdate(FigureChangeEvent e) {
        if (listener() != null) {
            listener().figureRequestUpdate(e);
        }
    }

    /**
     * Propagates the removeFromDrawing request up to the container.
     * @see FigureChangeListener
     */
    @Override
    public void figureRequestRemove(FigureChangeEvent e) {
        if (listener() != null) {
            listener().figureRequestRemove(StorableApi.createFigureChangeEvent(this));
        }
    }

    /**
     * Forwards figures to its contained figure.
     */
    @Override
    public FigureEnumeration figures() {
        return fComponent.figures();
    }

    /**
     * Forwards decompose to its contained figure.
     */
    @Override
    public FigureEnumeration decompose() {
        return fComponent.decompose();
    }

    /**
     * Forwards setAttribute to its contained figure.
     */
    @Override
    public void setAttribute(String name, Object value) {
        fComponent.setAttribute(name, value);
    }

    /**
     * Forwards getAttribute to its contained figure.
     */
    @Override
    public Object getAttribute(String name) {
        return fComponent.getAttribute(name);
    }

    /**
     * Returns the locator used to located connected text.
     */
    @Override
    public Locator connectedTextLocator(Figure text) {
        return fComponent.connectedTextLocator(text);
    }

    /**
     * Returns the Connector for the given location.
     */
    @Override
    public Connector connectorAt(int x, int y) {
        return fComponent.connectorAt(x, y);
    }

    /**
     * Forwards the connector visibility request to its component.
     */
    @Override
    public void connectorVisibility(boolean isVisible) {
        fComponent.connectorVisibility(isVisible);
    }

    /**
     * Writes itself and the contained figure to the StorableOutput.
     */
    @Override
    public void write(StorableOutput dw) {
        super.write(dw);
        dw.writeStorable(fComponent);
    }

    /**
     * Reads itself and the contained figure from the StorableInput.
     */
    @Override
    public void read(StorableInput dr) throws IOException {
        super.read(dr);
        decorate((Figure) dr.readStorable());
    }

    @Serial
    private void readObject(ObjectInputStream s) throws ClassNotFoundException, IOException {
        s.defaultReadObject();

        fComponent.addToContainer(this);
    }
}