/// <summary>
    /// Gets a list of objects corresponding to the relevancy of the request. Is async with callback in most cases.
    /// </summary>
    /// <typeparam name="T">The type of objects to list</typeparam>
    /// <param name="list">The list to fetch</param>
    /// <param name="callback">A callback to handle the requested data. Can be null to just queue update from server or heat up data from disk cache.</param>
    public static void List <T>(string list, Action <IEnumerable <T> > callback) where T : NetworkDataObject, new()
    {
        string eventName = typeof(T).Name + ".list";
        int    hash      = eventName.GetHashCode();

        if (CommunicationsApi.IsAvailable)
        {
            // fetch array with ids, then Get each object (allows us to fetch from local cache instead of sending buttloads of data over net by default)
            CommunicationsApi.Socket.Emit(eventName, list, "", o =>
            {
                CommunicationsApi.RunOnMainThread(() =>
                {
                    List <T> returns = new List <T>();
                    var got          = (o as JsonEncodedEventMessage).GetFirstArgAs <string[]>();
                    int i            = got.Length;
                    foreach (var id in got)
                    {
                        Get <T>(id, obj =>
                        {
                            returns.Add(obj);
                            i--;
                            if (i == 0)
                            {
                                if (callback != null)
                                {
                                    callback(returns);
                                }
                            }
                        });
                    }
                });
            });
        }
        else
        {
            var cache = OfflineCache.Fetch <T>(hash);
            if (cache != null)
            {
                List <T> returns = new List <T>();
                var      got     = (cache as string[]);
                int      i       = got.Length;
                foreach (var id in got)
                {
                    Get <T>(id, obj =>
                    {
                        returns.Add(obj);
                        i--;
                        if (i == 0)
                        {
                            if (callback != null)
                            {
                                callback(returns);
                            }
                        }
                    });
                }
            }
            else
            {
                if (callback != null)
                {
                    callback(new T[0]);
                }
            }
        }
    }
    /// <summary>
    /// Retreives an object from a datasource, depending on the availability.
    /// </summary>
    /// <typeparam name="T">Type of object to retreive, must of type NetworkDataObject</typeparam>
    /// <param name="id">The Id for the object to retreive</param>
    /// <param name="callback">A callback to handle the retreived data. Can be null to just queue update from server or heat up data from disk cache.</param>
    public static void Get <T>(string id, Action <T> callback) where T : NetworkDataObject, new()
    {
        // we define event as "get Type", needs to be mapped on server as well
        string eventName = typeof(T).Name + ".get";
        // get unique-ish hash key for object
        int hash = GetHashCode(typeof(T), id);
        // if object was last modified less than a minute ago, return instantly and queue an update
        bool fast = false;

        if (ObjectTracker.ContainsKey(hash) && ObjectTracker[hash].LastModified > (DateTime.UtcNow - TimeSpan.FromMinutes(1)))
        {
            if (callback != null)
            {
                callback(ObjectTracker[hash] as T);
            }
            fast = true;
        }
        if (CommunicationsApi.IsAvailable)
        {
            // Queue update from server
            CommunicationsApi.Socket.Emit(eventName, id, "", o =>
            {
                CommunicationsApi.RunOnMainThread(() =>
                {
                    // New object? create empty instance and merge data to it
                    if (!ObjectTracker.ContainsKey(hash))
                    {
                        ObjectTracker[hash] = new T();
                    }
                    ObjectTracker[hash].Merge((o as JsonEncodedEventMessage).GetFirstArgAs <T>());
                    // Update Offline Cache, is done async so it doesn't block
                    OfflineCache.QueueStore(hash, ObjectTracker[hash]);
                    if (!fast && callback != null)
                    {
                        callback(ObjectTracker[hash] as T);
                    }
                });
            });
        }
        else
        {
            if (fast) // fast cache but API offline? not our problem for now
            {
                return;
            }
            // Got an object tracked but older than a minute? lets just use it
            if (ObjectTracker.ContainsKey(hash))
            {
                if (callback != null)
                {
                    callback(ObjectTracker[hash] as T);
                }
                return;
            }
            // Attempt to fetch sync from Offline Cache
            var cache = OfflineCache.Fetch <T>(hash);
            if (cache != null)
            {
                ObjectTracker[hash] = cache;
                if (callback != null)
                {
                    callback(cache);
                }
                return;
            }
            else
            {
                if (callback != null)
                {
                    callback(new T()); // returns empty object that is considered unavailable
                }
            }
        }
    }