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

import java.awt.BasicStroke;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.geom.Area;
import java.awt.geom.GeneralPath;
import java.awt.geom.Point2D;

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

import net.sf.jaxodraw.util.JaxoUtils;
import net.sf.jaxodraw.util.graphics.JaxoGraphics2D;


/**
 * A dashed bezier curve.
 *
 * @since 2.0
 */
public abstract class JaxoDashBezier extends JaxoBezierObject {
    private static final long serialVersionUID = 314159L;

    private void readObject(final ObjectInputStream in)
        throws IOException, ClassNotFoundException {
        in.defaultReadObject();
        resetStroke();
    }

    /** {@inheritDoc} */
    public final void paint(final JaxoGraphics2D g2) {
        g2.setColor(getColor());
        g2.setStroke(getStroke());
        g2.draw(getObjectPath());

        if (isPaintArrow()) {
            paintArrow(g2);
        }
    }

    /**
     * Returns the bounding box of this object.
     *
     * @return the bounding box of this object.
     */
    public Rectangle getBounds() {
        // use Area for bounding box calculation instead of gp.getBounds(),
        // see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4599407
        final Rectangle bb =
            getStroke().createStrokedShape(new Area(getObjectPath()))
                .getBounds();

        if (isPaintArrow()) {
            bb.add(getArrow().getBounds(arrowCoordinates()));
        }

        return bb;
    }

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

        final Point2D latexP1 = getLatexPoint(getX(), getY(), scale, canvasHeight);
        final Point2D latexP2 = getLatexPoint(getX2(), getY2(), scale, canvasHeight);
        final Point2D latexP3 = getLatexPoint(getX3(), getY3(), scale, canvasHeight);
        final Point2D latexP4 = getLatexPoint(getX4(), getY4(), scale, canvasHeight);

        final String options = "[dash,dsize=" + D_FORMAT.format(getDash() / scale) + "]";
        final String command = bezierLatexCommand(options, latexP1, latexP2, latexP3, latexP4);

        if (isPaintArrow()) {
            final float k = .0025f;
            final float arrowPosition = getArrowPosition();

            final Point2D b1 = getPointOnCurve(arrowPosition - k);
            final Point2D b2 = getPointOnCurve(arrowPosition + k);
            final Point2D startPoint = getLatexPoint(b1.getX(), b1.getY(), scale, canvasHeight);
            final Point2D endPoint = getLatexPoint(b2.getX(), b2.getY(), scale, canvasHeight);
            final String arrowcmd = getArrowCommand(scale);

            arrowCommand = "\\Line" +  arrowcmd + "("
                + D_FORMAT.format(startPoint.getX()) + ","
                + D_FORMAT.format(startPoint.getY()) + ")" + "("
                + D_FORMAT.format(endPoint.getX()) + ","
                + D_FORMAT.format(endPoint.getY()) + ")";

            jdIdentifier += arrowcmd;
        }

        return command + arrowCommand + jdIdentifier;
    }

    /** {@inheritDoc} */
    @Override
    protected void resetStroke() {
        if (JaxoUtils.zero(getStrokeWidth()) || JaxoUtils.zero(getDash())) {
            // during initialization, either of them is still null
            // so wait until both are set
            return;
        }

        setStroke(new BasicStroke(getStrokeWidth(), BasicStroke.CAP_ROUND,
                BasicStroke.JOIN_MITER, 10.0f, strokeDashes(), 0.0f));
    }

    private GeneralPath getObjectPath() {
        final GeneralPath gp = getGeneralPath();
        gp.reset();

        gp.moveTo(getX(), getY());
        gp.curveTo(getX2(), getY2(), getX3(), getY3(), getX4(), getY4());

        return gp;
    }

    /**
     * Returns an array that is used as the dash parameter in
     * {@link java.awt.BasicStroke} to paint this object.
     * @return a dash array.
     */
    protected abstract float[] strokeDashes();

    /**
     * Convenience method for the Latex import/export
     * Should be removed when axodraw2 is ready
     *
     * @return a String to identify the Bezier in an axodraw file.
     */
    protected abstract String getIdentifier();
}
