using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using Decal.Adapter.Support;

namespace Decal.Adapter;

public class DisposableObjectDictionary<K, T> : DisposableByRefObject, IDictionary<K, T>, ICollection<KeyValuePair<K, T>>, IEnumerable<KeyValuePair<K, T>>, IEnumerable where T : DisposableByRefObject
{
	private Dictionary<K, T> items = new Dictionary<K, T>();

	private PropertyInfo keyProperty;

	public ICollection<K> Keys => items.Keys;

	public ICollection<T> Values => items.Values;

	public T this[K key]
	{
		get
		{
			return items[key];
		}
		set
		{
			items[key] = value;
		}
	}

	public int Count => ((ICollection<KeyValuePair<K, T>>)items).Count;

	public bool IsReadOnly => ((ICollection<KeyValuePair<K, T>>)items).IsReadOnly;

	public DisposableObjectDictionary(string keyPropertyName)
	{
		keyProperty = typeof(T).GetProperty(keyPropertyName, BindingFlags.Instance | BindingFlags.Public);
	}

	protected override void Dispose(bool userCalled)
	{
		if (userCalled)
		{
			Clear();
		}
		base.Dispose(userCalled);
	}

	private void value_Disposing(object sender, EventArgs e)
	{
		K key = (K)keyProperty.GetValue(sender, null);
		((T)sender).Disposing -= value_Disposing;
		items.Remove(key);
	}

	public void Add(K key, T value)
	{
		items.Add(key, value);
		value.Disposing += value_Disposing;
	}

	public bool ContainsKey(K key)
	{
		return items.ContainsKey(key);
	}

	public bool Remove(K key)
	{
		return items.Remove(key);
	}

	public bool TryGetValue(K key, out T value)
	{
		return items.TryGetValue(key, out value);
	}

	public void Add(KeyValuePair<K, T> item)
	{
		items.Add(item.Key, item.Value);
	}

	public void Clear()
	{
		foreach (T value in items.Values)
		{
			try
			{
				value.Disposing -= value_Disposing;
				value.Dispose();
			}
			catch (Exception ex)
			{
				Util.WriteLine("GDW_Clear: Exception: {0}", ex.Message);
			}
		}
		items.Clear();
	}

	public bool Contains(KeyValuePair<K, T> item)
	{
		return ((ICollection<KeyValuePair<K, T>>)items).Contains(item);
	}

	public void CopyTo(KeyValuePair<K, T>[] array, int arrayIndex)
	{
		((ICollection<KeyValuePair<K, T>>)items).CopyTo(array, arrayIndex);
	}

	public bool Remove(KeyValuePair<K, T> item)
	{
		return ((ICollection<KeyValuePair<K, T>>)items).Remove(item);
	}

	public IEnumerator<KeyValuePair<K, T>> GetEnumerator()
	{
		return ((IEnumerable<KeyValuePair<K, T>>)items).GetEnumerator();
	}

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