package drawing;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Point;

/**
 * This class represents a link for the uml diagram
 * @author MC
 */
public class Link {
	/**
	 * the start point for the link
	 */
	private Point start;
	/**
	 * the end point of the link
	 */
	private Point end;
	/**
	 * the right vertex of the diamond
	 */
	private Point right;
	/**
	 * the left vertex of the diamond
	 */
	private Point left;
	/**
	 * the bottom vertex of the diamond
	 */
	private Point bottom;
	/**
	 * the y axes diamond length 
	 */
	static final double axeY = 20;
	/**
	 * the x axes diamond length
	 */
	static final double axeX = 10;
	/**
	 * the classunit where the link starts
	 */
	public UnitClass startUnit;
	/**
	 * the classUnit where the link ends
	 */
	public UnitClass endUnit;
	/**
	 * the instances number of the end unit
	 */
	public int nbInstance;
	/**
	 * the instances temporary number of the end unit 
	 */
	public int nbInstanceTemp;
	
	public boolean autoRefers;
	/**
	 * constructor
	 * @param startU
	 * @param endU
	 */
	public Link(UnitClass startU, UnitClass endU){
		startUnit = startU;
		endUnit = endU;
		start = new Point();
		end = new Point();
		
		nbInstance = 1;
		nbInstanceTemp = 1;
		if(startUnit.isEqual(endUnit)){
			autoRefers = true;
			upDateCoordinatesAutoRef();
			
		}
		else{
			autoRefers = false;
			upDateCoordinates2();
		}
	}
	
