using System;
using System.Collections.Generic;
using System.Collections;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.ComponentModel;
namespace DevComponents.DotNetBar.Primitives
{
    /// 
    /// Represents custom collection with INotifyPropertyChanged and INotifyCollectionChanged interface support.
    /// 
    /// 
    [Serializable, DebuggerDisplay("Count = {Count}"), ComVisible(false)]
    public class CustomCollection : IList, IList, INotifyPropertyChanged, INotifyCollectionChanged
    {
        #region Events
        /// 
        /// Occurs when property value has changed.
        /// 
        public event PropertyChangedEventHandler PropertyChanged;
        #endregion
        #region Private variables
        private SimpleMonitor _monitor;
        private object _SyncRoot;
        private readonly IList _Items;
        private bool _FloatLastItem;
        #endregion
        #region Constructors
        /// 
        /// Creates new instance of object.
        /// 
        public CustomCollection()
        {
            _monitor = new SimpleMonitor();
            _Items = new List();
        }
        public void Dispose()
        {
            _monitor.Dispose();
        }
        /// 
        /// Creates new instance of object.
        /// 
        public CustomCollection(int capacity)
        {
            _monitor = new SimpleMonitor();
            _Items = new List(capacity);
        }
        /// 
        /// Creates new instance of object.
        /// 
        /// List to initialize collection with.
        public CustomCollection(IList list)
        {
            if (list == null)
                throw new ArgumentNullException("list");
            _monitor = new SimpleMonitor();
            _Items = list;
        }
        #endregion
        #region Add
        /// 
        /// Add item to collection.
        /// 
        /// Item to add.
        public void Add(T item)
        {
            if (_Items.IsReadOnly)
                throw new NotSupportedException("collection is read-only");
            InsertItem(_Items.Count, item);
        }
        #endregion
        #region Sort
        //
        // Summary:
        //     Sorts the elements in the entire collection using
        //     the default comparer.
        //
        // Exceptions:
        //   System.InvalidOperationException:
        //     The default comparer System.Collections.Generic.Comparer.Default cannot
        //     find an implementation of the System.IComparable generic interface or
        //     the System.IComparable interface for type T.
        public void Sort()
        {
            if (_Items.IsReadOnly)
                throw new NotSupportedException("collection is read-only");
            if(!(_Items is List))
                throw new NotSupportedException("collection must be default List collection");
            ((List)_Items).Sort();
            OnCollectionChanged(NotifyCollectionChangedAction.Reset, null, -1);
        }
        //
        // Summary:
        //     Reverse sorts the elements in the entire collection.
        //
        public void SortReverse()
        {
            if (_Items.IsReadOnly)
                throw new NotSupportedException("collection is read-only");
            if (!(_Items is List))
                throw new NotSupportedException("collection must be default List collection");
            ((List)_Items).Sort();
            ((List)_Items).Reverse();
            OnCollectionChanged(NotifyCollectionChangedAction.Reset, null, -1);
        }
        //
        // Summary:
        //     Sorts the elements in the entire collection using
        //     the specified System.Comparison.
        //
        // Parameters:
        //   comparison:
        //     The System.Comparison to use when comparing elements.
        //
        // Exceptions:
        //   System.ArgumentNullException:
        //     comparison is null.
        //
        //   System.ArgumentException:
        //     The implementation of comparison caused an error during the sort. For example,
        //     comparison might not return 0 when comparing an item with itself.
        public void Sort(Comparison comparison)
        {
            if (_Items.IsReadOnly)
                throw new NotSupportedException("collection is read-only");
            if (!(_Items is List))
                throw new NotSupportedException("collection must be default List collection");
            ((List)_Items).Sort(comparison);
            OnCollectionChanged(NotifyCollectionChangedAction.Reset, null, -1);
        }
        //
        // Summary:
        //     Sorts the elements in the entire System.Collections.Generic.List using
        //     the specified comparer.
        //
        // Parameters:
        //   comparer:
        //     The System.Collections.Generic.IComparer implementation to use when comparing
        //     elements, or null to use the default comparer System.Collections.Generic.Comparer.Default.
        //
        // Exceptions:
        //   System.InvalidOperationException:
        //     comparer is null, and the default comparer System.Collections.Generic.Comparer.Default
        //     cannot find implementation of the System.IComparable generic interface
        //     or the System.IComparable interface for type T.
        //
        //   System.ArgumentException:
        //     The implementation of comparer caused an error during the sort. For example,
        //     comparer might not return 0 when comparing an item with itself.
        public void Sort(IComparer comparer)
        {
            if (_Items.IsReadOnly)
                throw new NotSupportedException("collection is read-only");
            if (!(_Items is List))
                throw new NotSupportedException("collection must be default List collection");
            ((List)_Items).Sort(comparer);
            OnCollectionChanged(NotifyCollectionChangedAction.Reset, null, -1);
        }
        //
        // Summary:
        //     Sorts the elements in a range of elements in System.Collections.Generic.List
        //     using the specified comparer.
        //
        // Parameters:
        //   index:
        //     The zero-based starting index of the range to sort.
        //
        //   count:
        //     The length of the range to sort.
        //
        //   comparer:
        //     The System.Collections.Generic.IComparer implementation to use when comparing
        //     elements, or null to use the default comparer System.Collections.Generic.Comparer.Default.
        //
        // Exceptions:
        //   System.ArgumentOutOfRangeException:
        //     index is less than 0.-or-count is less than 0.
        //
        //   System.ArgumentException:
        //     index and count do not specify a valid range in the System.Collections.Generic.List.-or-The
        //     implementation of comparer caused an error during the sort. For example,
        //     comparer might not return 0 when comparing an item with itself.
        //
        //   System.InvalidOperationException:
        //     comparer is null, and the default comparer System.Collections.Generic.Comparer.Default
        //     cannot find implementation of the System.IComparable generic interface
        //     or the System.IComparable interface for type T.
        public void Sort(int index, int count, IComparer comparer)
        {
            if (_Items.IsReadOnly)
                throw new NotSupportedException("collection is read-only");
            if (!(_Items is List))
                throw new NotSupportedException("collection must be default List collection");
            ((List)_Items).Sort(index, count, comparer);
            OnCollectionChanged(NotifyCollectionChangedAction.Reset, null, -1);
        }
        #endregion
        #region Clear
        /// 
        /// Remove all items from collection.
        /// 
        public void Clear()
        {
            if (_Items.IsReadOnly)
                throw new NotSupportedException("collection is read-only");
            ClearItems();
        }
        /// 
        /// Remove all items from collection.
        /// 
        protected virtual void ClearItems()
        {
            CheckReentrancy();
            T item = default(T);
            if (_FloatLastItem == true)
            {
                if (_Items.Count > 0)
                    item = _Items[_Items.Count - 1];
            }
            _Items.Clear();
            OnPropertyChanged(new PropertyChangedEventArgs(CountString));
            OnPropertyChanged(new PropertyChangedEventArgs(ItemString));
            OnCollectionReset();
            if (_FloatLastItem == true)
                _Items.Add(item);
        }
        #endregion
        #region Contains
        /// 
        /// Checks whether collection contains item.
        /// 
        /// Item to look for.
        /// true if item is in collection.
        public bool Contains(T item)
        {
            OnCollectionReadAccess();
            return (_Items.Contains(item));
        }
        #endregion
        #region CopyTo
        /// 
        /// Copy collection to array.
        /// 
        /// Array to copy to.
        /// Index to copy from.
        public void CopyTo(T[] array, int index)
        {
            OnCollectionReadAccess();
            _Items.CopyTo(array, index);
        }
        /// 
        /// Copy collection to array.
        /// 
        /// Array to copy to.
        public void CopyTo(T[] array)
        {
            CopyTo(array, 0);
        }
        #endregion
        #region Count
        /// 
        /// Returns number of items in collection.
        /// 
        public int Count
        {
            get
            {
                OnCollectionReadAccess();
                return (_Items.Count);
            }
        }
        #endregion
        #region CountString
        private string CountString
        {
            get { return ("Count"); }
        }
        #endregion
        #region FloatLastItem
        internal bool FloatLastItem
        {
            get { return (_FloatLastItem); }
            set { _FloatLastItem = value; }
        }
        #endregion
        #region GetEnumerator
        /// 
        /// Gets enumerator for collection.
        /// 
        /// Enumerator.
        public IEnumerator GetEnumerator()
        {
            OnCollectionReadAccess();
            return (_Items.GetEnumerator());
        }
        #endregion
        #region Indexer[int]
        /// 
        /// Returns item at index.
        /// 
        /// Index of item.
        /// Item at index.
        public T this[int index]
        {
            get
            {
                OnCollectionReadAccess();
                return (_Items[index]);
            }
            set
            {
                if (_Items.IsReadOnly)
                    throw new NotSupportedException("collection is read-only");
                if ((index < 0) || (index >= _Items.Count))
                    throw new ArgumentOutOfRangeException();
                SetItem(index, value);
            }
        }
        #endregion
        #region IndexOf
        /// 
        /// Returns index of an item.
        /// 
        /// Reference to item.
        /// Index of item.
        public int IndexOf(T item)
        {
            OnCollectionReadAccess();
            return (_Items.IndexOf(item));
        }
        #endregion
        #region Insert
        /// 
        /// Insert item at specified location.
        /// 
        /// Index to insert item in.
        /// Item to insert.
        public void Insert(int index, T item)
        {
            if ((index < 0) || (index > this._Items.Count))
                throw new ArgumentOutOfRangeException("index");
            InsertItem(index, item);
        }
        #endregion
        #region InsertItem
        /// 
        /// Inserts item.
        /// 
        /// Index to insert item at.
        /// Reference to item.
        protected virtual void InsertItem(int index, T item)
        {
            CheckReentrancy();
            if (_FloatLastItem == true)
            {
                if (_Items.Count > 0 && index == _Items.Count)
                    index--;
            }
            _Items.Insert(index, item);
            OnPropertyChanged(new PropertyChangedEventArgs(CountString));
            OnCollectionChanged(NotifyCollectionChangedAction.Add, item, index);
        }
        #endregion
        #region IsCompatibleObject
        private static bool IsCompatibleObject(object value)
        {
            return (value is T) || (value == null && !typeof(T).IsValueType);
        }
        #endregion
        #region ItemString
        private string ItemString
        {
            get { return ("Item[]"); }
        }
        #endregion
        #region Remove
        /// 
        /// Removes item from collection.
        /// 
        /// Item to remove.
        /// true if item was removed.
        public bool Remove(T item)
        {
            if (_Items.IsReadOnly)
                throw new NotSupportedException("collection is read-only");
            int index = _Items.IndexOf(item);
            if (index < 0)
                return (false);
            RemoveItem(index);
            return (true);
        }
        #endregion
        #region RemoveAt
        /// 
        /// Remove item at specified location.
        /// 
        /// Index of item to remove.
        public void RemoveAt(int index)
        {
            if (_Items.IsReadOnly)
                throw new NotSupportedException("collection is read-only");
            if ((index < 0) || (index >= _Items.Count))
                throw new ArgumentOutOfRangeException();
            RemoveItem(index);
        }
        #endregion
        #region RemoveItem
        /// 
        /// Remove item at specified location.
        /// 
        /// Index of item to remove.
        protected virtual void RemoveItem(int index)
        {
            CheckReentrancy();
            object item = _Items[index];
            _Items.RemoveAt(index);
            OnPropertyChanged(new PropertyChangedEventArgs(CountString));
            OnCollectionChanged(NotifyCollectionChangedAction.Remove, item, index);
        }
        #endregion
        #region SetItem
        /// 
        /// Set item on location.
        /// 
        /// Index
        /// Item to assign.
        protected virtual void SetItem(int index, T item)
        {
            CheckReentrancy();
            T oldItem = _Items[index];
            _Items[index] = item;
            OnPropertyChanged(new PropertyChangedEventArgs(CountString));
            OnPropertyChanged(new PropertyChangedEventArgs(ItemString));
            OnCollectionChanged(NotifyCollectionChangedAction.Replace, oldItem, item, index);
        }
        #endregion
        #region IList support
        #region Add
        int IList.Add(object value)
        {
            if (_Items.IsReadOnly)
                throw new NotSupportedException("collection is read-only");
            VerifyValueType(value);
            Add((T)value);
            return (Count - 1);
        }
        #endregion
        #region Contains
        bool IList.Contains(object value)
        {
            return (IsCompatibleObject(value) && Contains((T)value));
        }
        #endregion
        #region GetItemsDirect
        /// 
        /// Returns items directly without checks.
        /// 
        /// List of items.
        protected IList GetItemsDirect()
        {
            return (_Items);
        }
        #endregion
        #region Indexer[int]
        object IList.this[int index]
        {
            get
            {
                OnCollectionReadAccess();
                return this._Items[index];
            }
            set
            {
                VerifyValueType(value);
                this[index] = (T)value;
            }
        }
        #region IndexOf
        int IList.IndexOf(object value)
        {
            OnCollectionReadAccess();
            return (IsCompatibleObject(value) ? IndexOf((T)value) : -1);
        }
        #endregion
        #region Insert
        void IList.Insert(int index, object value)
        {
            if (this._Items.IsReadOnly)
                throw new NotSupportedException("collection is read-only");
            VerifyValueType(value);
            Insert(index, (T)value);
        }
        #endregion
        #region IsFixedSize
        bool IList.IsFixedSize
        {
            get
            {
                IList items = _Items as IList;
                return ((items != null) && items.IsFixedSize);
            }
        }
        #endregion
        #region IsReadOnly
        bool IList.IsReadOnly
        {
            get { return (_Items.IsReadOnly); }
        }
        #endregion
        #region Items
        /// 
        /// Returns the IList interface for items in collection.
        /// 
        protected IList Items
        {
            get
            {
                OnCollectionReadAccess();
                return (_Items);
            }
        }
        #endregion
        #region Remove
        void IList.Remove(object value)
        {
            if (_Items.IsReadOnly)
                throw new NotSupportedException("collection is read-only");
            if (IsCompatibleObject(value))
                Remove((T)value);
        }
        #endregion
        #endregion
        #region VerifyValueType
        private static void VerifyValueType(object value)
        {
            if (!IsCompatibleObject(value))
                throw new ArgumentException("value is of wrong type");
        }
        #endregion
        #endregion
        #region IEnumerable.GetEnumerator
        IEnumerator IEnumerable.GetEnumerator()
        {
            OnCollectionReadAccess();
            return (_Items.GetEnumerator());
        }
        #endregion
        #region ICollection support
        #region CopyTo
        void ICollection.CopyTo(Array array, int index)
        {
            CheckReentrancy();
            OnCollectionReadAccess();
            if (array == null)
                throw new ArgumentNullException("array");
            if (array.Rank != 1)
                throw new ArgumentException("Argument array.Rank multi-dimensional not supported");
            if (array.GetLowerBound(0) != 0)
                throw new ArgumentException("Argument array non zero lower bound not supported");
            if (index < 0)
                throw new ArgumentOutOfRangeException("index", "index must be non-negative number");
            if ((array.Length - index) < this.Count)
                throw new ArgumentException("array too small");
            T[] localArray = array as T[];
            if (localArray != null)
            {
                _Items.CopyTo(localArray, index);
            }
            else
            {
                Type elementType = array.GetType().GetElementType();
                Type c = typeof(T);
                if (elementType == null ||
                    (!elementType.IsAssignableFrom(c) && !c.IsAssignableFrom(elementType)))
                {
                    throw new ArgumentException("Argument array of invalid type");
                }
                object[] objArray = array as object[];
                if (objArray == null)
                    throw new ArgumentException("Argument array invalid type");
                int count = this._Items.Count;
                try
                {
                    for (int i = 0; i < count; i++)
                        objArray[index++] = this._Items[i];
                }
                catch (ArrayTypeMismatchException)
                {
                    throw new ArgumentException("Argument array invalid type");
                }
            }
        }
        #endregion
        #region IsSynchronized
        bool ICollection.IsSynchronized
        {
            get { return false; }
        }
        #endregion
        #region IsReadOnly
        bool ICollection.IsReadOnly
        {
            get { return this._Items.IsReadOnly; }
        }
        #endregion
        #region SyncRoot
        object ICollection.SyncRoot
        {
            get
            {
                if (_SyncRoot == null)
                {
                    ICollection items = _Items as ICollection;
                    if (items != null)
                        _SyncRoot = items.SyncRoot;
                    else
                        System.Threading.Interlocked.CompareExchange(ref _SyncRoot, new object(), null);
                }
                return (_SyncRoot);
            }
        }
        #endregion
        #endregion
        #region OnCollectionReadAccess
        /// 
        /// Occurs when collection is read.
        /// 
        protected virtual void OnCollectionReadAccess()
        {
        }
        #endregion
        #region OnPropertyChanged
        /// 
        /// Occurs when collection property has changed.
        /// 
        /// Event arguments.
        protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, e);
        }
        #endregion
        #region BlockReentrancy
        /// 
        /// Blocks the collection reentrancy.
        /// 
        /// IDisposable to end re-entrancy
        protected IDisposable BlockReentrancy()
        {
            _monitor.Enter();
            return (_monitor);
        }
        #endregion
        #region CheckReentrancy
        /// 
        /// Checks whether call creates reentrancy.
        /// 
        protected void CheckReentrancy()
        {
            if ((_monitor.Busy && (CollectionChanged != null)) &&
                (CollectionChanged.GetInvocationList().Length > 1))
            {
                throw new InvalidOperationException("CustomCollectionReentrancyNotAllowed");
            }
        }
        #endregion
        #region SimpleMonitor
        [Serializable]
        private class SimpleMonitor : IDisposable
        {
            // Fields
            private int _BusyCount;
            // Methods
            public void Dispose()
            {
                _BusyCount--;
            }
            public void Enter()
            {
                _BusyCount++;
            }
            // Properties
            public bool Busy
            {
                get { return (_BusyCount > 0); }
            }
        }
        #endregion
        #region INotifyCollectionChanged Members
        /// 
        /// Occurs when collection has changed.
        /// 
        public event NotifyCollectionChangedEventHandler CollectionChanged;
        private void OnCollectionChanged(NotifyCollectionChangedAction action, object item, int index)
        {
            this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(action, item, index));
        }
        private void OnCollectionChanged(NotifyCollectionChangedAction action, object oldItem, object newItem, int index)
        {
            this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(action, newItem, oldItem, index));
        }
        private void OnCollectionReset()
        {
            this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
        }
        /// 
        /// Called when collection has changed.
        /// 
        /// Event arguments.
        protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
        {
            if (this.CollectionChanged != null)
            {
                using (this.BlockReentrancy())
                {
                    this.CollectionChanged(this, e);
                }
            }
        }
        #endregion
    }
    #region INotifyCollectionChanged
    /// 
    /// Represents collection changed notification interface.
    /// 
    public interface INotifyCollectionChanged
    {
        /// 
        /// Occurs when collection changed.
        /// 
        event NotifyCollectionChangedEventHandler CollectionChanged;
    }
    /// 
    /// Defines change actions.
    /// 
    public enum NotifyCollectionChangedAction
    {
        /// 
        /// Items were added.
        /// 
        Add,
        /// 
        /// Items were removed.
        /// 
        Remove,
        /// 
        /// Items were replaced.
        /// 
        Replace,
        /// 
        /// Items were moved.
        /// 
        Move,
        /// 
        /// Collection was reset.
        /// 
        Reset
    }
    /// 
    /// Defines delegate for collection notification events.
    /// 
    /// Event sender.
    /// Event arguments.
    public delegate void NotifyCollectionChangedEventHandler(object sender, NotifyCollectionChangedEventArgs e);
    /// 
    /// Defines collection change notification event arguments.
    /// 
    public class NotifyCollectionChangedEventArgs : EventArgs
    {
        #region Private Vars
        private NotifyCollectionChangedAction _Action;
        private IList _NewItems;
        private int _NewStartingIndex;
        private IList _OldItems;
        private int _OldStartingIndex;
        #endregion
        /// 
        /// Create new instance of object.
        /// 
        /// Action
        public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action)
        {
            this._NewStartingIndex = -1;
            this._OldStartingIndex = -1;
            if (action != NotifyCollectionChangedAction.Reset)
            {
                throw new ArgumentException("WrongActionForCtor");
            }
            this.InitializeAdd(action, null, -1);
        }
        /// 
        /// Creates new instance of object.
        /// 
        /// Specifies action.
        /// List of changed items.
        public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, IList changedItems)
        {
            this._NewStartingIndex = -1;
            this._OldStartingIndex = -1;
            if (((action != NotifyCollectionChangedAction.Add) && (action != NotifyCollectionChangedAction.Remove)) && (action != NotifyCollectionChangedAction.Reset))
            {
                throw new ArgumentException("MustBeResetAddOrRemoveActionForCtor");
            }
            if (action == NotifyCollectionChangedAction.Reset)
            {
                if (changedItems != null)
                {
                    throw new ArgumentException("ResetActionRequiresNullItem");
                }
                this.InitializeAdd(action, null, -1);
            }
            else
            {
                if (changedItems == null)
                {
                    throw new ArgumentNullException("changedItems");
                }
                this.InitializeAddOrRemove(action, changedItems, -1);
            }
        }
        /// 
        /// Creates new instance of object.
        /// 
        /// Specifies action.
        /// Item that was changed.
        public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, object changedItem)
        {
            this._NewStartingIndex = -1;
            this._OldStartingIndex = -1;
            if (((action != NotifyCollectionChangedAction.Add) && (action != NotifyCollectionChangedAction.Remove)) && (action != NotifyCollectionChangedAction.Reset))
            {
                throw new ArgumentException("MustBeResetAddOrRemoveActionForCtor");
            }
            if (action == NotifyCollectionChangedAction.Reset)
            {
                if (changedItem != null)
                {
                    throw new ArgumentException("ResetActionRequiresNullItem");
                }
                this.InitializeAdd(action, null, -1);
            }
            else
            {
                this.InitializeAddOrRemove(action, new object[] { changedItem }, -1);
            }
        }
        /// 
        /// Creates new instance of object.
        /// 
        /// Action.
        /// New items in collection.
        /// Old items in collection.
        public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, IList newItems, IList oldItems)
        {
            this._NewStartingIndex = -1;
            this._OldStartingIndex = -1;
            if (action != NotifyCollectionChangedAction.Replace)
            {
                throw new ArgumentException("WrongActionForCtor");
            }
            if (newItems == null)
            {
                throw new ArgumentNullException("newItems");
            }
            if (oldItems == null)
            {
                throw new ArgumentNullException("oldItems");
            }
            this.InitializeMoveOrReplace(action, newItems, oldItems, -1, -1);
        }
        /// 
        /// Creates new instance of object.
        /// 
        /// Action.
        /// List of changed items.
        /// Starting index of change.
        public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, IList changedItems, int startingIndex)
        {
            this._NewStartingIndex = -1;
            this._OldStartingIndex = -1;
            if (((action != NotifyCollectionChangedAction.Add) && (action != NotifyCollectionChangedAction.Remove)) && (action != NotifyCollectionChangedAction.Reset))
            {
                throw new ArgumentException("MustBeResetAddOrRemoveActionForCtor");
            }
            if (action == NotifyCollectionChangedAction.Reset)
            {
                if (changedItems != null)
                {
                    throw new ArgumentException("ResetActionRequiresNullItem");
                }
                if (startingIndex != -1)
                {
                    throw new ArgumentException("ResetActionRequiresIndexMinus1");
                }
                this.InitializeAdd(action, null, -1);
            }
            else
            {
                if (changedItems == null)
                {
                    throw new ArgumentNullException("changedItems");
                }
                if (startingIndex < -1)
                {
                    throw new ArgumentException("IndexCannotBeNegative");
                }
                this.InitializeAddOrRemove(action, changedItems, startingIndex);
            }
        }
        /// 
        /// Creates new instance of object.
        /// 
        /// Action
        /// Changed item
        /// Index of change
        public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, object changedItem, int index)
        {
            this._NewStartingIndex = -1;
            this._OldStartingIndex = -1;
            if (((action != NotifyCollectionChangedAction.Add) && (action != NotifyCollectionChangedAction.Remove)) && (action != NotifyCollectionChangedAction.Reset))
            {
                throw new ArgumentException("MustBeResetAddOrRemoveActionForCtor");
            }
            if (action == NotifyCollectionChangedAction.Reset)
            {
                if (changedItem != null)
                {
                    throw new ArgumentException("ResetActionRequiresNullItem");
                }
                if (index != -1)
                {
                    throw new ArgumentException("ResetActionRequiresIndexMinus1");
                }
                this.InitializeAdd(action, null, -1);
            }
            else
            {
                this.InitializeAddOrRemove(action, new object[] { changedItem }, index);
            }
        }
        /// 
        /// Creates new instance of object.
        /// 
        /// Action
        /// New item
        /// Old item
        public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, object newItem, object oldItem)
        {
            this._NewStartingIndex = -1;
            this._OldStartingIndex = -1;
            if (action != NotifyCollectionChangedAction.Replace)
            {
                throw new ArgumentException("WrongActionForCtor");
            }
            this.InitializeMoveOrReplace(action, new object[] { newItem }, new object[] { oldItem }, -1, -1);
        }
        /// 
        /// Creates new instance of object.
        /// 
        /// Action
        /// New items.
        /// Removed items.
        /// Starting index of change.
        public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, IList newItems, IList oldItems, int startingIndex)
        {
            this._NewStartingIndex = -1;
            this._OldStartingIndex = -1;
            if (action != NotifyCollectionChangedAction.Replace)
            {
                throw new ArgumentException("WrongActionForCtor");
            }
            if (newItems == null)
            {
                throw new ArgumentNullException("newItems");
            }
            if (oldItems == null)
            {
                throw new ArgumentNullException("oldItems");
            }
            this.InitializeMoveOrReplace(action, newItems, oldItems, startingIndex, startingIndex);
        }
        /// 
        /// Creates new instance of object.
        /// 
        /// Action
        /// Changed items
        /// New index
        /// Old index
        public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, IList changedItems, int index, int oldIndex)
        {
            this._NewStartingIndex = -1;
            this._OldStartingIndex = -1;
            if (action != NotifyCollectionChangedAction.Move)
            {
                throw new ArgumentException("WrongActionForCtor");
            }
            if (index < 0)
            {
                throw new ArgumentException("IndexCannotBeNegative");
            }
            this.InitializeMoveOrReplace(action, changedItems, changedItems, index, oldIndex);
        }
        /// 
        /// Creates new instance of object.
        /// 
        /// Action
        /// Changed item
        /// New index
        /// Old index
        public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, object changedItem, int index, int oldIndex)
        {
            this._NewStartingIndex = -1;
            this._OldStartingIndex = -1;
            if (action != NotifyCollectionChangedAction.Move)
            {
                throw new ArgumentException("WrongActionForCtor");
            }
            if (index < 0)
            {
                throw new ArgumentException("IndexCannotBeNegative");
            }
            object[] newItems = new object[] { changedItem };
            this.InitializeMoveOrReplace(action, newItems, newItems, index, oldIndex);
        }
        /// 
        /// Creates new instance of object.
        /// 
        /// Action.
        /// New item
        /// Old item
        /// New index
        public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, object newItem, object oldItem, int index)
        {
            this._NewStartingIndex = -1;
            this._OldStartingIndex = -1;
            if (action != NotifyCollectionChangedAction.Replace)
            {
                throw new ArgumentException("WrongActionForCtor");
            }
            this.InitializeMoveOrReplace(action, new object[] { newItem }, new object[] { oldItem }, index, index);
        }
        private void InitializeAdd(NotifyCollectionChangedAction action, IList newItems, int newStartingIndex)
        {
            this._Action = action;
            this._NewItems = (newItems == null) ? null : ArrayList.ReadOnly(newItems);
            this._NewStartingIndex = newStartingIndex;
        }
        private void InitializeAddOrRemove(NotifyCollectionChangedAction action, IList changedItems, int startingIndex)
        {
            if (action == NotifyCollectionChangedAction.Add)
            {
                this.InitializeAdd(action, changedItems, startingIndex);
            }
            else if (action == NotifyCollectionChangedAction.Remove)
            {
                this.InitializeRemove(action, changedItems, startingIndex);
            }
        }
        private void InitializeMoveOrReplace(NotifyCollectionChangedAction action, IList newItems, IList oldItems, int startingIndex, int oldStartingIndex)
        {
            this.InitializeAdd(action, newItems, startingIndex);
            this.InitializeRemove(action, oldItems, oldStartingIndex);
        }
        private void InitializeRemove(NotifyCollectionChangedAction action, IList oldItems, int oldStartingIndex)
        {
            this._Action = action;
            this._OldItems = (oldItems == null) ? null : ArrayList.ReadOnly(oldItems);
            this._OldStartingIndex = oldStartingIndex;
        }
        /// 
        /// Gets the type of the collection change action.
        /// 
        public NotifyCollectionChangedAction Action
        {
            get
            {
                return this._Action;
            }
        }
        /// 
        /// Gets list of newly added items.
        /// 
        public IList NewItems
        {
            get
            {
                return this._NewItems;
            }
        }
        /// 
        /// Gets new starting index.
        /// 
        public int NewStartingIndex
        {
            get
            {
                return this._NewStartingIndex;
            }
        }
        /// 
        /// Gets list of removed items.
        /// 
        public IList OldItems
        {
            get
            {
                return this._OldItems;
            }
        }
        /// 
        /// Old starting index.
        /// 
        public int OldStartingIndex
        {
            get
            {
                return this._OldStartingIndex;
            }
        }
    }
    #endregion
}