using System;
using System.Collections;
using NUnit.Framework;
using Icarus.Logic;
using Icarus.Logic.Physics;

namespace Icarus.PhysicsEngineTester
{
	
	/// <summary>
	/// Contain unit tests for NUnit.
	/// All tests are written as following the test plan, section 3.2
	/// </summary>
	[TestFixture]
	public class PhysicsEngineTest
	{
		WorldObject testobj;
		Vector v;
		Point p;
		ArrayList al;
		
		public PhysicsEngineTest()
		{
			
		}
		
		[Test]
			/// <summary>
			/// Carries out test plan 3.2.2.1
			/// Creates a physics object with original location at the origin
			/// and inital velocity (2, 0, 0). Gravity is set to 0, so as not
			/// to upset the experiment. The physics object is run through the
			/// physics engine once. The final location should be (2, 0, 0).
		public void TestVelocity3221() 
		{
			al = new ArrayList();
			v = new Vector();
			p = new Point();
			testobj = new WorldObject();

			v.i = 2;
			v.j = 0;
			v.j = 0;
			testobj.Velocity = v;
			p.x = 0;
			p.y = 0;
			p.z = 0;
			testobj.Location = p;
			
			v = new Vector();
			v.i = 0;
			v.k =0;
			v.j=0;
			PhysicsSettings.Instance.sv_gravity = v;

			al.Add(testobj);
			PhysicsEngine.Instance.updateWorld((PhysicsObject[]) al.ToArray(typeof(PhysicsObject)));
			Assert.AreEqual(testobj.Location.x, 2);
			Assert.AreEqual(testobj.Location.y, 0);
			Assert.AreEqual(testobj.Location.z, 0);
		}

		[Test]
			/// <summary>
			/// Carries out test plan 3.2.2.2
			/// Creates a physics object with original location at the origin
			/// and inital angular velocity 2 rads/update
			/// Final angle should be 2 radians
			/// 
		public void TestAngularVelocity3222()
		{
			al = new ArrayList();
			v = new Vector();
			testobj = new WorldObject();

			v.i = 2;
			v.j = 0;
			v.j = 0;
			testobj.AngularVelocity = v;
			
			al.Add(testobj);
			PhysicsEngine.Instance.updateWorld((PhysicsObject[]) al.ToArray(typeof(PhysicsObject)));
			
			///TODO: Make some way to check angle,
			///then fix this test
			Assert.AreEqual(0, 1);
		}

		[Test]
			/// <summary>
			/// Carries out test plan 3.2.2.3
			/// Creates a physics object with inital location (0,0,0)
			/// and inital velocity (0,0,0). Sets inital accelleration
			/// to (0,0,2). Final velocity after 2 ticks of the physics
			/// engine should be (0,0,4). Final location should be
			/// (0,0,4). Gravity is set to 0 so as not to upset the 
			/// experiment
		public void TestAcceleration3223()
		{
			al = new ArrayList();
			v = new Vector();
			p = new Point();
			testobj = new WorldObject();
			
			v.i=0;
			v.j=0;
			v.j=2;
			testobj.Acceleration = v;
			v= new Vector();
			v.i = 0;
			v.j = 0;
			v.j = 0;
			testobj.Velocity = v;
			p.x = 0;
			p.y = 0;
			p.z = 0;
			testobj.Location = p;
				
			v = new Vector();
			v.i = 0;
			v.k =0;
			v.j=0;
			PhysicsSettings.Instance.sv_gravity = v;

			al.Add(testobj);
			PhysicsEngine.Instance.updateWorld((PhysicsObject[]) al.ToArray(typeof(PhysicsObject)));
			PhysicsEngine.Instance.updateWorld((PhysicsObject[]) al.ToArray(typeof(PhysicsObject)));
			
			Assert.AreEqual(testobj.Location.x, 0);
			Assert.AreEqual(testobj.Location.y, 0);
			Assert.AreEqual(testobj.Location.z, 4);
		
			Assert.AreEqual(testobj.Velocity.i, 0);
			Assert.AreEqual(testobj.Velocity.j, 0);
			Assert.AreEqual(testobj.Velocity.k, 4);
		}

