/**
 *  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.vertex;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.geom.AffineTransform;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Point2D;

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

import net.sf.jaxodraw.object.JaxoFillColorObject;
import net.sf.jaxodraw.object.JaxoHandle;
import net.sf.jaxodraw.object.JaxoObject;
import net.sf.jaxodraw.object.JaxoObjectEditPanel;
import net.sf.jaxodraw.util.JaxoColor;
import net.sf.jaxodraw.util.JaxoConstants;
import net.sf.jaxodraw.util.graphics.JaxoGraphics2D;


/** A vertex type 2 object (a cross with a circle).
 * @since 2.0
 */
public class JaxoVertexT2 extends JaxoVertex implements JaxoFillColorObject {
    private static final long serialVersionUID = 314159L;
    private transient Ellipse2D blob = new Ellipse2D.Float();

    /** The fill color of this fillObject. */
    private Color fillColor;
    private boolean filled = true;

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

    // Bean getter and setter methods

    /** {@inheritDoc} */
    public final boolean isFilled() {
        return filled;
    }

    /** {@inheritDoc} */
    public final void setFilled(final boolean value) {
        final Boolean old = Boolean.valueOf(filled);
        filled = value;
        firePropertyChange("filled", old, Boolean.valueOf(filled));
    }

    /** {@inheritDoc} */
    public final Color getFillColor() {
        return fillColor;
    }

    /** {@inheritDoc} */
    public final void setFillColor(final Color color) {
        final Color old = fillColor;
        this.fillColor = color;
        firePropertyChange("fillColor", old, fillColor);
    }

    /** Sets all parameters from the given object to the current one.
     * @param temp The object to copy from.
     */
    public final void copyFrom(final JaxoVertexT2 temp) {
        super.copyFrom(temp);
        setFillColor(temp.getFillColor());
        setFilled(temp.isFilled());
    }

    /** {@inheritDoc} */
    @Override
    public void setState(final JaxoObject o) {
        if (o instanceof JaxoVertexT2) {
            copyFrom((JaxoVertexT2) 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 JaxoVertexT2) {
            final JaxoVertexT2 vertexT2 = (JaxoVertexT2) comp;
            if (super.isCopy(comp)
                    && vertexT2.getFillColor().equals(getFillColor())
                    && (vertexT2.isFilled() == isFilled())) {
                isCopy = true;
            }
        }

        return isCopy;

    }

    /** {@inheritDoc} */
    @Override
    public boolean canBeSelected(final int handle, final int mode) {
        boolean active = ((handle == SELECT_P1) || (handle == SELECT_P2));
        if (mode == JaxoConstants.RESIZE) {
            active = (handle == SELECT_P2);
        }
        return active;
    }

    /** {@inheritDoc} */
    @Override
    public void paintHandles(final JaxoGraphics2D g2, final JaxoHandle h, final int editMode) {
        if (editMode == JaxoConstants.UNGROUP) {
            return;
        }

        h.paint(g2, getX(), getY(), isMarked(), !canBeSelected(SELECT_P1, editMode));
        h.paint(g2, getX2(), getY2(), isMarked(), !canBeSelected(SELECT_P2, editMode));
    }

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

        if (isFilled()) {
            g2.setColor(getFillColor());
            g2.fill(blob);
        }

        g2.setColor(getColor());
        g2.setStroke(getStroke());
        g2.draw(blob);

        final int sepx = (int) Math.round(getRelh() / Math.sqrt(2.d));
        final int sepy = (int) Math.round(getRelw() / Math.sqrt(2.d));

        g2.drawLine(getX() + sepx, getY() - sepy, getX() - sepx, getY() + sepy);
        g2.drawLine(getX() - sepy, getY() - sepx, getX() + sepy, getY() + sepx);

    }

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

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

    /** {@inheritDoc} */
    public final String latexCommand(final float scale, final Dimension canvasDim) {
        final float radius = getLaTexRadius(scale);

        if ((int) radius == 0) {
            return "%";
        }

        final Point2D center = getLaTexCenter(scale, canvasDim.height);
        final Point2D axes = getLaTexAxes(scale);
        String command = "";

        final float angle =
            (float) Math.toDegrees(Math.atan2((float) getRelh(),
                    (float) getRelw()));

        String command1 = "";
        final String tlc = JaxoColor.getColorName(getColor());

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

        final Point2D invec1 =
            new Point2D.Float((float) (center.getX() - (radius * 0.5f)),
                (float) (center.getY() - (radius * 0.5f)));
        final Point2D finvec1 =
            new Point2D.Float((float) (center.getX() + (radius * 0.5f)),
                (float) (center.getY() + (radius * 0.5f)));
        final Point2D invec2 =
            new Point2D.Float((float) (center.getX() - (radius * 0.5f)),
                (float) (center.getY() + (radius * 0.5f)));
        final Point2D finvec2 =
            new Point2D.Float((float) (center.getX() + (radius * 0.5f)),
                (float) (center.getY() - (radius * 0.5f)));

        final double theta = (Math.PI / 4) - Math.atan2(getRelh(), getRelw());

        final AffineTransform at = new AffineTransform();
        at.rotate(theta, center.getX(), center.getY());

        final Point2D invect1 = at.transform(invec1, null);
        final Point2D finvect1 = at.transform(finvec1, null);
        final Point2D invect2 = at.transform(invec2, null);
        final Point2D finvect2 = at.transform(finvec2, null);

        final String command2 =
            "\\Line" + "(" + D_FORMAT.format(invect1.getX()) + ","
            + D_FORMAT.format(invect1.getY()) + ")" + "("
            + D_FORMAT.format(finvect1.getX()) + ","
            + D_FORMAT.format(finvect1.getY()) + ")";

        final String command3 =
            "\\Line" + "(" + D_FORMAT.format(invect2.getX()) + ","
            + D_FORMAT.format(invect2.getY()) + ")" + "("
            + D_FORMAT.format(finvect2.getX()) + ","
            + D_FORMAT.format(finvect2.getY()) + ")";

        command = command1 + command2 + command3;

        return command;
    }

    /** {@inheritDoc} */
    @Override
    public void setPreferences() {
        super.setPreferences();
        setFilled(true);
        setFillColor(JaxoColor.WHITE);
    }

    /** {@inheritDoc} */
    public void prepareEditPanel(final JaxoObjectEditPanel editPanel) {
        final int r = (int) Math.round(getRadius());

        editPanel.addXYRPanel(getX(), getY(), r, 0, 0);
        editPanel.addRotationPanel(getRotationAngle(), 0, 1);
        editPanel.addStrokePanel(getStrokeWidth(), 0, 2);
        editPanel.addFillLineColorPanels(getColor(), getFillColor(),
            isFilled(), 1, 1, 1, 0);

        editPanel.setTitleAndIcon("Vertex_parameters", "vertexT2.png");
    }

    private Point2D getLaTexAxes(final float scaleFactor) {
        final float wdt = (float) getRadius() / scaleFactor;

        return new Point2D.Float(wdt, wdt);
    }

    private void updateBlob() {
        final double len = getRadius();

        blob.setFrame(-len + getX(), -len + getY(), 2 * len, 2 * len);
    }
}
