/****************************************************
    文件：TableView.cs
    作者：陶长春
    邮箱：376248129@qq.com
    日期：2024年12月12日 8:25:50
    UnityVersion: 2021.3.13f1
    功能：表格绘制
*****************************************************/
using System.Collections;
using UnityEngine;
using System.Collections.Generic;
using UnityEditor.IMGUI.Controls;
using UnityEditor;

namespace TFramework
{
    public class TableView<T> : TreeView where T : class, new()
    {
        /// <summary>
        /// 表格数据
        /// </summary>
        private List<T> _datas;
        /// <summary>
        /// 当前选择的表格数据
        /// </summary>
        private List<T> _selectionDatas;
        /// <summary>
        /// 根元素
        /// </summary>
        private TableViewItem<T> _rootItem;
        /// <summary>
        /// 所有的元素
        /// </summary>
        private List<TableViewItem<T>> _items;
        /// <summary>
        /// 所有的元素绘制项
        /// </summary>
        private List<TreeViewItem> _drawItems;
        /// <summary>
        /// 搜索控件
        /// </summary>
        private SearchField _searchField;
        /// <summary>
        /// 元素ID标记
        /// </summary>
        private int _idSign = 0;

        /// <summary>
        /// 当选择项改变
        /// </summary>
        public event TAction<List<T>> OnSelectionChanged;
        /// <summary>
        /// 搜索数据时的方法
        /// </summary>
        public TFunc<T, string, bool> OnSearch;

        /// <summary>
        /// 添加右键单击上下文菜单项
        /// </summary>
        public TAction<GenericMenu> AddContextMenu;

        /// <summary>
        /// 行高度
        /// </summary>
        public float RowHeight
        {
            get
            {
                return rowHeight;
            }
            set
            {
                rowHeight = value;
            }
        }
        /// <summary>
        /// 是否启用上下文右键点击
        /// </summary>
        public bool IsEnableContextClick { get; set; } = true;

        /// <summary>
        /// 是否允许多选
        /// </summary>
        public bool IsCanMultiSelect { get; set; } = true;
        /// <summary>
        /// 是否启用搜索框
        /// </summary>
        public bool IsEnableSearch { get; set; } = false;
        /// <summary>
        /// 绘制搜索框
        /// </summary>
        /// <param>"arg0"是整个表格的矩形</param>
        public TFunc<Rect, Rect> DrawSearch;

        /// <summary>
        /// 是否启用筛选
        /// </summary>
        public bool IsEnableFiltrate { get; set; } = false;

        public List<TableViewItem<T>> Items => _items;

        /// <summary>
        /// 筛选时执行的方法
        /// </summary>
        public TFunc<T, bool> OnFiltrte;

        /// <summary>
        /// 表格视图
        /// </summary>
        /// <param name="datas">表格数据</param>
        /// <param name="columns">列标题数据</param>
        /// <param name="columnHeader">自定义列标题</param>
        /// <param name="isShowIndex">是否显示换序行号</param>
        public TableView(List<T> datas, List<TableColumn<T>> columns, TableColumnHeader<T> columnHeader = null,bool isShowIndex=true) : base(new TreeViewState())
        {
            showAlternatingRowBackgrounds = true;
            showBorder = true;
            rowHeight = EditorGUIUtility.singleLineHeight + 4;
            if (isShowIndex)
                columns.Insert(0, GetIndexColumn());
            if (columnHeader == null)
                multiColumnHeader = new TableColumnHeader<T>(new MultiColumnHeaderState(columns.ToArray()));
            else
                multiColumnHeader = columnHeader;
            multiColumnHeader.sortingChanged += OnSortingChanged;
            multiColumnHeader.visibleColumnsChanged += OnVisibleColumnsChanged;

            _datas = datas;
            _selectionDatas = new List<T>();
            _rootItem = new TableViewItem<T>(-1, -1, null);
            _items = new List<TableViewItem<T>>();
            for (var i = 0; i < _datas.Count; i++)
            {
                _items.Add(new TableViewItem<T>(_idSign, 0, _datas[i]));
                _idSign += 1;
            }
            _drawItems = new List<TreeViewItem>();
            _searchField = new SearchField();

            Reload();
        }

        /// <summary>
        /// 当列激活状态改变
        /// </summary>
        private void OnVisibleColumnsChanged(MultiColumnHeader multiColumnHeader)
        {
            Reload();
        }

