using System.Collections.Generic;
using System.Linq;
using Telerik.Windows.Controls;
using Telerik.Windows.Controls.GridView;
using Telerik.Windows.Persistence.Services;
using Telerik.Windows.Data;
using System.Diagnostics;

namespace Telerik.Windows.Examples.PersistenceFramework.GridViewCustomSerialization
{
    public class GridViewCustomPropertyProvider : ICustomPropertyProvider
    {
        public CustomPropertyInfo[] GetCustomProperties()
        {
            // Create three custom properties to persist the Columns, Sorting and Group descriptors using proxy objects
            return new CustomPropertyInfo[]
            {
                new CustomPropertyInfo("Columns", typeof(List<ColumnProxy>)),
                new CustomPropertyInfo("SortDescriptors", typeof(List<SortDescriptorProxy>)),
                new CustomPropertyInfo("FilterDescriptors", typeof(List<FilterSetting>)),
                new CustomPropertyInfo("GroupDescriptors", typeof(List<GroupDescriptorProxy>)),
            };
        }

        public void InitializeObject(object context)
        {
            if (context is RadGridView)
            {
                RadGridView gridView = context as RadGridView;
                gridView.SortDescriptors.Clear();
                gridView.GroupDescriptors.Clear();
                gridView.FilterDescriptors.Clear();
            }
        }

        public object InitializeValue(CustomPropertyInfo customPropertyInfo, object context)
        {
            return null;
        }

        public object ProvideValue(CustomPropertyInfo customPropertyInfo, object context)
        {
            RadGridView gridView = context as RadGridView;
            if (customPropertyInfo.Name == "Columns")
            {
                // create proxies for all of the columns and save only specific properties
                List<ColumnProxy> proxies = new List<ColumnProxy>();
                foreach (GridViewColumn column in gridView.Columns)
                {
                    proxies.Add(new ColumnProxy()
                    {
                        UniqueName = column.UniqueName,
                        Header = column.Header.ToString(),
                        DisplayOrder = column.DisplayIndex,
                        Width = column.Width,
                    });
                }
                return proxies;
            }
            else if (customPropertyInfo.Name == "SortDescriptors")
            {
                // create proxies for all of the sort descriptors and save only specific properties
                List<SortDescriptorProxy> proxies = new List<SortDescriptorProxy>();
                foreach (ColumnSortDescriptor descriptor in gridView.SortDescriptors)
                {
                    proxies.Add(new SortDescriptorProxy()
                    {
                        ColumnUniqueName = descriptor.Column.UniqueName,
                        SortDirection = descriptor.SortDirection,
                    });
                }
                return proxies;
            }
            else if (customPropertyInfo.Name == "GroupDescriptors")
            {
                // create proxies for all of the group descriptors and save only specific properties
                List<GroupDescriptorProxy> proxies = new List<GroupDescriptorProxy>();
                foreach (ColumnGroupDescriptor descriotor in gridView.GroupDescriptors)
                {
                    proxies.Add(new GroupDescriptorProxy()
                    {
                        ColumnUniqueName = descriotor.Column.UniqueName,
                        SortDirection = descriotor.SortDirection,
                    });
                }
                return proxies;
            }
            else if (customPropertyInfo.Name == "FilterDescriptors")
            {
				List<FilterSetting> settings = new List<FilterSetting>();

				foreach (GridViewDataColumn column in gridView.Columns
					.OfType<GridViewDataColumn>()
					.Where(column => column.ColumnFilterDescriptor.IsActive))
				{
					FilterSetting setting = new FilterSetting();
					
					setting.ColumnUniqueName = column.UniqueName;

					if (column.ColumnFilterDescriptor.FieldFilter.Filter1.IsActive)
					{
						setting.Filter1 = new FilterDescriptorProxy();
						setting.Filter1.Operator = column.ColumnFilterDescriptor.FieldFilter.Filter1.Operator;
						setting.Filter1.Value = column.ColumnFilterDescriptor.FieldFilter.Filter1.Value;
						setting.Filter1.IsCaseSensitive = column.ColumnFilterDescriptor.FieldFilter.Filter1.IsCaseSensitive;
					}

					if (column.ColumnFilterDescriptor.FieldFilter.Filter2.IsActive)
					{
						setting.Filter2 = new FilterDescriptorProxy();
						setting.Filter2.Operator = column.ColumnFilterDescriptor.FieldFilter.Filter2.Operator;
						setting.Filter2.Value = column.ColumnFilterDescriptor.FieldFilter.Filter2.Value;
						setting.Filter2.IsCaseSensitive = column.ColumnFilterDescriptor.FieldFilter.Filter2.IsCaseSensitive;
					}

					foreach (object distinctValue in column.ColumnFilterDescriptor.DistinctFilter.DistinctValues)
					{
						setting.SelectedDistinctValues.Add(distinctValue);
					}

					settings.Add(setting);
				}

				return settings;
            }
            
