using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;


public delegate void EnterFrameUpdate(float timeElapsed);


public class EnterFrameManager : MonoBehaviour
{
    private Dictionary<object, EnterFrameUpdate> enterFrameCallbacks = new Dictionary<object, EnterFrameUpdate>();
    private Dictionary<object, EnterFrameUpdate> addQueue = new Dictionary<object, EnterFrameUpdate>();
    private List<object> removeQueue = new List<object>();

    public Action<Exception> OnException = null;

    public void Add(object obj, EnterFrameUpdate func)
    {
        // If the item is marked for removal, cancel the removal.
        if (removeQueue.Contains(obj))
        {
            removeQueue.Remove(obj);

            // don't add to the queue if this item is already active
            if (enterFrameCallbacks.ContainsKey(obj)) return;
        }

        // Queue (if we aren't already adding this object...)
        if (!addQueue.ContainsKey(obj))
        {
            addQueue.Add(obj, func);
        }
    }

        
    public void Remove(object obj)
    {

        // If we haven't added this object yet, just remove it from the add queue
        if (addQueue.ContainsKey(obj))
        {
            addQueue.Remove(obj);
            return;
        }

        // Queue for removal
        if (!removeQueue.Contains(obj))
        {
            removeQueue.Add(obj);
        }
    }

    public int LastItemsUpdated = 0;
    public float LastTimeUpdated = 0;

    void Update()
    {
        float timeElapsed = Time.deltaTime;

        foreach (object obj in removeQueue)
        {
            if (enterFrameCallbacks.ContainsKey(obj))
            {
                enterFrameCallbacks.Remove(obj);
            }
        }
        removeQueue.Clear();

        foreach (KeyValuePair<object, EnterFrameUpdate> add in addQueue)
        {
            if (!enterFrameCallbacks.ContainsKey(add.Key))
            {
                enterFrameCallbacks.Add(add.Key, add.Value);
            }
        }
        addQueue.Clear();

        LastItemsUpdated = 0;
        foreach (KeyValuePair<object, EnterFrameUpdate> entry in enterFrameCallbacks)
        {
               
            if (OnException == null)
            {
                entry.Value(timeElapsed);
                LastItemsUpdated++;
            }
            else
            {
                try {
                    entry.Value(timeElapsed);
                    LastItemsUpdated++;
                }
                catch (Exception e)
                {
                    OnException(e);
                }
            }

        }

        LastTimeUpdated = timeElapsed;

    }

}