/**
 *  Licensed under GPL. For more information, see
 *    http://jaxodraw.sourceforge.net/license.html
 *  or the LICENSE file in the jaxodraw distribution.
 */
package net.sf.jaxodraw.object.fill;

import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.Ellipse2D;
import java.awt.geom.GeneralPath;
import java.awt.geom.Point2D;

import java.io.IOException;
import java.io.ObjectInputStream;

import net.sf.jaxodraw.object.JaxoObject;
import net.sf.jaxodraw.object.JaxoObjectEditPanel;
import net.sf.jaxodraw.object.JaxoRotationObject;
import net.sf.jaxodraw.util.JaxoColor;
import net.sf.jaxodraw.util.graphics.JaxoGraphics2D;


/** A blob object: a general ellypse that can be rotated.
 * @since 2.0
 */
public class JaxoBlob extends JaxoFillObject
    implements JaxoRotationObject {
    private static final long serialVersionUID = 2L;
    private transient Ellipse2D blob = new Ellipse2D.Float();

    private static final int LP4 = 12;

    /** The rotation angle of the ellipse */
    private int rotationAngle;

    private void readObject(final ObjectInputStream in)
        throws IOException, ClassNotFoundException {
        in.defaultReadObject();
        blob = new Ellipse2D.Float();
    }

    // Bean getter and setter methods

    /** Returns the rotation angle of this blob.
     * @return The rotation angle of this blob
     */
    public final int getRotationAngle() {
        return rotationAngle;
    }

    /** Sets the rotation angle of this blob.
     * @param newangle The rotation angle of this blob
     */
    public final void setRotationAngle(final int newangle) {
        final Integer old = Integer.valueOf(rotationAngle);
        this.rotationAngle = newangle;
        firePropertyChange("rotationAngle", old, Integer.valueOf(rotationAngle));
    }

    /** Sets all parameters from the given object to the current one.
     * @param temp The object to copy from.
     */
    public final void copyFrom(final JaxoBlob temp) {
        super.copyFrom(temp);
        setRotationAngle(temp.getRotationAngle());
    }

    /** {@inheritDoc} */
    @Override
    public void setState(final JaxoObject o) {
        if (o instanceof JaxoBlob) {
            copyFrom((JaxoBlob) o);
        } else {
            throw new UnsupportedOperationException("Cannot copy from super type!");
        }
    }

    /** {@inheritDoc} */
    @Override
    public final boolean isCopy(final JaxoObject comp) {
        boolean isCopy = false;

        if (comp instanceof JaxoBlob) {
            final JaxoBlob temp = (JaxoBlob) comp;
            if ((temp.getRotationAngle() == getRotationAngle()) && super.isCopy(temp)) {
                isCopy = true;
            }
        }

        return isCopy;
    }

    /** {@inheritDoc} */
    @Override
    public final void paintVisualAid(final JaxoGraphics2D g2) {
        final int x = getX();
        final int y = getY();

        g2.drawLine(x - LP4, y, x + LP4, y);
        g2.drawLine(x, y - LP4, x, y + LP4);
    }

    /** {@inheritDoc} */
    public final void paint(final JaxoGraphics2D g2) {
        updateShape();

        if (isFilled()) {
            g2.setColor(getFillColor());
            g2.fill(getShape());
        }
        g2.setColor(getColor());
        g2.setStroke(getStroke());
        g2.draw(getShape());
    }

    /**
     * Returns the bounding box of this object.
     *
     * @return the bounding box of this object.
     */
    public Rectangle getBounds() {
        updateShape();

        return getStroke().createStrokedShape(getShape()).getBounds();
    }

    /** {@inheritDoc} */
    public final String latexCommand(final float scale, final Dimension canvasDim) {
        final int canvasHeight = canvasDim.height;

        final Point2D axes = getLaTexAxes(scale);
        if (((int) axes.getX() == 0) && ((int) axes.getY() == 0)) {
            return "%";
        }

        final Point2D center = getLaTexCenter(scale, canvasHeight);
        final int rotate = getLaTexRotation();
        String command = "";

        if (isFilled()) {
            if (JaxoColor.isGrayScale(getFillColor())) {
                final float grayScale = JaxoColor.getGrayScaleFloat(getFillColor());
                command =
                    "\\GOval" + "(" + D_FORMAT.format(center.getX()) + ","
                    + D_FORMAT.format(center.getY()) + ")" + "("
                    + D_FORMAT.format(axes.getY()) + ","
                    + D_FORMAT.format(axes.getX()) + ")" + "("
                    + D_FORMAT.format(rotate) + ")" + "{"
                    + GRAY_SCALE_FORMAT.format(grayScale) + "}";
            } else {
                String tlc;
                if (JaxoColor.isGrayScale(getColor())) {
                    tlc = "Gray";
                } else {
                    tlc = JaxoColor.getColorName(getColor());
                }
                final String tfc = JaxoColor.getColorName(getFillColor());
                command =
                    "\\COval" + "(" + D_FORMAT.format(center.getX()) + ","
                    + D_FORMAT.format(center.getY()) + ")" + "("
                    + D_FORMAT.format(axes.getY()) + ","
                    + D_FORMAT.format(axes.getX()) + ")" + "("
                    + D_FORMAT.format(rotate) + ")" + "{" + tlc + "}" + "{"
                    + tfc + "}";
            }
        } else {
            command =
                "\\Oval" + "(" + D_FORMAT.format(center.getX()) + ","
                + D_FORMAT.format(center.getY()) + ")" + "("
                + D_FORMAT.format(axes.getY()) + ","
                + D_FORMAT.format(axes.getX()) + ")" + "("
                + D_FORMAT.format(rotate) + ")";
        }

        return command;
    }

    /** {@inheritDoc} */
    @Override
    public void setPreferences() {
        super.setPreferences();
        setRotationAngle(0);
    }

    /** {@inheritDoc} */
    public void prepareEditPanel(final JaxoObjectEditPanel editPanel) {
        editPanel.addCenterSizePanel(getX(), getY(), getWidth(), getHeight(),
            0, 0);
        editPanel.addRotationPanel(getRotationAngle(), 0, 1);
        editPanel.addStrokePanel(getStrokeWidth(), 0, 2);
        editPanel.addFillLineColorPanels(getColor(), getFillColor(), isFilled(),
            1, 1, 1, 0);

        editPanel.setTitleAndIcon("Blob_parameters", "blob.png");
    }

      //
     // private methods
    //

    private Point2D getLaTexCenter(final float scaleFactor, final int canvasHeight) {
        return getLaTexLocation(scaleFactor, canvasHeight);
    }

    private Point2D getLaTexAxes(final float scaleFactor) {
        final Point2D axesVec = new Point2D.Float();
        float wdt;
        float hgt;

        wdt = getWidth() / scaleFactor;
        hgt = getHeight() / scaleFactor;
        axesVec.setLocation(wdt, hgt);

        return axesVec;
    }

    private int getLaTexRotation() {
        return -rotationAngle;
    }

    // Use 'blob' directly if rotation angle is zero
    // -- could also do for 90, 180 etc.
    // Also the calculation of the bounding box can be done
    // directly for any angle, but probably is not worth it.

    // Call updateShape() before
    private Shape getShape() {
        return rotationAngle == 0 ? blob : (Shape) getGeneralPath();
    }

    private void updateShape() {
        blob.setFrame(-getWidth() + getX(), -getHeight() + getY(),
            2 * getWidth(), 2 * getHeight());

        if (rotationAngle != 0) {
            final GeneralPath p = getGeneralPath();
            p.reset();
            p.append(blob, false);
            p.transform(AffineTransform.getRotateInstance(
                Math.toRadians(rotationAngle), getX(), getY()));
        }
    }
}
