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

using FormulaEditor;
using CategoryTheory;

namespace DataPerformer
{
    [Serializable()]
    public class FormulaFilterIterator : FilterIterator, ISerializable, ICategoryObject, IPostSetArrow
    {
        #region Fields

        protected object obj;

        ObjectFormulaTree tree;

        Dictionary<string, string> variables = new Dictionary<string, string>();

        Dictionary<string, object> constants = new Dictionary<string, object>();

        Dictionary<char, IMeasure> measures = new Dictionary<char,IMeasure>();

        /// <summary>
        /// Formula arguments
        /// </summary>
        private ElementaryObjectArgument arg;


        string formula = "";

        #endregion

        #region Ctor

        public FormulaFilterIterator()
        {
        }

        protected FormulaFilterIterator(SerializationInfo info, StreamingContext context)
        {
            variables = info.GetValue("Variables", typeof(Dictionary<string, string>)) as Dictionary<string, string>;
            constants = info.GetValue("Constants", typeof(Dictionary<string, object>)) as Dictionary<string, object>;
            formula = info.GetValue("Formula", typeof(string)) as string;
        }

        #endregion

        #region ISerializable Members

        void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
        {
            info.AddValue("Variables", variables, typeof(Dictionary<string, string>));
            info.AddValue("Constants", constants, typeof(Dictionary<string, object>));
            info.AddValue("Formula", formula, typeof(string));
        }

        #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()
        {
            Set(variables);
        }

        #endregion

        #region Overriden Membres

        protected override bool? AllowNext
        {
            get 
            {
                if (tree == null)
                {
                    return null;
                }
                foreach (char c in measures.Keys)
                {
                    arg[c] = measures[c].Parameter();
                }
                foreach (string s in constants.Keys)
                {
                    arg[s[0]] = constants[s];
                }
                return (bool?)tree.Result; 
            }
        }

        #endregion

        #region Specific Members

        public string AllVariables
        {
            get
            {
                string s = "";
                try
                {
                    MathFormula f = MathFormula.FromString(MathSymbolFactory.Sizes, formula);
                    s = ElementaryObjectDetector.GetVariables(f);
                }
                catch (Exception)
                {
                }
                return s;
            }
        }

        public string Formula
        {
            get
            {
                return formula;
            }
            set
            {
                MathFormula f = MathFormula.FromString(MathSymbolFactory.Sizes, value);
                formula = value;
            }
        }

        /// <summary>
        /// Variables
        /// </summary>
        public string Constants
        {
            get
            {
                try
                {
                    string s = "";
                    MathFormula f = MathFormula.FromString(MathSymbolFactory.Sizes, formula);
                    string str = ElementaryObjectDetector.GetVariables(f);
                    foreach (char c in str)
                    {
                        if (!variables.ContainsKey("" + c) & s.IndexOf(c) < 0)
                        {
                            s += c;
                        }
                    }
                    return s;
                }
                catch (Exception)
                {
                }
                return "";
            }
            set
            {
                variables.Clear();
                constants.Clear();
                string s = "";
                MathFormula f = MathFormula.FromString(MathSymbolFactory.Sizes, formula);
                string str = ElementaryObjectDetector.GetVariables(f);
                double a = 0;
                foreach (char c in str)
                {
                    if (value.IndexOf(c) >= 0)
                    {
                        constants[c + ""] = a;
                    }
                    else
                    {
                        variables[c + ""] = "";
                    }
                }
            }
        }


        public string Variables
        {
            get
            {
                string s = AllVariables;
                string str = "";
                foreach (char c in s)
                {
                    if (!constants.ContainsKey(c + ""))
                    {
                        str += c;
                    }
                }
                return str;
            }
        }

        public Dictionary<string, string> VariableDictionary
        {
            get
            {
                return variables;
            }
            set
            {
                Set(value);
            }
        }

        public Dictionary<string, object> ConstDictionary
        {
            get
            {
                return constants;
            }
            set
            {
                constants = value;
            }
        }

        void Set(Dictionary<string, string> variables)
        {
            MathFormula f = MathFormula.FromString(MathSymbolFactory.Sizes, formula);
            measures.Clear();
            Hashtable table = new Hashtable();
            foreach (string key in variables.Keys)
            {
                IMeasure m = DataConsumer.FindMeasure(this, variables[key]);
                measures[key[0]] = m;
                table[key[0]] = m.Type;
            }
            ElementaryObjectsCreator prot = new ElementaryObjectsCreator(table);
            prot.Add(ElementaryRealDetector.Object);
            IFormulaObjectCreator creator = new FormulaArrayObjectCreator(prot);
            f = f.FullTransform;
            tree = new ObjectFormulaTree(f, creator);
            arg = new ElementaryObjectArgument();
            arg.Add(tree);
            this.variables = variables;
        }
    
        #endregion


    }
}