		[Test]
			///<summary>
			/// Carries out test plan 3.2.2.4
			/// Creates a physics object with original location at the origin
			/// and inital angular velocity 0 rads/update. Initial angular
			/// acceleration is set to 2 rads/update.
			/// Final angle after 2 updates should be 4 radians, and final
			/// angular velocity should be 4 rads/update
		public void TestAngularAcceleration3224()
		{
			al = new ArrayList();
			testobj = new WorldObject();
			
			v = new Vector();
			v.i = 0;
			v.j = 0;
			v.j = 0;
			testobj.AngularVelocity = v;
			
			p = new Point();
			p.x = 0;
			p.y = 0;
			p.z = 0;
			testobj.Location = p;
			
			v = new Vector();
			v.i = 2;
			v.j = 0;
			v.j = 0;
			testobj.AngularAcceleration = v;

			al.Add(testobj);
			PhysicsEngine.Instance.updateWorld((PhysicsObject[]) al.ToArray(typeof(PhysicsObject)));
			
			///TODO: Make some way to check angle, then
			///fix this test						
			Assert.AreEqual(0, 1);
		}

		[Test]
			///<summary>
			///Carries out test plan 3.2.2.5
			///Places a test object at the origin, initally at rest, with
			///no acceleration. Gravity is set to (0,-6,0). After 2 ticks,
			///final acceleration should be (0,-6,0). Final velocity should
			///be (0,-12,0). Final position should be (0,-12,0).
		public void TestGravity3225()
		{
			al = new ArrayList();
			testobj = new WorldObject();
			
			
			p = new Point();
			p.x=0;
			p.y=0;
			p.z=0;
			testobj.Location = p;

			v = new Vector();
			v.i=0;
			v.j=0;
			v.k=0;
			testobj.Acceleration = v;
			testobj.Velocity = v;

			v = new Vector();
			v.i=0;
			v.j=-6;
			v.k=0;
			PhysicsSettings.Instance.sv_gravity = v;
		
			al.Add(testobj);
			PhysicsEngine.Instance.updateWorld((PhysicsObject[]) al.ToArray(typeof(PhysicsObject)));
			PhysicsEngine.Instance.updateWorld((PhysicsObject[]) al.ToArray(typeof(PhysicsObject)));
			
			Assert.AreEqual(testobj.Location.x, 0);
			Assert.AreEqual(testobj.Location.y, -12);
			Assert.AreEqual(testobj.Location.z, 0);

			Assert.AreEqual(testobj.Velocity.i, 0);
			Assert.AreEqual(testobj.Velocity.j, -12);
			Assert.AreEqual(testobj.Velocity.k, 0);

			Assert.AreEqual(testobj.Acceleration.i, 0);
			Assert.AreEqual(testobj.Acceleration.j, -6);
			Assert.AreEqual(testobj.Acceleration.k, 0);
		}

		[Test]
			///<summary>
			///Carries out test plan 3.2.2.6
			///Places an object at the origin at rest,
			///with A_i = (5, 0, 0). Gravity is set to 0.
			///Friction is set to .5
			///After 2 ticks, final velocity should be (5,0,0),
			///and final position should be (5,0,0)
		public void TestFriction3226() 
		{
			al = new ArrayList();
			testobj = new WorldObject();
			
			
			p = new Point();
			p.x=0;
			p.y=0;
			p.z=0;
			testobj.Location = p;

			v = new Vector();
			v.i=0;
			v.j=0;
			v.k=0;			
			testobj.Velocity = v;

			v=new Vector();
			v.i=5;
			v.j=0;
			v.k=0;
			testobj.Acceleration = v;
			
			v = new Vector();
			v.i=0;
			v.j=0;
			v.k=0;
			PhysicsSettings.Instance.sv_gravity = v;


			//TODO: Make some way to set friction, then fix this test
			Assert.AreEqual(1, 0);
		}

	}
}
