using System;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
using System.Data;

namespace Platform.Controls.TableContainer
{
    /// <summary>
    /// DHCCTreeViewList.xaml 的交互逻辑
    /// </summary>
    public partial class DHCCTreeViewList : UserControl
    {
        #region field

        private DataTable _source;
        private Func<string, string, bool> _funcIsRoot = (pk, fk) => string.IsNullOrEmpty(fk);
        private TreeViewListColumn[] _columns;
        private bool _isAutoShowPageBar;
        Func<DataRow, object[]> _funcGetChildren = null;
        string _expanderStyle = "CellTemplate_Name";
        Type _type;

        bool _isShowSelectBar = true;
        bool _isShowPageBar = true;
        #region Page

        int _pageIndex = 0;
        int _pageSize = 10;
        int _pageCount = 1;
        int _recordCount = 0;

        #endregion

        #endregion

        #region property

        #region 传值
        /// <summary>
        /// 获取或设置数据源
        /// </summary>
        public DataTable Source
        {
            get
            {
                return _source;
            }
            set
            {
                _source = value;
            }
        }

        /// <summary>
        /// 获取或设置主键列
        /// </summary>
        public string PKColumnName { get; set; }
        /// <summary>
        /// 获取或设置外键列
        /// </summary>
        public string FKColumnName { get; set; }

        /// <summary>
        /// 获取或设置要显示的列集合
        /// PS：这里指定的第一列需要使用特定模板（前面一个可折叠按钮），故第一列列名指定为No
        ///     你也可以不修改数据源对应列列名，调用本属性会自动帮你修改。
        /// </summary>
        public TreeViewListColumn[] TreeViewListColumns
        {
            get { return _columns; }
            set
            {
                if (_columns != value && value.Length > 0)
                {
                    _columns = value;
                }
            }
        }

        /// <summary>
        /// 获取或设置是否为根节点的方法
        /// 第一个参表示PK，第二个参表示FK
        /// 如果未制定，使用默认值（string.IsNullOrEmpty(PKColumnName)）
        /// </summary>
        public Func<string, string, bool> FuncIsRoot
        {
            get
            {
                return _funcIsRoot;
            }
            set
            {
                _funcIsRoot = value;
            }
        }
        #endregion

        #region 扩展
        /// <summary>
        /// 获取控件中的TreeViewList控件
        /// </summary>
        public TreeViewList TreeViewList
        {
            get { return this.treeViewList; }
        }
        #endregion

        #region UI

        /// <summary>
        /// 获得或设置是否显示分页栏
        /// </summary>
        public bool IsShowPageBar
        {
            get { return _isShowPageBar; }
            set
            {
                _isShowPageBar = value;
                BorderPage.Visibility = value ? Visibility.Visible : Visibility.Collapsed;
            }
        }

        /// <summary>
        /// 获得或设置是否显示搜索栏
        /// </summary>
        public bool IsShowSelectBar
        {
            get
            {
                return _isShowSelectBar;
            }
            set
            {
                _isShowSelectBar = value;
                GridSelectBar.Visibility = value ? Visibility.Visible : Visibility.Collapsed;
            }
        }


        /// <summary>
        /// 获取或设置是否自动显示分页栏
        /// 即如果只有一页不显示分页栏
        /// 优先级高于IsShowPageBar
        /// </summary>
        public bool IsAutoShowPageBar
        {
            get
            {
                return _isAutoShowPageBar;
            }
            set
            {
                _isAutoShowPageBar = value;
            }
        }

        /// <summary>
        /// 获取或设置缩进
        /// </summary>
        public double IndentSize
        {
            get { return LevelToIndentConverter.IndentSize; }
            set { LevelToIndentConverter.IndentSize = value; }
        }

        /// <summary>
        /// 设置预定义的几种折叠按钮样式
        /// 现有1和2两种
        /// 1为三角，2为加号
        /// </summary>
        public int ExpanderStyle
        {
            set
            {
                switch (value)
                {
                    case 1:
                        _expanderStyle = "CellTemplate_Name";
                        break;
                    case 2:
                        _expanderStyle = "CellTemplate_Name2";
                        break;
                    default:
                        _expanderStyle = "CellTemplate_Name";
                        break;
                }

                if (treeViewList.Columns.Count > 0)
                {
                    treeViewList.Columns[0].CellTemplate = this.Resources[_expanderStyle] as DataTemplate;
                }
            }
        }

        #endregion

        #endregion

        #region ctor

