private void InsertAllGroupsAndPointPairLists(string[] uniqueGroupNames, int docNodeCount)
            {
                var uniqueGroups = uniqueGroupNames.Select(n => new ReplicateGroup(n,
                                                                                   ReplicateIndexSet.OfValues(ReplicateGroups.Where(r => r.GroupName == n).SelectMany(r => r.ReplicateIndexes)),
                                                                                   null, true));

                var newGroups = ReplicateGroups.ToList();

                foreach (var group in uniqueGroups)
                {
                    var group1     = group;
                    var firstIndex = newGroups.IndexOf(r => r.GroupName == group1.GroupName);
                    newGroups.Insert(firstIndex, group);

                    for (var node = 0; node < docNodeCount; ++node)
                    {
                        for (var step = 0; step < PointPairLists[node].Count; ++step)
                        {
                            if (PointPairLists[node][step].Any())
                            {
                                PointPairLists[node][step].Insert(firstIndex, new PointPair(firstIndex, double.NaN));
                            }
                        }
                    }
                }
                ReplicateGroups = newGroups;
            }
            private void MergeGroups(string[] uniqueGroupNames, List <List <PointPairRef> >[] references)
            {
                for (var nameIndex = 0; nameIndex < uniqueGroupNames.Length; ++nameIndex)
                {
                    var name         = uniqueGroupNames[nameIndex];
                    var groupIndices = ReplicateGroups.Select((r, index) => new { RepGroup = r, Index = index })
                                       .Where(g => g.RepGroup.GroupName == name).Select(g => g.Index).ToArray();

                    if (ShouldMerge(references, groupIndices.Skip(1)))
                    {
                        for (var node = 0; node < references.Length; ++node)
                        {
                            for (var step = 0; step < references[node].Count; ++step)
                            {
                                for (var group = 0; group < references[node][step].Count; ++group)
                                {
                                    if (groupIndices.Skip(1).Contains(references[node][step][group].PointPairListIndex))
                                    {
                                        var list  = PointPairLists[node][step];
                                        var index = groupIndices.First(i => ReplicateGroups[i].IsAllGroup);

                                        if (list[index].IsInvalid || !references[node][step][group].PointPair.IsInvalid)
                                        {
                                            var x = list[index].X; // Backup x value
                                            list[index] = new PointPair(references[node][step][group].PointPair)
                                            {
                                                X = x
                                            };
                                            references[node][step][group].PointPair.X = references[node][step][group].PointPair.Y = double.NaN;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
            private void RemoveEmptyGroups(int docNodeCount)
            {
                var groups = ReplicateGroups.ToList();

                for (var i = 0; i < groups.Count; ++i)
                {
                    var index       = i;
                    var removeGroup = ShouldRemoveGroup(index);
                    if (removeGroup && groups[index].IsAllGroup)
                    {
                        var fileGroups = groups.Select((g, j) => j).Where(j => groups[j].GroupName == groups[index].GroupName && !groups[j].IsAllGroup);
                        removeGroup = fileGroups.Any(j => !ShouldRemoveGroup(j));
                    }
                    if (removeGroup)
                    {
                        for (var node = 0; node < docNodeCount; ++node)
                        {
                            for (var step = 0; step < PointPairLists[node].Count; ++step)
                            {
                                if (PointPairLists[node][step].Any())
                                {
                                    PointPairLists[node][step].RemoveAt(i);
                                    // Fix x values
                                    for (var j = i; j < PointPairLists[node][step].Count; ++j)
                                    {
                                        --PointPairLists[node][step][j].X;
                                    }
                                }
                            }
                        }
                        groups.RemoveAt(i);
                        --i;
                    }
                }
                ReplicateGroups = groups;
            }