using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Runtime.InteropServices;
using DevComponents.DotNetBar.Charts.Style;
namespace DevComponents.DotNetBar.Charts
{
    /// 
    /// 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;
        #endregion
        #region Constructors
        /// 
        /// Creates new instance of object.
        /// 
        public CustomCollection()
        {
            _Monitor = new SimpleMonitor();
            _Items = new List();
        }
        /// 
        /// 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 AddRange
        /// 
        /// Add range of items to collection.
        /// 
        /// 
        public void AddRange(IEnumerable collection)
        {
            if (_Items.IsReadOnly)
                throw new NotSupportedException("collection is read-only");
            CheckReentrancy();
            int index = _Items.Count;
            foreach (T item in collection)
                _Items.Insert(index++, item);
            OnPropertyChanged(CountString);
            List list = new List(collection);
            NotifyCollectionChangedEventArgs e = new
                NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, list);
            OnCollectionChanged(e);
        }
        #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();
            _Items.Clear();
            OnPropertyChanged(CountString);
            OnPropertyChanged(ItemString);
            OnCollectionReset();
        }
        #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);
        }
        #endregion
        #region Count
        /// 
        /// Returns number of items in collection.
        /// 
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public int Count
        {
            get
            {
                OnCollectionReadAccess();
                return (_Items.Count);
            }
        }
        #endregion
        #region CountString
        protected string CountString
        {
            get { return ("Count"); }
        }
        #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 > _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();
            _Items.Insert(index, item);
            OnPropertyChanged(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
        protected 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(CountString);
            OnCollectionChanged(NotifyCollectionChangedAction.Remove, item, index);
        }
        #endregion
        #region RemoveRange
        /// 
        /// Removes a range of items from the collection.
        /// 
        /// 
        public void RemoveRange(int index, int count)
        {
            if (_Items.IsReadOnly)
                throw new NotSupportedException("collection is read-only");
            CheckReentrancy();
            List list = new List(count);
            for (int i = index + count - 1; i >= index; i--)
            {
                if ((uint)i < _Items.Count)
                {
                    list.Add(_Items[i]);
                    _Items.RemoveAt(i);
                }
            }
            OnPropertyChanged(CountString);
            NotifyCollectionChangedEventArgs e = new
                NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, list);
            OnCollectionChanged(e);
        }
        #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(CountString);
            OnPropertyChanged(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 (_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 (_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) < 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 = _Items.Count;
                try
                {
                    for (int i = 0; i < count; i++)
                        objArray[index++] = _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 (_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)
        {
            PropertyChangedEventHandler eh = PropertyChanged;
            if (eh != null)
                eh(this, e);
        }
        /// 
        /// Default PropertyChanged processing
        /// 
        /// 
        protected void OnPropertyChanged(string s)
        {
            if (PropertyChanged != null)
                OnPropertyChanged(new PropertyChangedEventArgs(s));
        }
        protected void OnPropertyChangedEx(string s, VisualChangeType changeType)
        {
            if (PropertyChanged != null)
                OnPropertyChanged(new VisualPropertyChangedEventArgs(s, changeType));
        }
        protected void OnStyleChanged(string property,
            INotifyPropertyChanged oldValue, INotifyPropertyChanged newValue)
        {
            StyleVisualChangeHandler(oldValue, newValue);
            OnPropertyChanged(property);
        }
        #region StyleVisualChangeHandler
        protected virtual void StyleVisualChangeHandler(
            INotifyPropertyChanged oldValue, INotifyPropertyChanged newValue)
        {
            if (oldValue != null)
                oldValue.PropertyChanged -= StyleChanged;
            if (newValue != null)
                newValue.PropertyChanged += StyleChanged;
        }
        #region StyleChanged
        /// 
        /// Occurs when one of element visual styles has property changes.
        /// Default implementation invalidates visual appearance of element.
        /// 
        /// VisualStyle that changed.
        /// Event arguments.
        protected virtual void StyleChanged(object sender, PropertyChangedEventArgs e)
        {
            VisualChangeType changeType = ((VisualPropertyChangedEventArgs)e).ChangeType;
            OnPropertyChangedEx(e.PropertyName, changeType);
        }
        #endregion
        #endregion
        #endregion
        #region BlockReentrancy
        /// 
        /// Blocks the collection reentrancy.
        /// 
        /// IDisposable to end reentrancy
        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;
        protected void OnCollectionChanged(NotifyCollectionChangedAction action, object item, int index)
        {
            OnCollectionChanged(new NotifyCollectionChangedEventArgs(action, item, index));
        }
        protected void OnCollectionChanged(NotifyCollectionChangedAction action, object oldItem, object newItem, int index)
        {
            OnCollectionChanged(new NotifyCollectionChangedEventArgs(action, newItem, oldItem, index));
        }
        protected void OnCollectionReset()
        {
            OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
        }
        /// 
        /// Called when collection has changed.
        /// 
        /// Event arguments.
        protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
        {
            if (CollectionChanged != null)
            {
                using (BlockReentrancy())
                {
                    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)
        {
            _NewStartingIndex = -1;
            _OldStartingIndex = -1;
            if (action != NotifyCollectionChangedAction.Reset)
            {
                throw new ArgumentException("WrongActionForCtor");
            }
            InitializeAdd(action, null, -1);
        }
        /// 
        /// Creates new instance of object.
        /// 
        /// Specifies action.
        /// List of changed items.
        public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, IList changedItems)
        {
            _NewStartingIndex = -1;
            _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");
                }
                InitializeAdd(action, null, -1);
            }
            else
            {
                if (changedItems == null)
                {
                    throw new ArgumentNullException("changedItems");
                }
                InitializeAddOrRemove(action, changedItems, -1);
            }
        }
        /// 
        /// Creates new instance of object.
        /// 
        /// Specifies action.
        /// Item that was changed.
        public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, object changedItem)
        {
            _NewStartingIndex = -1;
            _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");
                }
                InitializeAdd(action, null, -1);
            }
            else
            {
                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)
        {
            _NewStartingIndex = -1;
            _OldStartingIndex = -1;
            if (action != NotifyCollectionChangedAction.Replace)
            {
                throw new ArgumentException("WrongActionForCtor");
            }
            if (newItems == null)
            {
                throw new ArgumentNullException("newItems");
            }
            if (oldItems == null)
            {
                throw new ArgumentNullException("oldItems");
            }
            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)
        {
            _NewStartingIndex = -1;
            _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");
                }
                InitializeAdd(action, null, -1);
            }
            else
            {
                if (changedItems == null)
                {
                    throw new ArgumentNullException("changedItems");
                }
                if (startingIndex < -1)
                {
                    throw new ArgumentException("IndexCannotBeNegative");
                }
                InitializeAddOrRemove(action, changedItems, startingIndex);
            }
        }
        /// 
        /// Creates new instance of object.
        /// 
        /// Action
        /// Changed item
        /// Index of change
        public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, object changedItem, int index)
        {
            _NewStartingIndex = -1;
            _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");
                }
                InitializeAdd(action, null, -1);
            }
            else
            {
                InitializeAddOrRemove(action, new object[] { changedItem }, index);
            }
        }
        /// 
        /// Creates new instance of object.
        /// 
        /// Action
        /// New item
        /// Old item
        public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, object newItem, object oldItem)
        {
            _NewStartingIndex = -1;
            _OldStartingIndex = -1;
            if (action != NotifyCollectionChangedAction.Replace)
            {
                throw new ArgumentException("WrongActionForCtor");
            }
            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)
        {
            _NewStartingIndex = -1;
            _OldStartingIndex = -1;
            if (action != NotifyCollectionChangedAction.Replace)
            {
                throw new ArgumentException("WrongActionForCtor");
            }
            if (newItems == null)
            {
                throw new ArgumentNullException("newItems");
            }
            if (oldItems == null)
            {
                throw new ArgumentNullException("oldItems");
            }
            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)
        {
            _NewStartingIndex = -1;
            _OldStartingIndex = -1;
            if (action != NotifyCollectionChangedAction.Move)
            {
                throw new ArgumentException("WrongActionForCtor");
            }
            if (index < 0)
            {
                throw new ArgumentException("IndexCannotBeNegative");
            }
            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)
        {
            _NewStartingIndex = -1;
            _OldStartingIndex = -1;
            if (action != NotifyCollectionChangedAction.Move)
            {
                throw new ArgumentException("WrongActionForCtor");
            }
            if (index < 0)
            {
                throw new ArgumentException("IndexCannotBeNegative");
            }
            object[] newItems = new object[] { changedItem };
            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)
        {
            _NewStartingIndex = -1;
            _OldStartingIndex = -1;
            if (action != NotifyCollectionChangedAction.Replace)
            {
                throw new ArgumentException("WrongActionForCtor");
            }
            InitializeMoveOrReplace(action, new object[] { newItem }, new object[] { oldItem }, index, index);
        }
        private void InitializeAdd(NotifyCollectionChangedAction action, IList newItems, int newStartingIndex)
        {
            _Action = action;
            _NewItems = (newItems == null) ? null : ArrayList.ReadOnly(newItems);
            _NewStartingIndex = newStartingIndex;
        }
        private void InitializeAddOrRemove(NotifyCollectionChangedAction action, IList changedItems, int startingIndex)
        {
            if (action == NotifyCollectionChangedAction.Add)
            {
                InitializeAdd(action, changedItems, startingIndex);
            }
            else if (action == NotifyCollectionChangedAction.Remove)
            {
                InitializeRemove(action, changedItems, startingIndex);
            }
        }
        private void InitializeMoveOrReplace(NotifyCollectionChangedAction action, IList newItems, IList oldItems, int startingIndex, int oldStartingIndex)
        {
            InitializeAdd(action, newItems, startingIndex);
            InitializeRemove(action, oldItems, oldStartingIndex);
        }
        private void InitializeRemove(NotifyCollectionChangedAction action, IList oldItems, int oldStartingIndex)
        {
            _Action = action;
            _OldItems = (oldItems == null) ? null : ArrayList.ReadOnly(oldItems);
            _OldStartingIndex = oldStartingIndex;
        }
        /// 
        /// Gets the type of the collection change action.
        /// 
        public NotifyCollectionChangedAction Action
        {
            get
            {
                return _Action;
            }
        }
        /// 
        /// Gets list of newly added items.
        /// 
        public IList NewItems
        {
            get
            {
                return _NewItems;
            }
        }
        /// 
        /// Gets new starting index.
        /// 
        public int NewStartingIndex
        {
            get
            {
                return _NewStartingIndex;
            }
        }
        /// 
        /// Gets list of removed items.
        /// 
        public IList OldItems
        {
            get
            {
                return _OldItems;
            }
        }
        /// 
        /// Old starting index.
        /// 
        public int OldStartingIndex
        {
            get
            {
                return _OldStartingIndex;
            }
        }
    }
    #endregion
    public class CustomNamedCollection : CustomCollection where T : class, INamed
    {
        #region Indexer[name]
        /// 
        /// Returns item at index.
        /// 
        /// Name of item.
        /// Item or null.
        public T this[string name]
        {
            get
            {
                if (string.IsNullOrEmpty(name) == false)
                {
                    OnCollectionReadAccess();
                    foreach (T item in Items)
                    {
                        if (name.Equals(item.Name) == true)
                            return (item);
                    }
                }
                return (null);
            }
            set
            {
                if (Items.IsReadOnly)
                    throw new NotSupportedException("Collection is read-only");
                T item = this[name];
                if (item == null)
                    throw new ArgumentOutOfRangeException();
                int index = Items.IndexOf(item);
                if ((uint)index >= Items.Count)
                    throw new ArgumentOutOfRangeException();
                SetItem(index, value);
            }
        }
        #endregion
        #region GetUniqueName
        public string GetUniqueName(string rootText)
        {
            for (int i = 1; i < 500; i++)
            {
                string s = rootText + i;
                if (this[s] == null)
                    return (s);
            }
            return (rootText);
        }
        #endregion
    }
    #region INamed
    public interface INamed
    {
        string Name { get; set; }
    }
    #endregion
}