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


using CategoryTheory;
using DiagramUI;
using DataPerformer;


namespace Motion6D
{
    [Serializable()]
    public class ReferenceFrameData : RigidReferenceFrame,
        IDataConsumer, IPostSetArrow
    {

        #region Fields

        protected object obj;
        protected List<string> parameters = new List<string>();
        protected double[,] qd = new double[4, 4];
        private double[] der = new double[4];
        protected List<IMeasurements> measurementsData = new List<IMeasurements>();
        protected IMeasure[] measurements = new IMeasure[7];

  
        #endregion

        #region Constructors

        public ReferenceFrameData()
        {
        }

        private ReferenceFrameData(SerializationInfo info, StreamingContext context)
        {
            parameters = info.GetValue("Parameters", typeof(List<string>)) as List<string>;
            isSerialized = true;
        }



        #endregion

        #region ISerializable Members

 
        #endregion

        #region IDataConsumer Members

        void IDataConsumer.Add(IMeasurements measurements)
        {
            measurementsData.Add(measurements);
        }

        void IDataConsumer.Remove(IMeasurements measurements)
        {
            measurementsData.Remove(measurements);
        }

        void IDataConsumer.UpdateChildrenData()
        {
            try
            {
                foreach (IMeasurements m in measurementsData)
                {
                    m.UpdateMeasurements();
                }
            }
            catch (Exception e)
            {
                PureDesktop.ThrowException(this, e);
            }
        }

        int IDataConsumer.Count
        {
            get { return measurementsData.Count; }
        }

        IMeasurements IDataConsumer.this[int n]
        {
            get { return measurementsData[n]; }
        }

        void IDataConsumer.Reset()
        {
            DataConsumer.Reset(this);
        }

        #endregion

        #region IPostSetArrow Members

        void IPostSetArrow.PostSetArrow()
        {
            setParameters();
            CreateFrame();
        }

        #endregion

        #region Overriden Members

        public override void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            info.AddValue("Parameters", parameters, typeof(List<string>));
        }


        public override IReferenceFrame Parent
        {
            get
            {
                return parent;
            }
            set
            {
                if (value != null & parent != null)
                {
                    throw new Exception("Root");
                }
                parent = value;
                if (parent == null)
                {
                    own = Motion6DFrame.Base;
                    return;
                }
                parent.Children.Add(this);
                if (!isSerialized)
                {
                    isSerialized = false;
                    return;
                }
                CreateFrame();
            }

        }


        public override void Update()
        {
            DataConsumer.Reset(this);
            IDataConsumer cons = this;
            cons.UpdateChildrenData();
            IPosition p = relative;
            double[] x = p.Position;
            for (int i = 0; i < 3; i++)
            {
                x[i] = (double) measurements[i].Parameter();    
            }
            if (relative is IVelocity)
            {
                IVelocity vel = relative as IVelocity;
                double[] v = vel.RevativeVelocity;
                for (int i = 0; i < 3; i++)
                {
                    IDerivation d = measurements[i] as IDerivation;
                    v[i] = d.Derivation;
                }
            }
            double[] qua = relative.Quaternion;
            for (int i = 0; i < qua.Length; i++)
            {
                IMeasure m = measurements[i + 3];
                qua[i] = (double)m.Parameter();
            }
            relative.SetMatrix();
            if (relative is IAngularVelocity)
            {
                IAngularVelocity av = relative as IAngularVelocity;
                double[] om = av.Omega;
                IOrientation or = relative as IOrientation;
                for (int i = 0; i < 4; i++)
                {
                    IDerivation d = measurements[i + 3] as IDerivation;
                    der[i] = d.Derivation;
                }
                Vector3D.V3DOperations.CalculateDynamics(or.Quaternion, der, om, qd); 
            }
            base.Update();
        }

        protected override bool IsAngularVelocity
        {
            get
            {
                if (!base.IsAngularVelocity)
                {
                    return false;
                }
                for (int i = 3; i < 7; i++)
                {
                    IMeasure m = measurements[i];
                    if (!(m is IDerivation))
                    {
                        return false;
                    }
                }
                return true;
            }
        }

        protected override bool IsVelocity
        {
            get
            {
                if (!base.IsVelocity)
                {
                    return false;
                }
                for (int i = 0; i < 3; i++)
                {
                    IMeasure m = measurements[i];
                    if (!(m is IDerivation))
                    {
                        return false;
                    }
                }
                return true;
            }
        }

        #endregion


        #region Specific Members

        public List<string> AllMeasurements
        {
            get
            {
                IDataConsumer c = this;
                List<string> list = new List<string>();
                for (int i = 0; i < c.Count; i++)
                {
                    IMeasurements m = c[i];
                    IAssociatedObject ao = m as IAssociatedObject;
                    string on = PureDesktop.GetRelativeName(this, ao) + ".";
                    for (int j = 0; j < m.Count; j++)
                    {
                        string s = on + m[j].Name;
                        list.Add(s);
                    }
                }
                return list;
            }
        }


        public List<string> Parameters
        {
            get
            {
                return parameters;
            }
            set
            {
                if (value.Count != 7)
                {
                    throw new Exception();
                }
                parameters = value;
            }

        }

        private void setParameters()
        {
            IDataConsumer c = this;
            for (int i = 0; i < parameters.Count; i++)
            {
                string p = parameters[i];
                for (int j = 0; j < c.Count; j++)
                {
                    IMeasurements m = c[j];
                    IAssociatedObject ao = m as IAssociatedObject;
                    string on = PureDesktop.GetRelativeName(this, ao) + ".";
                    for (int k = 0; k < m.Count; k++)
                    {
                        IMeasure mea = m[k];
                        string s = on + mea.Name;
                        if (s.Equals(p))
                        {
                            measurements[i] = mea;
                        }
                    }
                }
            }
        }

        #endregion
    }
}
