using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Configuration;
using System.ComponentModel;
using System.Windows;
using System.Windows.Data;
using Telerik.Windows.Controls;
using Telerik.Windows.Data;
using Telerik.Windows.Controls.GridView;

namespace Telerik.Settings
{
    public class RadGridViewSettings
    {
        protected class RadGridViewApplicationSettings : ApplicationSettingsBase
        {
            private RadGridViewSettings settings;

            public RadGridViewApplicationSettings(RadGridViewSettings settings)
                : base(settings.grid.PersistId.ToString())
            {
                this.settings = settings;
            }

            [UserScopedSetting]
            public int FrozenColumnCount
            {
                get
                {
                    if (this["FrozenColumnCount"] == null)
                    {
                        this["FrozenColumnCount"] = 0;
                    }

                    return (int) this["FrozenColumnCount"];
                }
                set
                {
                    this["FrozenColumnCount"] = value;
                }
            }

            [UserScopedSetting]
            public List<ColumnSetting> ColumnSettings
            {
                get
                {
                    if (this["ColumnSettings"] == null)
                    {
                        this["ColumnSettings"] = new List<ColumnSetting>();
                    }

                    return (List<ColumnSetting>) this["ColumnSettings"];
                }
            }

            [UserScopedSetting]
            public List<SortSetting> SortSettings
            {
                get
                {
                    if (this["SortSettings"] == null)
                    {
                        this["SortSettings"] = new List<SortSetting>();
                    }

                    return (List<SortSetting>) this["SortSettings"];
                }
            }

            [UserScopedSetting]
            public List<GroupSetting> GroupSettings
            {
                get
                {
                    if (this["GroupSettings"] == null)
                    {
                        this["GroupSettings"] = new List<GroupSetting>();
                    }

                    return (List<GroupSetting>) this["GroupSettings"];
                }
            }

            [UserScopedSetting]
            public List<FilterSetting> FilterSettings
            {
                get
                {
                    if (this["FilterSettings"] == null)
                    {
                        this["FilterSettings"] = new List<FilterSetting>();
                    }

                    return (List<FilterSetting>) this["FilterSettings"];
                }
            }
        }

        private RadGridView grid = null;

        public RadGridViewSettings(RadGridView grid)
        {
            this.grid = grid;
        }

        public static readonly DependencyProperty IsEnabledProperty
           = DependencyProperty.RegisterAttached("IsEnabled", typeof(bool), typeof(RadGridViewSettings),
                new FrameworkPropertyMetadata(new PropertyChangedCallback(OnIsEnabledPropertyChanged)));

        public static void SetIsEnabled(DependencyObject dependencyObject, bool enabled)
        {
            dependencyObject.SetValue(IsEnabledProperty, enabled);
        }

        private static void OnIsEnabledPropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
        {
            RadGridView grid = dependencyObject as RadGridView;
            if (grid != null)
            {
                if ((bool)e.NewValue)
                {
                    RadGridViewSettings settings = new RadGridViewSettings(grid);
                    settings.Attach();

                    if (grid.IsInitialized)
                    {
                        settings.LoadState();
                    }
                }
            }
        }

        public virtual void LoadState()
        {
            Settings.Reload();

            if (grid != null)
            {
                grid.Loaded += new RoutedEventHandler(grid_Loaded);

                grid.FrozenColumnCount = Settings.FrozenColumnCount;

                if (Settings.ColumnSettings.Count > 0)
                {
                    grid.AutoGenerateColumns = false;

                    foreach (ColumnSetting setting in Settings.ColumnSettings)
                    {
                        GridViewDataColumn column = new GridViewDataColumn();
                        column.UniqueName = setting.UniqueName;
                        column.HeaderText = setting.HeaderText;
                        if (setting.Width != null)
                        {
                            column.Width = new GridLength(setting.Width.Value);
                        }

                        grid.Columns.Add(column);
                    }
                }

                if (Settings.SortSettings.Count > 0)
                {
                    grid.SortDescriptions.Clear();

                    foreach (SortSetting setting in Settings.SortSettings)
                    {
                        SortDescription description = new SortDescription();
                        description.PropertyName = setting.PropertyName;
                        description.Direction = setting.SortDirection;

                        grid.SortDescriptions.Add(description);
                    }
                }

                if (Settings.GroupSettings.Count > 0)
                {
                    grid.GroupDescriptions.Clear();

                    foreach (GroupSetting setting in Settings.GroupSettings)
                    {
                        RadGroupDescription description = new RadGroupDescription();
                        description.PropertyName = setting.PropertyName;
                        description.SortDirection = setting.SortDirection;
                        description.DisplayContent = setting.DisplayContent;
                        description.StringComparison = setting.StringComparison;

                        grid.GroupDescriptions.Add(description);
                    }
                }
            }
        }

        void grid_Loaded(object sender, RoutedEventArgs e)
        {
            grid.Loaded -= new RoutedEventHandler(grid_Loaded);
            grid.ItemsControl.Loaded += new RoutedEventHandler(ItemsControl_Loaded);
        }