        /// <summary>
        /// 当重新排序
        /// </summary>
        private void OnSortingChanged(MultiColumnHeader multiColumnHeader)
        {
            bool isAscending = multiColumnHeader.IsSortedAscending(multiColumnHeader.sortedColumnIndex);
            TableColumn<T> column = multiColumnHeader.GetColumn(multiColumnHeader.sortedColumnIndex) as TableColumn<T>;
            if (column.Compare != null)
            {
                _items.Sort((a, b) =>
                {
                    if (isAscending)
                    {
                        return -column.Compare(a.Data, b.Data);
                    }
                    else
                    {
                        return column.Compare(a.Data, b.Data);
                    }
                });
                Reload();
            }
        }

        /// <summary>
        /// 获取项索引
        /// </summary>
        /// <returns></returns>
        private TableColumn<T> GetIndexColumn()
        {
            TableColumn<T> column = new TableColumn<T>();
            column.autoResize = false;//自适应列大小
            column.headerContent = new GUIContent("Index");
            column.width = 50;
            column.canSort = false;//不对列启用排序
            column.Compare = null;
            column.DrawCell = (rect, data, rowIndex, isSelected, isFocused) =>
            {
                if (GUI.Button(new Rect(rect.x, rect.y, 14, rect.height), new GUIContent() { text = "▲", tooltip = "上移" }, EditorStyles.miniButtonRight))
                {
                    MoveDataIndex(data, 1);
                }
                if (GUI.Button(new Rect(rect.x + 15, rect.y, 14, rect.height), new GUIContent() { text = "▼", tooltip = "下移" }, EditorStyles.miniButtonRight))
                {
                    MoveDataIndex(data, 0);
                }
                EditorGUI.LabelField(new Rect(rect.x + 30, rect.y, rect.width - 30, rect.height), rowIndex.ToString());
            };
            return column;
        }

        /// <summary>
        /// 构造根节点
        /// </summary>
        protected override TreeViewItem BuildRoot()
        {
            return _rootItem;
        }

        /// <summary>
        /// 构造所有行
        /// </summary>
        protected override IList<TreeViewItem> BuildRows(TreeViewItem root)
        {
            _drawItems.Clear();
            if (hasSearch && OnSearch != null)
            {
                for (int i = 0; i < _items.Count; i++)
                {
                    if (OnSearch(_items[i].Data, searchString))
                    {
                        if (_items[i].parent != null && _items[i].parent.id != -1 && !IsExpanded(_items[i].parent.id)) continue;
                        _drawItems.Add(_items[i]);
                    }
                }
            }
            else if (IsEnableFiltrate && OnFiltrte != null)
            {
                for (int i = 0; i < _items.Count; i++)
                {
                    if (OnFiltrte(_items[i].Data))
                    {
                        if (_items[i].parent != null && _items[i].parent.id != -1 && !IsExpanded(_items[i].parent.id)) continue;
                        _drawItems.Add(_items[i]);
                    }
                }
            }
            else
            {
                for (int i = 0; i < _items.Count; i++)
                {
                    if (_items[i].parent != null && _items[i].parent.id != -1 && !IsExpanded(_items[i].parent.id)) continue;
                    _drawItems.Add(_items[i]);
                }
            }
            SetupDepthsFromParentsAndChildren(root);
            return _drawItems;
        }

        /// <summary>
        /// 绘制行
        /// </summary>
        protected override void RowGUI(RowGUIArgs args)
        {
            TableViewItem<T> item = args.item as TableViewItem<T>;
            if (item.parent!=null && !IsExpanded(item.parent.id)&&item.parent.id!=-1) return;
            int visibleColumns = args.GetNumVisibleColumns();
            for (var i = 0; i < visibleColumns; i++)
            {
                Rect cellRect = args.GetCellRect(i);
                int index = args.GetColumn(i);
                CenterRectUsingSingleLineHeight(ref cellRect);
                TableColumn<T> column = multiColumnHeader.GetColumn(index) as TableColumn<T>;
                if (item.hasChildren&&i==0)
                {
                    cellRect.x += 13;
                    cellRect.width -= 13;
                }
                if (item.parent != null&&item.parent.id!=-1&&i==0)
                {
                    cellRect.x += 13 + 3 * item.depth+13* item.parent.depth;
                    cellRect.width -= 13 + 3 * item.depth + 13 * item.parent.depth;
                }
                column.DrawCell?.Invoke(cellRect, item.Data, args.row, args.selected, args.focused);
            }
        }

