using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.Serialization;


using CategoryTheory;

namespace Motion6D
{
    [Serializable()]
    public class RigidReferenceFrame : IReferenceFrame, ISerializable, ICategoryObject, IPostSetArrow
    {

        #region Fields


        protected ReferenceFrame own = Motion6DFrame.Base;

        protected ReferenceFrame relative;

        private double[] relativePosition = new double[] { 0, 0, 0 };

        private double[] relativeQuaternion = new double[] { 1, 0, 0, 0 };

        List<IPosition> children = new List<IPosition>();

        protected object obj;

        protected bool isSerialized = false;

        protected IReferenceFrame parent;

        protected object parameters;

        #endregion

        #region Ctor

        public RigidReferenceFrame()
        {
        }

        protected RigidReferenceFrame(SerializationInfo info, StreamingContext context)
        {
            relativePosition = info.GetValue("Position", typeof(double[])) as double[];
            relativeQuaternion = info.GetValue("Quaternion", typeof(double[])) as double[];
            isSerialized = true;
        }


        #endregion

        #region ISerializable Members

        public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            info.AddValue("Position", relativePosition, typeof(double[]));
            info.AddValue("Quaternion", relativeQuaternion, typeof(double[]));
        }

        #endregion

        #region IReferenceFrame Members

  
        ReferenceFrame IReferenceFrame.Own
        {
            get { return own; }
        }

        List<IPosition> IReferenceFrame.Children
        {
            get { return children; }
        }

 

        #endregion

        #region IPosition Members

        double[] IPosition.Position
        {
            get { return own.Position; }
        }
  
        public virtual IReferenceFrame Parent
        {
            get
            {
                return parent;
            }
            set
            {
                if (value != null & parent != null)
                {
                    throw new Exception("Parent");
                }
                parent = value;
                if (value == null)
                {
                    own = Motion6DFrame.Base;
                    return;
                }
                if (isSerialized)
                {
                    isSerialized = false;
                    return;
                }
                IPostSetArrow post = this;
                post.PostSetArrow();
            }
        }

        public virtual object Parameters
        {
            get
            {
                return parameters;
            }
            set
            {
                parameters = value;
            }
        }



        public virtual void Update()
        {
            own.Set(BaseFrame, relative);
        }




        #endregion

        #region ICategoryObject Members

        ICategory ICategoryObject.Category
        {
            get { throw new Exception("The method or operation is not implemented."); }
        }

        ICategoryArrow ICategoryObject.Id
        {
            get { throw new Exception("The method or operation is not implemented."); }
        }

        #endregion

        #region IAssociatedObject Members

        object IAssociatedObject.Object
        {
            get
            {
                return obj;
            }
            set
            {
                obj = value;
            }
        }

        #endregion

        #region IPostSetArrow Members

        void IPostSetArrow.PostSetArrow()
        {
            CreateFrame();
            for (int i = 0; i < 3; i++)
            {
                relative.Position[i] = relativePosition[i];
            }
            for (int i = 0; i < 4; i++)
            {
                relative.Quaternion[i] = relativeQuaternion[i];
            }
            relative.SetMatrix();

        }

        #endregion

        #region Specific Members


        public double[] RelativePosition
        {
            get { return relativePosition; }
        }

        public double[,] RelativeMatrix
        {
            get
            {
                double[,] m = new double[3, 3];
                double[,] q = new double[4, 4];
                Vector3D.V3DOperations.CalculateMatrix(relativeQuaternion, m, q);
                return m;
            }
            set
            {
                Vector3D.V3DOperations.ConvertMatrixToQuaternion(relativeQuaternion, value);
            }
        }




        protected ReferenceFrame BaseFrame
        {
            get
            {
                if (parent != null)
                {
                    return parent.Own;
                }
                return Motion6DFrame.Base;
            }
        }

 


        protected virtual void CreateFrame()
        {
           if (!IsVelocity & !IsAngularVelocity)
            {
                relative = new ReferenceFrame();
                own = new ReferenceFrame();
            }
            else if (!IsVelocity)
            {
                relative = new RotatedFrame();
                own = new RotatedFrame();
            }
            else
            {
                relative = new Motion6DFrame();
                own = new Motion6DFrame();
            }
        }

        protected virtual bool IsVelocity
        {
            get
            {
                if (parent == null)
                {
                    return true;
                }
                return parent.Own is IVelocity;
            }
        }

        protected virtual bool IsAngularVelocity
        {
            get
            {
                if (parent == null)
                {
                    return true;
                }
                return parent.Own is IAngularVelocity;
            }
        }




        #endregion

    }
}
