﻿/** Common javascript for TheFarm's JS Library
*   Common utilities and main namespace
*   @author: James Diacono
*   @date: 29th of April, 2010
*/

/** Namespace: TheFarm
*/
if (typeof TheFarm === 'undefined') {
    var TheFarm = {};
}

TheFarm = (function () {
    var eventManager = (function () {
        var events = {};

        var getEvent = function (id) {
            ///<summary>Gets the event for the given id</summary>
            if (!events[id]) {
                events[id] = [];
            }
            return events[id];
        };

        return {
            bind: function (name, fn, eventHandlerId) {
                ///<summary>Adds a particular event handler to the specified event</summary>
                ///<param name="name" type="String" optional="false" mayBeNull="false">Name of the event to bind to</param>
                ///<param name="fn" type="Function" optional="false" mayBeNull="false">Function to invoke when the event is triggered</param>
                var e = getEvent(name);
                if (!eventHandlerId) {
                    eventHandlerId = name + '-' + e.length + 1;
                }
                fn.id = eventHandlerId;
                e.push(fn);
            },
            trigger: function (name, source, args) {
                ///<summary>Raises a named event on the given source with the supplied arguments</summary>
                ///<param name="name" type="String" optional="false" mayBeNull="false">Name of the event to raise</param>
                ///<param name="source" type="Object" optional="false" mayBeNull="true">Object to bind the 'this' context to</param>
                ///<param name="args" type="Object" optional="true" mayBeNull="true">Arguments to pass to the event</param>
                var evt = getEvent(name);
                if (!evt || (evt.length === 0)) return null;
                evt = evt.length === 1 ? [evt[0]] : Array.apply(null, evt);
                for (var i = 0, l = evt.length; i < l; i++) {
                    if (!args) args = [];
                    if (args.constructor !== Array) args = [args];
                    evt[i].apply(source, args);
                }
            },
            unbind: function (name, eventHandlerId) {
                ///<summary>Unbinds a handler from a named event.</summary>
                ///<param name="name" type="String" optional="false" mayBeNull="false">Name of the event to unbind from</param>
                ///<param name="eventHandlerId" type="String" optional="true" mayBeNull="true">Unique name of the event handler to unbind, if not supplied all event handlers are unbound</param>
                var evt = getEvent(name);
                if (evt && evt.length > 0) {
                    if (eventHandlerId) {
                        for (var i = 0, l = evt.length; i < l; i++) {
                            var e = evt[i];
                            if (e.id === eventHandlerId) {
                                evt.pop(e);
                                break;
                            }
                        }
                    } else {
                        evt = {};
                    }
                }
            }
        };

    })();

    var registerNamespace = function (namespace, global) {
        ///<summary>Registers a namespace as an object.</summary>
        ///<param name="namespace" type="String" optional="false" mayBeNull="false">
        ///    Namespace as a string.  For instance, "TheFarm.web.stuff" would define the object
        ///    window.TheFarm.web.stuff = {}.
        ///</param>

        var go;
        go = function (object, properties) {
            if (properties.length) {
                var propertyToDefine = properties.shift();

                if (typeof object[propertyToDefine] === 'undefined') {
                    object[propertyToDefine] = {};
                }

                // Tell Visual Studio this is a namespace
                object[propertyToDefine].__namespace = true;

                go(object[propertyToDefine], properties);
            }
        };
        go(global || (function () { return this; })(), namespace.split('.'));
    };

    return {
        __namespace: true,
        eventManager: eventManager,
        registerNamespace: registerNamespace
    };
})();