        /// <summary>
        /// 上下文右键点击
        /// </summary>
        protected override void ContextClicked()
        {
            if (!IsEnableContextClick)
                return;

            List<TableViewItem<T>> selectedItems = new List<TableViewItem<T>>();
            foreach (var itemID in GetSelection())
            {
                TableViewItem<T> item = _items.Find((it) => { return it.id == itemID; });
                if (item != null) selectedItems.Add(item);
            }

            GenericMenu menu = new GenericMenu();
            menu.AddItem(new GUIContent("增加一行"), false, () =>
            {
                AddData(new T());
            });
            if (selectedItems.Count == 1)
            {
                menu.AddItem(new GUIContent("添加子行"), false, () =>
                {
                    AddChliderData(selectedItems[0]);
                });
            }
            if (selectedItems.Count > 0)
            {
                menu.AddItem(new GUIContent("删除选中行"), false, () =>
                {
                    DeleteDatas(selectedItems);
                });
            }
            menu.AddSeparator("");
            menu.AddItem(new GUIContent("删除所有行"), false, () =>
            {
                ClearData();
            });

            AddContextMenu?.Invoke(menu);
            menu.ShowAsContext();
        }

        /// <summary>
        /// 当选择项改变
        /// </summary>
        protected override void SelectionChanged(IList<int> selectedIds)
        {
            base.SelectionChanged(selectedIds);

            _selectionDatas.Clear();
            foreach (var itemID in selectedIds)
            {
                TableViewItem<T> item = _items.Find((it) => { return it.id == itemID; });
                if (item != null) _selectionDatas.Add(item.Data);
            }

            OnSelectionChanged?.Invoke(_selectionDatas);
        }

        /// <summary>
        /// 是否允许多选
        /// </summary>
        protected override bool CanMultiSelect(TreeViewItem item)
        {
            return IsCanMultiSelect;
        }

        /// <summary>
        /// 绘制表格视图
        /// </summary>
        /// <param name="rect">绘制区域</param>
        public override void OnGUI(Rect rect)
        {
            if (IsEnableSearch)
            {
                Rect sub = new Rect(rect.x, rect.y, 60, 16);
                if (DrawSearch != null)
                {
                    sub = DrawSearch.Invoke(rect);
                }
                else
                {
                    EditorGUI.LabelField(sub, "Search: ");
                    sub.Set(rect.x + 60, rect.y, rect.width - 60, 18);
                }
                searchString = _searchField.OnGUI(sub, searchString);
                rect.y += sub.height;
                rect.height -= sub.height;
                base.OnGUI(rect);
            }
            else
            {
                base.OnGUI(rect);
            }
        }

        /// <summary>
        /// 添加数据
        /// </summary>
        /// <param name="data">数据</param>
        public void AddData(T data)
        {
            if (_datas.Contains(data))
                return;

            _datas.Add(data);
            _items.Add(new TableViewItem<T>(_idSign, 0, data));
            _idSign += 1;
            Reload();
        }

        /// <summary>
        /// 添加子数据
        /// </summary>
        /// <param name="selectedItems"></param>
        private void AddChliderData(TableViewItem<T> selectedItem)
        {
            T data = new T();
            _datas.Add(data);
            TableViewItem<T> item = new TableViewItem<T>(_idSign, selectedItem.depth+1, data);
            item.parent = selectedItem;
            item.parent.id = selectedItem.id;
            selectedItem.AddChild(item);
            _items.Add(item);
            _idSign += 1;
            Reload();
        }

        /// <summary>
        /// 添加数据
        /// </summary>
        /// <param name="datas">数据</param>
        public void AddDatas(List<T> datas)
        {
            for (int i = 0; i < datas.Count; i++)
            {
                T data = datas[i];
                if (_datas.Contains(data))
                    continue;

                _datas.Add(data);
                _items.Add(new TableViewItem<T>(_idSign, 0, data));
                _idSign += 1;
            }
            Reload();
        }

        /// <summary>
        /// 删除数据
        /// </summary>
        /// <param name="data">数据</param>
        public void DeleteData(T data)
        {
            if (!_datas.Contains(data))
                return;

            _datas.Remove(data);
            TableViewItem<T> item = _items.Find((i) => { return i.Data == data; });
            if (item != null)
            {
                if (item.parent != null)
                {
                    item.parent.children.Remove(item);
                    item.parent = null;
                }
                if (item.hasChildren)
                {
                    for (int j = 0; j < item.children.Count; j++)
                    {
                        TableViewItem<T> viewItem = item.children[j] as TableViewItem<T>;
                        DeleteData(viewItem.Data);
                    }
                }
                _items.Remove(item);
            }
            Reload();
        }

