context: //
  // LinqDataSourceView.cs
  //
  // Author:
  //   Atsushi Enomoto  <atsushi@ximian.com>
  //
  // Copyright (C) 2008 Novell, Inc  http://novell.com
  //
  
  //
  // Permission is hereby granted, free of charge, to any person obtaining
  // a copy of this software and associated documentation files (the
  // "Software"), to deal in the Software without restriction, including
  // without limitation the rights to use, copy, modify, merge, publish,
  // distribute, sublicense, and/or sell copies of the Software, and to
  // permit persons to whom the Software is furnished to do so, subject to
  // the following conditions:
  // 
  // The above copyright notice and this permission notice shall be
  // included in all copies or substantial portions of the Software.
  // 
  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  //
  
  // FIXME: in general we should create something like
  // System.Web.Query,Dynamic.DynamicClass to execute DataContext operations.
  
  using System;
  using System.Collections;
  using System.Collections.Generic;
  using System.ComponentModel;
  using System.Data.Linq;
  using System.Reflection;
  using System.Security.Permissions;
  using System.Web.DynamicData;
  using System.Web.UI;
  
  namespace System.Web.UI.WebControls
  {
  	[AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
  	[AspNetHostingPermission (SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
  	public class LinqDataSourceView : DataSourceView, IStateManager
  	{
  		public LinqDataSourceView (LinqDataSource owner, string name, HttpContext context)
  			: base (owner, name)
  		{
  			source = owner;
  		}
  
  		LinqDataSource source;
  
  		bool tracking;
  		ParameterCollection delete_parameters,
  			insert_parameters,
  			select_new_parameters,
  			update_parameters;
  		ParameterCollection group_by_parameters,
  			order_by_parameters,
  			order_group_by_parameters,
  			where_parameters;
  
  		IEnumerable<ParameterCollection> AllParameters {
  			get {
  				yield return delete_parameters;
  				yield return insert_parameters;
  				yield return select_new_parameters;
  				yield return update_parameters;
  				yield return group_by_parameters;
  				yield return order_by_parameters;
  				yield return order_group_by_parameters;
  				yield return where_parameters;
  			}
  		}
  
  		[MonoTODO]
  		public bool AutoGenerateOrderByClause { get; set; }
  		[MonoTODO]
  		public bool AutoGenerateWhereClause { get; set; }
  		[MonoTODO]
  		public bool AutoPage { get; set; }
  		[MonoTODO]
  		public bool AutoSort { get; set; }
  
  		public override bool CanDelete {
  			get { return EnableDelete; }
  		}
  
  		public override bool CanInsert {
  			get { return EnableInsert; }
  		}
  
  		public override bool CanPage {
  			get { return true; }
  		}
  
  		public override bool CanRetrieveTotalRowCount {
  			get { return true; }
  		}
  
  		public override bool CanSort {
  			get { return true; }
  		}
  
  		public override bool CanUpdate {
  			get { return EnableUpdate; }
  		}
  
  		protected virtual Type ContextType {
  			get { return ((IDynamicDataSource) source).ContextType; }
  		}
  
  		public virtual string ContextTypeName {
  			get { return source.ContextTypeName; }
  			set { source.ContextTypeName = value; }
  		}
  
  		[MonoTODO]
  		public bool EnableDelete { get; set; }
  		[MonoTODO]
  		public bool EnableInsert { get; set; }
  		[MonoTODO]
  		public bool EnableObjectTracking { get; set; }
  		[MonoTODO]
  		public bool EnableUpdate { get; set; }
  
  		[MonoTODO]
  		public string TableName { get; set; }
  
  		[MonoTODO]
  		public string GroupBy { get; set; }
  
  		[MonoTODO]
  		public string OrderBy { get; set; }
  
  		[MonoTODO]
  		public string OrderGroupsBy { get; set; }
  
  		[MonoTODO]
  		public string SelectNew { get; set; }
  
  		[MonoTODO]
  		public string Where { get; set; }
  
  		public ParameterCollection DeleteParameters {
  			get { return GetParameterCollection (ref delete_parameters, false, false); }
  		}
  
  		public ParameterCollection InsertParameters {
  			get { return GetParameterCollection (ref insert_parameters, false, false); }
  		}
  
  		public ParameterCollection UpdateParameters {
  			get { return GetParameterCollection (ref update_parameters, true, true); }
  		}
  
  		public ParameterCollection SelectNewParameters {
  			get { return GetParameterCollection (ref select_new_parameters, false, false); }
  		}
  
  		public ParameterCollection WhereParameters {
  			get { return GetParameterCollection (ref where_parameters, true, true); }
  		}
  
  		public ParameterCollection GroupByParameters {
  			get { return GetParameterCollection (ref group_by_parameters, true, true); }
  		}
  
  		public ParameterCollection OrderByParameters {
  			get { return GetParameterCollection (ref order_by_parameters, true, true); }
  		}
  
  		public ParameterCollection OrderGroupsByParameters {
  			get { return GetParameterCollection (ref order_group_by_parameters, true, true); }
  		}
  
  		ParameterCollection GetParameterCollection (ref ParameterCollection output, bool propagateTrackViewState, bool subscribeChanged)
  		{
  			if (output != null)
  				return output;
  			
  			output = new ParameterCollection ();
  			if (subscribeChanged)
  				output.ParametersChanged += new EventHandler (ParametersChanged);
  			
  			if (IsTrackingViewState && propagateTrackViewState)
  				((IStateManager) output).TrackViewState ();
  			
  			return output;
  		}
  
  		void ParametersChanged (object source, EventArgs args)
  		{
  			OnDataSourceViewChanged (EventArgs.Empty);
  		}
  
  		object data_context;
  
  		object GetDataContext ()
  		{
  			if (data_context == null)
  				data_context = CreateContext (ContextType);
  			return data_context;
  		}
  
  		public int Delete (IDictionary keys, IDictionary oldValues)
  		{
  			return ExecuteDelete (keys, oldValues);
  		}
  
  		public int Insert (IDictionary values)
  		{
  			return ExecuteInsert (values);
  		}
  
  		public IEnumerable Select (DataSourceSelectArguments arguments)
  		{
  			return ExecuteSelect (arguments);
  		}
  
  		public int Update (IDictionary keys, IDictionary values, IDictionary oldValues)
  		{
  			return ExecuteUpdate (keys, values, oldValues);
  		}
  
  		[MonoTODO]
  		protected override int ExecuteDelete (IDictionary keys, IDictionary oldValues)
  		{
  			throw new NotImplementedException ();
  		}
  
  		protected override int ExecuteInsert (IDictionary values)
  		{
  			var dc = (DataContext) GetDataContext ();
  			foreach (var mt in dc.Mapping.GetTables ()) {
  				if (mt.TableName != TableName)
  					continue;
  
  				var t = mt.RowType.Type;
  				ITable table = dc.GetTable (t);
  				object entity = Activator.CreateInstance (t);
  				// FIXME: merge InsertParameters
  				foreach (DictionaryEntry p in values)
  					t.GetProperty ((string) p.Key).SetValue (entity, p.Value, null);
  
  				InsertDataObject (dc, table, entity);
  				return 1;
  			}
  			throw new InvalidOperationException (String.Format ("Table '{0}' was not found on the data context '{1}'", TableName, ContextType));
  		}
  
  		[MonoTODO]
  		protected override int ExecuteUpdate (IDictionary keys, IDictionary values, IDictionary oldValues)
  		{
  			throw new NotImplementedException ();
  		}
  
  		[MonoTODO]
  		protected internal override IEnumerable ExecuteSelect (DataSourceSelectArguments arguments)
  		{
  			int max = arguments.MaximumRows;
  			max = max == 0 ? int.MaxValue : max;
  			int total = arguments.TotalRowCount;
  			total = total < 0 ? int.MaxValue : total;
  			int end = total == int.MaxValue ? total : arguments.StartRowIndex + total;
  
  			DataContext dc = Activator.CreateInstance (ContextType, true) as DataContext;
  			MemberInfo mi = GetTableMemberInfo (dc.GetType ());
  
  			// am totally not sure it is fine.
  			IEnumerable results;
  			if (source.Select != null) {
  				// FIXME: merge SelectParameters.
  				results = dc.ExecuteQuery (mi is FieldInfo ? ((FieldInfo) mi).FieldType : ((PropertyInfo) mi).PropertyType, source.Select, new object [0]);
  			} else {
  				results = (IEnumerable) (mi is FieldInfo ? ((FieldInfo) mi).GetValue (dc) : ((PropertyInfo) mi).GetValue (dc, null));
  			}
  
  			int i = 0;
  			foreach (var e in results) {
  				if (i++ < arguments.StartRowIndex)
  					continue; // skip rows before StartRowIndex.
  				if (i < end)
  					yield return e;
  			}
  		}
  
  		protected virtual void DeleteDataObject (object dataContext, object table, object oldDataObject)
  		{
  			ITable itable = ((DataContext) dataContext).GetTable (table.GetType ());
  			itable.DeleteOnSubmit (oldDataObject);
  		}
  
  		protected virtual void InsertDataObject (object dataContext, object table, object newDataObject)
  		{
  			ITable itable = ((DataContext) dataContext).GetTable (table.GetType ());
  			itable.InsertOnSubmit (newDataObject);
  		}
  
  		[MonoTODO]
  		protected virtual void ResetDataObject (object table, object dataObject)
  		{
  			var dc = GetDataContext ();
  			ITable itable = ((DataContext) dc).GetTable (table.GetType ());
  			UpdateDataObject (dc, table, dataObject, itable.GetOriginalEntityState (dataObject));
  		}
  
  		protected virtual void UpdateDataObject (object dataContext, object table, object oldDataObject, object newDataObject)
  		{
  			DeleteDataObject (dataContext, table, oldDataObject);
  			InsertDataObject (dataContext, table, newDataObject);
  		}
  
  		protected virtual object CreateContext (Type contextType)
  		{
  			OnContextCreating (new LinqDataSourceContextEventArgs ());
  			var o = Activator.CreateInstance (contextType);
  			OnContextCreated (new LinqDataSourceStatusEventArgs (o));
  			return o;
  		}
  
  		[MonoTODO]
  		protected virtual Type GetDataObjectType (Type tableType)
  		{
  			throw new NotImplementedException ();
  		}
  
  		MemberInfo table_member;
  
  		protected virtual MemberInfo GetTableMemberInfo (Type contextType)
  		{
  			if (contextType == null)
  				throw new ArgumentNullException ("contextType");
  			if (String.IsNullOrEmpty (TableName))
  				throw new InvalidOperationException (String.Format ("The TableName property of LinqDataSource '{0}' must specify a table property or field on the data context type.", source.ID));
  
  			if (table_member != null && table_member.DeclaringType == contextType)
  				return table_member;
  
  			var marr = contextType.GetMember (TableName, BindingFlags.Public | BindingFlags.Instance | BindingFlags.GetField | BindingFlags.GetProperty);
  			if (marr == null || marr.Length == 0)
  				throw new InvalidOperationException (String.Format ("Could not find a property or field called '{0}' on the data context type '{1}' of LinqDataSource '{2}'", TableName, contextType, source.ID));
  
  			table_member = marr [0];
  			return table_member;
  		}
  
  		#region Validation
  
  		[MonoTODO]
  		protected virtual void ValidateContextType (Type contextType, bool selecting)
  		{
  			throw new NotImplementedException ();
  		}
  		[MonoTODO]
  		protected virtual void ValidateDeleteSupported (IDictionary keys, IDictionary oldValues)
  		{
  			throw new NotImplementedException ();
  		}
  		[MonoTODO]
  		protected virtual void ValidateInsertSupported (IDictionary values)
  		{
  			throw new NotImplementedException ();
  		}
  		[MonoTODO]
  		protected virtual void ValidateOrderByParameter (string name, string value)
  		{
  			throw new NotImplementedException ();
  		}
  		[MonoTODO]
  		protected virtual void ValidateParameterName (string name)
  		{
  			throw new NotImplementedException ();
  		}
  		[MonoTODO]
  		protected virtual void ValidateTableType (Type tableType, bool selecting)
  		{
  			throw new NotImplementedException ();
  		}
  		[MonoTODO]
  		protected virtual void ValidateUpdateSupported (IDictionary keys, IDictionary values, IDictionary oldValues)
  		{
  			throw new NotImplementedException ();
  		}
  
  		#endregion
  
  		#region ViewState
  
  		bool IStateManager.IsTrackingViewState {
  			get { return IsTrackingViewState; }
  		}
  
  		protected bool IsTrackingViewState {
  
gt: 			get { return tracking; }