        public DHCCTreeViewList()
        {
            InitializeComponent();

            #region UI
            btnHome.Click += (sender, e) => GetPageIndex(btnHome.Name);
            btnUp.Click += (sender, e) => GetPageIndex(btnUp.Name);
            btnNext.Click += (sender, e) => GetPageIndex(btnNext.Name);
            btnEnd.Click += (sender, e) => GetPageIndex(btnEnd.Name);

            txtSelect.LostFocus += (sender, e) => BindData();
            txtSelect.KeyDown += (sender, e) =>
            {
                if (e.Key == Key.Enter) BindData();
            };

            txtPageNum.KeyDown += (sender, e) =>
            {
                if (e.Key == Key.Enter) GetPageIndex(txtPageNum.Name);
            };

            ///修改每页条数
            Action action = () =>
            {
                int size;

                int.TryParse(txtRowNum.Text.Trim(), out size);

                size = size < 1 ? 1 : size;

                if (_pageSize != size)
                {
                    _pageSize = size;
                    _pageIndex = 0;
                    BindData();
                }
            };

            txtRowNum.LostFocus += (sender, e) => action();
            txtRowNum.KeyDown += (sender, e) =>
            {
                if (e.Key == Key.Enter) action();
            };
            #endregion
        }

        #endregion

        #region Method

        #region Page

        /// <summary>
        /// 得到分页的页数
        /// </summary>
        void GetPageCount()
        {
            if (_pageSize >= _recordCount)
            {
                _pageCount = 1;
            }
            else if (_recordCount % _pageSize == 0)
            {
                _pageCount = _recordCount / _pageSize;
            }
            else
            {
                _pageCount = (_recordCount / _pageSize) + 1;
            }
        }

        /// <summary>
        /// 得到当前页码
        /// </summary>
        /// <param name="type">分页类型</param>
        /// <returns></returns>
        void GetPageIndex(string type)
        {
            bool flg = false;

            switch (type)
            {
                case "btnHome":
                    if (_pageIndex != 0)
                    {
                        _pageIndex = 0;
                        flg = true;
                    }
                    break;
                case "btnEnd":
                    if (_pageIndex != _pageCount - 1)
                    {
                        _pageIndex = _pageCount - 1;
                        flg = true;
                    }
                    break;
                case "btnNext":
                    if (_pageIndex >= _pageCount - 1)
                    {
                        _pageIndex = _pageCount - 1;
                    }
                    else
                    {
                        _pageIndex++;
                        flg = true;
                    }
                    break;
                case "btnUp":
                    if (_pageIndex <= 0)
                    {
                        _pageIndex = 0;
                    }
                    else
                    {
                        _pageIndex--;
                        flg = true;
                    }
                    break;
                case "txtPageNum":
                    int index;
                    int.TryParse(txtPageNum.Text.Trim(), out index);
                    if (index < 1)
                    {
                        index = 1;
                    }
                    else if (index > _pageCount - 1)
                    {
                        index = _pageCount - 1;
                    }

                    if (_pageIndex != index - 1)
                    {
                        _pageIndex = index - 1;
                        flg = true;
                    }
                    break;
                default:
                    break;
            }

            if (flg) BindData();
        }

        /// <summary>
        /// 刷新页面信息
        /// </summary>
        void RefPageInfo()
        {
            //Page
            tbkCurrent.Text = (_pageIndex + 1).ToString();
            tbkTotal.Text = _pageCount.ToString();
            txtPageNum.Text = (_pageIndex + 1).ToString();

            txtRowNum.Text = _pageSize.ToString();

            //UI
            GridSelectBar.Visibility = this.IsShowSelectBar ? Visibility.Visible : Visibility.Collapsed;

            if (this._isAutoShowPageBar && _pageCount == 1)
            {
                BorderPage.Visibility = System.Windows.Visibility.Collapsed;
            }
            else
            {
                BorderPage.Visibility = this.IsShowPageBar ? Visibility.Visible : Visibility.Collapsed;
            }
        }

        #endregion

        /// <summary>
        /// 设置要显示的列集合
        /// </summary>
        void SetColumns()
        {
            ///这里实在没有办法修改DataTemplate中的TextBlock绑定值，才出此下策
            ///将数据模板中的TextBlock的Text属性绑定Path为No
            ///如果所传列集合第一项不是No，那么修改数据源（DataTable）中对应的列的列名为No
            if (this._source == null || this._source.Columns.Count < 1)
            {
                throw new Exception("请先指定数据源，数据源列数不能为空！");
            }

            if (string.Compare(_columns[0].BindPropertyName, "No", false) != 0)
            {
                for (int i = 0; i < this._source.Columns.Count; i++)
                {
                    if (string.Compare(_columns[0].BindPropertyName, this._source.Columns[i].ColumnName, false) == 0)
                    {
                        this._source.Columns[i].ColumnName = "No";

                        if (PKColumnName == _columns[0].BindPropertyName)
                        {
                            PKColumnName = "No";
                        }

                        if (FKColumnName == _columns[0].BindPropertyName)
                        {
                            FKColumnName = "No";
                        }

                        _columns[0].BindPropertyName = "No";
                    }
                }
            }

            GridViewColumn column = new GridViewColumn();
            column.Width = _columns[0].Width;
            column.Header = _columns[0].Header;
            column.CellTemplate = this.Resources[_expanderStyle] as DataTemplate;
            treeViewList.Columns.Add(column);

            for (int i = 1; i < _columns.Length; i++)
            {
                //这里动态生成了DataTemplate
                column = new GridViewColumn();
                column.Width = _columns[i].Width;
                column.Header = _columns[i].Header;
                DataTemplate dt = new DataTemplate();
                FrameworkElementFactory fef = new FrameworkElementFactory(typeof(TextBlock));
                //设置Binding
                Binding binding = new Binding();
                binding.Path = new PropertyPath(_columns[i].BindPropertyName);
                fef.SetBinding(TextBlock.TextProperty, binding);
                //修改TextBlock的HorizontalAlignment属性以
                fef.SetValue(TextBlock.HorizontalAlignmentProperty, HorizontalAlignment.Stretch);
                fef.SetValue(TextBlock.TextAlignmentProperty, _columns[i].TextAlignment);
                dt.VisualTree = fef;
                column.CellTemplate = dt;

                treeViewList.Columns.Add(column);
            }
        }

