using CustomFilterRow_WPF;
using System;
using System.ComponentModel;
using System.Data;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Xml.Linq;
using Telerik.Windows.Controls;
using Telerik.Windows.Controls.Animation;
using Telerik.Windows.Controls.GridView;
using Telerik.Windows.Controls.GridView.Selection;
using Telerik.Windows.Data;
using BooleanToVisibilityConverter = Telerik.Windows.Controls.BooleanToVisibilityConverter;
using GridViewColumn = Telerik.Windows.Controls.GridViewColumn;

namespace CustomFilterRow_WPF
{
	public class CustomFilterRow
	{
		private RadGridView radGridView;
		private FilteringRow filteringRow;

		public CustomFilterRow(RadGridView radGridView)
		{
			this.radGridView = radGridView;
			this.radGridView.IsFilteringAllowed = false;
			this.radGridView.DataLoaded += this.radGridView_DataLoaded;
		}

		private void radGridView_DataLoaded(object sender, EventArgs e)
		{
			this.filteringRow = new FilteringRow();
			this.filteringRow.Loaded += this.FilteringRow_Loaded;

			this.radGridView.RowLoaded += this.radGridView_RowLoaded;
			this.radGridView.ColumnDisplayIndexChanged += this.ReorderFilterCells;
			this.radGridView.Grouped += this.Grouped;

			this.radGridView.DataLoaded -= this.radGridView_DataLoaded;
		}

		public static bool GetIsEnabled(DependencyObject obj)
		{
			return (bool)obj.GetValue(IsEnabledProperty);
		}

		public static void SetIsEnabled(DependencyObject obj, bool value)
		{
			obj.SetValue(IsEnabledProperty, value);
		}

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

		private static void OnIsEnabledPropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
		{
			RadGridView radGridView = dependencyObject as RadGridView;
			if (radGridView != null)
			{
				if ((bool)e.NewValue)
				{
					CustomFilterRow row = new CustomFilterRow(radGridView);
				}
			}
		}

