using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Azimuth;
using Lodestone;

namespace Lodestone.UnitTests
{
    public class FrameTests : UnitTestSharp.TestFixture
    {
        readonly Lodestone.Frame a = new Frame
        {
            Position = new Vector(-10, 10),
            Velocity = new Vector(-13, 26),
            Acceleration = new Vector(-16, 7),
            Orientation = 2,
            AngularVelocity = 7,
            AngularAcceleration = 10,
        };

        readonly Lodestone.Frame neg_a = new Frame
        {
            Position = new Vector(10, -10),
            Velocity = new Vector(13, -26),
            Acceleration = new Vector(16, -7),
            Orientation = -2,
            AngularVelocity = -7,
            AngularAcceleration = -10,
        };

        readonly Frame b = new Frame
        {
            Position = new Vector(-5, 5),
            Velocity = new Vector(7, 2),
            Acceleration = new Vector(11, 19),
            Orientation = -2,
            AngularVelocity = 4,
            AngularAcceleration = 1,
        };

        public void Equality()
        {
            CheckEqual(a, a.Clone());
        }

        public void Inequality_All()
        {
            CheckNotEqual(a, b);
        }

        public void Negate()
        {
            CheckEqual(neg_a, a.Scale(-1));
        }

        public void Add()
        {
            Frame c = new Frame
            {
                Position = new Vector(-15, 15),
                Velocity = new Vector(-6, 28),
                Acceleration = new Vector(-5, 26),
                Orientation = 0,
                AngularVelocity = 11,
                AngularAcceleration = 11,
            };

            CheckEqual(c, a.Add(b));
            CheckEqual(c, b.Add(a));
        }

        public void Subtract()
        {
            Frame amb = new Frame
            {
                Position = new Vector(-5, 5),
                Velocity = new Vector(-20, 24),
                Acceleration = new Vector(-27, -12),
                Orientation = 4,
                AngularVelocity = 3,
                AngularAcceleration = 9,
            };

            CheckEqual(amb, a.Subtract(b));
            CheckEqual(amb.Scale(-1), b.Subtract(a));
        }

        public void Scale()
        {
            Scalar scale = -4;
            Frame c = new Frame
            {
                Position = a.Position * scale,
                Velocity = a.Velocity * scale,
                Orientation = a.Orientation * scale,
                AngularVelocity = a.AngularVelocity * scale,
                AngularAcceleration = a.AngularAcceleration * scale,
                Acceleration = a.Acceleration * scale,
            };

            CheckEqual(c, a.Scale(scale));
        }

        public void AssignmentAdd()
        {
            IVectorSpace<Frame> frame = a.Clone();
            frame.AddAssignment(b);
            
            CheckEqual(frame, a.Add(b));
        }

        public void AssignmentSubtract()
        {
            IVectorSpace<Frame> frame = a.Clone();
            frame.SubtractAssignment(b);

            CheckEqual(frame, a.Subtract(b));
        }

        public void AssignmentScale()
        {
            Scalar scale = -2;
            IVectorSpace<Frame> frame = a.Clone();

            frame.ScaleAssignment(scale);

            CheckEqual(frame, a.Scale(scale));
        }

        public void InnerProduct()
        {
            CheckEqual(1503, a.InnerProduct(a));
        }

        public void UnChanged()
        {
            Frame c = new Frame
            {
                Position = new Vector(-10, 10),
                Velocity = new Vector(-13, 26),
                Acceleration = new Vector(-16, 7),
                Orientation = 2,
                AngularVelocity = 7,
                AngularAcceleration = 10,
            };

            CheckEqual(c, a);
        }

        public void ToString_Test()
        {
            string frameToString =
                "Position: <-10 : 10> " +
                "Velocity: <-13 : 26> " +
                "Acceleration: <-16 : 7> " +
                "Orientation: 2 " +
                "Angular Velocity: 7 " +
                "Angular Acceleration: 10";

            string aToString = a.ToString();

            CheckEqual(frameToString, aToString);
        }

        public void Transform()
        {
            Frame frame = new Frame { Position = new Vector(1, 2), Orientation = 2 };

            Matrix matrix = new Matrix(2, new Vector(1, 2));

            CheckEqual(matrix, frame.Transform);
        }

        public class VelocityAtPoint : UnitTestSharp.TestFixture
        {
            public void HandlesPosition()
            {
                var frame = new Frame{
                    Position = new Vector(1, 2),
                    Velocity = new Vector(3, 4),
                };

                CheckEqual(new Vector(3, 4), frame.VelocityAtPoint_LS(Vector.Zero));
            }

            public void HandlesOffset()
            {
                var frame = new Frame
                {
                    Position = new Vector(1, 2),
                    Velocity = new Vector(3, 4),
                };

                CheckEqual(new Vector(3, 4), frame.VelocityAtPoint_LS(new Vector(4, 7)));
            }

            public void HandlesRotatedOffset()
            {
                var frame = new Frame{
                    AngularVelocity = 1,
                };

                CheckEqual(new Vector(-2, 1), frame.VelocityAtPoint_LS(new Vector(1, 2)));
            }
        }
    }
}