// Copyright (C) 2008-2012 Colin MacDonald
// No rights reserved: this software is in the public domain.

#include "testUtils.h"

using namespace irr;
using namespace core;

static bool testLines(line2df const & line1,
					  line2df const & line2,
					  bool expectedHit,
					  const vector2df & expectedIntersection)
{
	bool gotExpectedResult = true;

	logTestString("\nLine 1 = %.1f %.1f to %.1f %.1f \n",
		line1.start.X, line1.start.Y,
		line1.end.X, line1.end.Y);
	logTestString("Line 2 = %.1f %.1f to %.1f %.1f\n",
		line2.start.X, line2.start.Y,
		line2.end.X, line2.end.Y);

	vector2df intersection;
	logTestString("line1 with line2 = ");
	if(line1.intersectWith(line2, intersection))
	{
		logTestString("hit at %.1f %.1f - ",
			intersection.X, intersection.Y);

		if(!line1.isPointOnLine(intersection) || !line2.isPointOnLine(intersection))
		{
			logTestString("ERROR! point is not on both lines - ");
			gotExpectedResult = false;
		}

		if(expectedHit)
		{
			if(intersection == expectedIntersection)
			{
				logTestString("expected\n");
			}
			else
			{
				logTestString("unexpected intersection (expected %.1f %.1f)\n",
					expectedIntersection.X, expectedIntersection.Y);
				gotExpectedResult = false;
			}
		}
		else
		{
			logTestString("UNEXPECTED\n");
			gotExpectedResult = false;
		}
	}
	else
	{
		logTestString("miss - ");
		if(!expectedHit)
		{
			logTestString("expected\n");
		}
		else
		{
			logTestString("UNEXPECTED\n");
			gotExpectedResult = false;
		}
	}

	logTestString("line2 with line1 = ");
	if(line2.intersectWith(line1, intersection))
	{
		logTestString("hit at %.1f %.1f - ",
			intersection.X, intersection.Y);
		if(!line1.isPointOnLine(intersection) || !line2.isPointOnLine(intersection))
		{
			logTestString("ERROR! point is not on both lines - ");
			gotExpectedResult = false;
		}

		if(expectedHit)
		{
			if(intersection == expectedIntersection)
			{
				logTestString("expected\n");
			}
			else
			{
				logTestString("unexpected intersection (expected %.1f %.1f)\n",
					expectedIntersection.X, expectedIntersection.Y);
				gotExpectedResult = false;
			}
		}
		else
		{
			logTestString("UNEXPECTED\n");
			gotExpectedResult = false;
		}
	}
	else
	{
		logTestString("miss - ");
		if(!expectedHit)
		{
			logTestString("expected\n");
		}
		else
		{
			logTestString("UNEXPECTED\n");
			gotExpectedResult = false;
		}
	}

	return gotExpectedResult;
}

