context: using System;
  using System.Collections.Generic;
  using System.Text;
  
  using NHibernate.Engine;
  using NHibernate.Param;
  using NHibernate.Persister.Collection;
  using NHibernate.Persister.Entity;
  using NHibernate.Type;
  using NHibernate.Util;
  
  namespace NHibernate.Hql.Ast.ANTLR.Tree
  {
  	/// <summary>
  	/// Delegate that handles the type and join sequence information for a FromElement.
  	/// Author: josh
  	/// Ported by: Steve Strong
  	/// </summary>
  	[CLSCompliant(false)]
  	public class FromElementType
  	{
  		private static readonly IInternalLogger Log = LoggerProvider.LoggerFor(typeof(FromElementType));
  
  		private readonly FromElement _fromElement;
  		private readonly IEntityPersister _persister;
  		private readonly EntityType _entityType;
  		private IQueryableCollection _queryableCollection;
  		private CollectionPropertyMapping _collectionPropertyMapping;
  		private JoinSequence _joinSequence;
  		private IParameterSpecification _indexCollectionSelectorParamSpec;
  		private string _collectionSuffix;
  
  		public FromElementType(FromElement fromElement, IEntityPersister persister, EntityType entityType)
  		{
  			_fromElement = fromElement;
  			_persister = persister;
  			_entityType = entityType;
  
  			var queryable = persister as IQueryable;
  			if (queryable != null)
  				fromElement.Text = queryable.TableName + " " + fromElement.TableAlias;
  		}
  
  		protected FromElementType(FromElement fromElement)
  		{
  			_fromElement = fromElement;
  		}
  
  		public IEntityPersister EntityPersister
  		{
  			get { return _persister; }
  		}
  
  		private string TableAlias
  		{
  			get { return _fromElement.TableAlias; }
  		}
  
  		private string CollectionTableAlias
  		{
  			get { return _fromElement.CollectionTableAlias; }
  		}
  
  		public virtual IType DataType
  		{
  			get
  			{
  				if (_persister == null)
  				{
  					if (_queryableCollection == null)
  					{
  						return null;
  					}
  					return _queryableCollection.Type;
  				}
  				else
  				{
  					return _entityType;
  				}
  			}
  		}
  
  		public IType SelectType
  		{
  			get
  			{
  				if (_entityType == null)
  				{
  					return null;
  				}
  
  				bool shallow = _fromElement.FromClause.Walker.IsShallowQuery;
  				return TypeFactory.ManyToOne(_entityType.GetAssociatedEntityName(), shallow);
  			}
  		}
  
  		public string CollectionSuffix
  		{
  			get { return _collectionSuffix; }
  			set { _collectionSuffix = value; }
  		}
  
  		public IParameterSpecification IndexCollectionSelectorParamSpec
  		{
  			get { return _indexCollectionSelectorParamSpec; }
  			set { _indexCollectionSelectorParamSpec = value; }
  		}
  
  		public JoinSequence JoinSequence
  		{
  			get
  			{
  				if (_joinSequence != null)
  				{
  					return _joinSequence;
  				}
  
  				// Class names in the FROM clause result in a JoinSequence (the old FromParser does this).
  				var joinable = _persister as IJoinable;
  				if (joinable != null)
  				{
  					return _fromElement.SessionFactoryHelper.CreateJoinSequence().SetRoot(joinable, TableAlias);
  				}
  				
  				return null; // TODO: Should this really return null?  If not, figure out something better to do here.
  			}
  			set { _joinSequence = value; }
  		}
  
  		/// <summary>
  		/// Returns the identifier select SQL fragment.
  		/// </summary>
  		/// <param name="size">The total number of returned types.</param>
  		/// <param name="k">The sequence of the current returned type.</param>
  		/// <returns>the identifier select SQL fragment.</returns>
  		public string RenderIdentifierSelect(int size, int k)
  		{
  			CheckInitialized();
  
  			// Render the identifier select fragment using the table alias.
  			if (_fromElement.FromClause.IsSubQuery)
  			{
  				var queryable = Queryable;
  				if (queryable == null)
  					return string.Empty;
  
  				// TODO: Replace this with a more elegant solution.
  				string[] idColumnNames = queryable.IdentifierColumnNames;
  
  				var buf = new StringBuilder();
  				for (int i = 0; i < idColumnNames.Length; i++)
  				{
  					buf.Append(_fromElement.TableAlias).Append('.').Append(idColumnNames[i]);
  					if (i != idColumnNames.Length - 1) buf.Append(", ");
  				}
  				return buf.ToString();
  			}
  			else
  			{
  				var queryable = Queryable;
  				if (queryable == null)
  					throw new QueryException("not an entity");
  				
  				string fragment = queryable.IdentifierSelectFragment(TableAlias, GetSuffix(size, k));
  				return TrimLeadingCommaAndSpaces(fragment);
  			}
  		}
  
  		/// <summary>
  		/// Render the identifier select, but in a 'scalar' context (i.e. generate the column alias).
  		/// </summary>
  		/// <param name="i">the sequence of the returned type</param>
  		/// <returns>the identifier select with the column alias.</returns>
  		public virtual string RenderScalarIdentifierSelect(int i)
  		{
  			CheckInitialized();
  			string[] cols = GetPropertyMapping(Persister.Entity.EntityPersister.EntityID).ToColumns(TableAlias, Persister.Entity.EntityPersister.EntityID);
  			StringBuilder buf = new StringBuilder();
  			// For property references generate <tablealias>.<columnname> as <projectionalias>
  			for (int j = 0; j < cols.Length; j++)
  			{
  				string column = cols[j];
  				if (j > 0)
  				{
  					buf.Append(", ");
  				}
  				buf.Append(column).Append(" as ").Append(NameGenerator.ScalarName(i, j));
  			}
  			return buf.ToString();
  		}
  
  
  		/// <summary>
  		/// Returns the property select SQL fragment.
  		/// </summary>
  		/// <param name="size">The total number of returned types.</param>
  		/// <param name="k">The sequence of the current returned type.</param>
  		/// <param name="allProperties"></param>
  		/// <returns>the property select SQL fragment.</returns>
  		public string RenderPropertySelect(int size, int k, bool allProperties)
  		{
  			CheckInitialized();
  
  			var queryable = Queryable;
  			if (queryable == null)
  				return "";
  
  			string fragment = queryable.PropertySelectFragment(TableAlias, GetSuffix(size, k), allProperties);
  
  			return TrimLeadingCommaAndSpaces(fragment);
  		}
  
  		public string RenderCollectionSelectFragment(int size, int k)
  		{
  			if (_queryableCollection == null)
  				return "";
  
  			if (_collectionSuffix == null)
  
gt: 				_collectionSuffix = GenerateSuffix(size, k);