using System;
using System.Collections;
using System.Collections.Generic;
namespace Unity.VisualScripting
{
public class MergedCollection<T> : IMergedCollection<T>
{
public MergedCollection()
{
collections = new Dictionary<Type, ICollection<T>>();
}
private readonly Dictionary<Type, ICollection<T>> collections;
public int Count
{
get
{
int count = 0;
foreach (var collection in collections.Values)
{
count += collection.Count;
}
return count;
}
}
public bool IsReadOnly => false;
public void Include<TI>(ICollection<TI> collection) where TI : T
{
collections.Add(typeof(TI), new VariantCollection<T, TI>(collection));
}
public bool Includes<TI>() where TI : T
{
return Includes(typeof(TI));
}
public bool Includes(Type implementationType)
{
return GetCollectionForType(implementationType, false) != null;
}
public ICollection<TI> ForType<TI>() where TI : T
{
return ((VariantCollection<T, TI>)GetCollectionForType(typeof(TI))).implementation;
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public IEnumerator<T> GetEnumerator()
{
foreach (var collection in collections.Values)
{
foreach (var item in collection)
{
yield return item;
}
}
}
private ICollection<T> GetCollectionForItem(T item)
{
Ensure.That(nameof(item)).IsNotNull(item);
return GetCollectionForType(item.GetType());
}
private ICollection<T> GetCollectionForType(Type type, bool throwOnFail = true)
{
if (collections.ContainsKey(type))
{
return collections[type];
}
foreach (var collectionByType in collections)
{
if (collectionByType.Key.IsAssignableFrom(type))
{
return collectionByType.Value;
}
}
if (throwOnFail)
{
throw new InvalidOperationException($"No sub-collection available for type '{type}'.");
}
else
{
return null;
}
}
public bool Contains(T item)
{
return GetCollectionForItem(item).Contains(item);
}
public virtual void Add(T item)
{
GetCollectionForItem(item).Add(item);
}
public virtual void Clear()
{
foreach (var collection in collections.Values)
{
collection.Clear();
}
}
public virtual bool Remove(T item)
{
return GetCollectionForItem(item).Remove(item);
}
public void CopyTo(T[] array, int arrayIndex)
{
if (array == null)
{
throw new ArgumentNullException(nameof(array));
}
if (arrayIndex < 0)
{
throw new ArgumentOutOfRangeException(nameof(arrayIndex));
}
if (array.Length - arrayIndex < Count)
{
throw new ArgumentException();
}
var i = 0;
foreach (var collection in collections.Values)
{
collection.CopyTo(array, arrayIndex + i);
i += collection.Count;
}
}
}
}