using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic;

namespace FilteringByCustomTypeSilverlight
{
    public class DataTable : IEnumerable
    {
        List<DataColumn> columns = null;
        public List<DataColumn> Columns
        {
            get
            {
                if (columns == null)
                {
                    columns = new List<DataColumn>();
                }

                return columns;
            }
        }

        List<DataRow> rows = null;
        public List<DataRow> Rows
        {
            get
            {
                if (rows == null)
                {
                    rows = new List<DataRow>();
                }

                return rows;
            }
        }

        public object NewRow()
        {
            if (queryable != null)
            {
                return Activator.CreateInstance(queryable.ElementType);
            }

            return null;
        }

        #region IEnumerable Members

        IQueryable queryable = null;
        public IEnumerator GetEnumerator()
        {
            if (queryable == null)
            {
                var entries = new List<string>();
                int i = 0;

                foreach (DataColumn column in Columns)
                {
                    string name = String.IsNullOrEmpty(column.ColumnName) ?
                        String.Format("Column{0}", i) : column.ColumnName;

                    entries.Add(String.Format(@"{1}(it[""{0}""]) as {0}",
                        column.ColumnName, GetTypeName(column.DataType)));

                    i++;
                }

                var projection = String.Format("new ({0})",
                    String.Join(",", entries.ToArray()));

                queryable = Rows.AsQueryable().Select(projection);
            }

            return queryable.GetEnumerator();
        }

        #endregion

        static string GetTypeName(Type type)
        {
            Type baseType = GetNonNullableType(type);
            string s = baseType.Name;
            if (type != baseType) s += '?';
            return s;
        }

        static Type GetNonNullableType(Type type)
        {
            return IsNullableType(type) ? type.GetGenericArguments()[0] : type;
        }

        static bool IsNullableType(Type type)
        {
            return type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>);
        }
    }

    public class DataColumn
    {
        public DataColumn()
        {
            DataType = typeof(object);
        }

        public Type DataType { get; set; }
        public string ColumnName { get; set; }
    }

    public class DataRow : Dictionary<string, object>
    {
        //
    }
}
