package cnp.ew.diagram;

import java.awt.*;
import java.util.*;
import cnp.ew.util.*;
import cnp.ew.lightweight.*;


public class CpDependentConnector implements CpConnector, CpObserver
{
    CpDiagrammableLc startGo, endGo;
    public CpDependentLineLc line;
    public boolean orthogonal = true;
    Rectangle startBounds, endBounds;
    Dimension overlapStart, overlapEnd;
    boolean linesFromCenterXStart, linesFromCenterYStart = false, linesFromCenterXEnd = false, linesFromCenterYEnd = false;

    public CpDependentConnector(CpDependentLineLc newLine)
    {
        this(newLine, true, false);
    }

    public CpDependentConnector(CpDependentLineLc newLine, boolean newOrthogonal, boolean newLinesFromCenter)
    {
        line = newLine;
        startBounds = endBounds = new Rectangle(0,0,0,0);
        orthogonal = newOrthogonal;
      //  linesFromCenterX = linesFromCenterY = newLinesFromCenter;
    }

    public void connect(CpDiagrammableLc from, CpDiagrammableLc to)
    {
        startGo = from;
        endGo = to;
        linesFromCenterXStart = startGo.getConnectionLinesFromCenterX();
        linesFromCenterYStart = startGo.getConnectionLinesFromCenterY();
        linesFromCenterXEnd = endGo.getConnectionLinesFromCenterX();
        linesFromCenterYEnd = endGo.getConnectionLinesFromCenterY();
        overlapStart = startGo.getConnectionOverlap();
        overlapEnd = startGo.getConnectionOverlap();

        startGo.getDiagram().add(line);

        line.setPoints(calculatePoints());
        startGo.addObserver(this);
        endGo.addObserver(this);
    }

/*    public void setOverlap(Dimension d)
    {
        overlap = d;
    }

    public void setLinesFromCenter(boolean x, boolean y)
    {
        linesFromCenterX = x;
        linesFromCenterY = y;
    }
    */

    public void update(CpObservable o, int facet, Object arg)
    {
        if (facet == line.LC_DELETED) {
            // This is not good enough.  We should removeObserver(this) on both start and endGo.  null the line and avoid doing this if the line is null.
            line.remove();
        }
        if (!startBounds.equals(startGo.boundsDiagram()) || !endBounds.equals(endGo.boundsDiagram())) {
            line.setPoints(calculatePoints());
        }
    }

