context: /* Copyright (C) 2004 - 2009  Versant Inc.  http://www.db4o.com */
  
  using System;
  using System.Collections;
  using Db4objects.Db4o.Foundation;
  using Db4objects.Db4o.Internal;
  using Db4objects.Db4o.Qlin;
  using Db4objects.Db4o.Reflect;
  using Db4objects.Db4o.Reflect.Core;
  using Db4objects.Db4o.Reflect.Generic;
  
  namespace Db4objects.Db4o.Qlin
  {
  	/// <summary>creates prototype objects for classes.</summary>
  	/// <remarks>
  	/// creates prototype objects for classes. Each field on prototype objects is set
  	/// to a newly created object or primitive that can be identified either by it's
  	/// identity or by an int ID that is generated by the system. Creation of fields
  	/// is recursed to the depth specified in the constructor.<br />
  	/// <br />
  	/// Allows analyzing expressions called on prototype objects to find the
  	/// underlying field that delivers the return value of the expression. Passed
  	/// expressions should not have side effects on objects, otherwise the
  	/// "prototype world" will no longer work.<br />
  	/// <br />
  	/// We plan to supply an ImmutableFieldClassLoader to instrument the code to
  	/// throw on every modification. This ClassLoader could also supply information
  	/// about all the method calls involved.<br />
  	/// <br />
  	/// For now our approach only works if expressions are directly backed by a
  	/// single field.<br />
  	/// <br />
  	/// We were inspired for this approach when we saw that Thomas Mueller managed to
  	/// map expressions to fields for his JaQu query interface, Kudos!
  	/// http://www.h2database.com/html/jaqu.html<br />
  	/// <br />
  	/// We took the idea a bit further and made it work for all primitives except for
  	/// boolean and we plan to also get deeper expressions, collections and
  	/// interfaces working nicely.
  	/// </remarks>
  	public class Prototypes
  	{
  		private readonly IReflector _reflector;
  
  		private readonly Hashtable4 _prototypes = new Hashtable4();
  
  		private readonly bool _ignoreTransient;
  
  		private readonly int _recursionDepth;
  
  		public Prototypes(IReflector reflector, int recursionDepth, bool ignoreTransient)
  		{
  			_reflector = reflector;
  			_recursionDepth = recursionDepth;
  			_ignoreTransient = ignoreTransient;
  		}
  
  		public Prototypes() : this(DefaultReflector(), 5, false)
  		{
  		}
  
  		/// <summary>returns a prototype object for a specific class.</summary>
  		/// <remarks>returns a prototype object for a specific class.</remarks>
  		public virtual object PrototypeForClass(Type clazz)
  		{
  			if (clazz == null)
  			{
  				throw new PrototypesException("Class can not be null");
  			}
  			IReflectClass claxx = _reflector.ForClass(clazz);
  			if (claxx == null)
  			{
  				throw new PrototypesException("Not found in the reflector: " + clazz);
  			}
  			string className = claxx.GetName();
  			Prototypes.Prototype prototype = (Prototypes.Prototype)_prototypes.Get(className);
  			if (prototype != null)
  			{
  				return prototype.Object();
  			}
  			prototype = new Prototypes.Prototype(this, claxx);
  			_prototypes.Put(className, prototype);
  			return prototype.Object();
  		}
  
  		/// <summary>
  		/// analyzes the passed expression and tries to find the path to the
  		/// backing field that is accessed.
  		/// </summary>
  		/// <remarks>
  		/// analyzes the passed expression and tries to find the path to the
  		/// backing field that is accessed.
  		/// </remarks>
  		public virtual IEnumerator BackingFieldPath(Type clazz, object expression)
  		{
  			return BackingFieldPath(_reflector.ForClass(clazz), expression);
  		}
  
  		/// <summary>
  		/// analyzes the passed expression and tries to find the path to the
  		/// backing field that is accessed.
  		/// </summary>
  		/// <remarks>
  		/// analyzes the passed expression and tries to find the path to the
  		/// backing field that is accessed.
  		/// </remarks>
  		public virtual IEnumerator BackingFieldPath(IReflectClass claxx, object expression
  			)
  		{
  			return BackingFieldPath(claxx.GetName(), expression);
  		}
  
  		/// <summary>
  		/// analyzes the passed expression and tries to find the path to the
  		/// backing field that is accessed.
  		/// </summary>
  		/// <remarks>
  		/// analyzes the passed expression and tries to find the path to the
  		/// backing field that is accessed.
  		/// </remarks>
  		public virtual IEnumerator BackingFieldPath(string className, object expression)
  		{
  			Prototypes.Prototype prototype = (Prototypes.Prototype)_prototypes.Get(className);
  			if (prototype == null)
  			{
  				return null;
  			}
  			return prototype.BackingFieldPath(_reflector, expression);
  		}
  
  		private class Prototype
  		{
  			private readonly IdentityHashtable4 _fieldsByIdentity = new IdentityHashtable4();
  
  			private readonly Hashtable4 _fieldsByIntId = new Hashtable4();
  
  			private readonly object _object;
  
  			private int intIdGenerator;
  
  			public Prototype(Prototypes _enclosing, IReflectClass claxx)
  			{
  				this._enclosing = _enclosing;
  				this._object = (object)claxx.NewInstance();
  				if (this._object == null)
  				{
  					throw new PrototypesException("Prototype could not be created for class " + claxx
  						.GetName());
  				}
  				this.Analyze(this._object, claxx, this._enclosing._recursionDepth, null);
  			}
  
  			private void Analyze(object @object, IReflectClass claxx, int depth, List4 parentPath
  				)
  			{
  				if (depth < 0)
  				{
  					return;
  				}
  				ReflectorUtils.ForEachField(claxx, new _IProcedure4_130(this, parentPath, claxx, 
  					@object, depth));
  			}
  
  			private sealed class _IProcedure4_130 : IProcedure4
  			{
  				public _IProcedure4_130(Prototype _enclosing, List4 parentPath, IReflectClass claxx
  					, object @object, int depth)
  				{
  					this._enclosing = _enclosing;
  					this.parentPath = parentPath;
  					this.claxx = claxx;
  					this.@object = @object;
  					this.depth = depth;
  				}
  
  				public void Apply(object field)
  				{
  					if (((IReflectField)field).IsStatic())
  					{
  						return;
  					}
  					if (this._enclosing._enclosing._ignoreTransient && ((IReflectField)field).IsTransient
  						())
  					{
  						return;
  					}
  					IReflectClass fieldType = ((IReflectField)field).GetFieldType();
  					List4 path = new List4(parentPath, ((IReflectField)field));
  					Prototypes.IntegerConverter converter = Prototypes.IntegerConverterforClassName(claxx
  						.Reflector(), fieldType.GetName());
  					if (converter != null)
  					{
  						int id = ++this._enclosing.intIdGenerator;
  						object integerRepresentation = converter.FromInteger(id);
  						if (!Prototypes.TrySetField(((IReflectField)field), @object, integerRepresentation
  							))
  						{
  							return;
  						}
  						this._enclosing._fieldsByIntId.Put(id, new Pair(integerRepresentation, path));
  						return;
  					}
  					if (!fieldType.IsPrimitive())
  					{
  						object identityInstance = fieldType.NewInstance();
  						if (identityInstance == null)
  						{
  							return;
  						}
  						if (!Prototypes.TrySetField(((IReflectField)field), @object, identityInstance))
  						{
  							return;
  						}
  						this._enclosing._fieldsByIdentity.Put(identityInstance, path);
  						this._enclosing.Analyze(identityInstance, claxx, depth - 1, path);
  					}
  				}
  
  				private readonly Prototype _enclosing;
  
  				private readonly List4 parentPath;
  
  				private readonly IReflectClass claxx;
  
  				private readonly object @object;
  
  				private readonly int depth;
  			}
  
  			public virtual object Object()
  			{
  				return this._object;
  			}
  
  			public virtual IEnumerator BackingFieldPath(IReflector reflector, object expression
  				)
  			{
  				if (expression == null)
  				{
  					return null;
  				}
  				IReflectClass claxx = reflector.ForObject(expression);
  				if (claxx == null)
  				{
  					return null;
  				}
  				Prototypes.IntegerConverter converter = Prototypes.IntegerConverterforClassName(reflector
  					, claxx.GetName());
  				if (converter != null)
  				{
  					Pair entry = (Pair)this._fieldsByIntId.Get(converter.ToInteger(expression));
  					if (entry == null)
  					{
  						return null;
  					}
  					if (entry.first.Equals(expression))
  					{
  						return this.AsIterator((List4)entry.second);
  					}
  					return null;
  				}
  				if (claxx.IsPrimitive())
  				{
  					return null;
  				}
  				return this.AsIterator((List4)this._fieldsByIdentity.Get(expression));
  			}
  
  			private IEnumerator AsIterator(List4 lastElement)
  			{
  				return Iterators.Revert(Iterators.Map(Iterators.Iterate(lastElement), new _IFunction4_198
  					()));
  			}
  
  			private sealed class _IFunction4_198 : IFunction4
  			{
  				public _IFunction4_198()
  				{
  				}
  
  				public object Apply(object field)
  				{
  					return ((IReflectField)field).GetName();
  				}
  			}
  
  			private readonly Prototypes _enclosing;
  		}
  
  		private static Prototypes.IntegerConverter IntegerConverterforClassName(IReflector
  			 reflector, string className)
  		{
  			if (_integerConverters == null)
  			{
  				_integerConverters = new Hashtable4();
  				Prototypes.IntegerConverter[] converters = new Prototypes.IntegerConverter[] { new 
  					_IntegerConverter_211(), new _IntegerConverter_215(), new _IntegerConverter_219(
  					), new _IntegerConverter_223(), new _IntegerConverter_227(), new _IntegerConverter_231
  					(), new _IntegerConverter_235(), new _IntegerConverter_239() };
  				for (int converterIndex = 0; converterIndex < converters.Length; ++converterIndex)
  				{
  					Prototypes.IntegerConverter converter = converters[converterIndex];
  					_integerConverters.Put(converter.PrimitiveName(), converter);
  					if (!converter.PrimitiveName().Equals(converter.WrapperName(reflector)))
  					{
  						_integerConverters.Put(converter.WrapperName(reflector), converter);
  					}
  				}
  			}
  			return (Prototypes.IntegerConverter)_integerConverters.Get(className);
  		}
  
  		private sealed class _IntegerConverter_211 : Prototypes.IntegerConverter
  		{
  			public _IntegerConverter_211()
  			{
  			}
  
  			public override string PrimitiveName()
  			{
  				return typeof(int).FullName;
  			}
  
  			public override object FromInteger(int i)
  			{
  				return i;
  			}
  		}
  
  		private sealed class _IntegerConverter_215 : Prototypes.IntegerConverter
  		{
  			public _IntegerConverter_215()
  			{
  			}
  
  			public override string PrimitiveName()
  			{
  				return typeof(long).FullName;
  			}
  
  			public override object FromInteger(int i)
  			{
  				return System.Convert.ToInt64(i);
  			}
  		}
  
  		private sealed class _IntegerConverter_219 : Prototypes.IntegerConverter
  		{
  			public _IntegerConverter_219()
  			{
  			}
  
  			public override string PrimitiveName()
  			{
  				return typeof(double).FullName;
  			}
  
  			public override object FromInteger(int i)
  			{
  				return System.Convert.ToDouble(i);
  			}
  		}
  
  		private sealed class _IntegerConverter_223 : Prototypes.IntegerConverter
  		{
  			public _IntegerConverter_223()
  			{
  			}
  
  			public override string PrimitiveName()
  			{
  				return typeof(float).FullName;
  			}
  
  			public override object FromInteger(int i)
  			{
  				return System.Convert.ToSingle(i);
  			}
  		}
  
  		private sealed class _IntegerConverter_227 : Prototypes.IntegerConverter
  		{
  			public _IntegerConverter_227()
  			{
  			}
  
  			public override string PrimitiveName()
  			{
  				return typeof(byte).FullName;
  			}
  
  			public override object FromInteger(int i)
  			{
  				return (byte)i;
  			}
  		}
  
  		private sealed class _IntegerConverter_231 : Prototypes.IntegerConverter
  		{
  			public _IntegerConverter_231()
  			{
  			}
  
  			public override string PrimitiveName()
  			{
  				return typeof(char).FullName;
  			}
  
  			public override object FromInteger(int i)
  			{
  				return (char)i;
  			}
  		}
  
  		private sealed class _IntegerConverter_235 : Prototypes.IntegerConverter
  		{
  			public _IntegerConverter_235()
  			{
  			}
  
  			public override string PrimitiveName()
  			{
  				return typeof(short).FullName;
  			}
  
  			public override object FromInteger(int i)
  			{
  				return (short)i;
  			}
  		}
  
  		private sealed class _IntegerConverter_239 : Prototypes.IntegerConverter
  		{
  			public _IntegerConverter_239()
  			{
  			}
  
  			public override string PrimitiveName()
  			{
  				return typeof(string).FullName;
  			}
  
  			public override object FromInteger(int i)
  			{
  				return Prototypes.StringIdentifier + i;
  			}
  
  			public override int ToInteger(object obj)
  			{
  				if (!(obj is string))
  				{
  					return -1;
  				}
  				string str = (string)obj;
  				if (str.Length < Prototypes.StringIdentifier.Length)
  				{
  					return -1;
  				}
  
gt: 				if (str.IndexOf(Prototypes.StringIdentifier) != 0)