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

import java.awt.Dimension;
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.JaxoSymmetricObject;
import net.sf.jaxodraw.object.JaxoWiggleObject;
import net.sf.jaxodraw.util.JaxoUtils;


/** A photon line.
 * @since 2.0
 */
public class JaxoPLine extends JaxoLineObject implements JaxoWiggleObject,
    JaxoSymmetricObject {
    private static final long serialVersionUID = 314159L;
    private transient float freq;
    private boolean symmetric;

    private void readObject(final ObjectInputStream in)
        throws IOException, ClassNotFoundException {
        in.defaultReadObject();
        freq = 0.f;
    }

    /**
     * Returns the symmetric property of this JaxoPLine.
     * This determines whether the wiggles of this photon
     * line start and end in the same direction.
     *
     * @return The symmetric property of this JaxoPLine.
     */
    public final boolean isSymmetric() {
        return symmetric;
    }

    /**
     * Sets the symmetric property of this line object.
     *
     * @param newSymm The symmetric property of this line object.
     */
    public final void setSymmetric(final boolean newSymm) {
        final Boolean old = Boolean.valueOf(symmetric);
        this.symmetric = newSymm;
        firePropertyChange("symmetric", old, Boolean.valueOf(symmetric));
    }

    /** Sets all parameters from the given object to the current one.
     * @param temp The object to copy from.
     */
    public void copyFrom(final JaxoPLine temp) {
        super.copyFrom(temp);
        this.freq = temp.getFrequency();
        this.symmetric = temp.isSymmetric();
    }

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

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

        if (comp instanceof JaxoPLine) {
            final JaxoPLine line = (JaxoPLine) comp;
            if ((line.isSymmetric() == isSymmetric()) && super.isCopy(line)) {
                isCopy = true;
            }
        }

        return isCopy;
    }

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

        final Point2D startPoint = getLaTexStartPoint(scale, canvasHeight);
        final Point2D endPoint = getLaTexEndPoint(scale, canvasHeight);

        if (((int) endPoint.getX() == (int) startPoint.getX())
                && ((int) endPoint.getY() == (int) startPoint.getY())) {
            return "%";
        }

        final float amplitude = getAmp() / (2.f * scale);
        final float wiggles = getLaTexWiggleNumber();
        final String options = getAxo4JOptions(scale);

        return "\\Photon" + options + "(" + D_FORMAT.format(startPoint.getX()) + ","
            + D_FORMAT.format(startPoint.getY()) + ")" + "("
            + D_FORMAT.format(endPoint.getX()) + ","
            + D_FORMAT.format(endPoint.getY()) + ")" + "{"
            + D_FORMAT.format(amplitude) + "}" + "{"
            + D_FORMAT.format(wiggles) + "}";
    }

    /** {@inheritDoc} */
    public float getFrequency() {
        return freq;
    }

    /** {@inheritDoc} */
    public void setWigglesFromFrequency(final float frequency) {
        this.freq = frequency;
        setWigglesFromFrequency();
    }

    /** {@inheritDoc} */
    public void setWigglesFromFrequency() {
        final int n = (int) Math.round(length() * getFrequency());
        setWiggles(n);
    }

    /** {@inheritDoc} */
    public void setFrequencyFromWiggles(final int wiggles) {
        setWiggles(wiggles);
        this.freq = (float) (wiggles / length());
    }

    /** {@inheritDoc} */
    @Override
    public void setPreferences() {
        super.setPreferences();
        setPaintArrow(false);
        setArrowPosition(0.f);
        setSymmetric(false);
        setWigglesFromFrequency(PHOTON_FREQ);
    }

    /** {@inheritDoc} */
    public void prepareEditPanel(final JaxoObjectEditPanel editPanel) {
        editPanel.add2PointsPanel(getPoints(), 0, 0);
        editPanel.addWigglePanel(getAmp(), getWiggles(), 1, 0);
        editPanel.addSymmPanel(isSymmetric(), 2, 0);
        editPanel.addStrokePanel(getStrokeWidth(), 0, 1);
        editPanel.addDoubleLinePanel(isDoubleLine(), getDLSeparation(), 1, 1);
        editPanel.addColorPanel(getColor(), JaxoObjectEditPanel.TYPE_LINE_COLOR, 2, 1);

        editPanel.setTitleAndIcon("Photon_line_parameters", "photon.png");
    }

      //
     // private methods
    //

    private float getLaTexWiggleNumber() {
        float n = (float) getWiggles();
        if (isSymmetric()) {
            n += 0.5f;
        }
        return n;
    }

    /** {@inheritDoc} */
    protected GeneralPath getObjectPath() {
        final GeneralPath gp = getGeneralPath();
        gp.reset();

        if (JaxoUtils.zero(freq)) {
            setFrequencyFromWiggles(getWiggles());
        } else {
            setWigglesFromFrequency();
        }

        if (isDoubleLine()) {
            final float dlsep = getDLSeparation() / 2.f;
            appendFullLine(gp, dlsep);
            appendFullLine(gp, -dlsep);
        } else {
            appendFullLine(gp, 0.f);
        }

        return gp;
    }

    private void appendFullLine(final GeneralPath gp, final float sep) {
        final float length = (float) getRadius();

        int n = 2 * getWiggles();
        if (isSymmetric()) {
            n += 1;
        }

        final float ts = length / n;

        final float sin = getRelh() / length;
        final float cos = getRelw() / length;

        final float c = 4.f / 3.f * ts / (float) Math.PI;
        float amp = -2.f / 3.f * getAmp();

        gp.moveTo(getX(), getY() + sep);
        float x0;

        for (int i = 1; i <= n; i++) {
            x0 = (i - 1) * ts;
            curveTo(gp, x0 + c, amp + sep, x0 + ts - c, amp + sep, x0 + ts, sep, cos, sin);
            amp = -amp;
        }
    }

    private void curveTo(final GeneralPath gp, final float x1, final float y1,
            final float x2, final float y2, final float x3, final float y3,
            final float cos, final float sin) {

        gp.curveTo(x1 * cos - y1 * sin + getX(), x1 * sin + y1 * cos + getY(),
                x2 * cos - y2 * sin + getX(), x2 * sin + y2 * cos + getY(),
                x3 * cos - y3 * sin + getX(), x3 * sin + y3 * cos + getY());
    }

    // Get the axodraw4j options set for this line

    /** {@inheritDoc} */
    protected String getAxo4JOptions(final float scale) {

        String optioncmd = "";

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

        return optioncmd;
    }
}
