using System;
using System.Collections.Generic;

public static class SEventManager
{
    public enum EVENT
    {
        BEGIN = 0,

        UI_ACTIVE_ADD,
        UI_ACTIVE_DOWNLOAD_LINK,
        UI_ACTIVE_SEED_MISSION,
        UI_ACTIVE_PLAYER_INFO,
        UI_ACTIVE_PLAYER_ICON,
        UI_ACTIVE_LOGIN,
        UI_ACTIVE_REGISTER,
        UI_ACTIVE_FORGET_PASSWORD,

        LOGIC_ACTIVE,
        LOGIC_WAITING,
        LOGIC_STOPPED,
        LOGIC_DOWNLOAD_LINK_OK,
        LOGIC_SEED_MISSION_OK,
        LOGIC_LOGIN_OK,
        LOGIC_REGISTER_OK,
        LOGIC_FORGET_PASSWORD_OK,

        END,
    }

    public delegate void EventCallbackDelegate(EVENT ev, Object[] args);

    private static Dictionary<EVENT, EventCallbackDelegate> _dictEvents;
    private static List<EventCallbackDelegate> _lstGlobalEventCallback;
    private static List<Action> _lstActions;
    static SEventManager()
    {
        _lstGlobalEventCallback = new List<EventCallbackDelegate>() { DefaultEventCallback };
        _lstActions = new List<Action>();
        _dictEvents = new Dictionary<EVENT, EventCallbackDelegate>();
        for (EVENT ev = EVENT.BEGIN + 1; ev < EVENT.END; ++ev)
        {
            _dictEvents[ev] = new EventCallbackDelegate(DefaultEventCallback);
        }
    }

    public static void DestroyAllSceneEvent()
    {
        for (EVENT ev = EVENT.BEGIN + 1; ev < EVENT.END; ++ev)
        {
            foreach (Delegate i in _dictEvents[ev].GetInvocationList())
            {
                if (!_lstGlobalEventCallback.Contains(i as EventCallbackDelegate))
                {
                    _dictEvents[ev] -= (i as EventCallbackDelegate);
                }
            }
        }
    }

    private static void DefaultEventCallback(EVENT ev, Object[] args)
    {
    }

    public static void RegisterGlobalEvent(EVENT ev, EventCallbackDelegate cb)
    {
        _lstActions.Add(() =>
        {
            _lstGlobalEventCallback.Add(cb);
            _dictEvents[ev] += cb;
        });

        TryProcessActions();
    }

    public static void RegisterEvent(EVENT ev, EventCallbackDelegate cb)
    {
        _lstActions.Add(() =>
        {
            _dictEvents[ev] += cb;
        });

        TryProcessActions();
    }

    public static void UnregisterEvent(EVENT ev, EventCallbackDelegate cb)
    {
        _lstActions.Add(() =>
        {
            _dictEvents[ev] -= cb;
            _lstGlobalEventCallback.Remove(cb);
        });
        TryProcessActions();
    }

    private static void TryProcessActions()
    {
        if (_lstActions.Count > 1)
        {
            return;
        }

        while (_lstActions.Count > 0)
        {
            Action action = _lstActions[0];
            try
            {
                action();
            }
            catch (Exception e)
            {
                UnityEngine.Debug.LogError(String.Format("ProcessAction Error:" + e.StackTrace));
            }
            finally
            {
                UnityEngine.Debug.Assert(_lstActions[0] == action, "Action List Changed during Processing");
                _lstActions.RemoveAt(0);
            }
        }
    }

    private static void FireEventInternal(EVENT ev, Object[] args)
    {
        //UnityEngine.Debug.Log("FireEvent:" + ev.ToString());
        foreach (EventCallbackDelegate cb in _dictEvents[ev].GetInvocationList())
        {
            try
            {
                cb(ev, args);
            }
            catch (Exception e)
            {
                UnityEngine.Debug.LogError(String.Format("ProcessEvent {0} Message:{1} Error:{2}", ev.ToString(), e.Message, e.StackTrace));
            }
        }
    }

    public static void FireEvent(EVENT ev, params object[] args)
    {
        //UnityEngine.Debug.Log("EventManager FireEvent -> Event.Name: " + ev.ToString() + " Length: " + args.Length.ToString());

        _lstActions.Add(() =>
        {
            FireEventInternal(ev, args);
        });

        TryProcessActions();
    }
}