using System;
using System.Collections.Generic;
using System.Collections;

namespace FastReport.AdvMatrix
{
    // header descriptor extension methods
    internal static partial class DescriptorExt
    {
        public static bool IsEmpty(this HeaderDescriptor descr)
        {
            descr = descr.Root;
            return descr.AllItems.Count == 1 && !descr.Items[0].IsGroup && String.IsNullOrEmpty(descr.Items[0].DisplayText);
        }
        
        public static string[] GetAvailableCollapseButtons(this HeaderDescriptor descr)
        {
            List<string> list = new List<string>();
            Action<HeaderDescriptor> func = (root) =>
            {
                if (root == null)
                    return;
                foreach (HeaderDescriptor d in root.Items)
                {
                    if (d != descr && d.TemplateCell != null)
                    {
                        MatrixCollapseButton b = d.TemplateCell.GetCollapseButton();
                        if (b != null)
                            list.Add(b.Name);
                    }
                }
            };
            
            func(descr.Parent);
            if (descr.Parent != null)
                func(descr.Parent.Parent);
            return list.ToArray();
        }

        public static string[] GetAvailableSortButtons(this HeaderDescriptor descr)
        {
            List<string> list = new List<string>();
            foreach (Base c in descr.Matrix.Report.AllObjects)
            {
                MatrixSortButton btn = c as MatrixSortButton;
                if (btn != null)
                {
                    if (btn.Cell == null || (btn.Cell.Table == descr.Matrix && btn.Cell.GetMatrixElement() == MatrixElement.Corner))
                        list.Add(btn.Name);
                }
            }
            return list.ToArray();
        }

        public static string[] GetAvailableTotals(this HeaderDescriptor descr)
        {
            List<string> list = new List<string>();
            foreach (AggregateExpressionPair ag in descr.Matrix.Data.CellData.SharedAggregates)
                list.Add(ag.ToString());
            return list.ToArray();
        }

        public static string CreateUniqueName(this HeaderDescriptor descr, string baseName)
        {
            Hashtable t = new Hashtable();
            foreach (HeaderDescriptor d in descr.Root.AllItems)
            {
                t[d.Name] = 1;
            }

            int num = 1;
            while (true)
            {
                string name = baseName + num.ToString();
                if (!t.ContainsKey(name))
                {
                    descr.Name = name;
                    return name;
                }
                num++;
            }
        }

        public static void CreateTopNItems(this HeaderDescriptor descr)
        {
            HeaderDescriptor totalItem = new HeaderDescriptor() { Visible = descr.TopN.Total.Visible, DisplayText = descr.TopN.Total.Text };
            HeaderDescriptor othersItem = new HeaderDescriptor() { Visible = descr.TopN.Others.Visible };
            HeaderDescriptor othersTotalItem = new HeaderDescriptor() { Visible = descr.TopN.OthersTotal.Visible, DisplayText = descr.TopN.OthersTotal.Text };

            descr.InsertAfter(totalItem).InsertAfter(othersItem).InsertAfter(othersTotalItem);

            descr.TopN.Total.Name = totalItem.CreateUniqueName("TotalItem");
            descr.TopN.Others.Name = othersItem.CreateUniqueName("OthersItem");
            descr.TopN.OthersTotal.Name = othersTotalItem.CreateUniqueName("OthersTotalItem");
        }

        public static bool TopNItemsPresent(this HeaderDescriptor descr)
        {
            return descr.TopN.Total.Descriptor != null &&
                descr.TopN.Others.Descriptor != null &&
                descr.TopN.OthersTotal.Descriptor != null;
        }

        private static void DeleteTopNItem(TopNInfo.ItemInfo itemInfo)
        {
            HeaderDescriptor descr = itemInfo.Descriptor;
            if (descr != null)
                descr.DeleteThis();
            itemInfo.Name = "";
        }

        public static void DeleteTopNItems(this HeaderDescriptor descr)
        {
            DeleteTopNItem(descr.TopN.Total);
            DeleteTopNItem(descr.TopN.Others);
            DeleteTopNItem(descr.TopN.OthersTotal);
        }

        public static bool HasParent(this HeaderDescriptor descr, HeaderDescriptor parent)
        {
            while (descr.Parent != null)
            {
                descr = descr.Parent;
                if (descr == parent)
                    return true;
            }
            return false;
        }

        private static void UpdateTemplateItems(HeaderDescriptor descr, HeaderDescriptor newItem)
        {
            if (newItem.TemplateColumn == null || newItem.TemplateRow == null)
            {
                newItem.TemplateColumn = descr.TemplateColumn;
                newItem.TemplateRow = descr.TemplateRow;
            }
        }

        public static HeaderDescriptor InsertAfter(this HeaderDescriptor descr, HeaderDescriptor newItem)
        {
            HeaderDescriptor parent = descr.Parent;
            newItem.SetParent(parent);
            parent.Items.Insert(parent.Items.IndexOf(descr) + 1, newItem);
            UpdateTemplateItems(descr, newItem);
            return newItem;
        }

        public static HeaderDescriptor InsertBefore(this HeaderDescriptor descr, HeaderDescriptor newItem)
        {
            HeaderDescriptor parent = descr.Parent;
            newItem.SetParent(parent);
            parent.Items.Insert(parent.Items.IndexOf(descr), newItem);
            UpdateTemplateItems(descr, newItem);
            return newItem;
        }

        public static HeaderDescriptor InsertParent(this HeaderDescriptor descr, HeaderDescriptor newItem)
        {
            HeaderDescriptor parent = descr.Parent;
            newItem.SetParent(parent);
            parent.Items.Insert(parent.Items.IndexOf(descr), newItem);
            parent.Items.Remove(descr);
            descr.SetParent(newItem);
            newItem.Items.Add(descr);
            UpdateTemplateItems(descr, newItem);
            return newItem;
        }

        public static HeaderDescriptor InsertChild(this HeaderDescriptor descr, HeaderDescriptor newItem)
        {
            newItem.SetParent(descr);
            foreach (HeaderDescriptor d in descr.Items)
            {
                d.SetParent(newItem);
                newItem.Items.Add(d);
            }
            descr.Items.Clear();
            descr.Items.Add(newItem);
            UpdateTemplateItems(descr, newItem);
            return newItem;
        }

        public static void DeleteThis(this HeaderDescriptor descr)
        {
            HeaderDescriptor parent = descr.Parent;
            foreach (HeaderDescriptor d in descr.Items)
            {
                d.SetParent(parent);
            }
            parent.Items.InsertRange(parent.Items.IndexOf(descr), descr.Items);
            parent.Items.Remove(descr);
            descr.Items.Clear();
        }

        public static void DeleteTree(this HeaderDescriptor descr)
        {
            descr.Parent.Items.Remove(descr);
        }
    }
}