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

using CategoryTheory;
using DiagramUI;
using FormulaEditor;
using GeneralLinearMethod;
using AnalyticPolynom;


namespace DataPerformer
{
    /// <summary>
    /// Base class of data consumers
    /// </summary>
    [Serializable()]
    public class FormulaRegression : ICategoryObject, ISerializable
    {
        /// <summary>
        /// Auxilirary Variable
        /// </summary>
        private int a = 0;

        /// <summary>
        /// Selection
        /// </summary>
        private ArgumentMultiSelection selection = new ArgumentMultiSelection();

        /// <summary>
        /// Formula
        /// </summary>
        private VectorFormulaConsumer formula;

        /// <summary>
        /// Calculatror
        /// </summary>
        private FormulaStructuredCalculator calculator;

        /// <summary>
        /// Method
        /// </summary>
        private StructuredGLM method;


        /// <summary>
        /// Argument
        /// </summary>
        private double[] x;

        /// <summary>
        /// Dispersion
        /// </summary>
        private double[] d;

        /// <summary>
        /// Iteration delta
        /// </summary>
        private double[] dx;

        /// <summary>
        /// Associated object
        /// </summary>
        private object obj;

        /// <summary>
        /// Children measurements
        /// </summary>
        private ArrayList measurements = new ArrayList();

        /// <summary>
        /// Constuctor
        /// </summary>
        public FormulaRegression()
        {
        }

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="info">Serialization info</param>
        /// <param name="context">Streaming context</param>
        public FormulaRegression(SerializationInfo info, StreamingContext context)
        {
            a = (int)info.GetValue("A", typeof(int));
        }

        /// <summary>
        /// ISerializable interface implementation
        /// </summary>
        /// <param name="info">Serialization info</param>
        /// <param name="context">Streaming context</param>
        public void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            info.AddValue("A", a);
        }

        /// <summary>
        /// Creates correspond xml
        /// </summary>
        /// <param name="doc">document to create element</param>
        /// <returns>The created element</returns>
        /*public XmlElement CreateXml(XmlDocument doc)
        {
            XmlElement el = doc.CreateElement("FormulaRegression");
            return el;
        }
        */



        /// <summary>
        /// The category of this object
        /// </summary>
        public ICategory Category
        {
            get
            {
                return null;
            }
        }
        /// <summary>
        /// The identical arrow of this object
        /// </summary>
        public ICategoryArrow Id
        {
            get
            {
                return null;
            }
        }



        /// <summary>
        /// Associated object
        /// </summary>
        public object Object
        {
            get
            {
                return obj;
            }
            set
            {
                obj = value;
            }
        }

        /// <summary>
        /// Access to s - th parameter
        /// </summary>
        public double this[string s]
        {
            get
            {
                return calculator[s];
            }
            set
            {
                calculator[s] = value;
            }
        }

        /// <summary>
        /// Access to n th output parameter
        /// </summary>
        public double this[int n]
        {
            get
            {
                IMeasurements m = formula;
                return (double)m[n].Parameter();
            }
        }

        /// <summary>
        /// Updates itself
        /// </summary>
        public void Update()
        {
            foreach (IMeasurements mea in measurements)
            {
                mea.IsUpdated = false;
            }
            IMeasurements m = formula;
            m.UpdateMeasurements();
        }

        /// <summary>
        /// Adds selection
        /// </summary>
        /// <param name="selection">Selection to add</param>
        public void AddSelection(IArgumentSelection selection)
        {
            this.selection.AddSelection(selection);
        }

        /// <summary>
        /// Removes selection
        /// </summary>
        /// <param name="sel">Selection to remove</param>
        public void RemoveSelection(IArgumentSelection sel)
        {
            selection.RemoveSelection(sel);
        }


        /// <summary>
        /// Formula
        /// </summary>
        public VectorFormulaConsumer Formula
        {
            set
            {
                if (formula != null)
                {
                    throw new Exception("Formula already exists");
                }
                calculator = new FormulaStructuredCalculator(selection, value);
                formula = value;
                measurements.Clear();
                DataConsumer.GetMeasurements(formula, measurements);
                createMethod();
            }
            get
            {
                return formula;
            }
        }

        public FormulaStructuredCalculator Calculator
        {
            get
            {
                return calculator;
            }
        }

        /// <summary>
        /// Input selection
        /// </summary>
        public Series GetSeries(int i)
        {
            if (selection.GetSelection(i) is Series)
            {
                return selection.GetSelection(i) as Series;
            }
            return null;
        }

        /// <summary>
        /// Iterate
        /// </summary>
        /// <param name="n">Number of iterations</param>
        /// <param name="d">Array of variances</param>
        /// <returns>Square residual</returns>
        public double Iterate(int n, double[] d)
        {
            for (int i = 0; i < calculator.Parameters.Count; i++)
            {
                string p = calculator.Parameters[i] as string;
                x[i] = calculator[p];
            }
            double a = 0;
            for (int i = 0; i < n; i++)
            {
                a = method.Iterate(x, dx, d);
            }
            for (int i = 0; i < calculator.Parameters.Count; i++)
            {
                string p = calculator.Parameters[i] as string;
                calculator[p] = x[i];
            }
            return a;
        }

        /// <summary>
        /// The selection
        /// </summary>
        public IArgumentSelection Selection
        {
            get
            {
                return selection;
            }
        }


        /// <summary>
        /// Creates method
        /// </summary>
        public void createMethod()
        {
            method = new StructuredGLM(selection, calculator);
            x = new double[method.Dimension];
            d = new double[method.Dimension];
            dx = new double[d.Length];
            for (int i = 0; i < dx.Length; i++)
            {
                dx[i] = 0.000000001;
            }
        }

    }
}
