using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Linq;

namespace BS.Shared.Core
{
    public class ObservableSortCollection<T> : ObservableCollection<T>
    {
        private readonly List<NotifyCollectionChangedEventHandler> _ChangedHandler = new List<NotifyCollectionChangedEventHandler>();

        private readonly Comparison<T> _Comparer;

        public ObservableSortCollection()
        {
        }

        public ObservableSortCollection(IEnumerable<T> pList)
            : base(pList.ToList())
        {
        }

        public ObservableSortCollection(Comparison<T> pComparer)
            : this()
        {
            this._Comparer = pComparer;
            this.Sort();
        }

        public ObservableSortCollection(IEnumerable<T> pList, Comparison<T> pComparer)
            : this(pList)
        {
            this._Comparer = pComparer;
            this.Sort();
        }

        public override event NotifyCollectionChangedEventHandler CollectionChanged
        {
            add
            {
                this._ChangedHandler.Add(value);
                base.CollectionChanged += value;
            }

            remove
            {
                this._ChangedHandler.Remove(value);
                base.CollectionChanged -= value;
            }
        }

        public void Sort()
        {
            if (this._Comparer != null)
            {
                this.DisconnectHandler();
                List<T> lTemp = this.ToList();
                lTemp.Sort(this._Comparer);
                for (int i = 0; i < this.Count; i++)
                {
                    this[i] = lTemp[i];
                }

                this.ReconnectHandler();
                this.NotifyHandlerAfterSort();
            }
        }

        public void Sort(Comparison<T> pComparer)
        {
            this.DisconnectHandler();
            List<T> lTemp = this.ToList();
            lTemp.Sort(pComparer);
            for (int i = 0; i < this.Count; i++)
            {
                this[i] = lTemp[i];
            }

            this.ReconnectHandler();
            this.NotifyHandlerAfterSort();
        }

        private void DisconnectHandler()
        {
            foreach (var iHandler in this._ChangedHandler)
            {
                base.CollectionChanged -= iHandler;
            }
        }

        private void NotifyHandlerAfterSort()
        {
            foreach (var iHandler in this._ChangedHandler)
            {
                iHandler(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
            }
        }

        private void ReconnectHandler()
        {
            foreach (var iHandler in this._ChangedHandler)
            {
                base.CollectionChanged += iHandler;
            }
        }
    }
}