// Carnegie Mellon University
//   Information Networking Institute and
//   School of Computer Science
//
// Master Thesis: A Monitoring Tool for Overlay Network
// By: TungFai Chan and Annie Cheng
//
// File: Link.java
// Path: userInterfaces/graph/
// Description: Object extends VisualElement represent a link on the graph


package userInterfaces.graph;

import userInterfaces.*;

import java.awt.*;
import java.lang.*;


public class Link extends VisualElement {

    final double ACCURACY = 0.01;

    Node srcNode = null;
    Node destNode = null;

    double slope;

    Color color = null;
    Color mutualColor = null;
    Color selectColor = null;
    Color routeColor = null;

    double dx;
    double dy;

    boolean mutualAgreement = false;
    boolean isRoutingLink = false;


    public Link(Node src, Node dest, 
		Color col,        // (currently not used)
		Color mutCol,     // mutual
		Color selCol,     // select
		Color routCol) {  // forwarding trees

        srcNode = src;
        destNode = dest;
	color = col;
        mutualColor = mutCol;
        selectColor = selCol;
        routeColor = routCol;

        src.addChild(dest);
        dest.setParentNode(src);

        elementType = VisualElement.LINK;


    }

    public void calculateLocations() {

        dx = destNode.getCoordination().x - srcNode.getCoordination().x;
        dy = destNode.getCoordination().y - srcNode.getCoordination().y;
        double len = dx * dx + dy * dy;

        if (len == 0)
            return;

        len = Math.sqrt(len);
        dx /= len;
        dy /= len;
        dx *= Node.IMG_RADIUS;
        dy *= Node.IMG_RADIUS;

        if (destNode.getCoordination().x == srcNode.getCoordination().x)
            slope = Double.NEGATIVE_INFINITY;
        else
            slope = (double)(destNode.getCoordination().y - srcNode.getCoordination().y) /
                    (destNode.getCoordination().x - srcNode.getCoordination().x);

    }

    public void setSrcNode(Node src) {
        srcNode = src;
    }

    public void setDestNode(Node dest) {
        destNode = dest;
    }

    public void setColor(Color col) {
	color = col;
    }

    public void setSelectedColor(Color selCol) {
        selectColor = selCol;
    }

    public void setMutualAgreement(boolean mutual) {
        mutualAgreement = mutual;
    }

    public void setRoutingLink(boolean routing) {
        isRoutingLink = routing;
    }

    public Node getSrcNode() {
        return srcNode;
    }

    public Node getDestNode() {
        return destNode;
    }

    public Color getColor() {
	return color;
    }

    public Color getSelectedColor() {
        return selectColor;
    }

    public boolean getMutualAgreement() {
        return mutualAgreement;
    }

    public boolean isRoutingLink() {
        return isRoutingLink;
    }

    public void draw(Graphics g, int graphType) {
        calculateLocations();

        switch (graphType) {
            case NodeGraphPanel.NEIGHBOR_TYPE:
                if (selected) {
                    g.setColor(selectColor);
                    int x = (destNode.getCoordination().x + srcNode.getCoordination().x) / 2;
                    int y = (destNode.getCoordination().y + srcNode.getCoordination().y) / 2;
                }
                else {
                    if (mutualAgreement)
                        g.setColor(mutualColor);
                    else
                        g.setColor(color);
                }

                g.drawLine((int)(destNode.getCoordination().x - dx),
                           (int)(destNode.getCoordination().y - dy),
	                   (int)(srcNode.getCoordination().x + dx),
                           (int)(srcNode.getCoordination().y + dy));
                break;

            case NodeGraphPanel.ROUTING_TYPE:
                if (isRoutingLink) {
                    g.setColor(routeColor);
                    g.drawLine((int)(destNode.getCoordination().x - dx),
                               (int)(destNode.getCoordination().y - dy),
	                       (int)(srcNode.getCoordination().x + dx),
                               (int)(srcNode.getCoordination().y + dy));
                }
                break;
        }

    }

    public void clear() {
        srcNode.removeChild(destNode.getNodeID());
        destNode.setParentNode(null);
    }

    public boolean isOnThisLink(Coordination coord) {
        calculateLocations();
        double checkSlope1;
        double checkSlope2;

        if (coord.x == srcNode.getCoordination().x) {
            checkSlope1 = Double.NEGATIVE_INFINITY;
            checkSlope2 = Double.NEGATIVE_INFINITY;
        }
        else {
            checkSlope1 = (double)(coord.y - srcNode.getCoordination().y) /
                          (coord.x - srcNode.getCoordination().x);
            checkSlope2 = (double)(coord.y - destNode.getCoordination().y) /
                          (coord.x - destNode.getCoordination().x);
        }

        boolean inXRange = ((coord.x > srcNode.getCoordination().x + dx &&
                             coord.x < destNode.getCoordination().x - dx) ||
                            (coord.x < srcNode.getCoordination().x  + dx &&
                             coord.x > destNode.getCoordination().x - dx));
        boolean inYRange = ((coord.y > srcNode.getCoordination().y + dy&&
                             coord.y < destNode.getCoordination().y - dy) ||
                            (coord.y < srcNode.getCoordination().y + dy&&
                             coord.y > destNode.getCoordination().y - dy));
        double diff1 = Math.abs(slope - checkSlope1);
        double diff2 = Math.abs(slope - checkSlope2);
        selected = ((diff1 < ACCURACY || diff2 < ACCURACY) && diff1 < Math.abs(slope) &&
                    inXRange && inYRange);

        return selected;

    }

    public String toString() {
        return "Link: " + srcNode.getNodeLabel() + " -> " + destNode.getNodeLabel();
    }

}
