using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Text;

namespace ObservableCollection.Ex
{
    public class IndexedObservableCollection<T, K> : INotifyPropertyChanged
    {
        private ObservableCollection<T> dataList = new ObservableCollection<T>();
        private Dictionary<K, Int32> indexedMap = new Dictionary<K, Int32>();
        private T selectedItem;

        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = this.PropertyChanged;
            if (handler != null)
            {
                var e = new PropertyChangedEventArgs(propertyName);
                handler(this, e);
            }
        }

        public ObservableCollection<T> DataList { get => dataList; set => dataList = value; }

        public T SelectedItem
        {
            get { return selectedItem; }
            set
            {
                if (value != null &&
                    !value.Equals(selectedItem))
                {
                    selectedItem = value;
                    this.OnPropertyChanged("SelectedItem");
                }
            }
        }

        public void SaveOrUpdate(T data, K key)
        {
            lock (this)
            {
                Int32 storedIndex;
                if (indexedMap.TryGetValue(key, out storedIndex))
                {
                    DataList[storedIndex] = data;
                }
                else
                {
                    DataList.Add(data);
                    indexedMap[key] = DataList.Count - 1;
                }
            }
        }

        public bool TryGetValue(K key, [MaybeNullWhen(false)] out T data)
        {
            lock (this)
            {
                Int32 storedIndex;
                if (indexedMap.TryGetValue(key, out storedIndex))
                {
                    data = DataList[storedIndex];
                    return true;
                }

                data = default(T);
                return false;
            }
        }


        public void Clear()
        {
            lock (this)
            {
                indexedMap.Clear();
                dataList.Clear();
            }
        }
    }
}