File: DynamicData\Util\MetaTableHelper.cs
Project: ndp\fx\src\xsp\system\DynamicData\System.Web.DynamicData.csproj (System.Web.DynamicData)
namespace System.Web.DynamicData.Util {
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Globalization;
    using System.Linq;
    using System.Reflection;
    using System.Web.Resources;
    using System.Web.UI;
    using System.ComponentModel;
    using IDataBoundControlInterface = System.Web.UI.WebControls.IDataBoundControl;
 
    internal static class MetaTableHelper {
 
        private static object s_mappingKey = new object();
 
        internal static Dictionary<object, MappingInfo> GetMapping(HttpContextBase httpContext) {
            Dictionary<object, MappingInfo> mapping = httpContext.Items[s_mappingKey] as Dictionary<object, MappingInfo>;
            if (mapping == null) {
                mapping = new Dictionary<object, MappingInfo>();
                httpContext.Items[s_mappingKey] = mapping;
            }
            return mapping;
        }
 
        /// <summary>
        /// Gets a table from the mapping. Does not throw.
        /// </summary>
        internal static MetaTable GetTableFromMapping(HttpContextBase httpContext, object control) {
            IDictionary<object, MappingInfo> mapping = GetMapping(httpContext);
            // don't throw if no mapping found
            MappingInfo mappingInfo;
            if (mapping.TryGetValue(control, out mappingInfo)) {
                return mappingInfo.Table;
            }
            return null;
        }
 
        private static MappingInfo GetMappingInfo(object control, HttpContextBase httpContext) {
            IDictionary<object, MappingInfo> mapping = GetMapping(httpContext);
            MappingInfo mappingInfo;
            if (!mapping.TryGetValue(control, out mappingInfo)) {
                mappingInfo = new MappingInfo();
                mapping[control] = mappingInfo;
            }
            return mappingInfo;
        }
 
        internal static void SetTableInMapping(HttpContextBase httpContext, object control, MetaTable table, IDictionary<string, object> defaultValues) {
            MappingInfo mappingInfo = GetMappingInfo(control, httpContext);
            mappingInfo.Table = table;
            if (defaultValues != null) {
                mappingInfo.DefaultValueMapping = new DefaultValueMapping(defaultValues);
            }
        }
 
        internal static MetaTable GetTableWithFullFallback(IDataSource dataSource, HttpContextBase context) {
            MetaTable table = GetTableFromMapping(context, dataSource);
            if (table != null) {
                return table;
            }
 
            IDynamicDataSource dynamicDataSource = dataSource as IDynamicDataSource;
            if (dynamicDataSource != null) {
                table = GetTableFromDynamicDataSource(dynamicDataSource);
                if (table != null) {
                    return table;
                }
            }
 
            table = DynamicDataRouteHandler.GetRequestMetaTable(context);
            if (table != null) {
                return table;
            }
 
            Control c = dataSource as Control;
            string id = (c != null ? c.ID : String.Empty);
            throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture,
                DynamicDataResources.MetaTableHelper_CantFindTable,
                id));
        }
 
        internal static MetaTable GetMetaTableFromObject(object dataSource) {
            IEnumerable enumerable = dataSource as IEnumerable;
            if (enumerable == null) {
                return null;
            }
 
            // Use the first item to determine the type
            // 
            foreach (object o in enumerable) {
                if (o != null) {
                    return MetaTable.GetTable(o.GetType());
                }
            }
 
            return null;
        }
 
        /// Gets a table from an IDynamicDataSource's ContextType and EntitySetName.
        /// Does not throw, returns null on failure.
        internal static MetaTable GetTableFromDynamicDataSource(IDynamicDataSource dynamicDataSource) {
            string tableName = dynamicDataSource.EntitySetName;
            Type contextType = dynamicDataSource.ContextType;
            if (contextType == null || String.IsNullOrEmpty(tableName)) {
                return null;
            }
 
 
            MetaModel model;
            if (MetaModel.MetaModelManager.TryGetModel(contextType, out model)) {
                Debug.Assert(model != null);
                MetaTable table;
                if (model.TryGetTable(tableName, out table)) {
                    return table;
                }
            }
 
            return null;
        }
 
        internal static MetaTable FindMetaTable(Control current) {
            return FindMetaTable(current, HttpContext.Current.ToWrapper());
        }
 
        internal static DefaultValueMapping GetDefaultValueMapping(Control current, HttpContextBase context) {
            IDictionary<object, MappingInfo> mapping = GetMapping(context);
            if (!(current is INamingContainer)) {
                current = current.NamingContainer;
            }
 
            for (; current != null; current = current.NamingContainer) {
                MappingInfo mappingInfo;
                // If we find a mapping then return that value
                if (mapping.TryGetValue(current, out mappingInfo)) {
                    return mappingInfo.DefaultValueMapping;
                }
            }
            return null;
        }
 
        internal static MetaTable FindMetaTable(Control current, HttpContextBase context) {
            MetaTable table = null;
            // Start from the first naming container
            if (!(current is INamingContainer)) {
                current = current.NamingContainer;
            }
            for (; current != null; current = current.NamingContainer) {
                // Find the first table mapped to a control
                table = GetTableFromMapping(context, current);
                if (table != null) {
                    return table;
                }
 
                IDataBoundControlInterface dataBoundControl = DataControlHelper.GetDataBoundControl(current, false /*failIfNotFound*/);
 
                // Not a data control: continue searching
                if (dataBoundControl == null) {
                    continue;
                }
 
                IDataSource dataSourceControl = dataBoundControl.DataSourceObject;
                // Check if it's associated with a DataSource or can be retrieved from the current route
                if (dataSourceControl != null) {
                    return GetTableWithFullFallback(dataSourceControl, context);
                }
 
                // Check if it has a datasource (i.e. not a control, but directly some data)
                object dataSource = dataBoundControl.DataSource;
                if (dataSource != null) {
                    // Try to get a MetaTable from it.  If so, we're done
                    table = GetMetaTableFromObject(dataSource);
                    if (table != null) {
                        return table;
                    }
                }
            }
 
            return null;
        }
    }
}