using System;
using System.Collections.Generic;
using System.Text;

using CategoryTheory;
using DiagramUI;

namespace DataPerformer
{
    /// <summary>
    /// This class performs most common operations
    /// </summary>
    public class DataPerformerOperations
    {

        protected IDataConsumer consumer;

        protected List<string> measurements = new List<string>();

        protected List<string> aliasNames = new List<string>();

        protected List<object[]> aliases = new List<object[]>();

        protected List<IMeasure> measures = new List<IMeasure>();
        


        #region Specific Members


        public void Transform(object[] input, object[] output)
        {
            for (int i = 0; i < input.Length; i++)
            {
                object[] al = aliases[i];
                IAlias a = al[0] as IAlias;
                string s = al[1] as string;
                a[s] = input[i];
            }
            Reset(consumer);
            consumer.UpdateChildrenData();
            for (int i = 0; i < output.Length; i++)
            {
                IMeasure m = measures[i];
                output[i] = m.Parameter();
            }
        }


        public static void UpdateChildernData(IDataConsumer consumer)
        {
            int n = consumer.Count;
            for (int i = 0; i < n; i++)
            {
                consumer[i].UpdateMeasurements();
            }
        }

        public void Set(IDataConsumer consumer, List<string> measurements, List<string> aliasNames)
        {
            aliases.Clear();
            measures.Clear();
            this.measurements = measurements;
            this.aliasNames = aliasNames;
            this.consumer = consumer;
            Set();
        }


        public void Set()
        {
            SetMeasurements(consumer, measurements, measures);
            SetAliases(consumer, aliasNames, aliases);
        }

        /// </summary>
        /// Resets data consumer
        /// </summary>
        /// <param name="consumer">The consumer</param>
        public static void Reset(IDataConsumer consumer)
        {
            if (consumer is IMeasurements)
            {
                IMeasurements mea = consumer as IMeasurements;
                mea.IsUpdated = false;
            }
            for (int i = 0; i < consumer.Count; i++)
            {
                IMeasurements m = consumer[i] as IMeasurements;
                m.IsUpdated = false;
                if (m is IDataConsumer)
                {
                    IDataConsumer c = m as IDataConsumer;
                    c.Reset();
                }
            }
        }

        /// <summary>
        /// Finds alias
        /// </summary>
        /// <param name="consumer">Data consumer</param>
        /// <param name="alias">Alias</param>
        /// <returns>Pair object[] {alias, name}</returns>
        public static object[] FindAlias(IDataConsumer consumer, string alias)
        {
            return findAlias(consumer, consumer, alias);
        }

 

        public static void SetMeasurements(IDataConsumer consumer, List<string> measures, List<IMeasure> measuresData)
        {
            measuresData.Clear();
            IAssociatedObject ac = consumer as IAssociatedObject;
            foreach (string ms in measures)
            {
                for (int i = 0; i < consumer.Count; i++)
                {
                    IMeasurements m = consumer[i];
                    IAssociatedObject ao = m as IAssociatedObject;
                    string on = PureDesktop.GetRelativeName(ac, ao) + ".";

                    for (int j = 0; j < m.Count; j++)
                    {
                        IMeasure mea = m[j];
                        string s = on + mea.Name;
                        if (s.Equals(ms))
                        {
                            measuresData.Add(mea);
                        }
                    }
                }
            }
        }

        /// <summary>
        /// Gets all aliases of consumer and all its children
        /// </summary>
        /// <param name="consumer">The consumer</param>
        /// <param name="list">List of aliases</param>
        public static void GetAliases(IDataConsumer consumer, List<string> list)
        {
            getAliases(consumer, consumer, list);
        }

        /// <summary>
        /// Gets all aliases of consumer and all its children
        /// </summary>
        /// <param name="consumer">The consumer</param>
        /// <param name="list">List of aliases</param>
        public static List<string> GetAliases(IDataConsumer consumer)
        {
            List<string> list = new List<string>();
            GetAliases(consumer, list);
            return list;
        }


        public static void SetAliases(IDataConsumer consumer, List<string> aliasNames, List<object[]> aliases)
        {
            List<string> al = new List<string>();
            GetAliases(consumer, al);
            for (int i = 0; i < aliasNames.Count; i++)
            {
                string an = aliasNames[i];
                object[] o = FindAlias(consumer, an);
                aliases.Add(o);
            }
        }


        private static void getAliases(IDataConsumer baseObject, IDataConsumer consumer, List<string> list)
        {
            IAssociatedObject ao = consumer as IAssociatedObject;
            PureObjectLabel.GetObjectAliases(ao, consumer, list);
            for (int i = 0; i < consumer.Count; i++)
            {
                object o = consumer[i];
                if (o is IDataConsumer)
                {
                    IDataConsumer c = o as IDataConsumer;
                    getAliases(consumer, c, list);
                }
                else
                {
                    PureObjectLabel.GetObjectAliases(ao, o, list);
                }
            }
        }



        /// <summary>
        /// Finds alias
        /// </summary>
        /// <param name="baseObject">Base object</param>
        /// <param name="consumer">Consumer</param>
        /// <param name="alias">Alias</param>
        /// <returns>Pair object[] {alias, name}</returns>
        public static object[] findAlias(IDataConsumer baseObject, IDataConsumer consumer, string alias)
        {
            IAssociatedObject ao = baseObject as IAssociatedObject;
            INamedComponent nc = PureObjectLabel.PrefixComponent(ao, consumer, alias);
            if ((nc != null) & (consumer is IAlias))
            {
                return new object[] { consumer, PureObjectLabel.Suffix(alias) };
            }
            for (int i = 0; i < consumer.Count; i++)
            {
                object o = consumer[i];
                if (o is IDataConsumer)
                {
                    IDataConsumer c = o as IDataConsumer;
                    object[] r = findAlias(baseObject, c, alias);
                    if (r != null)
                    {
                        return r;
                    }
                }
                else
                {
                    INamedComponent comp = PureObjectLabel.PrefixComponent(ao, o, alias);
                    if ((comp != null) & (o is IAlias))
                    {
                        return new object[] { o, PureObjectLabel.Suffix(alias) };
                    }
                }
            }
            return null;
        }

        static public List<string> GetAllMeasurements(IDataConsumer consumer, object type)
        {
            List<string> list = new List<string>();
            for (int i = 0; i < consumer.Count; i++)
            {
                IMeasurements m = consumer[i];
                IAssociatedObject ao = m as IAssociatedObject;
                IAssociatedObject th = consumer as IAssociatedObject;
                string on = PureDesktop.GetRelativeName(th, ao) + ".";
                for (int j = 0; j < m.Count; j++)
                {
                    IMeasure mea = m[j];
                    string s = on + mea.Name;
                    if (type == null)
                    {
                        list.Add(s);
                        continue;
                    }
                    if (mea.Type.Equals(type))
                    {
                        list.Add(s);
                    }
                }
            }
            return list;
        }


        #endregion

    }
}
