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

import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.geom.Arc2D;
import java.awt.geom.GeneralPath;

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.line.JaxoFLine;
import net.sf.jaxodraw.util.JaxoUtils;
import net.sf.jaxodraw.util.graphics.JaxoGraphics2D;


/** A fermion arc.
 * @since 2.0
 */
public class JaxoFArc extends JaxoArcObject {
    private static final long serialVersionUID = 314159L;
    private transient Arc2D arc = new Arc2D.Double();

    private void readObject(final ObjectInputStream in)
        throws IOException, ClassNotFoundException {
        in.defaultReadObject();
        arc = new Arc2D.Double();
    }

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

        if (comp instanceof JaxoFArc) {
            isCopy = super.isCopy(comp);
        }

        return isCopy;

    }

    /** {@inheritDoc} */
    public final void paint(final JaxoGraphics2D g2) {
        final GeneralPath gp = getObjectPath();

        if (gp == null) {
            return;
        }

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

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

    /**
     * Returns the bounding box of this object.
     *
     * @return the bounding box of this object.
     */
    public Rectangle getBounds() {
        final GeneralPath gp = getObjectPath();
        Rectangle bb;
        if (gp == null) {
            // singular arc: return a Rectangle that just contains
            // the three arc points to avoid NPE
            bb = new Rectangle(getX(), getY(), 0, 0);
            bb.add(getX2(), getY2());
            bb.add(getX3(), getY3());
        } else {
            bb = getStroke().createStrokedShape(getObjectPath()).getBounds();
        }

        if (isPaintArrow()) {
            final Rectangle arrowBB = getArrow().getBounds(arrowCoordinates());
            bb.add(arrowBB);
        }

        return bb;
    }

    /** {@inheritDoc} */
    public final String latexCommand(final float scale, final Dimension canvasDim) {
        if (isSingular()) {
            return "% Singular FArc, ignored!" + JaxoUtils.LINE_SEPARATOR;
        }

        if (isOneLine()) {
            final JaxoFLine line = new JaxoFLine();
            line.setLocation(getX(), getY(), getX3(), getY3());
            line.setStrokeWidth(getStrokeWidth());
            line.setArrow(getArrow().copy());
            line.setArrowPosition(getArrowPosition());
            line.setPaintArrow(isPaintArrow());
            line.setFlip(isFlip());
            line.setDoubleLine(isDoubleLine());
            line.setDLSeparation(getDLSeparation());
            return line.latexCommand(scale, canvasDim);
        }

        final double[] par = getArcParameters();
        final double cx = par[0] / scale;
        final double cy = (canvasDim.height - par[1]) / scale;
        final double r = par[2] / scale;

        final double sa = par[4];
        final double ea = par[3] + par[4];
        final boolean clockwise = (par[3] < 0.d);

        final String options = getOptionsCommand(scale, clockwise);

        return "\\Arc" + options + "(" + D_FORMAT.format(cx) + ","
                + D_FORMAT.format(cy) + ")" + "(" + D_FORMAT.format(r) + ","
                + D_FORMAT.format(sa) + "," + D_FORMAT.format(ea) + ")";
    }

    /** {@inheritDoc} */
    public void prepareEditPanel(final JaxoObjectEditPanel editPanel) {
        editPanel.add3PointsPanel(getPoints(), 0, 0, 2);
        //editPanel.addArrowPanel(isPaintArrow(), isFlip(), true, arrowAtEnd(), 2, 0);
        editPanel.addArrowPanel(isPaintArrow(), isFlip(), getArrowPosition(), 2, 0);
        editPanel.addArrowOptionsEditPanel(getArrow(), 3, 0);
        editPanel.addStrokePanel(getStrokeWidth(), 0, 1);
        editPanel.addDoubleLinePanel(isDoubleLine(), getDLSeparation(), 1, 1);
        editPanel.addLineColorPanel(getColor(), 2, 1);

        editPanel.setTitleAndIcon("Fermion_arc_parameters", "farc.png");
    }

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

        if (isSingular()) {
            return null;
        }

        if (isOneLine()) {
            return getFLine(gp);
        }

        final double[] par = getArcParameters();

        if (isDoubleLine()) {
            arc.setArcByCenter(par[0], par[1], par[2] + getDLSeparation() / 2.f,
                    par[4], par[3], Arc2D.OPEN);
            gp.append(arc, false);
            arc.setArcByCenter(par[0], par[1], par[2] - getDLSeparation() / 2.f,
                    par[4], par[3], Arc2D.OPEN);
            gp.append(arc, false);
        } else {
            arc.setArcByCenter(par[0], par[1], par[2], par[4], par[3], Arc2D.OPEN);
            gp.append(arc, false);
        }

        return gp;
    }

    private GeneralPath getFLine(final GeneralPath gp) {
        if (isDoubleLine()) {
            final float length = (float) Math.sqrt((getX() - getX3()) * (getX() - getX3())
                        + (getY() - getY3()) * (getY() - getY3()));
            final float sepx = (getY3() - getY()) / length * getDLSeparation() / 2.f;
            final float sepy = (getX3() - getX()) / length * getDLSeparation() / 2.f;
            gp.moveTo(getX() - sepx, getY() + sepy);
            gp.lineTo(getX3() - sepx, getY3() + sepy);
            gp.moveTo(getX() + sepx, getY() - sepy);
            gp.lineTo(getX3() + sepx, getY3() - sepy);
        } else {
            gp.moveTo(getX(), getY());
            gp.lineTo(getX3(), getY3());
        }

        return gp;
    }

    // Get the axodraw4j options set for this arc

    private String getOptionsCommand(final float scale, final boolean clockwise) {

        final StringBuffer optioncmd = new StringBuffer(128); //Assumes all option default to false in axodraw4j

        if (isPaintArrow()) {
            final float arpos = getArrowPosition();
            optioncmd.append(this.getArrow().latexCommand(arpos, scale));

            if (isFlip()) {
                optioncmd.append(",flip");
            }

            if (isDoubleLine()) {
                optioncmd.append(",double,sep=").append(
                    D_FORMAT.format(this.getDLSeparation()));
            }

            if (clockwise) {
                optioncmd.append(",clock");
            }

            optioncmd.insert(0, "[").append("]");

        } else if (isDoubleLine()) {
            optioncmd.append("double,sep=").append(
                    D_FORMAT.format(this.getDLSeparation()));

            if (clockwise) {
                optioncmd.append(",clock");
            }

            optioncmd.insert(0, "[").append("]");

        } else if (clockwise) {
            optioncmd.append("[clock]");
        }

        return optioncmd.toString();
    }
}
