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

import java.awt.geom.Point2D;

import net.sf.jaxodraw.util.JaxoConstants;
import net.sf.jaxodraw.util.JaxoGeometry;
import net.sf.jaxodraw.util.graphics.JaxoGraphics2D;

/**
 *
 */
public abstract class Jaxo3PointObject extends JaxoParticleObject {
    /** Third point (index 2). */
    public static final int SELECT_P3 = 2;

    // private
    private static final long serialVersionUID = 2L;
    private static final int POINT_COUNT = 3;

    static {
        setTransient(Jaxo3PointObject.class, new String[] {"x3", "y3"});
    }

    /** The third point of this arc object. */
    private int x3;

    /** The third point of this arc object. */
    private int y3;


    /**
     * {@inheritDoc}
     *
     * @return 3.
     */
    @Override
    public int getPointCount() {
        return POINT_COUNT;
    }

    /** {@inheritDoc} */
    @Override
    public int getX(final int index) {
        if (index == SELECT_P3) {
            return x3;
        }
        return super.getX(index);
    }

    /** {@inheritDoc} */
    @Override
    public int getY(final int index) {
        if (index == SELECT_P3) {
            return y3;
        }
        return super.getY(index);
    }

    /** {@inheritDoc} */
    @Override
    public void setX(final int index, final int value) {
        if (index == SELECT_P3) {
            x3 = value;
        } else {
            super.setX(index, value);
        }
    }

    /** {@inheritDoc} */
    @Override
    public void setY(final int index, final int value) {
        if (index == SELECT_P3) {
            y3 = value;
        } else {
            super.setY(index, value);
        }
    }

    /**
     * Sets the x coordinate of the first click point of this arc.
     *
     * @param newx3 The x coordinate of the first click point of this arc.
     */
    public final void setX3(final int newx3) {
        setX(SELECT_P3, newx3);
    }

    /**
     * Returns the x coordinate of the first click point of this arc.
     * @return The x coordinate of the first click point of this arc.
     */
    public final int getX3() {
        return getX(SELECT_P3);
    }

    /**
     * Sets the y coordinate of the first click point of this arc.
     *
     * @param newy3 The y coordinate of the first click point of this arc.
     */
    public final void setY3(final int newy3) {
        setY(SELECT_P3, newy3);
    }

    /**
     * Returns the y coordinate of the first click point of this arc.
     * @return The y coordinate of the first click point of this arc.
     */
    public final int getY3() {
        return getY(SELECT_P3);
    }

    /**
     * Sets the points of this 3 point object.
     *
     * @param x1 The x coordinate of the first point.
     * @param y1 The y coordinate of the first point.
     * @param x2 The x coordinate of the second point.
     * @param y2 The y coordinate of the second point.
     * @param p3 The x coordinate of the third point.
     * @param q3 The y coordinate of the third point.
     * @deprecated unused. Use {@link #setLocation(int,int,int,int,int,int)} instead.
     */
    public final void set3Pts(final int x1, final int y1, final int x2, final int y2, final int p3, final int q3) {
        setLocation(x1, y1, x2, y2, p3, q3);
    }

    /**
     * Sets the points of this 3 point object.
     *
     * @param x1 The x coordinate of the first point.
     * @param y1 The y coordinate of the first point.
     * @param x2 The x coordinate of the second point.
     * @param y2 The y coordinate of the second point.
     * @param p3 The x coordinate of the third point.
     * @param q3 The y coordinate of the third point.
     */
    public final void setLocation(final int x1, final int y1, final int x2, final int y2, final int p3, final int q3) {
        setLocation(x1, y1, x2, y2);
        setX3(p3);
        setY3(q3);
    }

    /**
     * Sets all parameters from the given objet to the current one.
     *
     * @param temp The object to copy from.
     */
    public void copyFrom(final Jaxo3PointObject temp) {
        super.copyFrom(temp);
        setX3(temp.getX3());
        setY3(temp.getY3());
    }

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

        if (comp instanceof Jaxo3PointObject) {
            final Jaxo3PointObject tmp = (Jaxo3PointObject) comp;
            if ((tmp.getX3() == getX3()) && (tmp.getY3() == getY3())
                    && super.isCopy(tmp)) {
                isCopy = true;
            }
        }

        return isCopy;
    }

    /** {@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));
        h.paint(g2, getX3(), getY3(), isMarked(), !canBeSelected(SELECT_P3, editMode));
    }

    /** {@inheritDoc} */
    @Override
    public float smallestDistanceTo(final int px, final int py) {
        final float dist1 = super.smallestDistanceTo(px, py);
        final int distX = px - getX3();
        final int distY = py - getY3();
        final float dist2 = (float) Math.sqrt((distX * distX) + (distY * distY));

        return (dist1 < dist2) ? dist1 : dist2;
    }

    /** {@inheritDoc} */
    @Override
    public boolean canBeSelected(final int handle, final int mode) {
        return ((handle == SELECT_P1) || (handle == SELECT_P2)
            || (handle == SELECT_P3));
    }

    /** {@inheritDoc} */
    @Override
    public int getGrabbedHandle(final int clickX, final int clickY, final JaxoHandle h) {
        int selected = super.getGrabbedHandle(clickX, clickY, h);

        if (isAround(SELECT_P3, clickX, clickY, h)) {
            selected = SELECT_P3;
        }

        return selected;
    }

    /** {@inheritDoc} */
    @Override
    public void moveBy(final int deltaX, final int deltaY) {
        if ((deltaX != 0) || (deltaY != 0)) {
            setX3(getX3() + deltaX);
            setY3(getY3() + deltaY);
            super.moveBy(deltaX, deltaY);
        }
    }

    /** {@inheritDoc} */
    public void rescaleObject(final int orx, final int ory, final float scale) {
        final Point2D p1 = JaxoGeometry.scaledPoint(orx, ory, scale, getX(), getY());
        final Point2D p2 =
            JaxoGeometry.scaledPoint(orx, ory, scale, getX2(), getY2());
        final Point2D p3 =
            JaxoGeometry.scaledPoint(orx, ory, scale, getX3(), getY3());

        setLocation((int) Math.round(p1.getX()), (int) Math.round(p1.getY()),
            (int) Math.round(p2.getX()), (int) Math.round(p2.getY()),
            (int) Math.round(p3.getX()), (int) Math.round(p3.getY()));

        setAmp(Math.round(getAmp() * scale));
        setWiggles(Math.round(getWiggles() * scale));
    }

    /**
     * Determines if the three points lie exactly on one line.
     * Note that the result of this method is independent of the point order.
     *
     * @return true if the three points are co-linear.
     */
    protected boolean isOneLine() {
        final int area = (getX2() - getX()) * (getY3() - getY())
                - (getY2() - getY()) * (getX3() - getX());

        return (area == 0);
    }
}