    Vector calculatePoints()
	{
	    Vector points = new Vector();

	    int overlapX, overlapY, startX, startY, endX, endY, splitX, splitY;

	    startBounds = startGo.boundsDiagram();
        int startGoLeft = startBounds.x;
        int startGoRight = startBounds.x + startBounds.width;
        int startGoTop = startBounds.y;
        int startGoBottom = startBounds.y + startBounds.height;
        endBounds = endGo.boundsDiagram();
        int endGoLeft = endBounds.x;
        int endGoRight = endBounds.x + endBounds.width;
        int endGoTop = endBounds.y;
        int endGoBottom = endBounds.y + endBounds.height;


	    overlapY = Math.max(startGoTop, endGoTop) - Math.min(startGoBottom, endGoBottom);
	    overlapX = Math.max(startGoLeft, endGoLeft) - Math.min(startGoRight, endGoRight);

        int x1, x2, y1, y2;

        if ((overlapX < 0) & (overlapY < 0)) {
            return points;
        }
	    if (overlapX > overlapY) {  // Primarily right left
	        x1 = Math.min(startGoRight, endGoRight);
	        x2 = Math.max(startGoLeft, endGoLeft);
	        if (!(linesFromCenterYStart || linesFromCenterYEnd) && overlapY < -(overlapStart.height + overlapEnd.height)) {
	            y1 = y2 = Math.max(startGoTop, endGoTop) - overlapY / 2;
	            splitX = -1;
	        } else {
	            splitX = x1 + (x2 - x1) / 2;
                if (linesFromCenterYStart) {
                    y1 = startGoTop + startBounds.height / 2;
                } else if (startGoTop < endGoTop) {
                    y1 = startGoBottom - overlapStart.height;
                } else {
                    y1 = startGoTop + overlapStart.height;
                }
                if (linesFromCenterYEnd) {
                    y2 = endGoTop + endBounds.height / 2;
                } else if (startGoTop < endGoTop) {
                    y2 = endGoTop + overlapEnd.height;
                } else {
                    y2 = endGoBottom - overlapEnd.height;
                }
	        }
	        if (x1 == startGoRight) {
	            startX = x1;  startY = y1;
	            endX = x2; endY = y2;
	        } else {
	            startX = x2; startY = y1;
	            endX = x1; endY = y2;
	        }
            if (orthogonal && splitX != -1) {
                points.addElement(new Point(startX, startY));
                points.addElement(new Point(splitX, startY));
                points.addElement(new Point(splitX, endY));
                points.addElement(new Point(endX, endY));
            }
	    } else {
            y1 = Math.min(startGoBottom, endGoBottom);
	        y2 = Math.max(startGoTop, endGoTop);
	        x1 = x2 = splitY = -99999;
	        if (!(linesFromCenterXStart && linesFromCenterXEnd) && overlapX < -(overlapStart.width + overlapEnd.width)) {
	            // Put this logic in left to right lines too
	            if (linesFromCenterXStart) {
	                x1 = x2 = startGoLeft + startBounds.width / 2;
	            } else if (linesFromCenterXEnd) {
	                x1 = x2 = endGoLeft + endBounds.width / 2;
	            } else {
    	            x1 = x2 = Math.max(startGoLeft, endGoLeft) - overlapX / 2;
    	        }
	            splitY = -1;
    	    }
    	    // Ugly and not even right
    	    if (x1 == -99999 || x1 < startGoLeft || x1 < endGoLeft || x1 > startGoRight || x1 > endGoRight) {
	            splitY = y1 + (y2 - y1) / 2;
                if (linesFromCenterXStart) {
                    x1 = startGoLeft + startBounds.width / 2;
                } else if (startGoLeft < endGoLeft) {
                    x1 = startGoRight - overlapStart.width;
                } else {
                    x1 = startGoLeft + overlapStart.width;
                }
                if (linesFromCenterXEnd) {
                    x2 = endGoLeft + endBounds.width / 2;
                } else if (startGoLeft < endGoLeft) {
                    x2 = endGoLeft + overlapEnd.width;
                } else {
                    x2 = endGoRight - overlapEnd.width;
                }
            }
	        if (y1 == startGoBottom) {
	            startX = x1;  startY = y1;
	            endX = x2; endY = y2;
	        } else {
	            startX = x1; startY = y2;
	            endX = x2; endY = y1;
	        }
            if (orthogonal && splitY != -1) {
                points.addElement(new Point(startX, startY));
                points.addElement(new Point(startX, splitY));
                points.addElement(new Point(endX, splitY));
                points.addElement(new Point(endX, endY));
            }
	    }
	    if (points.isEmpty()) {
            points.addElement(new Point(startX, startY));
            points.addElement(new Point(endX, endY));
        }
        return points;
	}

        //  LABEL POSITIONING:
        //
        //            int textX = xForY(startY + 15 + g.getFontMetrics().getAscent());
       //             g.drawString(startText, textX - (g.getFontMetrics().stringWidth(startText) / 2), startY + 15 + g.getFontMetrics().getAscent());
       //             textX = xForY(endY - 15);
       //             g.drawString(endText, textX - (g.getFontMetrics().stringWidth(endText) / 2), endY - 20);

       /*  ARROW DRAWING:

                       int rise = end.y - start.y;
                int run = end.x - start.x;

             //   int xDistance = Math.sqrt(rise * rise + run * run);
            //    xDistance = run * 5 / xDistance;

                double angle = Math.atan((double)rise / (double)run);
                int px = end.x + (int)(Math.cos(angle + Math.PI) * 10);
                int py = end.y + (int)(Math.sin(angle + Math.PI) * 10);
             //   System.out.println("px = " + px + " py = " + py);
             //   g.setColor(Color.red);
             //   g.drawLine(end.x, end.y, end.x + px, end.y + py);
             //   g.setColor(Color.black);

                int p1x = px + (int)(Math.cos(angle + Math.PI / 2) * 4);
                int p1y = py + (int)(Math.sin(angle + Math.PI / 2) * 4);

                int p2x = px + (int)(Math.cos(angle + -Math.PI / 2) * 4);
                int p2y = py + (int)(Math.sin(angle + -Math.PI / 2) * 4);

                Polygon arrow = new Polygon();
                arrow.addPoint(endX, endY);
                arrow.addPoint(p1x, p1y);
                arrow.addPoint(p2x, p2y);
                arrow.addPoint(endX, endY);
                g.fillPolygon(arrow);
         */
}