private static NotifyBatchCollectionChangedEventArgs Combine(NotifyBatchCollectionChangedEventArgs x, NotifyBatchCollectionChangedEventArgs y)
        {
            if (x == null)
            {
                return(y);
            }

            if (y == null)
            {
                return(x);
            }

            var replacements = default(BiMap);
            var result       = default(NotifyBatchCollectionChangedEventArgs);

            if (x.Action == y.Action)
            {
                switch (x.Action)
                {
                case NotifyCollectionChangedAction.Replace:
                {
                    replacements = NotifyBatchCollectionChangedEventArgs.Merge(
                        NotifyBatchCollectionChangedEventArgs.Map(x.OldItems, x.NewItems),
                        NotifyBatchCollectionChangedEventArgs.Map(y.OldItems, y.NewItems));
                    if (replacements == null)
                    {
                        return(null);
                    }

                    result = new NotifyBatchCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset);
                }
                break;

                case NotifyCollectionChangedAction.Add:
                case NotifyCollectionChangedAction.Remove:
                case NotifyCollectionChangedAction.Move:
                    result = new NotifyBatchCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset);
                    break;

                case NotifyCollectionChangedAction.Reset:
                    result       = new NotifyBatchCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset);
                    replacements = NotifyBatchCollectionChangedEventArgs.Merge(x.m_fromTo, y.m_fromTo);
                    break;

                default:
                    throw new NotSupportedException();
                }
            }
            else
            {
                if (x.Action == NotifyCollectionChangedAction.Replace)
                {
                    replacements = NotifyBatchCollectionChangedEventArgs.Merge(NotifyBatchCollectionChangedEventArgs.Map(x.OldItems, x.NewItems), null);
                }
                else if ((x.Action == NotifyCollectionChangedAction.Reset) && (x.m_fromTo != null))
                {
                    replacements = new BiMap(x.m_fromTo, x.m_toFrom);
                }

                switch (y.Action)
                {
                case NotifyCollectionChangedAction.Add:
                {
                    if (replacements != null)
                    {
                        var fromTo = replacements.FromTo;
                        var toFrom = replacements.ToFrom;

                        foreach (var item in y.NewItems)
                        {
                            object to;

                            if (fromTo.TryGetValue(item, out to))
                            {
                                fromTo.Remove(item);
                                toFrom.Remove(to);
                            }
                        }
                    }
                }
                break;

                case NotifyCollectionChangedAction.Remove:
                {
                    if (replacements != null)
                    {
                        var fromTo = replacements.FromTo;
                        var toFrom = replacements.ToFrom;

                        foreach (var item in y.OldItems)
                        {
                            object from;

                            if (toFrom.TryGetValue(item, out from))
                            {
                                fromTo.Remove(from);
                                toFrom.Remove(item);
                            }
                        }
                    }
                }
                break;

                case NotifyCollectionChangedAction.Replace:
                {
                    var mapping = NotifyBatchCollectionChangedEventArgs.Map(y.OldItems, y.NewItems);

                    if (replacements != null)
                    {
                        replacements = NotifyBatchCollectionChangedEventArgs.Merge(replacements.FromTo, mapping);
                    }
                    else
                    {
                        replacements = NotifyBatchCollectionChangedEventArgs.Merge(mapping, null);
                    }
                }
                break;

                case NotifyCollectionChangedAction.Move:
                    break;

                case NotifyCollectionChangedAction.Reset:
                {
                    if (replacements != null)
                    {
                        replacements = NotifyBatchCollectionChangedEventArgs.Merge(replacements.FromTo, y.m_fromTo);
                    }
                    else
                    {
                        replacements = NotifyBatchCollectionChangedEventArgs.Merge(y.m_fromTo, null);
                    }
                }
                break;

                default:
                    throw new NotSupportedException();
                }

                result = new NotifyBatchCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset);
            }

            if ((result != null) && (replacements != null))
            {
                result.m_fromTo = replacements.FromTo;
                result.m_toFrom = replacements.ToFrom;
            }

            return(result);
        }
 internal static NotifyBatchCollectionChangedEventArgs Combine(NotifyCollectionChangedEventArgs x, NotifyCollectionChangedEventArgs y)
 {
     return(NotifyBatchCollectionChangedEventArgs.Combine(
                NotifyBatchCollectionChangedEventArgs.Create(x),
                NotifyBatchCollectionChangedEventArgs.Create(y)));
 }