
using System.Collections.Generic;

namespace XGame.Framework
{
    public delegate void EventDelegate(int eventId, object args);

    public sealed partial class EventModule : IEventModule, System.IDisposable
    {
        Dictionary<int, HashSet<EventDelegate>> dic;


        public EventModule()
        {
            dic = new Dictionary<int, HashSet<EventDelegate>>();
        }


        public void AddListener(int eventId, EventDelegate handler)
        {
            Assert.IsNotNull(handler, $"EventModule.AddListener handler is null, eventId: {eventId}");

            if (!dic.TryGetValue(eventId, out var handlers))
            {
                handlers = new HashSet<EventDelegate>();
                dic[eventId] = handlers;
            }

            Assert.IsFalse(handlers.Contains(handler), $"EventModule.AddListener Handler Allready Exists!! {handler.Method.DeclaringType.FullName}::{handler.Method.Name}");

            handlers.Add(handler);
        }

        public void RemoveListener(int eventId, EventDelegate handler)
        {
            Assert.IsNotNull(handler, $"EventModule.RemoveListener handler is null, eventId: {eventId}");

            if (dic.TryGetValue(eventId, out var handlers))
            {
                Assert.IsTrue(handlers.Contains(handler), $"EventModule.RemoveListener Handler Doesn't Exists!! {handler.Method.DeclaringType.FullName}::{handler.Method.Name}");
                handlers.Remove(handler);

                if (handlers.Count <= 0)
                    dic.Remove(eventId);
            }
        }

        public void Notify(int eventId)
        {
            Notify(eventId, null);
        }

        public void Notify(int eventId, object args)
        {
            if (dic.TryGetValue(eventId, out var handlers))
            {
                foreach (var handler in handlers)
                {
                    try
                    {
                        handler?.Invoke(eventId, args);
                    }
                    catch (System.Exception e)
                    {
                        Log.Exception($"EventModule.Notify({eventId}) Error: \n" +
                                $"Occur: {handler.Method?.DeclaringType?.FullName + "::" + handler.Method?.Name},\n", e);
                    }
                }
            }
        }


        public void Dispose()
        {
            dic.Clear();
        }
    }
}