			return null;
        }

        public void RestoreValue(CustomPropertyInfo customPropertyInfo, object context, object value)
        {
            RadGridView gridView = context as RadGridView;
            if (customPropertyInfo.Name == "Columns")
            {
                List<ColumnProxy> savedProxies = value as List<ColumnProxy>;
                
                // restore properties on the saved columns:
                foreach (ColumnProxy proxy in savedProxies)
                {
                    GridViewColumn column = this.GetColumnInstance(gridView, proxy.UniqueName);
                    if (column != null)
                    {
                        column.DisplayIndex = proxy.DisplayOrder;
                        column.Header = proxy.Header;
                        column.Width = proxy.Width;
                    }
                }
            }
            else if (customPropertyInfo.Name == "SortDescriptors")
            {
                gridView.SortDescriptors.Clear();
                List<SortDescriptorProxy> savedProxies = value as List<SortDescriptorProxy>;

                // restore properties on the saved sort descriptors:
                foreach (SortDescriptorProxy proxy in savedProxies)
                {
                    GridViewColumn column = this.GetColumnInstance(gridView, proxy.ColumnUniqueName);
                    gridView.SortDescriptors.Add(new ColumnSortDescriptor() { Column = column, SortDirection = proxy.SortDirection });
                }
            }
            else if (customPropertyInfo.Name == "GroupDescriptors")
            {
                gridView.GroupDescriptors.Clear();
                List<GroupDescriptorProxy> savedProxies = value as List<GroupDescriptorProxy>;

                // restore properties on the saved group descriptors:
                foreach (GroupDescriptorProxy proxy in savedProxies)
                {
                    GridViewColumn column = this.GetColumnInstance(gridView, proxy.ColumnUniqueName);
                    gridView.GroupDescriptors.Add(new ColumnGroupDescriptor() { Column = column, SortDirection = proxy.SortDirection });
                }
            }
            else if (customPropertyInfo.Name == "FilterDescriptors")
            {
				gridView.FilterDescriptors.SuspendNotifications();

				foreach (var c in gridView.Columns)
				{
					if (c.ColumnFilterDescriptor.IsActive)
					{
						c.ClearFilters();
					}
				}
                
				List<FilterSetting> settings = value as List<FilterSetting>;
                
				foreach (FilterSetting setting in settings)
                {
					GridViewDataColumn column = gridView.Columns
						.OfType<GridViewDataColumn>()
						.Single(c => c.UniqueName == setting.ColumnUniqueName);

					if (column != null)
                    {
						IColumnFilterDescriptor cfd = column.ColumnFilterDescriptor;

						if (setting.Filter1 != null)
						{
							cfd.FieldFilter.Filter1.Operator = setting.Filter1.Operator;
							cfd.FieldFilter.Filter1.Value = setting.Filter1.Value;
							cfd.FieldFilter.Filter1.IsCaseSensitive = setting.Filter1.IsCaseSensitive;
						}

						if (setting.Filter2 != null)
						{
							cfd.FieldFilter.Filter2.Operator = setting.Filter2.Operator;
							cfd.FieldFilter.Filter2.Value = setting.Filter2.Value;
							cfd.FieldFilter.Filter2.IsCaseSensitive = setting.Filter2.IsCaseSensitive;
						}

                        foreach (object distinctValue in setting.SelectedDistinctValues)
                        {
							cfd.DistinctFilter.AddDistinctValue(distinctValue);
                        }
                    }
                }

				gridView.FilterDescriptors.ResumeNotifications();
            }
        }

        private GridViewColumn GetColumnInstance(RadGridView gridView, string uniqueName)
        {
            foreach (GridViewColumn column in gridView.Columns)
            {
                if (column.UniqueName == uniqueName)
                    return column;
            }
            return null;
        }
    }
}