        /// <summary>
        /// 删除数据
        /// </summary>
        /// <param name="datas">数据</param>
        public void DeleteDatas(List<TableViewItem<T>> datas)
        {
            for (int i = 0; i < datas.Count; i++)
            {
                T data = datas[i].Data;
                if (!_datas.Contains(data))
                    continue;
                DeleteData(data);
                //_datas.Remove(data);
                //TableViewItem<T> item = _items.Find((t) => { return t.Data == data; });
                //if (item != null)
                //{
                //    if (item.parent != null)
                //    {
                //        item.parent.children.Remove(item);
                //        item.parent = null;
                //    }
                //    if (item.hasChildren)
                //    {
                //        for (int j = 0; j < item.children.Count; j++)
                //        {
                //            TableViewItem<T> viewItem = item.children[j] as TableViewItem<T>;
                //            DeleteData(viewItem.Data);
                //        }
                //    }
                //    _items.Remove(item);
                //}
            }
            //Reload();
        }

        /// <summary>
        /// 选中数据
        /// </summary>
        /// <param name="data">数据</param>
        public void SelectData(T data)
        {
            if (!_datas.Contains(data))
                return;

            TableViewItem<T> item = _items.Find((i) => { return i.Data == data; });
            if (item != null)
            {
                SetSelection(new int[] { item.id });
            }
        }
        /// <summary>
        /// 选中数据
        /// </summary>
        /// <param name="data">数据</param>
        /// <param name="options">选中的操作</param>
        public void SelectData(T data, TreeViewSelectionOptions options)
        {
            if (!_datas.Contains(data))
                return;

            TableViewItem<T> item = _items.Find((i) => { return i.Data == data; });
            if (item != null)
            {
                SetSelection(new int[] { item.id }, options);
            }
        }
        /// <summary>
        /// 选中数据
        /// </summary>
        /// <param name="datas">数据</param>
        public void SelectDatas(List<T> datas)
        {
            List<int> ids = new List<int>();
            for (int i = 0; i < datas.Count; i++)
            {
                T data = datas[i];
                if (!_datas.Contains(data))
                    continue;

                TableViewItem<T> item = _items.Find((t) => { return t.Data == data; });
                if (item != null)
                {
                    ids.Add(item.id);
                }
            }

            if (ids.Count > 0)
            {
                SetSelection(ids);
            }
        }
        /// <summary>
        /// 选中数据
        /// </summary>
        /// <param name="datas">数据</param>
        /// <param name="options">选中的操作</param>
        public void SelectDatas(List<T> datas, TreeViewSelectionOptions options)
        {
            List<int> ids = new List<int>();
            for (int i = 0; i < datas.Count; i++)
            {
                T data = datas[i];
                if (!_datas.Contains(data))
                    continue;

                TableViewItem<T> item = _items.Find((t) => { return t.Data == data; });
                if (item != null)
                {
                    ids.Add(item.id);
                }
            }

            if (ids.Count > 0)
            {
                SetSelection(ids, options);
            }
        }

        /// <summary>
        /// 清空所有数据
        /// </summary>
        public void ClearData()
        {
            _datas.Clear();
            _items.Clear();
            Reload();
        }

        /// <summary>
        /// 移动数据位置
        /// </summary>
        /// <param name="data">数据</param>
        /// <param name="AorS">上移：1，下移：0</param>
        public void MoveDataIndex(T data, int AorS)
        {
            if (!_datas.Contains(data))
                return;
            TableViewItem<T> item = _items.Find((i) => { return i.Data == data; });
            if (AorS == 0)
            {
                if (_datas.IndexOf(data) + 1 >= _datas.Count) return;
                _datas.Swap(_datas.IndexOf(data), _datas.IndexOf(data) + 1);
                if (item != null && _items.IndexOf(item) + 1 < _items.Count)
                {
                    _items.Swap(_items.IndexOf(item), _items.IndexOf(item) + 1);
                }
            }
            else
            {
                if (_datas.IndexOf(data) - 1 < 0) return;
                _datas.Swap(_datas.IndexOf(data), _datas.IndexOf(data) - 1);
                if (item != null && _items.IndexOf(item) - 1 >= 0)
                {
                    _items.Swap(_items.IndexOf(item), _items.IndexOf(item) - 1);
                }
            }
            Reload();
        }
    }
}