using System;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Collections;
using System.Collections.Generic;
using System.Xml;


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


namespace DataPerformer
{


	/// <summary>
	/// Formula transformer of mesurements. It is measurements consumer
	/// </summary>
	[Serializable()]
	public class FormulaDataConsumer : DataConsumer, IMeasurements, ISerializable,
		IPostSetArrow, IAlias
	{
		/// <summary>
		/// Output measurement
		/// </summary>
		private IMeasure measure;

		/// <summary>
		/// Output value
		/// </summary>
		private double result;

		/// <summary>
		/// String representation of formula
		/// </summary>
		private string formulaString = "";

		/// <summary>
		/// The object's formula
		/// </summary>
		private MathFormula formula;

		/// <summary>
		/// Tree of the formula
		/// </summary>
		private ObjectFormulaTree tree;

		/// <summary>
		/// The formula argument
		/// </summary>
		private ElementaryObjectArgument arg;

		/// <summary>
		/// Input parameter
		/// </summary>
		private DynamicalParameter par;

		/// <summary>
		/// The formula arguments
		/// </summary>
		private ArrayList arguments;

		/// <summary>
		/// Derivation of output parameter
		/// </summary>
		private double derivation;

		/// <summary>
		/// Partial derivations
		/// </summary>
		private Hashtable derivations = new Hashtable();

		/// <summary>
		/// Table of parameters
		/// </summary>
		private Hashtable parameters = new Hashtable();
		
		/// <summary>
		/// Constructor
		/// </summary>
		public FormulaDataConsumer() : base(11)
		{
			init();
			arguments = new ArrayList();
		}
		
		/// <summary>
		/// Constructor
		/// </summary>
		/// <param name="info">Serialization info</param>
		/// <param name="context">Streaming context</param>
		public FormulaDataConsumer(SerializationInfo info, StreamingContext context) : 
			base(11)
		{
			formulaString = (string)info.GetValue("Formula", typeof(string));
			if (formulaString.Length > 0)
			{
				Formula = formulaString;
			}
			arguments = (ArrayList)info.GetValue("Arguments", typeof(ArrayList));
			parameters = (Hashtable)info.GetValue("Parameters", typeof(Hashtable));
			init();
		}

		/// <summary>
		/// ISerializable interface implementation
		/// </summary>
		/// <param name="info">Serialization info</param>
		/// <param name="context">Streaming context</param>
		new public void GetObjectData(SerializationInfo info, StreamingContext context)
		{
			info.AddValue("Formula", formulaString);
			info.AddValue("Arguments", arguments);
			info.AddValue("Parameters", parameters);
		}

		/// <summary>
		/// Creates correspond xml
		/// </summary>
		/// <param name="doc">document to create element</param>
		/// <returns>The created element</returns>
		/*new public XmlElement CreateXml(XmlDocument doc)
		{
			XmlElement el = doc.CreateElement("FormulaDataConsumer");
			XmlAttribute attr = doc.CreateAttribute("Formula");
			attr.Value = Formula;
			el.Attributes.Append(attr);
			foreach (string s in arguments)
			{
				XmlElement ea = doc.CreateElement("FormulaArgument");
				XmlAttribute attrArg = doc.CreateAttribute("Argument");
				attrArg.Value = s;
				ea.Attributes.Append(attrArg);
				el.AppendChild(ea);
			}
			

			return el;
		}*/


		/// <summary>
		/// The count of measurements
		/// </summary>
		int IMeasurements.Count
		{
			get
			{
				return 1;
			}
		}

		/// <summary>
		/// Access to n - th measurement
		/// </summary>
		IMeasure IMeasurements.this[int n]
		{
			get
			{
				return measure;
			}
		}

		/// <summary>
		/// Updates measurements data
		/// </summary>
		public void UpdateMeasurements()
		{
			if (IsUpdated)
			{
				return;
			}
			try
			{
				if (par == null)
				{
					throw new Exception(DynamicalParameter.UndefinedParameters);
				}
				UpdateChildrenData();
				par.Set(arg);
				result = (double)tree.Result;
				derivation = 0;
				string str = arg.Variables;
				foreach (char c in str)
				{
					string s = c + "";
					if (parameters.ContainsKey(s))
					{
						continue;
					}
					IMeasure m = par[c];
                    if (!(m is IDerivation))
                    {
                        derivation = 0;
                        break;
                    }
                    IDerivation p = m as IDerivation;
					ObjectFormulaTree t = derivations[c] as ObjectFormulaTree;
					derivation += (double)t.Result * p.Derivation;
				}
				isUpdated = true;
			}
			catch (Exception e)
			{
				PureDesktop.ThrowException(this, e);
			}
		}

		/// <summary>
		/// The header control of measurements
		/// </summary>
		/*public Control HeaderControl
		{
			get
			{
				return new FormulaControl(this);
			}
		}*/

		/// <summary>
		/// Accepts parameters
		/// </summary>
		/// <param name="s">String of parameters</param>
		public void AcceptParameters(string s)
		{
			parameters.Clear();
			par = null;
			arg = new ElementaryObjectArgument();
			arg.Add(tree);
			string str = arg.Variables;
			foreach (char c in s)
			{
				if (str.IndexOf(c) < 0)
				{
					throw new Exception("Illegal formula parameter");
				}
			}
			foreach (char c in s)
			{
				double a = 0;
				parameters["" + c] = a;
				arg[c] = a;
			}
		}
	

		/// <summary>
		/// The operation that performs after arrows setting
		/// </summary>
		public void PostSetArrow()
		{
			if (tree == null)
			{
				return;
			}
			DynamicalParameter parameter = new DynamicalParameter();
            foreach (IMeasurements measurements in measurementsData)
			{
				/*IAssociatedObject cont = measurements as IAssociatedObject;
				INamedComponent comp = cont.Object as INamedComponent;*/
				string name = DataConsumer.GetName(this, measurements);//comp.Name;
				for (int i = 0; i < measurements.Count; i++)
				{
					IMeasure measure = measurements[i];
					string p = name + "." + measure.Name;
					foreach (string s in arguments)
					{
						if (s.Substring(4).Equals(p))
						{
							char c = s[0];
							parameter.Add(c, measure);
						}
					}
				}
			}
			foreach (string s in arguments)
			{
				if (s.Substring(4).Equals("Time"))
				{
					parameter.Add(s[0], DataConsumer.TimeMeasure);
				}
			}
			Parameter = parameter;
			foreach (string s in AliasNames)
			{
				arg[s[0]] = this[s];
			}
		}


		/// <summary>
		/// The name of measurements source
		/// </summary>
		public string SourceName
		{
			get
			{
				INamedComponent comp = obj as INamedComponent;
				return comp.Name;
			}
		}
		
		/// <summary>
		/// String representation of formula
		/// </summary>
		public string Formula
		{
			get
			{
				return formulaString;

			}
			set
			{
				formula = MathFormula.FromString(MathSymbolFactory.Sizes, value);
				formulaString = value;
				MathFormula f = formula.FullTransform;
				tree = new ObjectFormulaTree(f, ElementaryFunctionsCreator.Object);
				arg = new ElementaryObjectArgument();
				arg.Add(tree);
				string var = arg.Variables;
				derivations.Clear();
				parameters.Clear();
				foreach (char c in var)
				{
					ObjectFormulaTree t = DerivationPerformer.Derivation(tree, c + "");
					arg.Add(t);
					t = ElementarySimplifier.Simplify(t);
					derivations[c] = t;
				}
			}
		}

		/// <summary>
		/// The formula arguments
		/// </summary>
		public ArrayList Arguments
		{
			get
			{
				return arguments;
			}
			set
			{
				string str = Variables;
				bool b = false;
				foreach (char c in str)
				{
					foreach (string s in value)
					{
						if (s[0] == c)
						{
							goto m;
						}
					}
					throw new Exception(VariablesShortage);
				m:
					b = b;
				}
				arguments = value;
			}
		}

		/// <summary>
		/// Input dynamical parameter
		/// </summary>
		public DynamicalParameter Parameter
		{
			set
			{
				arg = new ElementaryObjectArgument();
				arg.Add(tree);
				par = value;
			}
		}

		/// <summary>
		/// Formula variables
		/// </summary>
		public string Variables
		{
			get
			{
				string s = "";
				ElementaryObjectArgument arg = new ElementaryObjectArgument();
				string str = arg.Variables;
				foreach (char c in str)
				{
					if (!parameters.ContainsKey("" + c))
					{
						s += c;
					}
				}
				return s;
			}
		}


		/// <summary>
		/// Names of aliases
		/// </summary>
		public List<string> AliasNames
		{
			get
			{
				List<string> s = new List<string>();
				foreach (string str in parameters.Keys)
				{
					s.Add(str);
				}
				return s;
			}
		}

		/// <summary>
		/// Access to alias object
		/// </summary>
		public object this[string alias]
		{
			get
			{
				return parameters[alias];
			}
			set
			{
				char c = alias[0];
				double a = (double)value;
				arg[c] = a;
				parameters[alias] = a;
			}
		}

        /// <summary>
        /// Gets alias type
        /// </summary>
        /// <param name="n"></param>
        /// <returns></returns>
        public object GetType(int n)
        {
            Double a = 0;
            return a;
        }


		/// <summary>
		/// Calculates formula result
		/// </summary>
		/// <returns>The formula result</returns>
		private object calculate()
		{
			return result;
		}

		/// <summary>
		/// Calculates derivation
		/// </summary>
		/// <returns>The derivation</returns>
		private object getDerivation()
		{
			return derivation;
		}
		
		/// <summary>
		/// Initialization
		/// </summary>
		private void init()
		{
			measure = new MeasureDerivation(tree.ReturnType, new MeasureParameter(calculate), new MeasureParameter(getDerivation), "result");
		}

	}