	/**
	 * constractor
	 * @param x1
	 * @param y1
	 * @param x2
	 * @param y2
	 */
	public Link(int x1, int y1, int x2, int y2){
		start = new Point(x1, y1);
		end = new Point(x2, y2);
		nbInstance = 1;
		computePath();
	}
	/**
	 * determines whether the link is equal to l
	 * @param l
	 * @return
	 */
	public boolean isEqual(Link l){
		if(l.startUnit.isEqual(startUnit) && l.endUnit.isEqual(endUnit))
			return true;
		else
			return false;
	}
	/**
	 * computes the coordinates of the top bottom left right and end vertices
	 *
	 */
	private void computePath(){
		double x1, y1, x2, y2;
		x1 = start.x;
		y1 = start.y;
		x2 = end.x;
		y2 = end.y;
		
		Point center;
		//Point vectU;
		double x;
		double y;
		double p1p2;
		p1p2 = Math.sqrt((x1 - x2)*(x1 - x2) + (y1 - y2)*(y1 - y2));
		x = x1 + (axeY/(2*p1p2))*(x2 - x1);
		y = y1 + (axeY/ (2*p1p2))*(y2 - y1);
		center = new Point((int)Math.round(x), (int)Math.round(y));
		bottom = new Point((int)Math.round(2*x - x1), (int)Math.round(2*y - y1));
		
		x = (double)(- y1 + y2)/(double)(center.x * (x1 - x2) + center.y * (y1 - y2));
		y = (double)(x1 - x2)/(double)(center.x * (x1 - x2) + center.y * (y1 - y2));
		
		if (y == 0){
			right = new Point((int)Math.round((double) axeX/2 + center.x), (int)Math.round(center.y));
			
		}
		else if(x == 0)
		{
			right = new Point((int)Math.round(center.x), (int)Math.round(center.y + (double)axeX/2));
		}
		else
		{
			right = new Point((int)Math.round( (double)axeX/2 * x/Math.sqrt(x*x+y*y) + center.x), (int)Math.round( (double)axeX/2 * y/Math.sqrt(x*x+y*y) + center.y));
		}
		left = new Point(2*center.x - right.x, 2*center.y - right.y);
	}
	/**
	 * updates the link coordinates
	 *
	 */
	public void upDateCoordinates(){
		if(!autoRefers)
			upDateCoordinates2();
		else
			upDateCoordinatesAutoRef();
	}
	private void upDateCoordinatesAutoRef(){
		start.x = startUnit.x + startUnit.getWidth();
		start.y = startUnit.y + startUnit.getHeight()/6;
		end.x = start.x + (int)((double)(4*axeY)/3);
		end.y = start.y;
		computePath();
	}	
	private void upDateCoordinates2(){
		double xs, ys, xe, ye;
		double a = 0;
		double b = 0;
		xs = startUnit.x + (double)startUnit.getWidth()/2;
		ys = startUnit.y + (double)startUnit.getHeight()/2;
		xe = endUnit.x + (double)endUnit.getWidth()/2;
		ye = endUnit.y + (double)endUnit.getHeight()/2;
		
		if(xs != xe){
			a = (ys - ye)/(xs - xe);
			b = ys - a*xs;
		}
				
		
		int pos = startUnit.position(endUnit);
		//left
		if(pos == 4)
		{
			xe = endUnit.x;
			ye = a*xe + b;
		}
		//right
		else if(pos == 3)
		{
			xe = endUnit.x + endUnit.getWidth();
			ye = a * xe + b;
		}
		//top
		else if(pos == 1)
		{	
			ye = endUnit.y + endUnit.getHeight();
			if(a != 0 && xe != xs){					
				xe = (ye - b)/a;
			}				
		}
		//bottom
		else if(pos == 2)
		{
			ye = endUnit.y;
			if(a != 0 && xe != xs){
				xe = (ye - b)/a;
			}			
		}
		else{
			System.out.println("hi");
		}
		
		pos = endUnit.position(startUnit);
		if(pos == 1)
		{	
			ys = startUnit.y + startUnit.getHeight();
			if(a != 0 && xe != xs){							
				xs = (ys - b)/a;
			}			
		}
		else if(pos == 2 && xe != xs)
		{
			ys = startUnit.y;
			if(a != 0){
				xs = (ys - b)/a;
			}			
		}
		else if(pos == 4)
		{
			xs = startUnit.x;
			ys = a*xs + b;
		}
		else if(pos == 3)
		{
			xs = startUnit.x + startUnit.getWidth();
			ys = a * xs + b;
		}
		
		start.x = (int)Math.round(xs);
		start.y = (int)Math.round(ys);
		end.x = (int)Math.round(xe);
		end.y = (int)Math.round(ye); 
		
		computePath();
		
	}
	/**
	 * @return  Returns the right.
	 * @uml.property  name="right"
	 */
	public Point getRight(){
		return right;
	}
	/**
	 * @return  Returns the left.
	 * @uml.property  name="left"
	 */
	public Point getLeft(){
		return left;
	}
	/**
	 * @return  Returns the bottom.
	 * @uml.property  name="bottom"
	 */
	public Point getBottom(){
		return bottom;
	}
	/**
	 * draws the link
	 * @param g2d
	 */
	public void draw(Graphics2D g2d){
		
		g2d.drawLine(start.x, start.y, left.x, left.y);
		g2d.drawLine(start.x, start.y, right.x, right.y);
		g2d.drawLine(bottom.x, bottom.y, left.x, left.y);
		g2d.drawLine(bottom.x, bottom.y, right.x, right.y);
		g2d.drawLine(bottom.x, bottom.y, end.x, end.y);
		
		if(autoRefers){
			int temp = (2*UnitClass.height)/3;
			g2d.drawLine(end.x, end.y, end.x, end.y - temp);
			int temp2 = (int)((double)(5 * axeY)/3);
			g2d.drawLine(end.x - temp2, end.y - temp, end.x, end.y - temp);
			g2d.drawLine(end.x - temp2, end.y - temp, end.x- temp2, startUnit.y);
			
		}
		else{
			g2d.setColor(Color.BLACK);
			g2d.drawString(""+nbInstance,end.x + 2, end.y - 1 );
		}
	}
	
}
