using System;
using System.Windows.Data;
using System.ComponentModel;
using System.Collections;
using System.Collections.ObjectModel;
using System.Collections.Specialized;

namespace InvExplorer
{
    /// <summary>
    /// Observable collection that exposes a View property and fires an
    /// ItemPropertyChanged event when items in the collection change.
    /// </summary>
    /// <remarks>
    /// Based on this article:
    /// http://stackoverflow.com/questions/269073/observablecollection-that-also-monitors-changes-on-the-elements-in-collection
    /// </remarks>
    public class ListView<T> : ObservableCollection<T>
    {
        CollectionViewSource _cvs;

        /// <summary>
        /// Gets an ICollectionView for this list.
        /// </summary>
        public ICollectionView View
        {
            get
            {
                if (_cvs == null)
                {
                    _cvs = new CollectionViewSource();
                    _cvs.Source = this;
                }
                return _cvs.View;
            }
        }
        /// <summary>
        /// Update IPropertyChanged notifications when items are added/removed.
        /// </summary>
        protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
        {
            Unsubscribe(e.OldItems);
            Subscribe(e.NewItems);
            base.OnCollectionChanged(e);
        }
        /// <summary>
        /// Update IPropertyChanged notifications when items are added/removed.
        /// </summary>
        protected override void ClearItems()
        {
            Unsubscribe(this);
            base.ClearItems();
        }
        /// <summary>
        /// Event that fires when a property changes in a contained item.
        /// </summary>
        public event EventHandler<PropertyChangedEventArgs> ItemPropertyChanged;
        /// <summary>
        /// Raises the <see cref="ItemPropertyChanged"/> event.
        /// </summary>
        /// <param name="item">Item that changed.</param>
        /// <param name="e"><see cref="PropertyChangedEventArgs"/> that contains the event data.</param>
        protected virtual void OnItemPropertyChanged(object item, PropertyChangedEventArgs e)
        {
            if (ItemPropertyChanged != null)
            {
                ItemPropertyChanged(item, e);
            }
        }

        // hook up notifications for items being added
        void Subscribe(IList list)
        {
            if (list != null)
            {
                foreach (var e in list)
                {
                    var npc = e as INotifyPropertyChanged;
                    if (npc != null)
                    {
                        npc.PropertyChanged += OnItemPropertyChanged;
                    }
                }
            }
        }

        // remove notifications for items being removed
        void Unsubscribe(IList list)
        {
            if (list != null)
            {
                foreach (var e in list)
                {
                    var npc = e as INotifyPropertyChanged;
                    if (npc != null)
                    {
                        npc.PropertyChanged -= OnItemPropertyChanged;
                    }
                }
            }
        }
    }
}