	/// <summary>
	/// Solver of ordinary differential equations systev
	/// </summary>
	[Serializable()]
	public class DifferentialEquationSolver : DataConsumer, IDifferentialEquationSolver, ISerializable,
		IPostSetArrow, IStarted, IAlias, ICheckCorrectness	
	{
		
		#region Fields
		/// <summary>
		/// arguments of right parts
		/// </summary>
		private ElementaryObjectArgument arg;

		/// <summary>
		/// Input dynamical parameter
		/// </summary>
		private DynamicalParameter par;

		/// <summary>
		/// Table of variables of equations. Table contains initial values and derivations of variables
		/// </summary>
		private Hashtable variables = new Hashtable();

		/// <summary>
		/// Table representation of input parameters
		/// </summary>
		private Hashtable parameters = new Hashtable();

		/// <summary>
		/// Output parameters
		/// </summary>
		private ArrayList output;
		
		/// <summary>
		/// The time
		/// </summary>
		private double time;

		/// <summary>
		/// Current time
		/// </summary>
		private double timeOld;

		/// <summary>
		/// List of right parts arguments
		/// </summary>
		private ArrayList arguments = new ArrayList();

		/// <summary>
		/// Table representation of variables
		/// </summary>
		private Hashtable vars = new Hashtable();

		/// <summary>
		/// Table representation of parameters
		/// </summary>
		private Hashtable pars = new Hashtable();

		/// <summary>
		/// Table of aliases
		/// </summary>
		private Hashtable aliases = new Hashtable();

		/// <summary>
		/// Table of aliases names
		/// </summary>
		private Hashtable aliasNames = new Hashtable();

		/// <summary>
		/// Table of external aliases
		/// </summary>
		private Hashtable  externalAliases = new Hashtable();


		/// <summary>
		/// The "is serialized" flag
		/// </summary>
		private bool isSerialized = false;

		#endregion

		#region Constructors
		
		/// <summary>
		/// Consructor
		/// </summary>
		public DifferentialEquationSolver() : base(30)
		{
			init();
			vars = new Hashtable();
			pars = new Hashtable();
			aliases = new Hashtable();
			arguments = new ArrayList();
		}
		

		/// <summary>
		/// Consructor
		/// </summary>
		/// <param name="info">Serialization info</param>
		/// <param name="context">Streaming context</param>
		public DifferentialEquationSolver(SerializationInfo info, StreamingContext context) : 
			base(30)
		{
			init();
			try
			{
				isSerialized = true; 
				vars = (Hashtable)info.GetValue("Vars", typeof(Hashtable));
				pars = (Hashtable)info.GetValue("Pars", typeof(Hashtable));
				aliases = (Hashtable)info.GetValue("Aliases", typeof(Hashtable));
				arguments = (ArrayList)info.GetValue("Arguments", typeof(ArrayList));
				aliasNames = (Hashtable)info.GetValue("AliasNames", typeof(Hashtable));
				comments = (ArrayList)info.GetValue("Comments", typeof(ArrayList));
			}
			catch (Exception)
			{
			}
		}

		#endregion

		/// <summary>
		/// ISerializable interface implementation
		/// </summary>
		/// <param name="info">Serialization info</param>
		/// <param name="context">Streaming context</param>
		new public void GetObjectData(SerializationInfo info, StreamingContext context)
		{
			info.AddValue("Vars", vars);
			info.AddValue("Pars", pars);
			info.AddValue("Aliases", aliases);
			info.AddValue("Arguments", arguments);
			info.AddValue("AliasNames", aliasNames);
			info.AddValue("Comments", comments);
		}


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

		/// <summary>
		/// Keys of variables
		/// </summary>
		public ICollection Keys
		{
			get
			{
				return variables.Keys;
			}
		}

		/// <summary>
		/// Access to variable
		/// </summary>
		public string this[char c]
		{
			get
			{
				object[] o = variables[c] as object[];
				return o[0] as string;
			}
		}

		/// <summary>
		/// Sets values of variables
		/// </summary>
		/// <param name="b">Begin index</param>
		/// <param name="x">Array of variables</param>
		public void SetVariables(int b, double[] x)
		{
			int i = b;
			foreach (object[] o in variables.Values)
			{
				o[3] = x[i];
				++i;
			}
		}


		/// <summary>
		/// Comments
		/// </summary>
		public ArrayList Comments
		{
			get
			{
				return comments;
			}
			set
			{
				comments = value;
			}
		}

		
		/// <summary>
		/// The count of measurements
		/// </summary>
		int IMeasurements.Count
		{
			get
			{
				if (output == null)
				{
					return 0;
				}
				return output.Count;
			}
		}

		/// <summary>
		/// Access to n - th measurement
		/// </summary>
		IMeasure IMeasurements.this[int n]
		{
			get
			{
				return output[n] as IMeasure;
			}
		}

		/// <summary>
		/// Updates measurements data
		/// </summary>
		public void UpdateMeasurements()
		{
			if (IsUpdated)
			{
				return;
			}
			try
			{
				UpdateChildrenData();
				isUpdated = true;
			}
			catch (Exception e)
			{
				PureDesktop.ThrowException(this, e);
			}
		}


		/// <summary>
		/// The time
		/// </summary>
		new public double Time
		{
			set
			{
				time = value;
			}
		}

		/// <summary>
		/// The operation that performs after arrows setting
		/// </summary>
		public void PostSetArrow()
		{
			postDeserialize();
			postSetAlias();
		}

		/// <summary>
		/// Checks its correctenss
		/// </summary>
		public void CheckCorrectness()
		{
			try
			{
				//PostSetArrow();
			}
			catch (Exception e)
			{
				PureDesktop.ThrowException(this, e);
			}
		}


		/// <summary>
		/// Accepts measurements
		/// </summary>
		private void acceptMeasurements()
		{
			DynamicalParameter parameter = new DynamicalParameter();
			parameters.Clear();
			foreach (IMeasurements measurements in measurementsData)
			{
				/*IAssociatedObject cont = measurements as IAssociatedObject;
				INamedComponent nc = cont.Object as INamedComponent;*/
				string name = DataConsumer.GetName(this, measurements);//nc.Name;
				for (int i = 0; i < measurements.Count; i++)
				{
					IMeasure measure = measurements[i];
					string p = name + "." + measure.Name;
					foreach (char c in pars.Keys)
					{
						if (!pars.ContainsKey(c))
						{
							continue;
						}
						if (pars[c] == null)
						{
							continue;
						}
						string s = pars[c] as string;
						if (s.Equals(p))
						{
							parameter.Add(c, measure);
							parameters[c] = measure;
						}
					}
				}
			}
			foreach (string s in arguments)
			{
				if (s.Substring(s.Length - 4).Equals("Time"))
				{
					parameter.Add(s[0], DataConsumer.TimeMeasure);
					parameters[s[0]] = DataConsumer.TimeMeasure;
				}
			}
			foreach (char c in pars.Keys)
			{
				if (!parameters.ContainsKey(c))
				{
					if (pars[c] != null)
					{
						PureDesktop.ThrowException(this, new Exception(PureDesktop.GetResourceString(VectorFormulaConsumer.ExternalParameter_) +
							c + PureDesktop.GetResourceString(VectorFormulaConsumer._IsNotDefined)));
					}
				}
			}
			Parameter = parameter;
		}




		/// <summary>
		/// The name of measurements source
		/// </summary>
		public string SourceName
		{
			get
			{
				INamedComponent comp = obj as INamedComponent;
				return comp.Name;
			}
		}
		
		/// <summary>
		/// Arguments of equations
		/// </summary>
		public ArrayList Arguments
		{
			get
			{
				return arguments;
			}
			set
			{
				bool b = false;
				string str = InputParameters;
				string sc = ConstantNames;
				foreach (char c in str)
				{
					if (aliases.ContainsKey(c + ""))
					{
						continue;
					}
					foreach (string s in value)
					{
						if (s[0] == c)
						{
							goto m;
						}
					}
					throw new Exception(DataConsumer.VariablesShortage);
				m:
					b = !b;
				}
				arguments = value;
				pars.Clear();
				foreach (string s in arguments)
				{
					pars[s[0]] = s.Substring(4);
				}
			}
		}

		/// <summary>
		/// Input dynamical parameter
		/// </summary>
		public DynamicalParameter Parameter
		{
			set
			{
				par = value;
			}
		}

		/// <summary>
		/// Starts this object
		/// </summary>
		new public void Start()
		{
			try
			{
				timeOld = time;
				foreach (object[] o in variables.Values)
				{
					o[3] = o[4];
				}
				//calculateDerivations();
			}
			catch (Exception e)
			{
				PureDesktop.ThrowException(this, e);
			}
		}

		/// <summary>
		/// Calculates initial value of variable
		/// </summary>
		/// <param name="c">The variable key</param>
		/// <returns>Initial value of variable</returns>
		public double GetInitialValue(char c)
		{
			object[] o = variables[c] as object[];
			return (double)o[4];
		}
		
		/// <summary>
		/// Adds variable
		/// </summary>
		/// <param name="c">The variable key</param>
		public void AddVariable(char c)
		{
			double a = 0;
			variables[c] = new object[]{"", null, null, a, a, a}; 
			vars[c] = new object[]{"", a};
		}

		/// <summary>
		/// Sets right part formula to variable
		/// </summary>
		/// <param name="c">The variable key</param>
		/// <param name="formula">The string representation of formula</param>
		public void SetVariable(char c, string formula)
		{
			object[] o = variables[c] as object[];
			o[0] = formula;
			object[] ob = vars[c] as object[];
			ob[0] = formula;
		}

		/// <summary>
		/// Sets initial value of variable
		/// </summary>
		/// <param name="c">The variable key</param>
		/// <param name="a">Initial value of variable</param>
		public void SetValue(char c, double a)
		{
			object[] o = variables[c] as object[];
			o[4] = a;
			object[] ob = vars[c] as object[];
			ob[1] = a;
		}


		/// <summary>
		/// All variabeles in formulas
		/// </summary>
		public string AllVariables
		{
			get
			{
				string s = "";
				foreach (object[] o in variables.Values)
				{
					string st = o[0] as string;
					MathFormula f = MathFormula.FromString(MathSymbolFactory.Sizes, st);
					string str = ElementaryObjectDetector.GetVariables(f);
					foreach (char c in str)
					{
						if (s.IndexOf(c) < 0)
						{
							s += c;
						}
					}
				}
				return s;
			}
		}

		/// <summary>
		/// Preparation
		/// </summary>
		public void Prepare()
		{
			
			//parameters.Clear();
			output = new ArrayList();
			string str = "";
			aliases.Clear();
			Double a = 0;
			string var = AllVariables;
			Hashtable table = new Hashtable();
			foreach (char c in var)
			{
				table[c] = a;
			}
			foreach (char c in pars.Keys)
			{
				IMeasure m = parameters[c] as IMeasure;
				table[c] = m.Type;
			}
			IFormulaObjectCreator creator = new FormulaArrayObjectCreator(
				new ElementaryObjectsCreator(table));

			foreach (object[] o in variables.Values)
			{
				string st = o[0] as string;
				MathFormula f = MathFormula.FromString(MathSymbolFactory.Sizes, st);
				o[1] = f;
				ObjectFormulaTree t = new ObjectFormulaTree(f.FullTransform, creator);
				o[2] = t;
				string s = ElementaryObjectDetector.GetVariables(f);
				foreach (char c in s)
				{
					if (str.IndexOf(c) < 0)
					{
						if (!aliases.ContainsKey("" + c))
						{
							str += c;
							if (variables.ContainsKey(c))
							{
								parameters.Remove(c);
								pars.Remove(c);
							}
						}
					}

				}
			}
			foreach (char c in variables.Keys)
			{
				Variable v = new Variable(this, c);
				IMeasure m  = new MeasureDerivation(a, new MeasureParameter(v.calculate), 
					new MeasureParameter(v.derivation), c + "");
				output.Add(m);
				if (str.IndexOf(c) < 0)
				{
					str += c;
				}
			}
			foreach (string s in aliases.Keys)
			{
				str += s;
			}
			arg = new ElementaryObjectArgument();
			foreach (object[] o in variables.Values)
			{
				ObjectFormulaTree tree = o[2] as ObjectFormulaTree;
				arg.Add(tree);
			}
			foreach (string s in aliases.Keys)
			{
				arg[s[0]] = aliases[s];
			}
		}


		/// <summary>
		/// Clears parameters
		/// </summary>
		public void ClearParameters()
		{
			parameters.Clear();
			pars.Clear();
		}

		/// <summary>
		/// String of parameters
		/// </summary>
		public string Parameters
		{
			get
			{
				string s = "";
				foreach (char c in parameters.Keys)
				{
					s += c;
				}
				return s;
			}
		}

		/// <summary>
		/// String of input parameters
		/// </summary>
		public string InputParameters
		{
			get
			{
				string s = "";
				string all = AllVariables;
				foreach (char c in all)
				{
					if (aliases.ContainsKey("" + c) | variables.ContainsKey(c))
					{
						continue;
					}
					s += c;
				}
				return s;
			}
		}

		/// <summary>
		/// String of input parameters
		/// </summary>
		public string AllParameters
		{
			get
			{
				string s = "";
				string all = AllVariables;
				foreach (char c in all)
				{
					if (variables.ContainsKey(c))
					{
						continue;
					}
					s += c;
				}
				return s;
			}
		}


		/// <summary>
		/// Clears aliases
		/// </summary>
		public void ResetAliases()
		{
			aliases.Clear();
			foreach (char c in vars.Keys)
			{
				AddAlias("" + c);
			}
		}

		/// <summary>
		/// Adds alias
		/// </summary>
		/// <param name="alias">The alias to add</param>
		public void AddAlias(string alias)
		{
			double a = 0;
			aliases[alias] = a;
		}

		/// <summary>
		/// Sets input parameter
		/// </summary>
		/// <param name="c">The parameter key</param>
		/// <param name="m">The parameter measurement</param>
		public void SetParameter(char c, IMeasure m)
		{
			parameters[c] = m;
			pars[c] = m.Name;
		}


		/// <summary>
		/// String of constants names
		/// </summary>
		public string ConstantNames
		{
			get
			{
				string str = "";
				List<string> l = AliasNames;
				foreach (string s in l)
				{
					if (!vars.ContainsKey(s[0]))
					{
						str += s;
					}
				}
				return str;
			}
		}

		/// <summary>
		/// Names of aliases
		/// </summary>
		public List<string> AliasNames
		{
			get
			{
				List<string> s = new List<string>();
				foreach (string str in aliases.Keys)
				{
					s.Add(str);
				}
				return s;
			}
		}

		/// <summary>
		/// Access to alias object
		/// </summary>
		public object this[string alias]
		{
			get
			{
				return aliases[alias];
			}
			set
			{
				char c = alias[0];
				double a = (double)value;
				arg[c] = a;
				aliases[alias] = a;
				if (variables.ContainsKey(c))
				{
					SetValue(c, a);
				}
			}
		}

        public object GetType(int n)
        {
            Double a = 0;
            return a;
        }



		/// <summary>
		/// Clears set of variables
		/// </summary>
		public void ClearVariables()
		{
			variables.Clear();
			vars.Clear();
		}
		
		/// <summary>
		/// Gets derivaton of variable
		/// </summary>
		/// <param name="c">The variable key</param>
		/// <returns>The derivation</returns>
		double getDerivation(char c)
		{
			object[] o = variables[c] as object[];
			return (double)o[5];
		}


		/// <summary>
		/// Performs operations after deserialization
		/// </summary>
		private void postDeserialize()
		{
			output = new ArrayList();
			foreach (char c in vars.Keys)
			{
				object[] o = vars[c] as object[];
				double d = 0;
				variables[c] = new object[]{o[0], null, null, o[1], o[1], d}; 
			}
			string str = "";
			foreach (object[] o in variables.Values)
			{
				string st = o[0] as string;
				MathFormula f = MathFormula.FromString(MathSymbolFactory.Sizes, st);
				o[1] = f;
				string s = ElementaryObjectDetector.GetVariables(f);
			}
			Double a = 0;
			foreach (char c in variables.Keys)
			{
				Variable v = new Variable(this, c);
				IMeasure m  = new MeasureDerivation(a, new MeasureParameter(v.calculate), 
					new MeasureParameter(v.derivation), c + "");
				output.Add(m);
				if (str.IndexOf(c) < 0)
				{
					str += c;
				}
			}
			foreach (string s in aliases.Keys)
			{
				str += s;
			}
			if (!isSerialized)
			{
				pars.Clear();
				isSerialized = false;
				foreach (string ps in arguments)
				{
					pars[ps[0]] = ps.Substring(4);
				}
			}
			acceptMeasurements();
			Hashtable table = new Hashtable();
			foreach (char c in str)
			{
				table[c] = a;
			}
			foreach (char c in pars.Keys)
			{
				if (pars.ContainsKey(c))
				{
					if (pars[c] != null)
					{
						IMeasure m = parameters[c] as IMeasure;
						table[c] = m.Type;
					}
				}
			}
			IFormulaObjectCreator creator = new FormulaArrayObjectCreator(
				new ElementaryObjectsCreator(table));
			foreach (object[] o in variables.Values)
			{
				string st = o[0] as string;
				MathFormula f = MathFormula.FromString(MathSymbolFactory.Sizes, st);
				o[1] = f;
				ObjectFormulaTree t = new ObjectFormulaTree(f.FullTransform, creator);
				o[2] = t;

			}

			arg = new ElementaryObjectArgument();
			foreach (object[] o in variables.Values)
			{
				ObjectFormulaTree tree = o[2] as ObjectFormulaTree;
				arg.Add(tree);
			}
			foreach (string s in aliases.Keys)
			{
				arg[s[0]] = (double)aliases[s];
			}
		}
	
		/// <summary>
		/// Initialization
		/// </summary>
		private void init()
		{
		}

		/// <summary>
		/// Gets value of variable
		/// </summary>
		/// <param name="c">The variable keu</param>
		/// <returns>The value of variable</returns>
		private double getValue(char c)
		{
			object[] o = variables[c] as object[];
			return (double)o[3];
		}

		/// <summary>
		/// Calculates derivations
		/// </summary>
		public void CalculateDerivations()
		{
			try
			{
				foreach (char c in externalAliases.Keys)
				{
					object[] o = externalAliases[c] as object[];
					IAlias al = o[0] as IAlias;
					string s = o[1] as string;
					object[] ob = variables[c] as object[];
					al[s] = ob[3];
				}
				UpdateChildrenData();
				foreach (char c in parameters.Keys)
				{
					IMeasure m = parameters[c] as IMeasure;
					if (m == null)
					{
						throw new Exception(DynamicalParameter.UndefinedParameters);
					}
					arg[c] = m.Parameter();
				}
				foreach (char c in variables.Keys)
				{
					object[] o = variables[c] as object[]; 
					arg[c] = o[3];
				}
				foreach (char c in variables.Keys)
				{
					object[] o = variables[c] as object[];
					ObjectFormulaTree t = o[2] as ObjectFormulaTree;
					o[5] = t.Result;
				}
			}
			catch (Exception e)
			{
				PureDesktop.ThrowException(this, e);
			}
		}

		public Hashtable ExternalAliases
		{
			get
			{
				return aliasNames;
			}
			set
			{
				aliasNames = value;
				postSetAlias();
			}
		}

		public override List<string> AllAliases
		{
			get
			{
				List<string> a = new List<string>();
				DataConsumer.GetAliases(this, a);
				return a;
			}
		}

		private void postSetAlias()
		{
			externalAliases.Clear();
			if (aliasNames == null)
			{
				return;
			}
			foreach (char c in aliasNames.Keys)
			{
				string s = aliasNames[c] as string;
				externalAliases[c] = DataConsumer.FindAlias(this, s);
			}
		}


		/// <summary>
		/// Auxiliary class for providing output measurements of differential equations solver
		/// </summary>
		public class Variable
		{
			/// <summary>
			/// The solver
			/// </summary>
			DifferentialEquationSolver solver;

			/// <summary>
			/// Index of the variable 
			/// </summary>
			char indx;

			/// <summary>
			/// Constructor
			/// </summary>
			/// <param name="solver">The solver</param>
			/// <param name="indx">Index of the variable</param>
			public Variable(DifferentialEquationSolver solver, char indx)
			{
				this.solver = solver;
				this.indx = indx;
			}

			/// <summary>
			/// Calculates value of measurement
			/// </summary>
			/// <returns>Value of measurement</returns>
			public object calculate()
			{
				return solver.getValue(indx);
			}

			/// <summary>
			/// Calculates time derivation of measurement
			/// </summary>
			/// <returns>Time derivation</returns>
			public object derivation()
			{
				return solver.getDerivation(indx);
			}
		}

	}