        void ItemsControl_Loaded(object sender, RoutedEventArgs e)
        {
            grid.ItemsControl.Loaded -= new RoutedEventHandler(ItemsControl_Loaded);
            if (Settings.FilterSettings.Count > 0)
            {
                CompositeFilterDescription cfd = grid.FilterDescription as CompositeFilterDescription;
                if (cfd != null)
                {
                    foreach (FilterSetting setting in Settings.FilterSettings)
                    {
                        FieldFilterDescription description = cfd.FilterDescriptions.OfType<FieldFilterDescription>().Where(fd => fd.FieldName == setting.PropertyName).FirstOrDefault();

                        if (description != null)
                        {
                            description.Filter1.Operator = setting.Filter1.Operator;
                            description.Filter1.Value = setting.Filter1.Value;

                            description.Filter2.Operator = setting.Filter2.Operator;
                            description.Filter2.Value = setting.Filter2.Value;

                            foreach (FilterDescriptor descriptor in setting.SelectedValues)
                            {
                                description.SelectedValues.Add(descriptor);
                            }
                        }
                    }
                }
            }
        }

        public virtual void ResetState()
        {
            Settings.Reset();
        }

        public virtual void SaveState()
        {
            if (grid != null)
            {
                if (grid.Columns != null)
                {
                    Settings.ColumnSettings.Clear();

                    foreach (GridViewColumn column in grid.Columns)
                    {
                        if(column is GridViewDataColumn)
                        {
                            GridViewDataColumn dataColumn = (GridViewDataColumn)column;

                            ColumnSetting setting = new ColumnSetting();
                            setting.PropertyName = dataColumn.DataMemberBinding.Path.Path;
                            setting.UniqueName = dataColumn.UniqueName;
                            setting.HeaderText = dataColumn.HeaderText;

                            GridViewHeaderRow headerRow = ((GridViewDataControl) dataColumn.Parent).ChildrenOfType<GridViewHeaderRow>().FirstOrDefault();
                            if (headerRow != null)
                            {
                                GridViewHeaderCell cell = headerRow.ChildrenOfType<GridViewHeaderCell>().Where(c => c.Column.UniqueName == setting.PropertyName).FirstOrDefault();
                                if (cell != null)
                                {
                                    setting.Width = cell.ActualWidth;
                                }
                            }

                            Settings.ColumnSettings.Add(setting);
                        }
                    }
                }

                if (grid.FilterDescription != null)
                {
                    Settings.FilterSettings.Clear();

                    CompositeFilterDescription cfd = grid.FilterDescription as CompositeFilterDescription;

                    foreach (FilterDescription description in cfd.FilterDescriptions)
                    {
                        if (description is FieldFilterDescription)
                        {
                            FieldFilterDescription ffd = (FieldFilterDescription) description;

                            if (ffd.IsActive)
                            {
                                FilterSetting setting = new FilterSetting();

                                setting.Filter1 = ffd.Filter1;
                                setting.Filter2 = ffd.Filter2;
                                setting.SelectedValues = new List<FilterDescriptor>(ffd.SelectedValues);
                                setting.PropertyName = ffd.FieldName;

                                Settings.FilterSettings.Add(setting);
                            }
                        }
                    }
                }

                if (grid.SortDescriptions != null)
                {
                    Settings.SortSettings.Clear();

                    foreach (SortDescription description in grid.SortDescriptions)
                    {
                        SortSetting setting = new SortSetting();

                        setting.PropertyName = description.PropertyName;
                        setting.SortDirection = description.Direction;

                        Settings.SortSettings.Add(setting);
                    }
                }

                if (grid.GroupDescriptions != null)
                {
                    Settings.GroupSettings.Clear();

                    foreach (RadGroupDescription description in grid.GroupDescriptions)
                    {
                        GroupSetting setting = new GroupSetting();

                        setting.PropertyName = description.PropertyName;
                        setting.SortDirection = description.SortDirection;
                        setting.DisplayContent = description.DisplayContent;
                        setting.StringComparison = description.StringComparison;

                        Settings.GroupSettings.Add(setting);
                    }
                }

                Settings.FrozenColumnCount = grid.FrozenColumnCount;
            }

            Settings.Save();
        }

        private void Attach()
        {
            if (grid != null)
            {
                Window parentWindow = Window.GetWindow(grid);
                if (parentWindow != null)
                {
                    parentWindow.Closing += new CancelEventHandler(Closing);
                    parentWindow.Initialized += new EventHandler(Initialized);
                }
            }
        }

        void Closing(object sender, CancelEventArgs e)
        {
            SaveState();
        }

        void Initialized(object sender, EventArgs e)
        {
            LoadState();
        }

        private RadGridViewApplicationSettings radGridViewApplicationSettings = null;

        protected virtual RadGridViewApplicationSettings CreateRadGridViewApplicationSettingsInstance()
        {
            return new RadGridViewApplicationSettings(this);
        }

        protected RadGridViewApplicationSettings Settings
        {
            get
            {
                if (radGridViewApplicationSettings == null)
                {
                    radGridViewApplicationSettings = CreateRadGridViewApplicationSettingsInstance();
                }
                return radGridViewApplicationSettings;
            }
        }
    }

    public class PropertySetting
    {
        public string PropertyName { get; set; }
    }

    public class SortSetting : PropertySetting
    {
        public ListSortDirection SortDirection { get; set; }
    }

    public class GroupSetting : SortSetting
    {
        public object DisplayContent { get; set; }
        public StringComparison StringComparison { get; set; }
    }

    public class FilterSetting : PropertySetting
    {
        public List<FilterDescriptor> SelectedValues { get; set; }
        public FilterDescriptor Filter1 { get; set; }
        public FilterDescriptor Filter2 { get; set; }
    }

    public class ColumnSetting : PropertySetting
    {
        public string UniqueName { get; set; }
        public string HeaderText { get; set; }
        public double? Width { get; set; }
    }
}
