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

namespace BS.Shared.Core
{
	public class ObservableDictionary<T, U> : IDictionary<T, U>, INotifyCollectionChanged
	{
		private readonly Dictionary<T, U> _dictionary = new Dictionary<T, U>();

		public IEnumerator<KeyValuePair<T, U>> GetEnumerator()
		{
			return _dictionary.GetEnumerator();
		}

		IEnumerator IEnumerable.GetEnumerator()
		{
			return GetEnumerator();
		}

		public ObservableDictionary(Dictionary<T, U> pDictionary)
		{
			_dictionary = pDictionary;
		}

		public void Add(KeyValuePair<T, U> item)
		{
			_dictionary.Add(item.Key, item.Value);
			OnNotifyCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item));
		}

		public void Clear()
		{
			_dictionary.Clear();
			OnNotifyCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
		}

		public bool Contains(KeyValuePair<T, U> item)
		{
			return _dictionary.Contains(item);
		}

		public void CopyTo(KeyValuePair<T, U>[] array, int arrayIndex)
		{
			var arr = _dictionary.ToArray();
			var j = 0;
			for (var i = arrayIndex; i < arr.Length; i++)
			{
				array[j] = arr[i];
				j++;
			}
		}

		public bool Remove(KeyValuePair<T, U> item)
		{
			var result = _dictionary.Remove(item.Key);
			OnNotifyCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
			return result;
		}

		public int Count { get { return _dictionary.Count; } }
		public bool IsReadOnly { get { return false; } }
		public bool ContainsKey(T key)
		{
			return _dictionary.ContainsKey(key);
		}

		public void Add(T key, U value)
		{
			_dictionary.Add(key, value);
			OnNotifyCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, new KeyValuePair<T, U>(key, value)));
		}

		public bool Remove(T key)
		{
			var result = _dictionary.Remove(key);
			OnNotifyCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
			return result;
		}

		public bool TryGetValue(T key, out U value)
		{
			return _dictionary.TryGetValue(key, out value);
		}

		public U this[T key]
		{
			get { return _dictionary[key]; }
			set { _dictionary[key] = value; }
		}

		public ICollection<T> Keys { get { return _dictionary.Keys; } }
		public ICollection<U> Values { get { return _dictionary.Values; } }
		public event NotifyCollectionChangedEventHandler CollectionChanged;

		private void OnNotifyCollectionChanged(NotifyCollectionChangedEventArgs args)
		{
			if (CollectionChanged != null)
				CollectionChanged(this, args);
		}
	}
}
