using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Tools.Collections.Concurrent.Extensions;
using Tools.Collections.Concurrent;
namespace Tools.Collections.Concurrent
{
/// <summary>
/// Thread safe key value link-item collection.
/// Besides LinkItem, it stores a collection of objects that refer to a key.
/// Base on LinkItem(ConcurrentDictionary).
/// Item remove if link count is 0.
/// </summary>
public class ObjectLinkItemDictionary<TKey, TData, TReferencingObject>
where TReferencingObject : class
{
#region
public IReadOnlyDictionary<TKey, IValueWrapper<LinkItem<TKey, ObjectLinkContainer<TData, TReferencingObject>>>> Storage { private set; get; }
private readonly LinkItemDictionary<TKey, ObjectLinkContainer<TData, TReferencingObject>> _Storage
= new LinkItemDictionary<TKey, ObjectLinkContainer<TData, TReferencingObject>>();
#endregion
#region
public ObjectLinkItemDictionary()
{
Storage = _Storage.Storage;
}
#endregion
#region
/// <summary>
/// Add link from referencingObject. Add or update Value
/// </summary>
public LinkItem<TKey, ObjectLinkContainer<TData, TReferencingObject>> AddLink(
TKey key,
TReferencingObject referencingObject,
Func<TKey, TData> addFactory,
Func<LinkItem<TKey, ObjectLinkContainer<TData, TReferencingObject>>, TData> updateFactory
)
{
return _Storage.AddLink
(
key,
(_key) =>
CreateBuilder()
.AddObject(referencingObject)
.UpdateData(addFactory != null ? addFactory(_key) : default(TData))
.Result(),
(LinkItem<TKey, ObjectLinkContainer<TData, TReferencingObject>> oldValue) =>
CreateBuilder(oldValue.Value)
.AddObject(referencingObject)
.UpdateData(updateFactory != null ? updateFactory(oldValue) : oldValue.Value.Data)
.Result()
);
}
/// <summary>
/// Add link from referencingObject. Add Value
/// </summary>
public LinkItem<TKey, ObjectLinkContainer<TData, TReferencingObject>> AddLink(
TKey key,
TReferencingObject referencingObject,
Func<TKey, TData> addFactory
)
{
return AddLink(key, referencingObject, addFactory, null);
}
/// <summary>
/// Add link from referencingObject. Update value if exsist
/// </summary>
public LinkItem<TKey, ObjectLinkContainer<TData, TReferencingObject>> AddLink(
TKey key,
TReferencingObject value,
Func<LinkItem<TKey, ObjectLinkContainer<TData, TReferencingObject>>, TData> updateFactory
)
{
return AddLink(key, value, null, updateFactory);
}
/// <summary>
/// Add link from referencingObject. No change value
/// </summary>
public LinkItem<TKey, ObjectLinkContainer<TData, TReferencingObject>> AddLink(
TKey key,
TReferencingObject value
)
{
return AddLink(key, value, null, null);
}
/// <summary>
/// Remove link from referencingObject. Update value
/// </summary>
public LinkItem<TKey, ObjectLinkContainer<TData, TReferencingObject>> RemoveLink(
TKey key,
TReferencingObject value,
Func<LinkItem<TKey, ObjectLinkContainer<TData, TReferencingObject>>, TData> updateFactory
)
{
return _Storage.RemoveLink(
key,
(LinkItem<TKey, ObjectLinkContainer<TData, TReferencingObject>> oldValue) =>
new ContainerBuilder<TData, TReferencingObject>(oldValue.Value)
.RemoveObject(value)
.UpdateData(updateFactory != null ? updateFactory(oldValue) : oldValue.Value.Data)
.Result()
);
}
/// <summary>
/// Remove link from referencingObject. No change value if not remove
/// </summary>
public LinkItem<TKey, ObjectLinkContainer<TData, TReferencingObject>> RemoveLink(
TKey key,
TReferencingObject value
)
{
return RemoveLink(key, value, null);
}
#endregion
private ContainerBuilder<TData, TReferencingObject> CreateBuilder(ObjectLinkContainer<TData, TReferencingObject> container = null)
{
return
container != null
? new ContainerBuilder<TData, TReferencingObject>(container)
: new ContainerBuilder<TData, TReferencingObject>();
}
}
}