package cnp.ew.diagram;

import java.awt.*;

import cnp.ew.lightweight.*;

public class CpGraphicsUtilities
{
	public static Rectangle RectangleFromPoints(Point p1, Point p2)
	{
	    Point leftTop = new Point(Math.min(p1.x, p2.x), Math.min(p1.y, p2.y));
	    Point rightBottom = new Point(Math.max(p1.x, p2.x), Math.max(p1.y, p2.y));
	    return RectangleOriginCorner(leftTop, rightBottom);
	}

	public static Rectangle RectangleOriginCorner(Point p1, Point p2)
	{
	    return new Rectangle(p1.x, p1.y, p2.x - p1.x, p2.y - p1.y);
	}

	// HEY BONEHEAD!  WHy don't you make a LINE class.  Geez.

	public static double slope(Point start, Point end)
	{
	    return (double)(end.y - start.y) / (double)(end.x - start.x);
	}

	// Given two points, return the x coordinate that corresponds to a particular y coordinate on that line
	public static int xForY(Point start, Point end, int y)
    {
        return (int)(start.x + ((y - start.y) / slope(start, end)));
    }

    // Given two points, return the y coordinate that corresponds to a particular x coordinate on that line
    public static int yForX(Point start, Point end, int x)
    {
        return (int)(start.y + ((x - start.x) * slope(start, end)));
    }

    // Hit detection on a line
    public static boolean lineHit(Point start, Point end, int x, int y)
	{
	    int threshold = 3;

        if (Math.abs(start.x - end.x) < threshold) { // Vertical line
            return (Math.abs(start.x - x) < threshold) && ((y > start.y - threshold && y < end.y + threshold) || (y > end.y - threshold && y < start.y + threshold));
        } else if ((x > start.x - threshold && x < end.x + threshold) || (x > end.x - threshold && x < start.x + threshold)) {
	        if (Math.abs(yForX(start, end, x) - y) < threshold) {
	            return true;
	        }
	    }

	    return false;
	}


    /*  Taken from Robert Sedgewick, Algorithms in C++.
        Returns whether, in traveling from the first to the second	to the third point,
        we turn counterclockwise (+1) or not (-1)
    */

    static int ccw(Point p0, Point p1, Point p2)
    {

        int dx1, dx2, dy1, dy2;

        dx1 = p1.x - p0.x; dy1 = p1.y - p0.y;
        dx2 = p2.x - p0.x; dy2 = p2.y - p0.y;

        if (dx1*dy2 > dy1*dx2) {
            return +1;
        }
        if (dx1*dy2 < dy1*dx2) {
            return -1;
        }
        if ((dx1*dx2 < 0) || (dy1*dy2 < 0)) {
            return -1;
        }
        if ((dx1*dx1 + dy1*dy1) < (dx2*dx2 + dy2*dy2)) {
            return +1;
        }
        return 0;
    }

    static boolean intersect(Point line1p1, Point line1p2, Point line2p1, Point line2p2)
    {
        return (( ccw(line1p1, line1p2, line2p1)			* ccw(line1p1, line1p2, line2p2)) <= 0)
            && (( ccw(line2p1, line2p2, line1p1)			* ccw(line2p1, line2p2, line1p2)) <= 0);
    }

	public static boolean lineIntersectsRect(Point start, Point end, Rectangle rect)
    {
        if (intersect(new Point(rect.x, rect.y), new Point(rect.x + rect.width, rect.y), start, end)
            || intersect(new Point(rect.x + rect.width, rect.y), new Point(rect.x + rect.width, rect.y + rect.height), start, end)
            || intersect(new Point(rect.x + rect.width, rect.y + rect.height), new Point(rect.x, rect.y + rect.height), start, end)
            || intersect(new Point(rect.x, rect.y + rect.height), new Point(rect.x, rect.y), start, end)) {
            return true;	// line intersects outline of rectangle
        }
        //	Now the line could still be completely within the rectangle. This would also count as an intersection.

        return (start.x >= rect.x && start.x <= rect.x + rect.width
            && start.y >= rect.y && start.y <= rect.y + rect.height);
    }

}