        void BindData()
        {
            //搜索
            Func<DataRow, bool> funcWhere = dr => dr.Table.Columns.Cast<DataColumn>()
                //搜索显示的列
               .Where(col => this._columns.Cast<TreeViewListColumn>().Select(tvlc => tvlc.BindPropertyName).Contains(col.ColumnName))
                //从所有列中搜索值
               .Where(col => dr[col.ColumnName].ToString().ToLower().Contains(txtSelect.Text.Trim().ToLower()))
               .Any();

            //根据判断根节点方法，得到根节点（DataRow集合）,然后转换成创建的类型
            var root = _source.Rows.Cast<DataRow>()
               .Where(
               string.IsNullOrEmpty(txtSelect.Text.Trim()) ?
               dr => this._funcIsRoot(dr[this.PKColumnName].ToString(), dr[this.FKColumnName].ToString()) :
               funcWhere)//根据传过来的方法筛选
               .Select(dr => dr.GetEntity(_type, _funcGetChildren(dr)));//转换为创建的动态类型

            this._recordCount = root.Count();

            var source = root.Skip(_pageIndex * _pageSize).Take(_pageSize);//分页

            GetPageCount();

            RefPageInfo();

            this.treeViewList.ItemsSource = source;
        }

        #region public

        /// <summary>
        /// 绑定数据
        /// </summary>
        public void Binding()
        {
            Binding(Source, _columns, PKColumnName, FKColumnName, FuncIsRoot);
        }

        /// <summary>
        /// 绑定数据，指定数据源，主键、外键列列名和是否为根节点的方法
        /// 除了数据源，其他参数可以为空，为空则表示使用默认值
        /// </summary>
        /// <param name="dtSource">数据源</param>
        /// <param name="columns">要显示的列集合</param>
        /// <param name="pkColumnName">主键列列名（默认值为数据源第一列列名）</param>
        /// <param name="fkColumnName">外键列列名（默认值为数据源最后一列列名）</param>
        /// <param name="funcIsRoot">是否根节点方法（默认值为string.IsNullOrEmpty(PKColumnName)）</param>
        public void Binding(DataTable dtSource, TreeViewListColumn[] columns, string pkColumnName = null, string fkColumnName = null, Func<string, string, bool> funcIsRoot = null)
        {
            if (dtSource == null || dtSource.Rows.Count == 0)
            {
                throw new Exception("数据源为空！");
            }
            else
            {
                _source = dtSource;
            }

            _columns = columns;

            if (string.IsNullOrEmpty(pkColumnName))
            {
                pkColumnName = dtSource.Columns[0].ColumnName;
            }

            this.PKColumnName = pkColumnName;

            if (string.IsNullOrEmpty(fkColumnName))
            {
                fkColumnName = dtSource.Columns[dtSource.Columns.Count - 1].ColumnName;
            }

            this.FKColumnName = fkColumnName;

            SetColumns();

            if (funcIsRoot == null)
            {
                funcIsRoot = this._funcIsRoot;
            }
            else
            {
                this._funcIsRoot = funcIsRoot;
            }

            //操作一次数据源，如果fk列值为空，则给null
            for (int i = 0; i < _source.Rows.Count; i++)
            {
                if (string.IsNullOrEmpty(_source.Rows[i][FKColumnName].ToString()))
                {
                    _source.Rows[i][FKColumnName] = null;
                }
            }

            //创建DataSet，使用DataRelation创建父子关系
            DataSet dst = new DataSet();
            dst.Tables.Add(_source);
            DataRelation relation = new DataRelation("fk_TreeViewList", _source.Columns[PKColumnName], _source.Columns[FKColumnName]);
            dst.Relations.Add(relation);

            //获取动态创建的类型
            _type = DynamicClassHelp.CreateDynamicPropertyClass(_source);

            //获取子项，这是一个递归，在此写为了简化代码量
            //可读性方面，如果认为2.0的写法易懂，我不多说什么。
            _funcGetChildren = drElement =>
            {
                DataRow[] drChildren = drElement.GetChildRows(relation);
                if (drChildren != null && drChildren.Length > 0)
                {
                    return drChildren.Select(dr => dr.GetEntity(_type, _funcGetChildren(dr))).ToArray();
                }
                else
                {
                    return null;
                }
            };

            BindData();
        }

        #endregion

        #endregion
    }
}