		private void FilteringRow_Loaded(object sender, RoutedEventArgs e)
		{
			GridViewScrollViewer gridViewScrollViewer = this.radGridView.ChildrenOfType<GridViewScrollViewer>().FirstOrDefault();
			gridViewScrollViewer.ScrollChanged += this.GridViewScrollViewer_ScrollChanged;

			this.radGridView.Dispatcher.BeginInvoke((Action)(() =>
			{
				this.BindToColumns();

				this.PlaceCommonHeaders();

				this.filteringRow.CustomFilterRowGrid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(1, GridUnitType.Star) });
			}));
		}

		private void radGridView_RowLoaded(object sender, RowLoadedEventArgs e)
		{
			if (e.Row is GridViewHeaderRow)
			{
				Grid rootPanelGrid = (from c in this.radGridView.ChildrenOfType<Grid>()
									  where c.Name == "PART_RootPanel"
									  select c).FirstOrDefault();

				if (rootPanelGrid != null && this.filteringRow.Parent == null)
				{
					rootPanelGrid.Loaded += this.rootPanelGrid_Loaded;
				}

				Border indicator = (from c in this.radGridView.ChildrenOfType<Border>()
									where c.Name == "PART_IndicatorPresenter"
									select c).FirstOrDefault();

				if (indicator != null)
				{
					this.filteringRow.CustomFilterRowRoot.ColumnDefinitions[0].Width = GridLength.Auto;
					Border indicatorFiller = new Border();
					indicatorFiller.Name = "PART_IndicatorPresenterForFilterRow";
					indicatorFiller.SetValue(Grid.ColumnProperty, 0);
					this.filteringRow.CustomFilterRowRoot.Children.Add(indicatorFiller);

					Binding widthBinding = new Binding("Width");
					widthBinding.Source = indicator;
					indicatorFiller.SetBinding(Border.WidthProperty, widthBinding);

					Binding visibilityBinding = new Binding("Visibility");
					visibilityBinding.Source = indicator;
					indicatorFiller.SetBinding(Border.VisibilityProperty, visibilityBinding);
				}
			}
		}

		void rootPanelGrid_Loaded(object sender, RoutedEventArgs e)
		{
			RecalculateIndentPresenterWidth();

			Grid rootPanelGrid = sender as Grid;
			if (this.filteringRow.Parent == null)
			{
				rootPanelGrid.Children.Add(this.filteringRow);
				this.filteringRow.SetValue(Grid.RowProperty, 0);
			}
		}

		private void Grouped(object sender, GridViewGroupedEventArgs e)
		{
			RecalculateIndentPresenterWidth();
		}

		private void RecalculateIndentPresenterWidth()
		{
			double presenterWidth = this.filteringRow.CustomFilterRowRoot.ColumnDefinitions[0].ActualWidth;
			this.filteringRow.CustomFilterRowRoot.ColumnDefinitions[1].Width = new GridLength(this.radGridView.GroupDescriptors.Count * presenterWidth);
		}

		private void BindToColumns()
		{
			this.filteringRow.CustomFilterRowGrid.ColumnDefinitions.Clear();
			foreach (GridViewColumn column in this.radGridView.Columns)
			{
				ColumnDefinition columndefinition = new ColumnDefinition();
				columndefinition.Width = GridLength.Auto;
				this.filteringRow.CustomFilterRowGrid.ColumnDefinitions.Add(columndefinition);
			}
		}

		private void PlaceCommonHeaders()
		{
			this.filteringRow.CustomFilterRowGrid.Children.Clear();

			int i = 0;
			foreach (GridViewColumn column in this.radGridView.Columns)
			{
				ColumnFilterCell filterCell = null;
				if (column is GridViewBoundColumnBase)
				{
					filterCell = ColumnFilterCellFactory.CreateColumnHeader((GridViewBoundColumnBase)column);
				}
				else
				{
					filterCell = new ColumnFilterCell();
				}
				filterCell.Column = column;
				filterCell.PropertyChanged += this.FilterCell_PropertyChanged;
				filterCell.SetValue(Grid.ColumnProperty, i);
				this.filteringRow.CustomFilterRowGrid.Children.Add(filterCell);
				filterCell.Loaded += this.filterCell_Loaded;

				i++;
			}

			ColumnFilterCell lastEmptyHeader = new ColumnFilterCell();
			lastEmptyHeader.SetValue(Grid.ColumnProperty, this.filteringRow.CustomFilterRowGrid.ColumnDefinitions.Count());
			this.filteringRow.CustomFilterRowGrid.Children.Add(lastEmptyHeader);
		}

		private static void BindWidthAndVisibilityOnFilterCell(ref ColumnFilterCell cell, GridViewColumn column)
		{
			Binding columnWidthBinding = new Binding("ActualWidth");
			columnWidthBinding.Source = column;
			Binding columnVisibilityBinding = new Binding("IsVisible");
			columnVisibilityBinding.Converter = new BooleanToVisibilityConverter();
			columnVisibilityBinding.Source = column;
			cell.SetBinding(ColumnFilterCell.VisibilityProperty, columnVisibilityBinding);
			cell.SetBinding(ColumnFilterCell.WidthProperty, columnWidthBinding);
		}

		void filterCell_Loaded(object sender, RoutedEventArgs e)
		{
			ColumnFilterCell filterCell = sender as ColumnFilterCell;
			if (filterCell.Column.MinWidth < filterCell.MinWidth)
			{
				filterCell.Column.MinWidth = filterCell.MinWidth;
			}
			BindWidthAndVisibilityOnFilterCell(ref filterCell, filterCell.Column);
		}

		private void ReorderFilterCells(object sender, GridViewColumnEventArgs e)
		{
			ColumnFilterCell firstCell = (from c in this.filteringRow.CustomFilterRowGrid.Children.OfType<ColumnFilterCell>()
										  where c.Column == e.Column
										  select c).FirstOrDefault();

			if (firstCell != null)
			{
				firstCell.SetValue(Grid.ColumnProperty, e.Column.DisplayIndex);
			}
		}

		private void GridViewScrollViewer_ScrollChanged(object sender, ScrollChangedEventArgs e)
		{
			this.filteringRow.ScrollViewer.ScrollToHorizontalOffset(e.HorizontalOffset);
		}

		private void FilterCell_PropertyChanged(object sender, PropertyChangedEventArgs e)
		{
			ColumnFilterCell columnHeader = (ColumnFilterCell)sender;
			RadGridView radGridView = columnHeader.ParentOfType<RadGridView>();

			if (e.PropertyName == "IsFilterActive")
			{
				if (columnHeader.IsFilterActive)
				{
					radGridView.FilterDescriptors.Add(columnHeader.FilterDescriptor);
				}
				else
				{
					radGridView.FilterDescriptors.Remove(columnHeader.FilterDescriptor);
				}
			}
		}
	}
}
