using System; using System.Collections; using System.Collections.Generic; using System.Linq; namespace FastReport.AdvMatrix { internal class HeaderData : IEnumerable { public HeaderDescriptor Descriptor { get; private set; } public HeaderData Parent { get; private set; } public List Items { get; } public object Value { get; set; } public int Index { get; set; } public int DataRowNo { get; set; } public int RowNo { get; private set; } internal HeaderDataList ParentDataList { get { if (Parent == null) return null; foreach (HeaderDataList dl in Parent.Items) { if (dl.Descriptor == Descriptor && dl.IndexOf(this) != -1) return dl; } return null; } } internal int Span { get { if (Descriptor != null && Descriptor.Stepped) return 1; int count = TerminalItems.Count; return count > 0 ? count : 1; } } internal List AllItems { get { List list = new List(); GetAllItems(this, list); return list; } } internal List TerminalItems { get { List list = new List(); GetTerminalItems(this, list); return list; } } // returns all terminal items including invisible ones. Needed for TopN processing internal List AllTerminalItems { get { List list = new List(); GetAllTerminalItems(this, list); return list; } } internal object[] Values { get { int count = 0; HeaderData item = this; while (item.Parent != null) { count++; item = item.Parent; } object[] values = new object[count]; item = this; int index = count - 1; while (item.Parent != null) { values[index] = item.Value; index--; item = item.Parent; } return values; } } internal int ItemCount { get { return this.Count(); } } private void GetAllItems(HeaderData root, List list) { foreach (HeaderDataList dl in root.Items) { list.Add(dl); foreach (HeaderData d in dl) { GetAllItems(d, list); } } } private void GetTerminalItems(HeaderData root, List list) { if (root.Items.Count == 0 || (root.Descriptor != null && root.Descriptor.Stepped)) list.Add(root); foreach (HeaderData d in root) { GetTerminalItems(d, list); } } private void GetAllTerminalItems(HeaderData root, List list) { if (root.Items.Count == 0 || (root.Descriptor != null && root.Descriptor.Stepped)) list.Add(root); foreach (HeaderDataList dl in root.Items) { foreach (HeaderData d in dl) { GetAllTerminalItems(d, list); } } } private HeaderDataList Find(HeaderDescriptor descr) { if (Items.Count == 0) { // Create data lists as they appear in the descriptor item list. // It fixes the problem when the descriptor's Filter property is set and some total items may appear before data foreach (HeaderDescriptor d in descr.Parent.Items) { Items.Add(new HeaderDataList(this, d)); } } foreach (HeaderDataList dataList in Items) { if (dataList.Descriptor == descr) return dataList; } // this should never happen return null; } public HeaderData Add(HeaderDescriptor descr) { HeaderDataList dataList = Find(descr); object value = descr.CalcValue(); int index = dataList.Find(value); if (index >= 0) { return dataList[index]; } else { HeaderData data = new HeaderData(this, descr) { Value = value }; dataList.Insert(~index, data); return data; } } public void Clear() { Items.Clear(); } // this iterator is needed to return data from all datalists as a single list // it skips invisible items and sorts data if "sort by value" is on public IEnumerator GetEnumerator() { foreach (HeaderDataList dl in Items) { if (!dl.Visible) continue; List list = dl.GetSortedList(); for (int i = 0; i < list.Count; i++) { HeaderData d = list[i]; d.RowNo = i + 1; yield return d; } } } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } public HeaderData(HeaderData parent, HeaderDescriptor descr) { Parent = parent; Descriptor = descr; Items = new List(); } } }