#region CPL License
/*
Nuclex Framework
Copyright (C) 2002-2010 Nuclex Development Labs
This library is free software; you can redistribute it and/or
modify it under the terms of the IBM Common Public License as
published by the IBM Corporation; either version 1.0 of the
License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
IBM Common Public License for more details.
You should have received a copy of the IBM Common Public
License along with this library
*/
#endregion
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
#if !NO_SPECIALIZED_COLLECTIONS
using System.Collections.Specialized;
#endif
namespace Nuclex.Support.Collections {
  /// Collection which fires events when items are added or removed
  /// Type of items the collection manages
  public class ObservableCollection :
    Collection,
#if !NO_SPECIALIZED_COLLECTIONS
    INotifyCollectionChanged,
#endif
    IObservableCollection {
    /// Raised when an item has been added to the collection
    public event EventHandler> ItemAdded;
    /// Raised when an item is removed from the collection
    public event EventHandler> ItemRemoved;
    /// Raised when the collection is about to be cleared
    /// 
    ///   This could be covered by calling ItemRemoved for each item currently
    ///   contained in the collection, but it is often simpler and more efficient
    ///   to process the clearing of the entire collection as a special operation.
    /// 
    public event EventHandler Clearing;
    /// Raised when the collection has been cleared
    public event EventHandler Cleared;
#if !NO_SPECIALIZED_COLLECTIONS
    /// Called when the collection has changed
    public event NotifyCollectionChangedEventHandler CollectionChanged;
#endif
    /// 
    ///   Initializes a new instance of the ObservableCollection class that is empty.
    /// 
    public ObservableCollection() : base() { }
    /// 
    ///   Initializes a new instance of the ObservableCollection class as a wrapper
    ///   for the specified list.
    /// 
    /// The list that is wrapped by the new collection.
    /// List is null
    public ObservableCollection(IList list) : base(list) { }
    /// Removes all elements from the Collection
    protected override void ClearItems() {
      OnClearing();
      base.ClearItems();
      OnCleared();
#if !NO_SPECIALIZED_COLLECTIONS
      OnCollectionChanged(NotifyCollectionChangedAction.Reset, default(TItem), -1);
#endif
    }
#if !NO_SPECIALIZED_COLLECTIONS
    /// Fires the CollectionChanged event
    /// Type of change that has occured
    /// The item that has been added, removed or replaced
    /// Index of the changed item
    protected virtual void OnCollectionChanged(
      NotifyCollectionChangedAction action, TItem item, int index
    ) {
      if (CollectionChanged != null) {
        CollectionChanged(
          this, new NotifyCollectionChangedEventArgs(action, item, index)
         );
      }
    }
#endif
    /// 
    ///   Inserts an element into the ObservableCollection at the specified index
    /// 
    /// 
    ///   The object to insert. The value can be null for reference types.
    /// 
    /// The zero-based index at which item should be inserted
    protected override void InsertItem(int index, TItem item) {
      base.InsertItem(index, item);
      OnAdded(item);
#if !NO_SPECIALIZED_COLLECTIONS
      OnCollectionChanged(NotifyCollectionChangedAction.Add, item, index);
#endif
    }
    /// 
    ///   Removes the element at the specified index of the ObservableCollection
    /// 
    /// The zero-based index of the element to remove
    protected override void RemoveItem(int index) {
      TItem item = base[index];
      base.RemoveItem(index);
      OnRemoved(item);
#if !NO_SPECIALIZED_COLLECTIONS
      OnCollectionChanged(NotifyCollectionChangedAction.Remove, item, index);
#endif
    }
    /// Replaces the element at the specified index
    /// 
    ///   The new value for the element at the specified index. The value can be null
    ///   for reference types
    /// 
    /// The zero-based index of the element to replace
    protected override void SetItem(int index, TItem item) {
      TItem oldItem = base[index];
      base.SetItem(index, item);
      OnRemoved(oldItem);
      OnAdded(item);
#if !NO_SPECIALIZED_COLLECTIONS
      OnCollectionChanged(NotifyCollectionChangedAction.Replace, item, index);
#endif
    }
    /// Fires the 'ItemAdded' event
    /// Item that has been added to the collection
    protected virtual void OnAdded(TItem item) {
      if (ItemAdded != null)
        ItemAdded(this, new ItemEventArgs(item));
    }
    /// Fires the 'ItemRemoved' event
    /// Item that has been removed from the collection
    protected virtual void OnRemoved(TItem item) {
      if (ItemRemoved != null)
        ItemRemoved(this, new ItemEventArgs(item));
    }
    /// Fires the 'Clearing' event
    protected virtual void OnClearing() {
      if (Clearing != null)
        Clearing(this, EventArgs.Empty);
    }
    /// Fires the 'Cleared' event
    protected virtual void OnCleared() {
      if (Cleared != null)
        Cleared(this, EventArgs.Empty);
    }
  }
} // namespace Nuclex.Support.Collections