	/// <summary>
	/// The state machine
	/// </summary>
	[Serializable()]
	public class StateMachine : DataConsumer, ISerializable,
		IPostSetArrow, IStarted, IMeasurements
	{
		/// <summary>
		/// Table of input parameters
		/// </summary>
		private Hashtable parameters = new Hashtable();

		/// <summary>
		/// Parameters
		/// </summary>
		private Hashtable pars;

		/// <summary>
		/// State transition table
		/// </summary>
		private int[,] table;

		/// <summary>
		/// Current state
		/// </summary>
		private int state;

		/// <summary>
		/// Initial state
		/// </summary>
		private int initialState;
		
		/// <summary>
		/// Table of parameters
		/// </summary>
		private Hashtable doubleParameters = new Hashtable();

		/// <summary>
		/// Output measurement
		/// </summary>
		private IMeasure measure;
		
		/// <summary>
		/// Constructor
		/// </summary>
		public StateMachine() : base(33)
		{
			pars = new Hashtable();
			init();
		}

		/// <summary>
		/// Constructor
		/// </summary>
		/// <param name="info">Serialization info</param>
		/// <param name="context">Streaming context</param>
		public StateMachine(SerializationInfo info, StreamingContext context) : 
			base(33)
		{
			table = (int[,])info.GetValue("Table", typeof(int[,]));
			pars = (Hashtable)info.GetValue("Parameters", typeof(Hashtable));
			initialState = (int)info.GetValue("Initial", typeof(int));
			init();
		}

		/// <summary>
		/// ISerializable interface implementation
		/// </summary>
		/// <param name="info">Serialization info</param>
		/// <param name="context">Streaming context</param>
		new public void GetObjectData(SerializationInfo info, StreamingContext context)
		{
			info.AddValue("Table", table);
			info.AddValue("Parameters", pars);
			info.AddValue("Initial", initialState);
		}

		/// <summary>
		/// Access to table
		/// </summary>
		public int this[int i, int j]
		{
			get
			{
				return table[i, j];
			}
		}

		/// <summary>
		/// The state
		/// </summary>
		public int State
		{
			get
			{
				return state;
			}
			set
			{
				state = value;
			}
		}

		/// <summary>
		/// The initial state
		/// </summary>
		public int InitialState
		{
			set
			{
				initialState = value;
			}
			get
			{
				return initialState;
			}
		}

		/// <summary>
		/// Gets state table dimension
		/// </summary>
		/// <param name="i">Numer of dimension</param>
		/// <returns></returns>
		public int GetLength(int i)
		{
			if (table == null)
			{
				return 0;
			}
			return table.GetLength(i);
		}

		/// <summary>
		/// The machine state transition table
		/// </summary>
		public int[,] Table
		{
			set
			{
				for (int i = 0; i < value.GetLength(0); i++)
				{
					for (int j = 0; j < value.GetLength(1); j++)
					{
						if (value[i, j] >= value.GetLength(0))
						{
							throw new Exception("State machine out of range");
						}
					}
				}
				doubleParameters.Clear();
				parameters.Clear();
				pars.Clear();
				table = value;
			}
		}

		/// <summary>
		/// The n th measurement
		/// </summary>
		new public IMeasure this[int n]
		{
			get
			{
				return parameters[n] as IMeasure;
			}
		}

		/// <summary>
		/// The count of measurements
		/// </summary>
		int IMeasurements.Count
		{
			get
			{
				return 1;
			}
		}

		/// <summary>
		/// Access to n - th measurement
		/// </summary>
		IMeasure IMeasurements.this[int n]
		{
			get
			{
				return measure;
			}
		}

		/// <summary>
		/// The keys of input parameters
		/// </summary>
		public ICollection Keys
		{
			get
			{
				return parameters.Keys;
			}
		}



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



		/// <summary>
		/// Updates measurements data
		/// </summary>
		public void UpdateMeasurements()
		{
			if (IsUpdated)
			{
				return;
			}
			try
			{
				UpdateChildrenData();
				foreach (int i in Keys)
				{
					double x = (double)doubleParameters[i];
					IMeasure m = this[i];
					double y = (double)m.Parameter();
					if ((y > 0) & (x <= 0))
					{
						state = table[state, i];
					}
					doubleParameters[i] = y;
				}
				isUpdated = true;
			}
			catch (Exception e)
			{
				PureDesktop.ThrowException(this, e);
			}
		}


		/// <summary>
		/// The operation that performs after arrows setting
		/// </summary>
		public void PostSetArrow()
		{
			postDeserialize();
			parameters.Clear();
			foreach (IMeasurements measurements in measurementsData)
			{
				/*IAssociatedObject cont = measurements as IAssociatedObject;
				INamedComponent c = cont.Object as INamedComponent;*/
				string name = DataConsumer.GetName(this, measurements);//c.Name;
				for (int i = 0; i < measurements.Count; i++)
				{
					IMeasure measure = measurements[i];
					string p = name + "." + measure.Name;
					foreach (int j in pars.Keys)
					{
						string s = pars[j] as string;
						if (s.Equals(p))
						{
							parameters[j] = measure;
						}
					}
				}
			}
		}

		/// <summary>
		/// The name of measurements source
		/// </summary>
		public string SourceName
		{
			get
			{
				INamedComponent comp = obj as INamedComponent;
				return comp.Name;
			}
		}
		
		/// <summary>
		/// Starts this object
		/// </summary>
		new public void Start()
		{
			try
			{
				foreach (int i in Keys)
				{
					double a = -1;
					doubleParameters[i] = a;
				}
				state = initialState;
			}
			catch (Exception e)
			{
				PureDesktop.ThrowException(this, e);
			}
		}

		/// <summary>
		/// Sets i - th input parameter
		/// </summary>
		/// <param name="i">The parameter number</param>
		/// <param name="name">The parameter name</param>
		/// <param name="m">The input measurement</param>
		public void SetParameter(int i, string name, IMeasure m)
		{
			parameters[i] = m;
			pars[i] = name + "." + m.Name;
		}

		/// <summary>
		/// Clears parameters
		/// </summary>
		public void ClearParameters()
		{
			parameters.Clear();
			pars.Clear();
			doubleParameters.Clear();
		}

		/// <summary>
		/// Gets name of i - th parameter
		/// </summary>
		/// <param name="i">The parameter number</param>
		/// <returns>The name of i - th parameter</returns>
		public string GetParameter(int i)
		{
			return pars[i] as string;
		}

		/// <summary>
		/// Operation after deserialization
		/// </summary>
		private void postDeserialize()
		{
			doubleParameters.Clear();
			parameters.Clear();
		}

		/// <summary>
		/// Gets state
		/// </summary>
		/// <returns></returns>
		private object getState()
		{
			return state;
		}

		/// <summary>
		/// Initialization
		/// </summary>
		private void init()
		{
			Int32 a = 0;
			measure = new Measure(a, new MeasureParameter(getState), "State");
		}

	}

	[Serializable()]
	public class Nulling : ICategoryObject, IMeasurements, ISerializable,
		IStarted
	{
		private double zero = 0;
		private double x;
		private double der;
		private bool switched = false;
		private IMeasure measure;
		private FormulaDataConsumer consumer;
		private StateMachine machine;
		private int state = 0;
		//private NamedComponent component;
		protected object obj;

		/// <summary>
		/// Update flag
		/// </summary>
		private bool isUpdated;


		public Nulling()
		{
			init();
		}

		public Nulling(SerializationInfo info, StreamingContext context) 
		{
			state = (int)info.GetValue("State", typeof(int));
			init();
		}

		/// <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("State", state);
		}


		/// <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("Nulling");
			return el;
		}*/

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


		/// <summary>
		/// Starts this object
		/// </summary>
		public void Start()
		{
			try
			{
				zero = 0;
				switched = false;
				if (consumer == null)
				{
					throw new Exception("Nulling has no consumer");
				}
				if (machine == null)
				{
					throw new Exception("Nulling has no machine");
				}
			}
			catch (Exception e)
			{
				PureDesktop.ThrowException(this, e);
			}
		}

		public int State
		{
			set
			{
				state = value;
			}
			get
			{
				return state;
			}
		}

		/// <summary>
		/// Updates measurements data
		/// </summary>
		public void UpdateMeasurements()
		{
			if (IsUpdated)
			{
				return;
			}
			try
			{
				consumer.UpdateMeasurements();
				IMeasurements m = consumer;
				IMeasure measure = m[0];
				x = (double)measure.Parameter();
                der = 0;
                if (measure is IDerivation)
                {
                    IDerivation d = measure as IDerivation;
                    der = d.Derivation;
                }
				machine.UpdateMeasurements();
				int s = machine.State;
				if (switched)
				{
					if (s != state)
					{
						switched = false;
					}
				}
				else
				{
					if (s == state)
					{
						zero = x;
						switched = true;
					}
				}
				isUpdated = true;
			}
			catch (Exception e)
			{
				PureDesktop.ThrowException(this, e);
			}
		}



		public void RemoveArrow(NullingArrow arrow)
		{
			object o = arrow.Target;
			if (o == machine)
			{
				machine = null;
				return;
			}
			if (o == consumer)
			{
				consumer = null;
			}
		}



		/// <summary>
		/// The name of measurements source
		/// </summary>
		public string SourceName
		{
			get
			{
				INamedComponent comp = obj as INamedComponent;
				return comp.Name;
			}
		}

		/// <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>
		/// The n th measurement
		/// </summary>
		public IMeasure this[int n]
		{
			get
			{
				return measure;
			}
		}

		/// <summary>
		/// The count of measurements
		/// </summary>
		public int Count
		{
			get
			{
				return 1;
			}
		}


		public void SetMachine(StateMachine machine)
		{
			if (this.machine != null)
			{
				throw new Exception("Machine already exists");
			}
			this.machine = machine;
		}

		public void SetConsumer(FormulaDataConsumer consumer)
		{
			if (this.consumer != null)
			{
				throw new Exception("Consumer already exists");
			}
			this.consumer = consumer;
		}

		public int States
		{
			get
			{
				if (machine == null)
				{
					return 0;
				}
				return machine.GetLength(0);
			}
		}

		public StateMachine Machine
		{
			get
			{
				return machine;
			}
		}

		public FormulaDataConsumer Consumer
		{
			get
			{
				return consumer;
			}
		}


		private object getValue()
		{
			return x - zero;
		}
		private object getDerivation()
		{
			return der;
		}

		
		private void init()
		{
			Double a = 0;
			measure = new MeasureDerivation(a, new MeasureParameter(getValue), 
				new MeasureParameter(getDerivation), "Nulling");
		}

		/// <summary>
		/// Shows, wreather the object is updated
		/// </summary>
		public bool IsUpdated
		{
			get
			{
				return isUpdated;
			}
			set
			{
				isUpdated = value;
			}
		}

	}

	[Serializable()]
	public class NullingArrow : ICategoryArrow, IRemovableObject, ISerializable
	{
		public Nulling source;
		/// <summary>
		/// The target of this arrow
		/// </summary>
		public ICategoryObject target;
		/// <summary>
		/// Linked object
		/// </summary>
		protected object obj;
		int a = 0;
		public NullingArrow()
		{
		}

		public NullingArrow(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>
		/// The source of this arrow
		/// </summary>
		public ICategoryObject Source
		{
			get
			{
				return source;
			}
			set
			{
				if (!(value is Nulling))
				{
					CategoryException.ThrowIllegalSourceException();
				}
				source = value as Nulling;
			}
		}

		/// <summary>
		/// The target of this arrow
		/// </summary>
		public ICategoryObject Target
		{
			get
			{
				return target;
			}
			set
			{
				if (value is StateMachine)
				{
					StateMachine machine = value as StateMachine;
					source.SetMachine(machine);
					return;
				}
				if (value is FormulaDataConsumer)
				{
					FormulaDataConsumer consumer = value as FormulaDataConsumer;
					source.SetConsumer(consumer);
					return;
				}
				CategoryException.ThrowIllegalTargetException();
			}
		}

		public bool IsMonomorphism
		{
			get
			{
				return false;
			}
		}

		public bool IsEpimorphism
		{
			get
			{
				return false;
			}
		}

		public bool IsIsomorphism
		{
			get
			{
				return false;
			}
		}


		/// <summary>
		/// Composes this arrow "f" with next arrow "g" 
		/// </summary>
		/// <param name="category"> The category of arrow</param>
		/// <param name="next"> The next arrow "g" </param>
		/// <returns>Composition "fg" </returns>
		public ICategoryArrow Compose(ICategory category, ICategoryArrow next)
		{
			return null;
		}

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


		/// <summary>
		/// The post remove operation
		/// </summary>
		public void RemoveObject()
		{
			source.RemoveArrow(this);
		}

	}




	/// <summary>
	/// Multidimensional dynamical parameter
	/// </summary>
	public class DynamicalParameter
	{
		/// <summary>
		/// Strig of parameters labels
		/// </summary>
		private string labels = "";
		
		/// <summary>
		/// List of parameters
		/// </summary>
		private ArrayList parameters = new ArrayList();

		/// <summary>
		/// Error message of undefined parameter
		/// </summary>
		public static readonly string UndefinedParameter = "Undefined parameter";

		/// <summary>
		/// Error message of undefined parameters
		/// </summary>
		public static readonly string UndefinedParameters = "Undefined parameters";

		/// <summary>
		/// Constructor
		/// </summary>
		public DynamicalParameter()
		{
		}
		
		/// <summary>
		/// Adds measurement
		/// </summary>
		/// <param name="c">Measurement label</param>
		/// <param name="m">Measurement</param>
		public void Add(char c, IMeasure m)
		{
			if (labels.IndexOf(c) >= 0)
			{
				throw new Exception("Double parameter '" + c + "'");
			}
			labels += c;
			parameters.Add(m);
		}
		
		/// <summary>
		/// Checks whether formula argument contains all parameters
		/// </summary>
		/// <param name="arg"></param>
		/*public void Check(FormulaArgument arg)
		{
			arg.Check(labels);
		}*/

		/// <summary>
		/// Gets measurement
		/// </summary>
		public IMeasure this[char c]
		{
			get
			{
				int n = labels.IndexOf(c);
				if (n < 0)
				{
					throw new Exception(UndefinedParameter);
				}
				return parameters[n] as IMeasure;
			}
		}

		/// <summary>
		/// Sets formula argument
		/// </summary>
		/// <param name="arg"></param>
		public void Set(ElementaryObjectArgument arg)
		{
			foreach(char c in labels)
			{
				arg[c] = this[c].Parameter();
			}
		}
		
		/// <summary>
		/// String of parameter variables
		/// </summary>
		public string Variables
		{
			get
			{
				return labels;
			}
		}
	}


	/// <summary>
	/// Base class of data consumers
	/// </summary>
	[Serializable()]
	public class DataConsumer : IDataConsumer, ICategoryObject, 
		ISerializable
	{

		/// <summary>
		/// Desktop
		/// </summary>
		static private IDesktop desktop;

		/// <summary>
		/// Type of variable
		/// </summary>
		static private Double a = 0;

		/// <summary>
		/// Time
		/// </summary>
		//static private double time;


		/// <summary>
		/// Step
		/// </summary>
		static private int stepNumber;

		/// <summary>
		/// Desktop
		/// </summary>
		public static IDesktop Desktop
		{
			get
			{
				return desktop;
			}
			set
			{
				desktop = value;
			}
		}

		static IMeasure timeMeasure = new MeasureDerivation(a, new MeasureParameter(GetTime), new MeasureParameter(Unity), "Time");


        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;
        }


        /// <summary>
        /// Gets measures type
        /// </summary>
        /// <param name="consumer">Consumer</param>
        /// <returns>Dictionary of types</returns>
        public static Dictionary<string, object> GetAllMeasuresType(IDataConsumer consumer)
        {
            Dictionary<string, object> dictionary = new Dictionary<string, object>();
            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;
                    dictionary[s] = mea.Type;
                }
            }
            return dictionary;
        }


  
	/// <summary>
	/// The unity
	/// </summary>
	/// <returns>Unity</returns>
		static private object Unity()
		{
			return (double)1;
		}



			/// <summary>
			/// Measurement of time
			/// </summary>
		static public IMeasure TimeMeasure
		{
			get
			{
				return timeMeasure;
			}
		}

		/// <summary>
		/// Number of step
		/// </summary>
		static public int StepNumber
		{
			get
			{
				return stepNumber;
			}
			set
			{
				stepNumber = value;
			}
		}

		
		/// <summary>
		/// Gets time
		/// </summary>
		/// <returns>The time</returns>
		static private object GetTime()
		{
			return DataPerformerStrategy.Object.Time;
		}


		/// <summary>
		/// The time
		/// </summary>