// Test the functionality of line2d>T>::intersectWith().
/** Validation is done with assert_log() against expected results. */
bool line2dIntersectWith(void)
{
	bool allExpected = true;

	// Crossing lines, horizontal and vertical
	allExpected &= testLines(line2df(vector2df(1,1),vector2df(1,3)),
							line2df(vector2df(0,2),vector2df(2,2)),
							true, vector2df(1,2));
	assert_log(allExpected);

	// Crossing lines, both diagonal
	allExpected &= testLines(line2df(vector2df(0,0),vector2df(2,2)),
							line2df(vector2df(0,2),vector2df(2,0)),
							true, vector2df(1,1));
	assert_log(allExpected);

	// Non-crossing lines, horizontal and vertical
	allExpected &= testLines(line2df(vector2df(1,1),vector2df(1,3)),
							line2df(vector2df(0,4),vector2df(2,4)),
							false, vector2df());
	assert_log(allExpected);

	// Non-crossing lines, both diagonal
	allExpected &= testLines(line2df(vector2df(0,0),vector2df(2,2)),
							line2df(vector2df(3,4),vector2df(4,3)),
							false, vector2df());
	assert_log(allExpected);

	// Meeting at a common point
	allExpected &= testLines(line2df(vector2df(0,0),vector2df(1,0)),
							line2df(vector2df(1,0),vector2df(2,0)),
							true, vector2df(1,0));
	assert_log(allExpected);
	allExpected &= testLines(line2df(vector2df(0,0),vector2df(1,0)),
							line2df(vector2df(1,0),vector2df(0,1)),
							true, vector2df(1,0));
	assert_log(allExpected);
	allExpected &= testLines(line2df(vector2df(0,0),vector2df(1,0)),
							line2df(vector2df(1,0),vector2df(0,-1)),
							true, vector2df(1,0));
	assert_log(allExpected);
	allExpected &= testLines(line2df(vector2df(0,0),vector2df(0,1)),
							line2df(vector2df(0,1),vector2df(1,1)),
							true, vector2df(0,1));
	assert_log(allExpected);
	allExpected &= testLines(line2df(vector2df(0,0),vector2df(0,1)),
							line2df(vector2df(0,1),vector2df(1,-1)),
							true, vector2df(0,1));
	assert_log(allExpected);
	allExpected &= testLines(line2df(vector2df(0,0),vector2df(0,1)),
							line2df(vector2df(0,1),vector2df(0,2)),
							true, vector2df(0,1));
	assert_log(allExpected);
	allExpected &= testLines(line2df(vector2df(0,0),vector2df(1,0)),
							line2df(vector2df(1,0),vector2df(2,0)),
							true, vector2df(1,0));
	assert_log(allExpected);
	allExpected &= testLines(line2df(vector2df(0,0),vector2df(1,1)),
							line2df(vector2df(1,1),vector2df(0,2)),
							true, vector2df(1,1));
	assert_log(allExpected);
	allExpected &= testLines(line2df(vector2df(0,0),vector2df(1,1)),
							line2df(vector2df(1,1),vector2df(2,0)),
							true, vector2df(1,1));
	assert_log(allExpected);
	allExpected &= testLines(line2df(vector2df(0,0),vector2df(1,1)),
							line2df(vector2df(1,1),vector2df(2,2)),
							true, vector2df(1,1));
	assert_log(allExpected);


	// Parallel lines, no intersection
	allExpected &= testLines(line2df(vector2df(0,0),vector2df(1,0)),
							line2df(vector2df(0,1),vector2df(1,1)),
							false, vector2df());
	assert_log(allExpected);
	allExpected &= testLines(line2df(vector2df(0,0),vector2df(0,1)),
							line2df(vector2df(1,0),vector2df(1,1)),
							false, vector2df());
	assert_log(allExpected);

	// Non parallel lines, no intersection
	allExpected &= testLines(line2df(vector2df(0,0),vector2df(1,0)),
							line2df(vector2df(0,1),vector2df(0,2)),
							false, vector2df());
	assert_log(allExpected);
	allExpected &= testLines(line2df(vector2df(0,0),vector2df(0,1)),
							line2df(vector2df(1,0),vector2df(2,0)),
							false, vector2df());
	assert_log(allExpected);

	// Coincident (and thus parallel) lines
	allExpected &= testLines(line2df(vector2df(0,0),vector2df(1,0)),
							line2df(vector2df(0,0),vector2df(1,0)),
							true, vector2df(0,0));
	assert_log(allExpected);
	allExpected &= testLines(line2df(vector2df(2,0),vector2df(0,2)),
							line2df(vector2df(2,0),vector2df(0,2)),
							true, vector2df(2,0));
	assert_log(allExpected);

	// Two segments of the same unlimited line, but no intersection
	allExpected &= testLines(line2df(vector2df(0,0),vector2df(1,1)),
							line2df(vector2df(2,2),vector2df(3,3)),
							false, vector2df());
	assert_log(allExpected);
	allExpected &= testLines(line2df(vector2df(0,0),vector2df(1,0)),
							line2df(vector2df(2,0),vector2df(3,0)),
							false, vector2df());
	assert_log(allExpected);
	allExpected &= testLines(line2df(vector2df(0,0),vector2df(0,1)),
							line2df(vector2df(0,2),vector2df(0,3)),
							false, vector2df());
	assert_log(allExpected);

	// Overlapping parallel lines
	allExpected &= testLines(line2df(vector2df(1,0),vector2df(2,0)),
							line2df(vector2df(0,0),vector2df(3,0)),
							true, vector2df(1.5f, 0));
	assert_log(allExpected);
	allExpected &= testLines(line2df(vector2df(0,1),vector2df(0,2)),
							line2df(vector2df(0,0),vector2df(0,3)),
							true, vector2df(0, 1.5f));
	assert_log(allExpected);
	allExpected &= testLines(line2df(vector2df(1,0),vector2df(2,0)),
							line2df(vector2df(0,0),vector2df(3,0)),
							true, vector2df(1.5f, 0));
	assert_log(allExpected);
	allExpected &= testLines(line2df(vector2df(0,1),vector2df(0,2)),
							line2df(vector2df(0,0),vector2df(0,3)),
							true, vector2df(0, 1.5f));
	assert_log(allExpected);
	allExpected &= testLines(line2df(vector2df(1,1),vector2df(2,2)),
							line2df(vector2df(0,0),vector2df(3,3)),
							true, vector2df(1.5f, 1.5f));
	assert_log(allExpected);
	allExpected &= testLines(line2df(vector2df(1,2),vector2df(2,1)),
							line2df(vector2df(0,3),vector2df(3,0)),
							true, vector2df(1.5f, 1.5f));
	assert_log(allExpected);
	allExpected &= testLines(line2df(vector2df(0,0),vector2df(10,8)),
							line2df(vector2df(2.5f,2.0f),vector2df(5.0f,4.0f)),
							true, vector2df(3.75f, 3.0f));
	assert_log(allExpected);
	allExpected &= testLines(line2df(vector2df(0,0),vector2df(2000,1000)),
							line2df(vector2df(2,1),vector2df(2.2f,1.4f)),
							true, vector2df(2.0f, 1.0f));
	assert_log(allExpected);

	if(!allExpected)
		logTestString("\nline2dIntersectWith failed\n");

	return allExpected;
}

bool getClosestPoint(void)
{
	// testcase that fails when integers are handled like floats
	irr::core::line2di line(-283, -372, 374, 289);
	irr::core::vector2di p1 = line.getClosestPoint( irr::core::vector2di(290,372) );
	irr::core::vector2di p2 = line.getClosestPoint( irr::core::vector2di(135,372) );
	if( p1 == p2 )
	{
		logTestString("getClosestPoint failed\n");
		return false;
	}

	return true;
}

bool testLine2d(void)
{
	bool allExpected = true;

	allExpected &= line2dIntersectWith();
	allExpected &= getClosestPoint();

	if(allExpected)
		logTestString("\nAll tests passed\n");
	else
		logTestString("\nFAIL!\n");

	return allExpected;
}