ObjectLinkItemDictionary.cs

150 lines | 4.963 kB Blame History Raw Download
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>();
        }

    }
}