/*--------------------------------------------------------------*
  Copyright (C) 2006-2015 OpenSim Ltd.

  This file is distributed WITHOUT ANY WARRANTY. See the file
  'License' for details on this and other legal matters.
*--------------------------------------------------------------*/

package org.omnetpp.figures.anchors;

import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.ScalableFigure;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.Rectangle;
import org.omnetpp.figures.CompoundModuleFigure;

/**
 * Creates a special chopbox anchor, where the reference point is not the owner figure's center
 *
 * @author rhornig
 */
public class NoncentralChopboxAnchor extends GateAnchor {

    // centrum point (relative in owner area ie 0.0 - 1.0)
    private double relRefPointX = 0.5f;
    private double relRefPointY = 0.5f;

    /**
     * An anchor where the connections can be directed to any particular point
     * in the owner's area (by default towards the center of the owner).
     * @param owner Owner figue
     */
    public NoncentralChopboxAnchor(IFigure owner) {
        super(owner);
    }

    /**
     * An anchor where the connections can be directed to any particular point
     * in the owner's area.
     * @param owner Owner figure
     * @param rX Relative place in owner (0.0 - 1.0)
     * @param rY Relative place in owner (0.0 - 1.0)
     */
    public NoncentralChopboxAnchor(IFigure owner, double rX, double rY) {
        super(owner);
        setRelRefPoint(rX, rY);
    }
    /**
     * @see org.eclipse.draw2d.AbstractConnectionAnchor#ancestorMoved(IFigure)
     */
    @Override
    public void ancestorMoved(IFigure figure) {
        if (figure instanceof ScalableFigure) return;
        super.ancestorMoved(figure);
    }

    @Override
    protected Rectangle getBox() {
        // if the owner is a label use only its icon area
        if (getOwner() instanceof CompoundModuleFigure) {
            Rectangle ib = ((CompoundModuleFigure)getOwner()).getHandleBounds();
            return ib;
        }

        return super.getBox();
    }


    // TODO maybe implement a constraint that the anchor should move only on allowed sides of the box
    @Override
    public Point getLocation(Point foreignRef) {

        Rectangle r = new Rectangle(getBox());
        r.translate(-1, -1);
        r.resize(1, 1);

        // get our own reference point (where the connection should head)
        Point o = getReferencePoint();

        // if no foreign reference point is given, use our own default reference point
        // the anchor's location if it is not attached to a connection
        if (foreignRef == null) {
//            long defX = Math.round(r.x + defaultX * r.width);
//            long defY = Math.round(r.y + defaultY * r.height);
//            Point defLoc = new Point(defX, defY);
//            getOwner().translateToAbsolute(defLoc);
//            return defLoc;
            return o;
        }


        if (r.isEmpty() || (foreignRef.x == o.x && foreignRef.y == o.y))
            return new Point(o.x, o.y);  //This avoids divide-by-zero

        double dx = foreignRef.x - o.x;
        double dy = foreignRef.y - o.y;

        //r.width, r.height, dx, and dy are guaranteed to be non-zero here.

        double scale = Math.min( Math.abs((dx > 0) ? (1.0f - relRefPointX)*r.width/dx : relRefPointX*r.width/dx),
                      Math.abs((dy > 0) ? (1.0f - relRefPointY)*r.height/dy : relRefPointY*r.height/dy));

        return new Point((int)Math.round(o.x + dx * scale), (int)Math.round(o.y + dy * scale));
    }

    /**
     * Reference point is the same where the connections are heading
     * @see org.eclipse.draw2d.ConnectionAnchor#getReferencePoint()
     */
    @Override
    public Point getReferencePoint() {
        Rectangle r = new Rectangle(getBox());
        r.translate(-1, -1);
        r.resize(1, 1);
        getOwner().translateToAbsolute(r);
        double oX = r.x + relRefPointX * r.width;
        double oY = r.y + relRefPointY * r.height;
        return new Point((int)Math.round(oX), (int)Math.round(oY));
    }

    public double getRelRefPointX() {
        return relRefPointX;
    }

    public void setRelRefPointX(double rX) {
        this.relRefPointX = rX;
        fireAnchorMoved();
    }

    public double getRelRefPointY() {
        return relRefPointY;
    }

    public void setRelRefPointY(double rY) {
        this.relRefPointY = rY;
        fireAnchorMoved();
    }

    public void setRelRefPoint(double rX, double rY) {
        this.relRefPointX = rX;
        this.relRefPointY = rY;
        fireAnchorMoved();
    }

}
