using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace BoFilTest.Utils
{
    public class EventBus
    {
        private readonly Dictionary<Type, object> lookup;

        public EventBus()
        {
            this.lookup = new Dictionary<Type, object>();
        }

        public Action Subscribe<T>(Action<T> handler)
        {
            var set = GetOrCreateSubscribersFor<T>();
            set.Add(handler);
            return () => set.Remove(handler);
        }

        public void Unsubscribe(Action handler)
        {
            handler();
        }

        public void Publish<T>(T news)
        {
            object untypedList;
            if (!this.lookup.TryGetValue(typeof(T), out untypedList))
                return;

            var list = (HashSet<Action<T>>)untypedList;
            foreach (var action in list)
            {
                action.Invoke(news);
            }
        }

        private HashSet<Action<T>> GetOrCreateSubscribersFor<T>()
        {
            Type key = typeof(T);

            if (!this.lookup.ContainsKey(key))
            {
                this.lookup.Add(key, new HashSet<Action<T>>());
            }

            return (HashSet<Action<T>>)this.lookup[key];
        }
    }
    public class SubscriberList
    {
        private readonly List<Action> subscribers;
        private readonly EventBus bus;

        public SubscriberList(EventBus bus)
        {
            this.subscribers = new List<Action>();
            this.bus = bus;
        }

        public void Subscribe<T>(Action<T> handler)
        {
            this.subscribers.Add(this.bus.Subscribe<T>(handler));
        }

        public void UnsubscribeAll()
        {
            foreach (var subscriber in subscribers)
            {
                this.bus.Unsubscribe(subscriber);
            }
            this.subscribers.Clear();
        }

        public EventBus EventBus()
        {
            return bus;
        }
    }
}