/*		public static double Time
		{
			set
			{
				IDesktop desktop = Desktop;
				ICollection components = DataPerformerStrategy.Object.Components;
				time = value;
				foreach (INamedComponent comp in components)
				{
					IDynamical dynamical = null;
					if (comp is IObjectLabel)
					{
						IObjectLabel label = comp as IObjectLabel;
						ICategoryObject obj = label.Object;
						if (!(obj is IDynamical))
						{
							continue;
						}
						dynamical = obj as IDynamical;
					}
					else if (comp is IArrowLabel)
					{
						IArrowLabel label = comp as IArrowLabel;
						ICategoryArrow arr = label.Arrow;
						if (!(arr is IDynamical))
						{
							continue;
						}
						dynamical = arr as IDynamical;
					}
					dynamical.Time = value;
				}
				DataPerformerStrategy.Object.UpdateAll(desktop);
				DataConsumer.ResetUpdatedMeasurements(desktop);
			}
			get
			{
				return time;
			}
		}
*/


		
		/// <summary>
		/// Error message of variables shortage
		/// </summary>
		public static readonly string VariablesShortage = "Shortage of variables";
		
		/// <summary>
		/// Arrows to data providers
		/// </summary>
		protected List<IMeasurements> measurementsData;

		/// <summary>
		/// Type of consumer
		/// </summary>
		protected int type;

		/// <summary>
		/// Object factory
		/// </summary>
		//protected ElectromagneticUIFactory factory;

		/// <summary>
		/// Linked desktop component
		/// </summary>
		//protected NamedComponent control;

		/// <summary>
		/// Linked object
		/// </summary>
		protected object obj;

		/// <summary>
		/// Update flag
		/// </summary>
		protected bool isUpdated;

		/// <summary>
		/// Comments
		/// </summary>
		protected ArrayList comments = new ArrayList();


		/// <summary>
		/// Controls of graph
		/// </summary>
		private ArrayList graphControls = new ArrayList();

		/// <summary>
		/// Start
		/// </summary>
		private double start = 0;

		/// <summary>
		/// Step
		/// </summary>
		private double step = 1;

		/// <summary>
		/// Number of steps
		/// </summary>
		private int steps = 2;

		/// <summary>
		/// Constructor
		/// </summary>
		/// <param name="type">Type of consumer</param>
		public DataConsumer(int type)
		{
			this.type = type;
			initialize();
		}

		/// <summary>
		/// Constructor
		/// </summary>
		/// <param name="info">Serialization info</param>
		/// <param name="context">Streaming context</param>
		public DataConsumer(SerializationInfo info, StreamingContext context) 
		{
			type = (int)info.GetValue("Type", typeof(int));
			try
			{
				graphControls = (ArrayList)info.GetValue("GraphConrtols", typeof(ArrayList));
				start = (double)info.GetValue("Start", typeof(double));
				step =  (double)info.GetValue("Step", typeof(double));
				steps = (int)info.GetValue("Steps", typeof(int));
			}
			catch (Exception)
			{
			}
			initialize();
		}

		/// <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("Type", type);
			info.AddValue("GraphConrtols", graphControls);
			info.AddValue("Start", start);
			info.AddValue("Step", step);
			info.AddValue("Steps", steps);
		}

		/// <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("DataConsumer");
			XmlAttribute attr = doc.CreateAttribute("Type");
			attr.Value = type + "";
			el.Attributes.Append(attr);
			if (ConsumerType == (int)ElectromagneticUI.ButtonKinds.GraphConsumer)
			{
				Form form = control.LabelForm;
				if (form != null)
				{
					IXmlElementCreator xml = form as IXmlElementCreator;
					XmlElement plotter = xml.CreateXml(doc);
					el.AppendChild(plotter);
				}
			}
			return el;
		}*/


        /// <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 list children measurements of data consumer
		/// </summary>
		/// <param name="consumer">The consumer</param>
		/// <param name="measurements">Children measurements</param>
		public static void GetMeasurements(IDataConsumer consumer, ArrayList measurements)
		{
			if (consumer is IMeasurements)
			{
				if (!measurements.Contains(consumer))
				{
					measurements.Add(consumer);
				}
			}
			for (int i = 0; i < consumer.Count; i++)
			{
				object o = consumer[i];
				if (o is IDataConsumer)
				{
					IDataConsumer c = o as IDataConsumer;
					GetMeasurements(c, measurements);
				}
				else
				{
					if (!(measurements.Contains(o)))
					{
						measurements.Add(o);
					}
				}
			}
		}

		/// <summary>
		/// Resets updated measurements
		/// </summary>
		/// <param name="desktop">The desktop</param>
		public static void ResetUpdatedMeasurements(IDesktop desktop)
		{
			ICollection comp = DataPerformerStrategy.Object.Components;
			foreach (object o in comp)
			{
				if (!(o is IObjectLabel))
				{
					continue;
				}
				IObjectLabel l = o as IObjectLabel;
				object ob = l.Object;
				if (!(ob is IMeasurements))
				{
					continue;
				}
				IMeasurements m = ob as IMeasurements;
				m.IsUpdated = false;
			}
		}

		public static ArrayList GetDataConsumers(IDesktop desktop)
		{
			ArrayList list = new ArrayList();
			ICollection comp = desktop.AllComponents;
			foreach (object o in comp)
			{
				if (!(o is IObjectLabel))
				{
					continue;
				}
				IObjectLabel l = o as IObjectLabel;
				object ob = l.Object;
				if (!(ob is IDataConsumer))
				{
					continue;
				}
				list.Add(ob);
			}
			return list;
		}

		/// <summary>
		/// Aliases of this object and all its children
		/// </summary>
        public virtual List<string> AllAliases
        {
            get
            {
                List<string> a = new List<string>();
                DataConsumer.GetAliases(this, a);
                return a;
            }
        }

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


		/// <summary>
		/// Gets relative name
		/// </summary>
		/// <param name="o">Base object</param>
		/// <param name="mea">Measurements</param>
		/// <returns>The name</returns>
		public static string GetName(IAssociatedObject o, IMeasurements mea)
		{
			IAssociatedObject ao = mea as IAssociatedObject;
			return PureDesktop.GetRelativeName(o, ao);
		}



		/// <summary>
		/// Controls of graph
		/// </summary>
		public ArrayList GraphControls
		{
			get
			{
				return graphControls;
			}
			set
			{
				graphControls = value;
			}
		}

		/// <summary>
		/// Adds target arrow
		/// </summary>
		/// <param name="arrow">Arrow to add</param>
		public void Add(IMeasurements arrow)
		{
			measurementsData.Add(arrow);
		}

		/// <summary>
		/// Removes target arrow
		/// </summary>
		/// <param name="arrow">Arrow to remove</param>
		public void Remove(IMeasurements arrow)
		{
			measurementsData.Remove(arrow);
		}



		/// <summary>
		/// Updates chidren measurements
		/// </summary>
		public void UpdateChildrenData()
		{
			try
			{
				foreach (IMeasurements m in measurementsData)
				{
					m.UpdateMeasurements();
				}
			}
			catch (Exception e)
			{
				PureDesktop.ThrowException(this, e);
			}
		}

		/// <summary>
		/// Resets measurements
		/// </summary>
		public void Reset()
		{
			Reset(this);
		}

		/// <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>
		/// Count of providers
		/// </summary>
		public int Count
		{
			get
			{
				return measurementsData.Count;
			}
		}

		/// <summary>
		/// Arrow of n th provider
		/// </summary>
		public IMeasurements this[int n]
		{
			get
			{
				return measurementsData[n];
			}
		}

		

		/// <summary>
		/// Gets aliases of this object and all its childen
		/// </summary>
		/// <param name="list"></param>
		//	public void GetAliases(ArrayList list)
		//	{
		//	}
		
		/// <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>
		/// Type of consumer
		/// </summary>
		public int ConsumerType
		{
			get
			{
				return type;
			}
		}

		/// <summary>
		/// The UI factory of domain
		/// </summary>
		/*	public IUIFactory Facrory
			{
				get
				{
					return factory;
				}
				set
				{
					factory = value as ElectromagneticUIFactory;
				}
			}*/

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

		/// <summary>
		/// Shows, wreather the object is updated
		/// </summary>
		public bool IsUpdated
		{
			get
			{
				return isUpdated;
			}
			set
			{
				isUpdated = value;
			}
		}

		/// <summary>
		/// Start
		/// </summary>
		public double Start
		{
			get
			{
				return start;
			}
			set
			{
				start = value;
			}
		}

		/// <summary>
		/// Step
		/// </summary>
		public double Step
		{
			get
			{
				return step;
			}
			set
			{
				step = value;
			}
		}

		/// <summary>
		/// Number of steps
		/// </summary>
		public int Steps
		{
			get
			{
				return steps;
			}
			set
			{
				steps = value;
			}
		}
		
		public static XmlDocument GetArraysXmlDocument(IDataConsumer consumer)
		{
			ArrayList meas = new ArrayList();
			int[] r = null;
			int n = consumer.Count;
			for (int i = 0; i < n; i++)
			{
				IMeasurements mea = consumer[i];
				int k = mea.Count;
				for (int j = 0; j < k; j++)
				{
					IMeasure m = mea[j];
					object type = m.Type;
					if (!(type is ArrayReturnType))
					{
						continue;
					}
                    ArrayReturnType art = type as ArrayReturnType;
					int[] rr = art.Dimension;
					if (rr.Length > 1)
					{
						continue;
					}
					if (r == null)
					{
						r = rr;
					}
					if (r[0] != rr[0])
					{
						continue;
					}
					meas.Add(m);
				}
			}
			if (r == null)
			{
				return null;
			}
			XmlDocument doc = new XmlDocument();
			doc.LoadXml("<?xml version=\"1.0\"?><ExperimentalData><Root></Root></ExperimentalData>");
			XmlElement root = doc.GetElementsByTagName("Root")[0] as XmlElement;
			XmlAttribute att = doc.CreateAttribute("uid");
			att.Value = Guid.NewGuid() + "";
			root.Attributes.Append(att);
			att = doc.CreateAttribute("time");
			att.Value = DateTime.Now + "";
			root.Attributes.Append(att);
			XmlElement descr = doc.CreateElement("ParametersDescription");
			root.AppendChild(descr);
			for (int i = 0; i < meas.Count; i++)
			{
				IMeasure m = meas[i] as IMeasure;
				XmlElement e = doc.CreateElement("ParameterDescription");
				descr.AppendChild(e);
				att = doc.CreateAttribute("id");
				att.Value = i + "";
				e.Attributes.Append(att);
				att = doc.CreateAttribute("name");
				att.Value = m.Name;
				e.Attributes.Append(att);
			}
			XmlElement results = doc.CreateElement("Results");
			root.AppendChild(results);
			for (int i = 0; i < r[0]; i++)
			{
				XmlElement result = doc.CreateElement("Result");
				results.AppendChild(result);
				for (int j = 0; j < meas.Count; j++)
				{
					IMeasure mea = meas[j] as IMeasure;
					XmlElement par = doc.CreateElement("Parameter");
					result.AppendChild(par);
					att = doc.CreateAttribute("id");
					att.Value = j + "";
					par.Attributes.Append(att);
					att = doc.CreateAttribute("value");
					object[] o = mea.Parameter() as object[];
					att.Value = o[i] + "";
					par.Attributes.Append(att);
				}
			}
			return doc;
		}

        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 object
		/// </summary>
		/// <param name="c">Data consumer</param>
		/// <param name="alias">Full alias</param>
		/// <returns>Pair objec[]{object, alias}</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;
		}

		/// <summary>
		/// Gets name of measure
		/// </summary>
		/// <param name="consumer">Data consumer</param>
		/// <param name="measure">Measure</param>
		/// <returns>The name</returns>
		public static string GetName(IDataConsumer consumer, IMeasure measure)
		{
			IAssociatedObject ass = consumer as IAssociatedObject;
			INamedComponent comp = ass.Object as INamedComponent;
			IDesktop d = comp.Desktop;
			for (int i = 0; i < consumer.Count; i++)
			{
				IMeasurements mea = consumer[i];
				for (int j = 0; j < mea.Count; j++)
				{
					IMeasure m = mea[j];
					if (m == measure)
					{
						IAssociatedObject ao = mea as IAssociatedObject;
						INamedComponent nc = ao.Object as INamedComponent;
						string name = PureObjectLabel.GetName(nc, d);
						return name + "." + m.Name;
					}
				}
			}
			return null;

		}

		/// <summary>
		/// Finds measure
		/// </summary>
		/// <param name="consumer">Data consumer</param>
		/// <param name="measure">Measure name</param>
		/// <returns>The measure</returns>
		public static IMeasure FindMeasure(IDataConsumer consumer, string measure)
		{
			int n = measure.LastIndexOf(".");
			string p = measure.Substring(0, n);
			string s = measure.Substring(n + 1);
			IAssociatedObject ass = consumer as IAssociatedObject;
			INamedComponent comp = ass.Object as INamedComponent;
			IDesktop d = comp.Desktop;
			for (int i = 0; i < consumer.Count; i++)
			{
				IMeasurements mea = consumer[i];
				IAssociatedObject ao = mea as IAssociatedObject;
				INamedComponent nc = ao.Object as INamedComponent;
				string name = PureObjectLabel.GetName(nc, d);
				if (!name.Equals(p))
				{
					continue;
				}
				for (int j = 0; j < mea.Count; j++)
				{
					IMeasure m = mea[j];
					if (s.Equals(m.Name))
					{
						return m;
					}
				}
			}
			return null;
		}



		/// <summary>
		/// Initialization
		/// </summary>
		private void initialize()
		{
			measurementsData = new List<IMeasurements>();
		}
	}


	[Serializable()]
	public class FourierSeriesLink : ICategoryArrow, ISerializable,
		IRemovableObject
	{

		/// <summary>
		/// The source of this arrow
		/// </summary>
		private FourierSeries source;

		/// <summary>
		/// The target of this arrow
		/// </summary>
		private Series target;
		
		/// <summary>
		/// Auxiliary field
		/// </summary>
		private int a = 0;
		
		/// <summary>
		/// Linked object
		/// </summary>
		protected object obj;

		
		/// <summary>
		/// Constuctor
		/// </summary>
		public FourierSeriesLink()
		{
		}
		
		/// <summary>
		/// Deserializetion contructor
		/// </summary>
		/// <param name="info">Serialization info</param>
		/// <param name="context">Streaming context</param>
		public FourierSeriesLink(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("FourierSeriesLink");
			return el;
		}*/

		/// <summary>
		/// The source of this arrow
		/// </summary>
		public ICategoryObject Source
		{
			set
			{
				if (!(value is FourierSeries))
				{
					CategoryException.ThrowIllegalSourceException();
				}
				source = value as FourierSeries;
			}

			get
			{
				return source as ICategoryObject;
			}
		}
		

		/// <summary>
		/// The target of this arrow
		/// </summary>
		public ICategoryObject Target
		{
			get
			{
				return target as ICategoryObject;
			}
			set
			{
				if (!(value is Series))
				{
					CategoryException.ThrowIllegalTargetException();
				}
				target = value as Series;
				source.AddSeries(target);
			}
		}

		public bool IsMonomorphism
		{
			get
			{
				return false;
			}
		}

		public bool IsEpimorphism
		{
			get
			{
				return false;
			}
		}

		public bool IsIsomorphism
		{
			get
			{
				return false;
			}
		}


		/// <summary>
		/// Composes this arrow "f" with next arrow "g" 
		/// </summary>
		/// <param name="category"> The category of arrow</param>
		/// <param name="next"> The next arrow "g" </param>
		/// <returns>Composition "fg" </returns>
		public ICategoryArrow Compose(ICategory category, ICategoryArrow next)
		{                      
			return null;
		}

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

		/// <summary>
		/// The post remove operation
		/// </summary>
		public void RemoveObject()
		{
			source.RemoveSeries(target);
		}
	}



	[Serializable()]
	public class SwitchLink : ICategoryArrow, ISerializable, IRemovableObject
	{
		private FormulaDataConsumer target;
		private ISwitched source;
		//private bool isUpdatable = false;
		/// <summary>
		/// Linked object
		/// </summary>
		protected object obj;
		int a;
		public SwitchLink()
		{
			a = 0;
		}
		public SwitchLink(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("SwitchLink");
			return el;
		}*/



		/// <summary>
		/// Composes this arrow "f" with next arrow "g" 
		/// </summary>
		/// <param name="category"> The category of arrow</param>
		/// <param name="next"> The next arrow "g" </param>
		/// <returns>Composition "fg" </returns>
		public ICategoryArrow Compose(ICategory category, ICategoryArrow next)
		{
			return null;
		}
		
		/// <summary>
		/// The category of this object
		/// </summary>
		public ICategory Category
		{
			get
			{
				return null;
			}
		}

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

		
		/// <summary>
		/// The post remove operation
		/// </summary>
		public void RemoveObject()
		{
			source.RemoveSwitch(this);
		}



		/// <summary>
		/// The source of this arrow
		/// </summary>
		public ICategoryObject Source
		{
			get
			{
				return source as ICategoryObject;
			}
			set
			{
				if (!(value is ISwitched))
				{
					CategoryException.ThrowIllegalSourceException();
				}
				source = value as ISwitched;
			}
		}
		
		/// <summary>
		/// The target of this arrow
		/// </summary>
		public ICategoryObject Target
		{
			get
			{
				return target;
			}
			set
			{
				if (source == null)
				{
					throw new Exception("Source object is missing");
				}
				if (source == value)
				{
					throw new Exception("Target of switch link should not concide with source");
				}
				if (!(value is FormulaDataConsumer))
				{
					CategoryException.ThrowIllegalTargetException();
				}
				target = value as FormulaDataConsumer;
				source.AddSwitch(this);
			}
		}

		public bool IsMonomorphism
		{
			get
			{
				return false;
			}
		}

		public bool IsEpimorphism
		{
			get
			{
				return false;
			}
		}

		public bool IsIsomorphism
		{
			get
			{
				return false;
			}
		}

	}

	[Serializable()]
	public class UnaryLink : ICategoryArrow, ISerializable, 
		IRemovableObject
	{
		private VectorFormulaConsumer source;
		
		private IObjectOperation target;

		/// <summary>
		/// Linked object
		/// </summary>
		protected object obj;
		
		int a;

		public UnaryLink()
		{
			a = 0;
		}

		public UnaryLink(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("SeriesLink");
			return el;
		}*/



		/// <summary>
		/// Composes this arrow "f" with next arrow "g" 
		/// </summary>
		/// <param name="category"> The category of arrow</param>
		/// <param name="next"> The next arrow "g" </param>
		/// <returns>Composition "fg" </returns>
		public ICategoryArrow Compose(ICategory category, ICategoryArrow next)
		{
			return null;
		}
		
		/// <summary>
		/// The category of this object
		/// </summary>
		public ICategory Category
		{
			get
			{
				return null;
			}
		}

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

		
		/// <summary>
		/// The post remove operation
		/// </summary>
		public void RemoveObject()
		{
			source.RemoveOperation(target);
		}



		/// <summary>
		/// The source of this arrow
		/// </summary>
		public ICategoryObject Source
		{
			get
			{
				return source;
			}
			set
			{
				if (!(value is VectorFormulaConsumer))
				{
					CategoryException.ThrowIllegalSourceException();
				}
				source = value as VectorFormulaConsumer;
			}
		}
		
		/// <summary>
		/// The target of this arrow
		/// </summary>
		public ICategoryObject Target
		{
			get
			{
				return target as ICategoryObject;
			}
			set
			{
				if (!(value is IObjectOperation))
				{
					CategoryException.ThrowIllegalTargetException();
				}
				target = value as IObjectOperation;
				source.AddOperation(target);
			}
		}

		public bool IsMonomorphism
		{
			get
			{
				return false;
			}
		}

		public bool IsEpimorphism
		{
			get
			{
				return false;
			}
		}

		public bool IsIsomorphism
		{
			get
			{
				return false;
			}
		}

	}



	[Serializable()]
	public class FormulaRegressionLink : ICategoryArrow, ISerializable, 
		IRemovableObject
	{
		/// <summary>
		/// The source
		/// </summary>
		private FormulaRegression source;

		/// <summary>
		/// The target
		/// </summary>
		private ICategoryObject target;

		/// <summary>
		/// Linked object
		/// </summary>
		protected object obj;
		int a;
		public FormulaRegressionLink()
		{
			a = 0;
		}
		public  FormulaRegressionLink(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("FormulaRegressionLink");
			return el;
		}*/



		/// <summary>
		/// Composes this arrow "f" with next arrow "g" 
		/// </summary>
		/// <param name="category"> The category of arrow</param>
		/// <param name="next"> The next arrow "g" </param>
		/// <returns>Composition "fg" </returns>
		public ICategoryArrow Compose(ICategory category, ICategoryArrow next)
		{
			return null;
		}
		
		/// <summary>
		/// The category of this object
		/// </summary>
		public ICategory Category
		{
			get
			{
				return null;
			}
		}

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


		/// <summary>
		/// The source of this arrow
		/// </summary>
		public ICategoryObject Source
		{
			get
			{
				return source;
			}
			set
			{
				if (!(value is FormulaRegression))
				{
					CategoryException.ThrowIllegalSourceException();
				}
				source = value as FormulaRegression;
			}
		}
		
		/// <summary>
		/// The target of this arrow
		/// </summary>
		public ICategoryObject Target
		{
			get
			{
				return target;
			}
			set
			{
				if (source == null)
				{
					throw new Exception("Source object is missing");
				}
				if (source == value)
				{
					throw new Exception("Target of switch link should not concide with source");
				}
				if (value is IArgumentSelection)
				{
					source.AddSelection(value as IArgumentSelection);
					target = value;
					return;
				}
				if (value is VectorFormulaConsumer)
				{
					source.Formula = value as VectorFormulaConsumer;
					target = value;
					return;
				}
				CategoryException.ThrowIllegalTargetException();
			}
		}

		public bool IsMonomorphism
		{
			get
			{
				return false;
			}
		}

		public bool IsEpimorphism
		{
			get
			{
				return false;
			}
		}

		public bool IsIsomorphism
		{
			get
			{
				return false;
			}
		}


		/// <summary>
		/// The post remove operation
		/// </summary>
		public void RemoveObject()
		{
			if (target is IArgumentSelection)
			{
				IArgumentSelection s = target as IArgumentSelection;
				source.RemoveSelection(s);
			}
		}


	}

	/// <summary>
	/// Selection with arguments
	/// </summary>
	public class ArgumentMultiSelection : IArgumentSelection
	{

		private ArrayList selections = new ArrayList();
		private ArrayList etalons = new ArrayList();
		//private int pointsCount;
		private int dim = 0;
		private string name = "";
		
		/// <summary>
		/// Count of points
		/// </summary>
		public int PointsCount
		{
			get
			{
				return first.PointsCount;		
			}
		}
		
		/// <summary>
		/// Free variables
		/// </summary>
		public string[] Variables
		{
			get
			{
				return first.Variables;
			}
		}
		/// <summary>
		/// Dimension of output vector
		/// </summary>
		public int VectorDimension
		{
			get
			{
				return dim;
			}
		}

		/// <summary>
		/// Gets value of variable
		/// </summary>
		public double this[int i, string str]
		{
			get
			{
				return first[i, str];
			}
		}

		/// <summary>
		/// Adds seletion
		/// </summary>
		/// <param name="sel">Selection to add</param>
		public void AddSelection(IArgumentSelection sel)
		{
			if (selections.Count == 0)
			{
				selections.Add(sel);
				etalons.Add(sel);
				dim += sel.VectorDimension;
				return;
			}
			string[] variables = first.Variables;
			string[] var = sel.Variables;
			if (var.Length != variables.Length)
			{
				throw new Exception("Illegal number of variables");
			}
			foreach (string s in var)
			{
				foreach (string s1 in variables)
				{
					if (s.Equals(s1))
					{
						goto m1;
					}
				}
				throw new Exception("Illegal variables");
			m1: continue;
			}
			dim += sel.VectorDimension;
			etalons.Add(sel);
			selections.Add(sel.SynchronizedSelection(selections[0] as IArgumentSelection));
		}

		/// <summary>
		/// Removes selection
		/// </summary>
		/// <param name="sel">Selection to remove</param>
		public void RemoveSelection(IArgumentSelection sel)
		{
			int n = etalons.IndexOf(sel);
			if (n >= 0)
			{
				etalons.RemoveAt(n);
				selections.RemoveAt(n);
				dim -= sel.VectorDimension;
			}
		}

		/// <summary>
		/// Component of i - th selection
		/// </summary>
		/// <param name="i">Selection number</param>
		/// <returns>The component</returns>
		public IObjectLabel GetComponent(int i)
		{
			ICategoryObject o = etalons[i] as ICategoryObject;
			return o.Object as IObjectLabel;
		}


		/// <summary>
		/// Dimension of data
		/// </summary>
		public int DataDimension
		{
			get
			{
				return PointsCount * VectorDimension;
			}
		}

		/// <summary>
		/// Access to n - th element
		/// </summary>
		public double? this[int n]
		{
			get
			{
				int m = n / dim;
				int k = n - dim * m;
				IArgumentSelection s = selections[k] as IArgumentSelection;
				return s[m];
			}
		}

		/// <summary>
		/// Weight of n - th element
		/// </summary>
		/// <param name="n">Element number</param>
		/// <returns>The weight</returns>
		public double GetWeight(int n)
		{
			return 1;
		}

		/// <summary>
		/// Aprior weight of n - th element
		/// </summary>
		/// <param name="n">Element number</param>
		/// <returns>The weight</returns>
		public double GetApriorWeight(int n)
		{
			return 0;
		}

		/// <summary>
		/// Tolerance of it - th element
		/// </summary>
		/// <param name="n">Element number</param>
		/// <returns>Tolerance</returns>
		public int GetTolerance(int n)
		{
			return 0;
		}

		/// <summary>
		/// Sets tolerance of n - th element
		/// </summary>
		/// <param name="n">Element number</param>
		/// <param name="tolerance">Tolerance to set</param>
		public void SetTolerance(int n, int tolerance)
		{
		}

		/// <summary>
		/// The "is fixed amount" sign
		/// </summary>
		public bool HasFixedAmount
		{
			get
			{
				foreach (IStructuredSelection s in selections)
				{
					if (!s.HasFixedAmount)
					{
						return false;
					}
				}
				return true;
			}
		}

		/// <summary>
		/// Selection name
		/// </summary>
		public string Name
		{
			get
			{
				return name;
			}
		}

		/// <summary>
		/// Calculates synchronized selection
		/// </summary>
		/// <param name="selection">The etalon selection</param>
		/// <returns>Synchronized selection</returns>
		public IArgumentSelection SynchronizedSelection(IArgumentSelection selection)
		{
			ArgumentMultiSelection sel = new ArgumentMultiSelection();
			for (int i = 0; i < selections.Count; i++)
			{
				IArgumentSelection s = selections[i] as IArgumentSelection;
				sel.AddSelection(s.SynchronizedSelection(selection));
			}
			return sel;
		}

		/// <summary>
		/// Gets i - th selection
		/// </summary>
		/// <param name="i">The selection nubmer</param>
		/// <returns>Choosen selection</returns>
		public IArgumentSelection GetSelection(int i)
		{
			return selections[i] as IArgumentSelection;
		}

		/// <summary>
		/// Count of selections
		/// </summary>
		public int SelectionCount
		{
			get
			{
				return selections.Count;
			}
		}

		/// <summary>
		/// First selection
		/// </summary>
		private IArgumentSelection first
		{
			get
			{
				if (selections.Count == 0)
				{
					return null;
				}
				return selections[0] as IArgumentSelection;
			}
		}

	}




	
	/// <summary>
	/// Switched object
	/// </summary>
	public interface ISwitched
	{
		/// <summary>
		/// Adds switch link
		/// </summary>
		/// <param name="link">Link to add</param>
		void AddSwitch(SwitchLink link);

		/// <summary>
		/// Removes switch link
		/// </summary>
		/// <param name="link">Link to remove</param>
		void RemoveSwitch(SwitchLink link);
	}


	/// <summary>
	/// ArrayCalculatorAccociated with formulas
	/// </summary>
	public class FormulaArrayCalculator
	{
		
		/// <summary>
		/// Number of calculator
		/// </summary>
		static private int staticNumber = 0;


		/// <summary>
		/// Global calculator
		/// </summary>
		//static public GlobalArrayCalculator GlobalCalculator = new  GlobalArrayCalculator(Calculate);

		
		/// <summary>
		/// Calculators
		/// </summary>
		static private Hashtable calculators = new Hashtable();
	
		/// <summary>
		/// Number of calculator
		/// </summary>
		private int number;
		
		/// <summary>
		/// Arguments
		/// </summary>
		private string[] arguments;

		/// <summary>
		/// Signal dimension
		/// </summary>
		private int dim;

		/// <summary>
		/// Formula consumer
		/// </summary>
		private VectorFormulaConsumer formulas;

		/// <summary>
		/// Diagram calculator
		/// </summary>
		private ArrayCalculator calculator;

		/// <summary>
		/// Constructor
		/// </summary>
		/// <param name="formulas">Formula consumer</param>
		public FormulaArrayCalculator(VectorFormulaConsumer formulas)
		{
			this.formulas = formulas;
			IMeasurements m = formulas;
			List<string> al = formulas.AliasNames;
			List<string> a = new List<string>();
            for (int i = 0; i < al.Count; i++)
            {
                a.Add(al[i]);
            }
			a.Sort();
			arguments = new string[al.Count];
			for (int i = 0; i < a.Count; i++)
			{
				arguments[i] = a[i] as string;
			}
			dim = formulas.Count;
			calculator = new ArrayCalculator(calculate);
			number = staticNumber;
			//AddCalculator(calculator);
		}


		/// <summary>
		/// Calculator
		/// </summary>
		/*public ArrayCalculator Calculator
		{
			get
			{
				return calculator;
			}
		}*/

		/// <summary>
		/// Destructor
		/// </summary>
		
		/*
		~FormulaArrayCalculator()
		{
			calculators[number] = null;
		}*/

		/// <summary>
		/// Calculates parameters of i - th calculator
		/// </summary>
		/// <param name="i">Calculator number</param>
		/// <param name="x">Input</param>
		/// <param name="data">Output</param>
/*		public static void Calculate(int i, int n, int m, double[] x, double [] data)
		{
			ArrayCalculator calc = calculators[i] as ArrayCalculator;
			calc(n, m, x, data);
		}*/


		/// <summary>
		/// Adds calculator
		/// </summary>
		/// <param name="calculator">Calculator to add</param>
		/*public static int AddCalculator(ArrayCalculator calculator)
		{
			calculators[staticNumber] = calculator;
			if (staticNumber == 0)
			{
				ArrayCalculatorWrapper.SetGlobalCalculator(GlobalCalculator);
			}
			staticNumber++;
			return staticNumber - 1;
		}*/

		/// <summary>
		/// Output dimension
		/// </summary>
		public int Dim
		{
			get
			{
				return dim;
			}
		}

		/// <summary>
		/// Formula calculator
		/// </summary>
		public ArrayCalculator Calculator
		{
			get
			{
				return calculator;
			}
		}

		/// <summary>
		/// Number of calculator
		/// </summary>
		public int Number
		{
			get
			{
				return number;
			}
		}

		/// <summary>
		/// Arguments of calculator
		/// </summary>
		public string[] Arguments
		{
			get
			{
				return arguments;
			}
		}


		/// <summary>
		/// Calculation
		/// </summary>
		/// <param name="x">Input</param>
		/// <param name="data">Output</param>
		private void calculate(int n, int m, double[] x, double [] data)
		{
			for (int i = 0; i < n; i++)
			{
				formulas[arguments[i]] = x[i];
			}
			IMeasurements mea = formulas;
			mea.UpdateMeasurements();
			for (int i = 0; i < m; i++)
			{
				data[i] = (double)mea[i].Parameter();
			}
		}
	}

	

	/// <summary>
	/// Vector formula data transformer
	/// </summary>
	[Serializable()]
	public class FourierSeries : DataConsumer, IMeasurements, ISerializable,
		IPostSetArrow, IAssociatedObject
	{
		/// <summary>
		/// Output measurements
		/// </summary>
		private IMeasure[] output = new IMeasure[2];

		/// <summary>
		/// Results of calculation
		/// </summary>
		private double[,] result = new double[2, 2];

		/// <summary>
		/// Arguments
		/// </summary>
		private string argument;

		/// <summary>
		/// Input measurements
		/// </summary>
		private IMeasure input;

		/// <summary>
		/// List of series
		/// </summary>
		private ArrayList seriesList = new ArrayList();

		/// <summary>
		/// Series
		/// </summary>
		private Series[] series = new Series[2];

		/// <summary>
		/// Names of unary
		/// </summary>
		private Hashtable seriesTable = new Hashtable();


		/// <summary>
		/// Constructor
		/// </summary>
		public FourierSeries() : base(65)
		{
			argument = "";
			for (int i = 0; i < 2; i++)
			{
				seriesTable[i] = "";
			}
			Double a = 0;
			output[0] = new MeasureDerivation(a, new MeasureParameter(getRe), new MeasureParameter(getReDerivation), "Real");
			output[1] = new MeasureDerivation(a, new MeasureParameter(getIm), new MeasureParameter(getImDerivation), "Image");
		}

		/// <summary>
		/// Constructor
		/// </summary>
		/// </summary>
		/// <param name="info">Serialization info</param>
		/// <param name="context">Streaming context</param>
		public FourierSeries(SerializationInfo info, StreamingContext context) : 
			base(65)
		{
			try
			{
				argument = (string)info.GetValue("Argument", typeof(string));
				seriesTable = info.GetValue("SeriesTable", typeof(Hashtable)) as Hashtable;
			}			
			catch (Exception)
			{
				seriesTable = new Hashtable();
				seriesTable[0] = "";
				seriesTable[1] = "";
			}
			if (seriesTable == null)
			{
			}
			Double a = 0;
			output[0] = new MeasureDerivation(a, new MeasureParameter(getRe), new MeasureParameter(getReDerivation), "Real");
			output[1] = new MeasureDerivation(a, new MeasureParameter(getIm), new MeasureParameter(getImDerivation), "Image");
		}

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

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

		/// <summary>
		/// Series table
		/// </summary>
		public Hashtable SeriesTable
		{
			get
			{
				return seriesTable;
			}
		}

		/// <summary>
		/// Table of series names
		/// </summary>
		/*	public Hashtable SeriesNames
			{
				get
				{
					return seriesNames;
				}
			}*/

		/// <summary>
		/// Adds series to list
		/// </summary>
		/// <param name="series">Series to remove</param>
		public void AddSeries(Series series)
		{
			if (seriesList.Count == 2)
			{
				throw new Exception("Too many series");
			}
			seriesList.Add(series);
		}


		/// <summary>
		/// Removes series
		/// </summary>
		/// <param name="series">Series to remove</param>
		public void RemoveSeries(Series series)
		{
			seriesList.Remove(series);
		}


		/// <summary>
		/// The count of measurements
		/// </summary>
		int IMeasurements.Count
		{
			get
			{
				return 2;
			}
		}

		/// <summary>
		/// Access to n - th measurement
		/// </summary>
		IMeasure IMeasurements.this[int n]
		{
			get
			{
				return output[n];
			}
		}

		/// <summary>
		/// Updates measurements data
		/// </summary>
		public void UpdateMeasurements()
		{
			if (IsUpdated)
			{
				return;
			}
			try
			{
				UpdateChildrenData();
				result[0, 0] = 0;
				result[1, 0] = 0;
				double x = (double)input.Parameter();
                IDerivation der = input as IDerivation;
				double d = (double)der.Derivation;
				for (int i = 0; i < series[0].Count; i++)
				{
					double om = series[0][i, 0];
					d *= om;
					double a = x * om;
					double s = Math.Sin(a);
					double c = Math.Cos(a);
					double re = series[0][i, 1] * c + series[1][i, 1] * s;
					double im = -series[0][i, 1] * s + series[1][i, 1] * c;
					result[0, 0] += re;
					result[1, 0] += im;
					result[0, 1] += d * im;
					result[1, 1] -= d * re;
				}
				isUpdated = true;
			}
			catch (Exception e)
			{
				PureDesktop.ThrowException(this, e);
			}
		}	

		/// <summary>
		/// The operation that performs after arrows setting
		/// </summary>
		public void PostSetArrow()
		{
			acceptArgument();
			AcceptSeries();
		}

		/// <summary>
		/// The name of measurements source
		/// </summary>
		public string SourceName
		{
			get
			{
				INamedComponent comp = obj as INamedComponent;
				return comp.Name;
			}
		}

		/// <summary>
		/// Argument
		/// </summary>
		public string Argument
		{
			get
			{
				return argument;
			}
			set
			{
				argument = value;
				acceptArgument();
			}
		}


		public DynamicalParameter Parameter
		{
			set
			{
				if (value.Variables.Length != 1)
				{
					throw new Exception("Fourier transform should have one parameter");
				}
				input = value['x'];
				argument = input.Name;
			}
		}

		/// <summary>
		/// Gets i - th unary
		/// </summary>
		/// <param name="i">Unary number</param>
		/// <returns>The i - th unary</returns>
		public IUnary GetUnary(int i)
		{
			return seriesList[i] as IUnary;
		}

		/// <summary>
		/// Count of unaries
		/// </summary>
		public int UnaryCount
		{
			get
			{
				return seriesList.Count;
			}
		}


		public void AcceptSeries()
		{
			if (seriesTable.Count != 2)
			{
				return;
			}
			for (int i = 0; i < 2; i++)
			{
				string sn = seriesTable[i] as string;
				foreach (Series s in seriesList)
				{
					//INamedComponent nc = s.Object as INamedComponent;
					if (sn.Equals(PureDesktop.GetRelativeName(this, s)))//nc.Name))
					{
						series[i] = s;
						continue;
					}
				}
			}
		}


		/// <summary>
		/// Accepts arguments
		/// </summary>
		private void acceptArgument()
		{
            foreach (IMeasurements measurements in measurementsData)
			{
				/*IAssociatedObject cont = measurements as IAssociatedObject;
				INamedComponent c = cont.Object as INamedComponent;*/
				string name = DataConsumer.GetName(this, measurements);//c.Name;
				for (int i = 0; i < measurements.Count; i++)
				{
					IMeasure measure = measurements[i];
					string p = name + "." + measure.Name;
					if (argument.Substring(4).Equals(p))
					{
						input = measure;
						break;
					}
				}
			}
			if (argument.Equals("Time"))
			{
				input = DataConsumer.TimeMeasure;
			}
		}







		/// <summary>
		/// Gets function value
		/// </summary>
		/// <returns>The value</returns>
		private object getRe()
		{
			return result[0, 0];
		}

		/// <summary>
		/// Gets function value
		/// </summary>
		/// <returns>The value</returns>
		private object getIm()
		{
			return result[1, 0];
		}

		/// <summary>
		/// Gets function derivation
		/// </summary>
		/// <returns>The derivation</returns>
		private object getReDerivation()
		{
			return result[0, 1];
		}

		/// <summary>
		/// Gets function derivation
		/// </summary>
		/// <returns>The derivation</returns>
		private object getImDerivation()
		{
			return result[1, 1];
		}
		
	}

	






	/// <summary>
	/// Processor for solving ordinary differential equations system 
	/// </summary>
	public abstract class DifferentialEquationProcessor
	{
		/// <summary>
		/// Processor
		/// </summary>
		static private DifferentialEquationProcessor processor;


		/// <summary>
		/// The is busy sign
		/// </summary>
		protected bool isBusy = false;
		
		/// <summary>
		/// Processor
		/// </summary>
		public static DifferentialEquationProcessor Object
		{
			get
			{
				return processor;
			}
			set
			{
				processor = value;
			}
		}
		
		
		/// <summary>
		/// Systems of equations
		/// </summary>
		protected ArrayList equations = new ArrayList();

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

		/// <summary>
		/// Constructor
		/// </summary>
		protected DifferentialEquationProcessor()
		{
		}

		/// <summary>
		/// Sets root data consumers
		/// </summary>
		/// <param name="consumers">Consumers to set</param>
		public virtual void Set(ArrayList consumers)
		{
			equations.Clear();
			measurements.Clear();
			foreach (IDataConsumer c in consumers)
			{
				DataConsumer.GetMeasurements(c, measurements);
			}
			foreach (IMeasurements m in measurements)
			{
				if (m is IDifferentialEquationSolver)
				{
					equations.Add(m);
				}
			}
		}

		/// <summary>
		/// Count of equations system
		/// </summary>
		public int Count
		{
			get
			{
				return equations.Count;
			}
		}

		/// <summary>
		/// Access to i - th equations sistem
		/// </summary>
		public IDifferentialEquationSolver this[int i]
		{
			get
			{
				return equations[i] as IDifferentialEquationSolver;
			}
		}


		/// <summary>
		/// Resets "is updated" sign
		/// </summary>
		public void Reset()
		{
			foreach (IMeasurements m in measurements)
			{
				m.IsUpdated = false;
			}
		}

		/// <summary>
		/// Sets root data consumer
		/// </summary>
		/// <param name="consumer">The consumer to set</param>
		public void Set(IDataConsumer consumer)
		{
			ArrayList l = new ArrayList();
			l.Add(consumer);
			Set(l);
		}

		/// <summary>
		/// Dimension of state vector
		/// </summary>
		public int Dim
		{
			get
			{
				int n = 0;
				foreach (IMeasurements m in equations)
				{
					n += m.Count;
				}
				return n;
			}
		}

		public void UpdateMeasurements()
		{
			if (Dim > 0)
			{
				foreach (IMeasurements m in measurements)
				{
					m.UpdateMeasurements();
				}
			}
		}
		
		/// <summary>
		/// Performs step of integration
		/// </summary>
		/// <param name="t0">Step start</param>
		/// <param name="t2">Step finish</param>
		abstract public void Step(double t0, double t2);


		/// <summary>
		/// The "is busy" sign
		/// </summary>
		public bool IsBusy
		{
			get
			{
				return isBusy;
			}
		}

	}

	/// <summary>
	/// Runge processor for solving ordinary differential equations system 
	/// </summary>
	public class RungeProcessor : DifferentialEquationProcessor
	{
		/// <summary>
		/// Coefficients of method
		/// </summary>
		static readonly double[] a = {0.5, 0.5, 1.0, 1.0, 0.5};


		/// <summary>
		/// One divide by three
		/// </summary>
		//static readonly double one_to_three = 1.0 / 3.0;
 
		/// <summary>
		/// Auxiliary buffer variable
		/// </summary>
		private double[] z;
 
		/// <summary>
		/// Auxiliary buffer variable
		/// </summary>
		private double[] w;
 
		/// <summary>
		/// Auxiliary buffer variable
		/// </summary>
		private double[] f;

		/// <summary>
		/// Auxiliary buffer variable
		/// </summary>
		private double[,] k;


		/// <summary>
		/// Singleton
		/// </summary>
		static public readonly RungeProcessor Processor = new RungeProcessor(); 

		protected RungeProcessor()
		{
		}

		/// <summary>
		/// Performs step of integration
		/// </summary>
		/// <param name="t0">Step start</param>
		/// <param name="t2">Step finish</param>
		public override void Step(double t0, double t1)
		{
			isBusy = true;
			if (Dim == 0)
			{
				return;
			}
			double dt = t1 - t0;
			int i = 0;
			foreach (IMeasurements m in equations)
			{
				for (int j = 0; j < m.Count; j++)
				{
					w[i] = (double)m[j].Parameter();
					f[i] = w[i];
					++i;
				}
			}
			double t = t0;
			DataPerformerStrategy.Object.Time = t;
			UpdateMeasurements();
			Reset();
			i = 0;
			foreach (IMeasurements m in equations)
			{
				IDifferentialEquationSolver s = m as IDifferentialEquationSolver;

				s.CalculateDerivations();
				for (int j = 0; j < m.Count; j++)
				{
                    IDerivation der = m[j] as IDerivation;
					z[i] = der.Derivation;
					k[0, i] = z[i] * dt;
					w[i] = f[i] + 0.5 * k[0, i];
					++i;
				}
				s.SetVariables(i - m.Count, w);
			}
			t = t0 + 0.5 * dt;
			DataPerformerStrategy.Object.Time = t;
			UpdateMeasurements();
			Reset();
			i = 0;
			foreach (IMeasurements m in equations)
			{
				IDifferentialEquationSolver s = m as IDifferentialEquationSolver;
				s.CalculateDerivations();
				for (int j = 0; j < m.Count; j++)
				{
                    IDerivation der = m[j] as IDerivation;
					z[i] = der.Derivation;
					k[1, i] = z[i] * dt;
					w[i] = f[i] + 0.5 * k[1, i];
					++i;
				}
				s.SetVariables(i - m.Count, w);
			}
			t = t0 + 0.5 * dt;
			DataPerformerStrategy.Object.Time = t;
			UpdateMeasurements();
			Reset();
			i = 0;
			foreach (IMeasurements m in equations)
			{
				IDifferentialEquationSolver s = m as IDifferentialEquationSolver;
				s.CalculateDerivations();
				for (int j = 0; j < m.Count; j++)
				{
                    IDerivation der = m[j] as IDerivation;
					z[i] = der.Derivation;
					k[2, i] = z[i] * dt;
					w[i] = f[i] + k[2, i];
					++i;
				}
				s.SetVariables(i - m.Count, w);
			}
			t = t0 + dt;
			DataPerformerStrategy.Object.Time = t;
			UpdateMeasurements();
			Reset();
			i = 0;
			foreach (IMeasurements m in equations)
			{
				IDifferentialEquationSolver s = m as IDifferentialEquationSolver;
				s.CalculateDerivations();
				for (int j = 0; j < m.Count; j++)
				{
                    IDerivation der = m[j] as IDerivation;
					z[i] = der.Derivation;
					k[3, i] = z[i] * dt;
					++i;
				}
			}
			i = 0;
			foreach (IMeasurements m in equations)
			{
				IDifferentialEquationSolver s = m as IDifferentialEquationSolver;
				for (int j = 0; j < m.Count; j++)
				{
					f[i] += (k[0, i] + 2 * k[1, i] + 2 * k[2, i] + k[3, i]) / 6;
					++i;
				}
				s.SetVariables(i - m.Count, f);
			}
			isBusy = false;
		}

		/// <summary>
		/// Sets root data consumers
		/// </summary>
		/// <param name="consumers">Consumers to set</param>
		public override void Set(ArrayList consumers)
		{
			base.Set(consumers);
			int n = Dim;
			w = new double[n];
			z = new double[n];
			f = new double[n];
			k = new double[4, n];
		}
	}

	public class EulerProcessor: DifferentialEquationProcessor
	{
		/// <summary>
		/// Singleton
		/// </summary>
		static public readonly DifferentialEquationProcessor Processor = new EulerProcessor();

		/// <summary>
		/// Auxiliary variable
		/// </summary>
		private double[] w;

		/// <summary>
		/// Constructor
		/// </summary>
		private EulerProcessor()
		{
		}

		/// <summary>
		/// Performs step of integration
		/// </summary>
		/// <param name="t0">Step start</param>
		/// <param name="t2">Step finish</param>
		public override void Step(double t0, double t1)
		{
			isBusy = true;
			if (Dim == 0)
			{
				return;
			}
			double dt = t1 - t0;
			int i = 0;
			double t = t0;
			foreach (IMeasurements m in equations)
			{
				for (int j = 0; j < m.Count; j++)
				{
					w[i] = (double)m[j].Parameter();
					++i;
				}
			}
			DataPerformerStrategy.Object.Time = t;
			DataConsumer.ResetUpdatedMeasurements(DataConsumer.Desktop);
			UpdateMeasurements();
			i = 0;
			foreach (IMeasurements m in equations)
			{
				IDifferentialEquationSolver s = m as IDifferentialEquationSolver;
				s.CalculateDerivations();
				for (int j = 0; j < m.Count; j++)
				{
                    IDerivation der = m[j] as IDerivation;
					w[i] = w[i] + der.Derivation * dt;
					++i;
				}
				s.SetVariables(i - m.Count, w);
			}
			isBusy = false;
		}

		/// <summary>
		/// Sets root data consumers
		/// </summary>
		/// <param name="consumers">Consumers to set</param>
		public override void Set(ArrayList consumers)
		{
			base.Set(consumers);
			int n = Dim;
			w = new double[n];
		}
	}

		

	//Finished code!!! But it don't working right.
	public class AdamsProcessor: DifferentialEquationProcessor
	{

		/// <summary>
		/// Values of previous steps
		/// </summary>
		private double[,] prevDeri;

		/// <summary>
		/// Values of parameters in previous ptep
		/// </summary>
		private double[] prevStep;

		/// <summary>
		/// Values of old step
		/// </summary>
		private double[] oldStep;

		/// <summary>
		/// Counter of steps
		/// </summary>
		private int stepCount;

		/// <summary>
		/// Counter of parameters in equations
		/// </summary>
		private int paramCount;

		/// <summary>
		/// Additional Runge - Kutta processor
		/// </summary>
		private RungeProcessor runge = RungeProcessor.Processor;

		/// <summary>
		/// Singleton
		/// </summary>
		static public readonly AdamsProcessor Processor = new AdamsProcessor();
 
		/// <summary>
		/// The massive of coefficients
		/// </summary>
		private double[] prCoeff;

		/// <summary>
		/// Accurate coefficient
		/// </summary>
		private double[] aqCoeff;

		/// <summary>
		/// The order of precision
		/// </summary>
		private int order;

		protected AdamsProcessor()
		{
		}

		/// <summary>
		/// Order
		/// </summary>
		public int Order
		{
			set
			{
				order = value;
			}
		}

		public override void Set(ArrayList consumers)
		{
			base.Set(consumers);
			int n = Dim;
			stepCount = 0;
			prevStep = new double[n];
			oldStep = new Double[n];
			prevDeri = new double[n, order];
			prCoeff = new double[order];
			aqCoeff = new Double[order];
			RealPolynom pNom = new RealPolynom(1);
			RealPolynom mult = new RealPolynom(2);
			mult[0] = 0;
			mult[1] = 1;
			for (int i = 0; i < order; i++)
			{
				pNom = new RealPolynom(1);
				pNom[0] = 1;
				for (int j = 0; j < order; j++)
				{
					if (i != j)
					{
						mult[0] = j;
						pNom *= mult / (j - i);
					}
				}
				pNom = ~pNom;
				prCoeff[i] = pNom[(double)(1)];
				aqCoeff[i] = - pNom[(double)(-1)];
			}
			runge.Set(consumers);
		}
		
		public override void Step(double t0, double t1)
		{
			isBusy = true;
			paramCount = 0;
			if (stepCount < order)
			{
				runge.Step(t0, t1);
				foreach (IMeasurements m in equations)
				{
					runge.Step(t0, t1);
					IDifferentialEquationSolver s = m as IDifferentialEquationSolver;
					s.CalculateDerivations();
					for (int j = 0; j < m.Count; j++)
					{
                        IDerivation der = m[j] as IDerivation;
						prevDeri[paramCount, stepCount] = der.Derivation;
						prevStep[paramCount] = (double)m[j].Parameter();
						++paramCount;
					}
					s.SetVariables(paramCount - m.Count, prevStep);
					++stepCount;
				}
				paramCount = 0;
			}
			
			else
			{
				foreach (IMeasurements m in equations)
				{
					IDifferentialEquationSolver s = m as IDifferentialEquationSolver;
					s.CalculateDerivations();
					for (int j = 0; j < m.Count; j++)
					{
						prevStep[paramCount] = (double)m[j].Parameter();
						oldStep[paramCount] = prevStep[paramCount];
						for (int i = 0; i < order; i++)
						{
							prevStep[paramCount] +=  prevDeri[paramCount, i] * prCoeff[i] * (t1 - t0);
						}
						++paramCount;
					}
					s.SetVariables(paramCount - m.Count, prevStep);
				}
				
				paramCount = 0;
				foreach (IMeasurements m in equations)
				{
					for (int j = 0; j < m.Count; j++)
					{
						for (int i = 0; i < order - 1; i++)
						{
							prevDeri[paramCount, i] = prevDeri[paramCount, i + 1];
						}
						++paramCount;
					}
				}

				paramCount = 0;
				foreach (IMeasurements m in equations)
				{
					IDifferentialEquationSolver s = m as IDifferentialEquationSolver;
					s.CalculateDerivations();
					for(int j = 0; j < m.Count; j++)
					{
                        IDerivation der = m[j] as IDerivation;
						prevDeri[paramCount, order - 1] = der.Derivation;
						++paramCount;
					}
				}
				paramCount = 0;


				foreach (IMeasurements m in equations)
				{
					IDifferentialEquationSolver s = m as IDifferentialEquationSolver;
					for (int j = 0; j < m.Count; j++)
					{
						prevStep[paramCount] = oldStep[paramCount];
						for (int i = 0; i < order; i++)
						{
							prevStep[paramCount] += prevDeri[paramCount, i] * aqCoeff[i] * (t1 - t0);
						}
						++paramCount;
					}
					s.SetVariables(paramCount - m.Count, prevStep);
				}
				++stepCount;
			}
			isBusy = false;
		}
	}

	[Serializable()]
	public class TimeProvider : IDataConsumer, IMeasurements, ISerializable, ICategoryObject, IAlias,
		IPostSetArrow
	{
		
		/// <summary>
		/// The singleton
		/// </summary>
		public static readonly TimeProvider Singleton = new TimeProvider();
		
		private List<IMeasurements> measurementsData = new List<IMeasurements>();
		private string formulaString;
		private MathFormula formula;

		/// <summary>
		/// Trees
		/// </summary>
		private ObjectFormulaTree tree;

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

		/// <summary>
		/// Input parameter
		/// </summary>
		private DynamicalParameter par;

		/// <summary>
		/// Input arguments
		/// </summary>
		private ArrayList arguments = new ArrayList();

		/// <summary>
		/// All variables
		/// </summary>
		private string allVariables;

		/// <summary>
		/// Parameters
		/// </summary>
		private Hashtable parameters = new Hashtable();

		/// <summary>
		/// Derivation trees
		/// </summary>
		//private Hashtable derivations;
		
		/// <summary>
		/// External unaries
		/// </summary>
		private ArrayList unary = new ArrayList();


		/// <summary>
		/// Names of unaries
		/// </summary>
		private Hashtable unaryNames = new Hashtable();

		/// <summary>
		/// The "is serialized" sign
		/// </summary>
		private bool isSerialized = false;

		
		/// <summary>
		/// Comments
		/// </summary>
		protected ArrayList comments = new ArrayList();

		private object obj;



		bool isActive = true;
		
		bool isUpdated;


		private TimeProvider()
		{
		}

		/// <summary>
		/// Create aliases
		/// </summary>
		/// <param name="str">String of aliases</param>
		public void CreateAliases(string str)
		{
			parameters.Clear();
			foreach (char c in str)
			{
				double a = 0;
				parameters["" + c] = a;
			}
		}


		#region ISerializable Members
		public TimeProvider(SerializationInfo info, StreamingContext context)
		{
			try
			{
				formulaString = (string)info.GetValue("Formulas", typeof(string));
				isSerialized = true;
				arguments = (ArrayList)info.GetValue("Arguments", typeof(ArrayList));
				parameters = (Hashtable)info.GetValue("Parameters", typeof(Hashtable));
				unaryNames = (Hashtable)info.GetValue("Unaries", typeof(Hashtable));
				comments = (ArrayList)info.GetValue("Comments", typeof(ArrayList));
			}
			catch (Exception)
			{
			}
		}

		public void GetObjectData(SerializationInfo info, StreamingContext context)
		{
			info.AddValue("Formulas", formulaString);
			info.AddValue("Arguments", arguments);
			info.AddValue("Parameters", parameters);
			info.AddValue("Unaries", unaryNames);
			info.AddValue("Comments", comments);
		}

		#endregion

		#region IDataConsumer Members

		public void Add(IMeasurements arrow)
		{
			measurementsData.Add(arrow);
		}

		public void Remove(IMeasurements arrow)
		{
			measurementsData.Remove(arrow);
		}

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

		}

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

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

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

		#endregion

		#region IMeasurements Members

		IMeasure IMeasurements.this[int n]
		{
			get
			{
				return DataConsumer.TimeMeasure;
			}
		}

		public void UpdateMeasurements()
		{
			if (!isActive)
			{
				return;
			}
			if (IsUpdated)
			{
				return;
			}
			try
			{
				if (par == null)
				{
					throw new Exception(DynamicalParameter.UndefinedParameters);
				}
				if (tree == null)
				{
					throw new Exception("Formula are not accepted");
				}
				UpdateChildrenData();
				par.Set(arg);
				DataPerformerStrategy.Object.Time = ElementaryIntegerOperation.ToDouble(tree.Result);
				isUpdated = true;
			}
			catch (Exception e)
			{
				PureDesktop.ThrowException(this, e);
			}

		}


		public string SourceName
		{
			get
			{
				return "Timer";
			}
		}

		public bool IsUpdated
		{
			get
			{
				return isUpdated;
			}
			set
			{
				isUpdated = value;
			}
		}

		#endregion

		public bool IsActive
		{
			get
			{
				return isActive;
			}
			set
			{
				isActive = value;
			}
		}




		#region ICategoryObject Members

		public ICategory Category
		{
			get
			{
				// TODO:  Add TimeProvider.Category getter implementation
				return null;
			}
		}

		public ICategoryArrow Id
		{
			get
			{
				// TODO:  Add TimeProvider.Id getter implementation
				return null;
			}
		}

		#endregion

		#region IAssociatedObject Members

		public object Object
		{
			get
			{
				return obj;
			}
			set
			{
				obj = value;
			}
		}

		#endregion

		#region IAlias Members

		public List<string> AliasNames
		{
			get
			{
				List<string> s = new List<string>();
				foreach (string str in parameters.Keys)
				{
					s.Add(str);
				}
				return s;
			}
		}

		object DiagramUI.IAlias.this[string alias]
		{
			get
			{
				return parameters[alias];
			}
			set
			{
				char c = alias[0];
				double a = (double)value;
				arg[c] = a;
				parameters[alias] = a;
				DataPerformerStrategy.Object.Time = ElementaryIntegerOperation.ToDouble(tree.Result);
			}
		}

        public object GetType(int n)
        {
            Double a = 0;
            return a;
        }


		#endregion


		/// <summary>
		/// The operation that performs after arrows setting
		/// </summary>
		public void PostSetArrow()
		{
			DynamicalParameter parameter = new DynamicalParameter();
            foreach (IMeasurements measurements in measurementsData)
			{
				IAssociatedObject cont = measurements as IAssociatedObject;
				INamedComponent nc = cont.Object as INamedComponent;
				string name = nc.Name;
				for (int i = 0; i < measurements.Count; i++)
				{
					IMeasure measure = measurements[i];
					string p = name + "." + measure.Name;
					foreach (string s in arguments)
					{
						if (s.Substring(4).Equals(p))
						{
							char c = s[0];
							parameter.Add(c, measure);
						}
					}
				}
			}
			foreach (string s in arguments)
			{
				if (s.Substring(4).Equals("Time"))
				{
					parameter.Add(s[0], DataConsumer.TimeMeasure);
				}
			}
			Parameter = parameter;
			string argStr = AllVariables; 
			foreach (string key in parameters.Keys)
			{
				arg[key[0]] = parameters[key];
			}
			postSetUnary();
		}
		


		/// <summary>
		/// Comments
		/// </summary>
		public ArrayList Comments
		{
			get
			{
				return comments;
			}
			set
			{
				comments = value;
			}
		}

		/// <summary>
		/// String representation of formula
		/// </summary>
		public string Formula
		{
			get
			{
				return formulaString;
			}
			set
			{
				formulaString = value;
			}
		}

		/// <summary>
		/// Accepts formulas
		/// </summary>
		public void AcceptFormulas()
		{
			try
			{
				parameters.Clear();
				arguments.Clear();
				par = null;
				formula = MathFormula.FromString(MathSymbolFactory.Sizes, formulaString);
				allVariables = ElementaryObjectDetector.GetVariables(formula);
			}
			catch (Exception e)
			{
				PureDesktop.ThrowException(this, e);
			}
		}



		/// <summary>
		/// Variables
		/// </summary>
		public string Variables
		{
			get
			{
				try
				{
					string s = "";
					string str = ElementaryObjectDetector.GetVariables(formula);
					foreach (char c in str)
					{
						if (!parameters.ContainsKey("" + c) & s.IndexOf(c) < 0)
						{
							s += c;
						}
					}					
					return s;
				}
				catch (Exception)
				{
				}
				return "";
			}
		}

		/// <summary>
		/// Arguments of this object
		/// </summary>
		public ArrayList Arguments
		{
			get
			{
				return arguments;
			}
			set
			{
				string str = Variables;
				bool b = false;
				foreach (char c in str)
				{
					foreach (string s in value)
					{
						if (s[0] == c)
						{
							goto m;
						}
					}
					throw new Exception(VectorFormulaConsumer.VariablesShortage);
				m:
					b = b;
				}
				arguments = value;
			}
		}



		/// <summary>
		/// All formulas variables
		/// </summary>
		public string AllVariables
		{
			get
			{
				try
				{
					if (allVariables == null)
					{
						formula = MathFormula.FromString(MathSymbolFactory.Sizes, formulaString);
						allVariables = ElementaryObjectDetector.GetVariables(formula);
					}
					return allVariables;
				}
				catch (Exception)
				{
				}
				return "";
			}
		}

		
		/// <summary>
		/// Adds unary source
		/// </summary>
		/// <param name="u">The source to add</param>
		public void AddUnary(IUnary u)
		{
			unary.Add(u);
		}

		/// <summary>
		/// Count of external unaries
		/// </summary>
		public int UnaryCount
		{
			get
			{
				return unary.Count;
			}
		}

		/// <summary>
		/// Gets i - th external unary
		/// </summary>
		/// <param name="i">The index of unary</param>
		/// <returns>The i - th unary</returns>
		public IUnary GetUnary(int i)
		{
			return unary[i] as IUnary;
		}

		/// <summary>
		/// Table of unaries
		/// </summary>
		public Hashtable UnaryTable
		{
			set
			{
				setUnaryNames(value);
				setUnaryTrees(value);
			}
			get
			{
				if (tree != null)
				{
					return ElementaryUnaryOperation.GetUnaryTable(tree);
				}
				return new Hashtable();
			}
		}

		/// <summary>
		/// Names of external unatries
		/// </summary>
		public Hashtable UnaryNames
		{
			get
			{
				return unaryNames;
			}
		}

		

		/// <summary>
		/// Removes unary source
		/// </summary>
		/// <param name="u">The source to add</param>
		public void RemoveUnary(IUnary u)
		{
			unary.Remove(u);
		}

		/// <summary>
		/// List of outside unary functions
		/// </summary>
		public ArrayList UnaryList
		{
			get
			{
				return ElementaryUnaryOperation.GetUnaryIndexes(tree);
			}
		}

		/// <summary>
		/// Input parameters
		/// </summary>
		public string InputParameters
		{
			get
			{
				string var = Variables;
				string s = "";
				foreach (char c in var)
				{
					if (parameters.ContainsKey("" + c))
					{
						continue;
					}
					s += c;
				}
				return s;
			}
		}

		/// <summary>
		/// The input dynamical parameter
		/// </summary>
		public DynamicalParameter Parameter
		{
			set
			{
				par = value;
				if (!isSerialized)
				{
					arguments.Clear();
				}
				isSerialized = false;
				Hashtable table = new Hashtable();
				string var = par.Variables;
				Double a = 0;
				if (allVariables == null)
				{
					allVariables = AllVariables;
				}
				foreach (char c in allVariables)
				{
					table[c] = a;
				}
				foreach (char c in var)
				{
					IMeasure m = par[c];
					table[c] = m.Type;
				}
				IFormulaObjectCreator creator = new FormulaArrayObjectCreator(
					new ElementaryObjectsCreator(table));
				MathFormula f = formula.FullTransform;
				tree = new ObjectFormulaTree(f, creator);
				arg = new ElementaryObjectArgument();
				arg.Add(tree);
				string str = par.Variables;
				Hashtable unaryTable = ElementaryUnaryOperation.GetUnaryTable(tree);
			}
		}

		private void setUnaryNames(Hashtable table)
		{
			unaryNames.Clear();
			foreach (int i in table.Keys)
			{
				ICategoryObject o = table[i] as ICategoryObject;
				//IObjectLabel l = o.Object as IObjectLabel;
				unaryNames[i] = PureDesktop.GetRelativeName(this, o);//l.Name;
			}
		}

		private void setUnaryTrees(Hashtable table)
		{
			string str = Variables;
			ElementaryUnaryOperation.SetUnary(tree, table);
		}

		
		private void postSetUnary()
		{
			Hashtable t = new Hashtable();
			foreach (ICategoryObject o in unary)
			{
				//IObjectLabel l = o.Object as IObjectLabel;
				string name = PureDesktop.GetRelativeName(this, o);//l.Name;
				if (!unaryNames.ContainsValue(name))
				{
					continue;
				}
				foreach (int i in unaryNames.Keys)
				{
					if (name.Equals(unaryNames[i]))
					{
						t[i] = o;
						break;
					}
				}
			}
			setUnaryTrees(t);
		}

	}

	/// <summary>
	/// Solver of differential equations system
	/// </summary>
	public interface IDifferentialEquationSolver : IMeasurements
	{
		/// <summary>
		/// Calculates derivations
		/// </summary>
		void CalculateDerivations();

		/// <summary>
		/// Sets variables to array
		/// </summary>
		/// <param name="b">Offset</param>
		/// <param name="x">The array</param>
		void SetVariables(int b, double[] x);
	}

	/// <summary>
	/// The parametrized series
	/// </summary>
	public class ParametrizedSeries : Series
	{
		protected MeasureParameter x;
		protected MeasureParameter y;
		public ParametrizedSeries(MeasureParameter x, MeasureParameter y)
		{
			this.x = x;
			this.y = y;
		}
		public virtual void Step()
		{
			AddXY(ElementaryIntegerOperation.ToDouble(x()), ElementaryIntegerOperation.ToDouble(y()));
		}
	}


	public interface IDataPerformerStrategy
	{
		/// <summary>
		/// Updates all components
		/// </summary>
		/// <param name="d">Desktop</param>
		void UpdateAll(IDesktop d);

		/// <summary>
		/// Starts all components
		/// </summary>
		/// <param name="d">Desktop</param>
		void StartAll(IDesktop d);

		/// <summary>
		/// Preparation
		/// </summary>
		/// <param name="d">Desktop</param>
		void PrepareAll(IDesktop d);

		/// <summary>
		/// Clears all components
		/// </summary>
		void ClearAll();

		/// <summary>
		/// Time
		/// </summary>
		double Time
		{
			get;
			set;
		}
	}

	public class DataPerformerStrategy : IDataPerformerStrategy, IStep
	{

		protected ArrayList components = new ArrayList();
		protected ArrayList objects = new ArrayList();
		protected ArrayList arrows = new ArrayList();
		protected ArrayList updatable = new ArrayList();
		protected int step;
		protected ArrayList dynamical = new ArrayList();
		protected ArrayList measurements = new ArrayList();
		protected double time;
		static private DataPerformerStrategy strategy;


		public DataPerformerStrategy()
		{

		}

		#region IDataPerformerStrategy Members


		/// <summary>
		/// Updates all elements
		/// </summary>
		public virtual void UpdateAll(IDesktop d)
		{
			foreach (IUpdatableObject up in updatable)
			{
				up.UpdateObject();
			}
		}


		/// <summary>
		/// Starts all desktop elements
		/// </summary>
		public virtual void StartAll(IDesktop d)
		{
			ICollection components = d.AllComponents;
			foreach (INamedComponent c in components)
			{
				if (c is IObjectLabel)
				{
					IObjectLabel l = c as IObjectLabel;
					if (!(l.Object is IStarted))
					{
						continue;
					}
					IStarted s = l.Object as IStarted;
					s.Start();
					continue;
				}
				if (c is IArrowLabel)
				{
					IArrowLabel l = c as IArrowLabel;
					if (!(l.Arrow is IStarted))
					{
						continue;
					}
					IStarted s = l.Arrow as IStarted;
					s.Start();
					continue;
				}
			}

		}

		public virtual void PrepareAll(IDesktop d)
		{
			ClearAll();
			prepareAll(d);
			updatable.Clear();
			foreach (INamedComponent c in components)
			{
				object o = null;
				if (c is IObjectLabel)
				{
					IObjectLabel l = c as IObjectLabel;
					o = l.Object;
				}
				else if (c is IArrowLabel)
				{
					IArrowLabel l = c as IArrowLabel;
					o = l.Arrow;
				}
				if (o == null)
				{
					continue;
				}
				if (o is IDynamical)
				{
					continue;
				}
				if (!(o is IUpdatableObject))
				{
					continue;
				}
				IUpdatableObject up = o as IUpdatableObject;
				if (up.ShouldUpdate)
				{
					updatable.Add(up);
				}
			}
			foreach (INamedComponent comp in components)
			{
				IDynamical dyn = null;
				if (comp is IObjectLabel)
				{
					IObjectLabel label = comp as IObjectLabel;
					ICategoryObject obj = label.Object;
					if (!(obj is IDynamical))
					{
						continue;
					}
					dyn = obj as IDynamical;
				}
				else if (comp is IArrowLabel)
				{
					IArrowLabel label = comp as IArrowLabel;
					ICategoryArrow arr = label.Arrow;
					if (!(arr is IDynamical))
					{
						continue;
					}
					dyn = arr as IDynamical;
				}
				dynamical.Add(dyn);
			}
			foreach (INamedComponent comp in components)
			{
				if (!(comp is IObjectLabel))
				{
					continue;
				}
				IObjectLabel l = comp as IObjectLabel;
				object ob = l.Object;
				if (!(ob is IMeasurements))
				{
					continue;
				}
				IMeasurements m = ob as IMeasurements;
				measurements.Add(m);
			}
		}


		/// <summary>
		/// Clears all components
		/// </summary>
		public void ClearAll()
		{
			if (components != null)
			{
				components.Clear();
			}
			if (objects != null)
			{
				objects.Clear();
			}
			if (arrows != null)
			{
				arrows.Clear();
			}
			updatable.Clear();
			dynamical.Clear();
			measurements.Clear();
			GC.Collect();
		}

		public double Time
		{
			get
			{
				return time;
			}
			set
			{
				time = value;
				foreach (IDynamical dyn in dynamical)
				{
					dyn.Time = value;
				}
				UpdateAll(null);
				ResetUpdatedMeasurements();
			}
		}



		#endregion


		#region IStep Members

		public int Step
		{
			get
			{
				return step;
			}
			set
			{
				step = value;
				foreach (object c in components)
				{
					object o = null;
					if (c is IObjectLabel)
					{
						IObjectLabel l = c as IObjectLabel;
						o = l.Object;

					}
					if (c is IArrowLabel)
					{
						IArrowLabel l = c as IArrowLabel;
						o = l.Arrow;
					}
					if (!(o is IStep))
					{
						continue;
					}
					IStep s = o as IStep;
					s.Step = value;
				}
			}
		}

		public void ResetUpdatedMeasurements()
		{
			foreach (IMeasurements m in measurements)
			{
				m.IsUpdated = false;
			}
		}

		#endregion

		#region Specific Members

		
		public static DataPerformerStrategy Object
		{
			get
			{
				return strategy;
			}
			set
			{
				strategy = value;
			}
		}

	

		
		public ICollection Components
		{
			get
			{
				return components;
			}
		}

		private void prepareAll(IDesktop d)
		{
			ICollection comps = d.Components;
			foreach (INamedComponent c in comps)
			{
				components.Add(c);
				if (c is IArrowLabel)
				{
					arrows.Add(c);
					continue;
				}
				if (!(c is IObjectLabel))
				{
					continue;
				}
				objects.Add(c);
				IObjectLabel l = c as IObjectLabel;
				if (l.Object is ObjectContainer)
				{
					ObjectContainer cont = l.Object as ObjectContainer;
					prepareAll(cont.Desktop);
				}
			}
		}


		#endregion

	}



	public class ArraySelectionCollection : IStructuredSelectionCollection, IMeasurements
	{
		#region Fields

		private ArraySelection[] selections;

		#endregion

		#region Constructors

		protected ArraySelectionCollection()
		{
		}

		#endregion

		#region IStructuredSelectionCollection Members

		int IStructuredSelectionCollection.Count
		{
			get
			{
				return selections.Length;
			}
		}

		IStructuredSelection IStructuredSelectionCollection.this[int i]
		{
			get
			{
				return selections[i];
			}
		}

		#endregion

		#region IMeasurements Members

		int IMeasurements.Count
		{
			get
			{
				return selections.Length;
			}
		}



		IMeasure IMeasurements.this[int n]
		{
			get
			{
				return selections[n];
			}
		}

		public void UpdateMeasurements()
		{
		}

		public string SourceName
		{
			get
			{
				return "";
			}
		}

		public bool IsUpdated
		{
			get
			{
				return true;
			}
			set
			{
			}
		}

		#endregion

		#region Specific Members

		protected void Set(string[] names, double[][] data)
		{
			if (names.Length != data.Length)
			{
				throw new Exception("Names length does not coincides with data length");
			}
			selections = new ArraySelection[names.Length];
			for (int i = 0; i < selections.Length; i++)
			{
				selections[i] = new ArraySelection(names[i], data[i]);
			}
		}

		#endregion
	}

	/// <summary>
	/// Scale selector
	/// </summary>
	public interface IScaleSelector
	{
		/// <summary>
		/// Selects scale
		/// </summary>
		/// <param name="scale">Scale</param>
		/// <returns>Selected scale</returns>
		double SelectScale(double scale);
	}


	/// <summary>
	/// Power scale selector
	/// </summary>
	public class PowerScaleSelector : IScaleSelector
	{
		
		#region Fields

		double begin;

		double pow;

		double[] scales;

		#endregion

		#region Constructors

		public PowerScaleSelector(double begin, double pow, double[] scales)
		{
			this.begin = begin;
			this.pow = pow;
			this.scales = scales;
		}

		#endregion
		
		
		#region IScaleSelector Members

		public double SelectScale(double scale)
		{
			double log = Math.Floor(Math.Log(scale / (begin * scales[0])) / Math.Log(pow));
			double b = begin * Math.Exp(log * Math.Log(pow));
			for (int i = 0; i < scales.Length; i++)
			{
				if (b * scales[i] > scale)
				{
					return b * scales[i];
				}
			}
			return 1;
		}

		#endregion
	}

	/// <summary>
	/// Histogram
	/// </summary>
	public class Histogram
	{

		/// <summary>
		/// Gets histogram
		/// </summary>
		/// <param name="selection">Selection</param>
		/// <param name="scaleSelector">Scale selector</param>
		/// <param name="prefferedSize">Preffered size</param>
		/// <returns>The histogram</returns>
		public static double[,] GetHistogram(double[] selection, IScaleSelector scaleSelector, int prefferedSize)
		{
			ArrayList l = new ArrayList(selection);
			l.Sort();
			double min = (double) l[0];
			double max = (double) l[selection.Length - 1];
			double a = (max - min) / (prefferedSize + 1);
			double scale = a;
			if (scaleSelector != null)
			{
				scale = scaleSelector.SelectScale(a);
			}
			int nmin = (int) (Math.Floor(min) / scale);
			int nmax = (int) (Math.Ceiling(max) / scale);
			int diapCount = nmax - nmin;
			double[,] data = new double[diapCount, 2];
			double current = (double) (nmin * scale);
			int nSel = 0;
			for (int i = 0; i < diapCount; i++)
			{
				data[i, 0] = current;
				data[i, 1] = 0;
				if (nSel < l.Count)
				{
					while (true)
					{
						double x = (double) l[nSel];
						if (x > (current + scale))
						{
							break;
						}
						++data[i, 1];
						++nSel;
						if (nSel >= l.Count)
						{
							break;
						}
					}
				}
				current += scale;
			}
			return data;
		}
	}
}
