/*
 * @(#)ChopRoundRectangleConnector.java 5.1
 *
 */

package CH.ifa.draw.figures;

import java.awt.Point;
import java.awt.Rectangle;
import java.io.Serial;

import CH.ifa.draw.standard.ChopBoxConnector;
import CH.ifa.draw.util.Geom;
import de.renew.draw.storables.ontology.Figure;

/**
 * A ChopRoundRectangleConnector locates a connection point by
 * chopping the connection at the round rectangle defined by the
 * figure's display box.
 */
public class ChopRoundRectangleConnector extends ChopBoxConnector {
    /** Logger used by the class */
    public static final org.apache.log4j.Logger LOGGER =
        org.apache.log4j.Logger.getLogger(ChopRoundRectangleConnector.class);

    /*
     * Serialization support.
     */
    @Serial
    private static final long serialVersionUID = -3165091511154766610L;

    /**
     * Constructs a new ChopRoundRectangleConnector.
     */
    public ChopRoundRectangleConnector() {}

    /**
     * Constructs a new ChopRoundRectangleConnector.
     *
     * @param owner the figure to which this connector is attached
     */
    public ChopRoundRectangleConnector(Figure owner) {
        super(owner);
    }

    /**
     * Method to calculate the points where a given line intersects a given Ellipse.
     *
     * @param rx semi-axis in x-direction
     * @param ry semi-axis in y-direction
     * @param a Slope of the line
     * @param b y intersection of the line
     * @return Array including both points of intersection
     */
    protected Point[] intersectEllipseLine(double rx, double ry, double a, double b) {
        /* Solve quadratic equation according to abc formula */
        double aa = a * a * rx * rx + ry * ry;
        double bb = 2 * b * a * rx * rx;
        double cc = (b * b - ry * ry) * rx * rx;

        /* x1 and x2 are real roots of aa * x * x + bb * x + cc */
        double sqrt = Math.sqrt(bb * bb - 4 * aa * cc);
        double x1 = (-bb + sqrt) / (2 * aa);
        double x2 = (-bb - sqrt) / (2 * aa);

        double y1 = b + a * x1;
        double y2 = b + a * x2;

        // logger.debug("a:" + a + " b:" + b + " aa:" + aa + " bb:" + bb + " cc:" + cc);
        return new Point[] { new Point((int) x1, (int) y1), new Point((int) x2, (int) y2) };
    }

    @Override
    protected Point chop(Figure target, Rectangle source) {
        Rectangle r = target.displayBox();
        Point from = Geom.center(source);
        Point to = Geom.center(r);

        Point targetArc = ((RoundRectangleFigure) target).getArc();

        double angle =
            Geom.pointToAngle(r, from) + (r.intersection(source).equals(r) ? Math.PI : 0);
        Point toMeet = Geom.angleToPoint(r, angle);

        int leftX = r.x + targetArc.x / 2;
        int rightX = r.x + r.width - targetArc.x / 2;
        int topY = r.y + targetArc.y / 2;
        int downY = r.y + r.height - targetArc.y / 2;
        boolean left = toMeet.x < leftX;
        boolean right = toMeet.x > rightX;
        boolean top = toMeet.y < topY;
        boolean down = toMeet.y > downY;

        // if the connection intersects the rounded area...
        if ((left || right) && (top || down)) {
            int xc; // center of ellipse
            int yc; // center of ellipse
            if (left) {
                xc = leftX;
            } else {
                xc = rightX;
            }
            if (top) {
                yc = topY;
            } else {
                yc = downY;
            }

            double a = (double) (from.y - to.y) / (double) (from.x - to.x);
            double b = (from.y - yc) - (from.x - xc) * a;

            Point[] intersections =
                intersectEllipseLine(targetArc.x / 2.0, targetArc.y / 2.0, a, b);

            Point intersection;

            if (left ^ (intersections[0].x < intersections[1].x)) {
                intersection = intersections[1];
            } else {
                intersection = intersections[0];
            }

            return new Point(intersection.x + xc, intersection.y + yc);

        } else {
            return toMeet;
        }
    }
}