using BPASmartClient.Helper;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;

/* ***********************************************
 * subject  事件总线，总线入口，后续按类型分发
 * author   张原川
 * date     2019/6/3 15:49:03 
 * ***********************************************/

namespace BPASmartClient.EventBus
{
    /// <summary>
    /// 事件总线
    /// </summary>
    public class EventBus : Singleton<EventBus>
    {
        /// <summary>
        /// 事件处理委托
        /// </summary>
        /// <param name="args"></param>
        public delegate void EventCallBackHandle(params object[] args);
        /// <summary>
        /// 事件处理委托
        /// </summary>
        /// <param name="event"></param>
        /// <param name="callBack"></param>
        public delegate void EventHandle(IEvent @event, EventCallBackHandle callBack = null);
        /// <summary>
        /// 事件订阅者集合
        /// </summary>
        private ConcurrentDictionary<int, ConcurrentDictionary<Type, List<EventHandle>>> _eventHandls = new ConcurrentDictionary<int, ConcurrentDictionary<Type, List<EventHandle>>>();


        /// <summary>
        /// 事件订阅
        /// </summary>
        public void Subscribe<TEvent>(int id,EventHandle handle)
        {
            if (!_eventHandls.ContainsKey(id))
                _eventHandls.TryAdd(id, new ConcurrentDictionary<Type, List<EventHandle>>());
            if (!_eventHandls[id].ContainsKey(typeof(TEvent)))
                _eventHandls[id].TryAdd(typeof(TEvent), new List<EventHandle>());
            lock (_eventHandls)
                _eventHandls[id][typeof(TEvent)].Add(handle);
        }

        /// <summary>
        /// 事件退订
        /// </summary>
        public void UnSubscribe<TEvent>(int id,EventHandle handle)
        {
            if (_eventHandls.ContainsKey(id))
            {
                if (_eventHandls[id].ContainsKey(typeof(TEvent)))
                {
                    if (_eventHandls[id][typeof(TEvent)].Contains(handle))
                    {
                        lock (_eventHandls)
                            _eventHandls[id][typeof(TEvent)].Remove(handle);
                    }
                }
            }
        }


        /// <summary>
        /// 事件发布，不带返回
        /// </summary>
        public void Publish<TEvent>(TEvent @event) where TEvent : IEvent
        {
            if (_eventHandls.ContainsKey(@event.DeviceId))
            {
                if (_eventHandls[@event.DeviceId].ContainsKey(typeof(TEvent)))
                {
                    for (int i = _eventHandls[@event.DeviceId][typeof(TEvent)].Count - 1; i >= 0; i--)
                        _eventHandls[@event.DeviceId][typeof(TEvent)][i](@event);

                    //_eventHandls[typeof(TEvent)].ForEach(p =>
                    //{
                    //    p(@event);
                    //});
                }
            }
        }

        /// <summary>
        /// 事件发布，带返回
        /// </summary>
        public void Publish<TEvent>(TEvent @event, EventCallBackHandle eventCallBack) where TEvent : IEvent
        {
            List<object> result = new List<object>();
            if (_eventHandls.ContainsKey(@event.DeviceId))
            {
                if (_eventHandls[@event.DeviceId].ContainsKey(typeof(TEvent)))
                {
                    //_eventHandls[typeof(TEvent)].ForEach(p =>
                    //{
                    //    p(@event, delegate (object[] args)
                    //    {
                    //        result.AddRange(args);
                    //    });
                    //});

                    for (int i = _eventHandls[@event.DeviceId][typeof(TEvent)].Count - 1; i >= 0; i--)
                    {
                        _eventHandls[@event.DeviceId][typeof(TEvent)][i](@event, delegate (object[] args)
                        {
                            result.AddRange(args);
                        });
                    }

                }
            }
            eventCallBack.Invoke(result.ToArray());
        }

        /// <summary>
        /// 事件总线释放
        /// </summary>
        public void Dispose()
        {
            _eventHandls.Clear();
        }
    }

}
