public ComparisonUnitGroup(
            IEnumerable <ComparisonUnit> comparisonUnitList,
            ComparisonUnitGroupType groupType,
            int level)
        {
            Contents = comparisonUnitList.ToList();
            ComparisonUnitGroupType = groupType;
            ComparisonUnit     first = Contents.First();
            ComparisonUnitAtom comparisonUnitAtom = GetFirstComparisonUnitAtomOfGroup(first);

            XElement[] ancestorsToLookAt = comparisonUnitAtom
                                           .AncestorElements
                                           .Where(e => e.Name == W.tbl || e.Name == W.tr || e.Name == W.tc || e.Name == W.p || e.Name == W.txbxContent)
                                           .ToArray();

            XElement ancestor = ancestorsToLookAt[level];

            if (ancestor == null)
            {
                throw new OpenXmlPowerToolsException("Internal error: ComparisonUnitGroup");
            }

            SHA1Hash           = (string)ancestor.Attribute(PtOpenXml.SHA1Hash);
            CorrelatedSHA1Hash = (string)ancestor.Attribute(PtOpenXml.CorrelatedSHA1Hash);
            StructureSHA1Hash  = (string)ancestor.Attribute(PtOpenXml.StructureSHA1Hash);
        }
 private static void DescendantsInternal(
     ComparisonUnit comparisonUnit,
     List <ComparisonUnit> comparisonUnitList)
 {
     foreach (ComparisonUnit cu in comparisonUnit.Contents)
     {
         comparisonUnitList.Add(cu);
         if (cu.Contents != null && cu.Contents.Any())
         {
             DescendantsInternal(cu, comparisonUnitList);
         }
     }
 }
        private static ComparisonUnitAtom GetFirstComparisonUnitAtomOfGroup(ComparisonUnit group)
        {
            ComparisonUnit thisGroup = group;

            while (true)
            {
                if (thisGroup is ComparisonUnitGroup tg)
                {
                    thisGroup = tg.Contents.First();
                    continue;
                }

                if (!(thisGroup is ComparisonUnitWord tw))
                {
                    throw new OpenXmlPowerToolsException("Internal error: GetFirstComparisonUnitAtomOfGroup");
                }

                var ca = (ComparisonUnitAtom)tw.Contents.First();
                return(ca);
            }
        }
        // The following method must be made internal if we ever turn this part of the partial class
        // into its own class.
        private static ComparisonUnit[] GetComparisonUnitList(
            ComparisonUnitAtom[] comparisonUnitAtomList,
            WmlComparerSettings settings)
        {
            var seed = new Atgbw
            {
                Key = null,
                ComparisonUnitAtomMember = null,
                NextIndex = 0
            };

            IEnumerable <Atgbw> groupingKey = comparisonUnitAtomList
                                              .Rollup(seed, (sr, prevAtgbw, i) =>
            {
                int?key;
                int nextIndex = prevAtgbw.NextIndex;
                if (sr.ContentElement.Name == W.t)
                {
                    string chr = sr.ContentElement.Value;
                    char ch    = chr[0];
                    if (ch == '.' || ch == ',')
                    {
                        var beforeIsDigit = false;
                        if (i > 0)
                        {
                            ComparisonUnitAtom prev = comparisonUnitAtomList[i - 1];
                            if (prev.ContentElement.Name == W.t && char.IsDigit(prev.ContentElement.Value[0]))
                            {
                                beforeIsDigit = true;
                            }
                        }

                        var afterIsDigit = false;
                        if (i < comparisonUnitAtomList.Length - 1)
                        {
                            ComparisonUnitAtom next = comparisonUnitAtomList[i + 1];
                            if (next.ContentElement.Name == W.t && char.IsDigit(next.ContentElement.Value[0]))
                            {
                                afterIsDigit = true;
                            }
                        }

                        if (beforeIsDigit || afterIsDigit)
                        {
                            key = nextIndex;
                        }
                        else
                        {
                            nextIndex++;
                            key = nextIndex;
                            nextIndex++;
                        }
                    }
                    else if (settings.WordSeparators.Contains(ch))
                    {
                        nextIndex++;
                        key = nextIndex;
                        nextIndex++;
                    }
                    else
                    {
                        key = nextIndex;
                    }
                }
                else if (WordBreakElements.Contains(sr.ContentElement.Name))
                {
                    nextIndex++;
                    key = nextIndex;
                    nextIndex++;
                }
                else
                {
                    key = nextIndex;
                }

                return(new Atgbw
                {
                    Key = key,
                    ComparisonUnitAtomMember = sr,
                    NextIndex = nextIndex
                });
            })
                                              .ToArray();

            if (False)
            {
                var sb = new StringBuilder();
                foreach (Atgbw item in groupingKey)
                {
                    sb.Append(item.Key + Environment.NewLine);
                    sb.Append("    " + item.ComparisonUnitAtomMember.ToString(0) + Environment.NewLine);
                }

                string sbs = sb.ToString();
                TestUtil.NotePad(sbs);
            }

            IEnumerable <IGrouping <int?, Atgbw> > groupedByWords = groupingKey
                                                                    .GroupAdjacent(gc => gc.Key)
                                                                    .ToArray();

            if (False)
            {
                var sb = new StringBuilder();
                foreach (IGrouping <int?, Atgbw> group in groupedByWords)
                {
                    sb.Append("Group ===== " + @group.Key + Environment.NewLine);
                    foreach (Atgbw gc in @group)
                    {
                        sb.Append("    " + gc.ComparisonUnitAtomMember.ToString(0) + Environment.NewLine);
                    }
                }

                string sbs = sb.ToString();
                TestUtil.NotePad(sbs);
            }

            WithHierarchicalGroupingKey[] withHierarchicalGroupingKey = groupedByWords
                                                                        .Select(g =>
            {
                string[] hierarchicalGroupingArray = g
                                                     .First()
                                                     .ComparisonUnitAtomMember
                                                     .AncestorElements
                                                     .Where(a => ComparisonGroupingElements.Contains(a.Name))
                                                     .Select(a => a.Name.LocalName + ":" + (string)a.Attribute(PtOpenXml.Unid))
                                                     .ToArray();

                return(new WithHierarchicalGroupingKey
                {
                    ComparisonUnitWord = new ComparisonUnitWord(g.Select(gc => gc.ComparisonUnitAtomMember)),
                    HierarchicalGroupingArray = hierarchicalGroupingArray
                });
            }
                                                                                )
                                                                        .ToArray();

            if (False)
            {
                var sb = new StringBuilder();
                foreach (WithHierarchicalGroupingKey group in withHierarchicalGroupingKey)
                {
                    sb.Append("Grouping Array: " +
                              @group.HierarchicalGroupingArray.Select(gam => gam + " - ").StringConcatenate() +
                              Environment.NewLine);
                    foreach (ComparisonUnit gc in @group.ComparisonUnitWord.Contents)
                    {
                        sb.Append("    " + gc.ToString(0) + Environment.NewLine);
                    }
                }

                string sbs = sb.ToString();
                TestUtil.NotePad(sbs);
            }

            ComparisonUnit[] cul = GetHierarchicalComparisonUnits(withHierarchicalGroupingKey, 0).ToArray();

            if (False)
            {
                string str = ComparisonUnit.ComparisonUnitListToString(cul);
                TestUtil.NotePad(str);
            }

            return(cul);
        }