/**
 * Main gC JavaScript library.
 *
 * @package gC
 * @subpackage gCjs
 */

if (typeof gCjs == "undefined" || !gCjs) {
    /**
     * The gCjs global namespace object.  If gCjs is already defined, the
     * existing gCjs object will not be overwritten so that defined
     * namespaces are preserved.
     * @class gCjs
     * @static
     */
    var gCjs = {};
}

/**
 * Returns the namespace specified and creates it if it doesn't exist
 * <pre>
 * gCjs.namespace("property.package");
 * gCjs.namespace("gCjs.property.package");
 * </pre>
 * Either of the above would create gCjs.property, then
 * gCjs.property.package
 *
 * Be careful when naming packages. Reserved words may work in some browsers
 * and not others. For instance, the following will fail in Safari:
 * <pre>
 * gCjs.namespace("really.long.nested.namespace");
 * </pre>
 * This fails because "long" is a future reserved word in ECMAScript
 *
 * @method namespace
 * @static
 * @param  {String*} arguments 1-n namespaces to create
 * @return {Object}  A reference to the last namespace object created
 */
gCjs.namespace = function() {
    var a=arguments, o=null, i, j, d;
    for (i=0; i<a.length; i=i+1) {
        d=a[i].split(".");
        o=gCjs;

        // gCjs is implied, so it is ignored if it is included
        for (j=(d[0] == "gCjs") ? 1 : 0; j<d.length; j=j+1) {
            o[d[j]]=o[d[j]] || {};
            o=o[d[j]];
        }
    }
    return o;
};


/**
 * Uses gCjs.widget.Logger to output a log message, if the widget is
 * available.
 *
 * @method log
 * @static
 * @param  {String}  msg  The message to log.
 * @param  {String}  cat  The log category for the message.  Default
 *                        categories are "info", "warn", "error", time".
 *                        Custom categories can be used as well. (opt)
 * @param  {String}  src  The source of the the message (opt)
 * @return {Boolean}      True if the log operation was successful.
 */
gCjs.log = function(msg, cat, src) {
    var l=gCjs.widget.Logger;
    if(l && l.log) {
        return l.log(msg, cat, src);
    } else {
        return false;
    }
};

/**
 * Registers a module with the gCjs object
 * @method register
 * @static
 * @param {String}   name    the name of the module (ecomm, media, etc)
 * @param {Function} mainClass a reference to class in the module.
 * @param {String}   constructor optional    the name of the constructor,
 *                                          if set, a new instance will be created
 */
gCjs.register = function(name, mainClass, constructor) {
    var mods = gCjs.env.modules;
    var insts = gCjs.env.instances;
    if (!mods[name]) {
        mods[name] = { versions: [], builds: [] };
    }
    var m = mods[name], ls = gCjs.env.listeners;
    m.name = name;
    m.mainClass = mainClass;
    // fire the module load listeners
    for (var i = 0; i < ls.length; i = i + 1) {
        ls[i](m);
    }

    // label the main class
    if (!mainClass) {
        gCjs.log("mainClass is undefined for module " + name, "warn");
    } else {
        if (typeof (mainClass) == 'function') {
            var instance = new mainClass();
            if (constructor) {
                instance[constructor]();
            }
            insts[name] = instance;
        }
    }
};

gCjs.getInstance = function(name) {
    var insts = gCjs.env.instances;
    return (insts[name]) ? insts[name]:false;
}

gCjs.isArray = function(v){
	return
		typeof(v) == 'object' &&
		v != null &&
		typeof(v.length) == 'number';
}

/**
 * Load a js file
 * @method loadModule
 * @static
 * @param {String}   name    the name of the file (ecomm, media, etc)
 * <pre>
 * gCjs.loadModule("module.package");
 * gCjs.loadModule("gCjs.module.package");
 * </pre>
 * Either of the above will load www/module/package.js if not loaded.
 */
gCjs.loadModule = function() {
    var a=arguments, f, aNamespace;
    for (i=0; i<a.length; i=i+1) {
        aNamespace = a[i].split(".");
        if (aNamespace[0] == "gCjs") {
            aNamespace.shift();
            f = "javascript/" + aNamespace.join("/") + ".js";
        } else {
        f = "javascript/" + aNamespace.join("/") + ".js";
        }
        // gCjs is implied, so it is ignored if it is included
        gCjs.log("trying to load " + f, "info");
        $.getScript(GCJS_JS_WEBROOT + "/" + f);
    }
}

/**
 * Fires the DOMReady event listeners the first time the document is
 * usable.
 * @method _ready
 * @static
 * @private
 */


/**
 * gCjs.env is used to keep track of what is known about the gCjs and
 * the browsing environment
 * @class gCjs.env
 * @static
 */
gCjs.env = gCjs.env || {

    /**
     * Keeps the version info for all gCjs modules that have reported themselves
     * @property modules
     * @type Object[]
     */
    modules: [],

    /**
     * Keeps instances created by gCjs.register
     * @property modules
     * @type Object[]
     */
    instances: {},


    /**
     * List of functions that should be executed every time a gCjs module
     * reports itself.
     * @property listeners
     * @type Function[]
     */
    listeners: []
};

/*
 * Initializes the global by creating the default namespaces and applying
 * any new configuration information that is detected.  This is the setup
 * for env.
 * @method init
 * @static
 * @private
 */
(function() {
    gCjs.namespace("util", "widget");
    if ("undefined" !== typeof gCjs_config) {
        var l=gCjs_config.listener,ls=gCjs.env.listeners,unique=true,i;
        if (l) {
            // if gCjs is loaded multiple times we need to check to see if
            // this is a new config object.  If it is, add the new component
            // load listener to the stack
            for (i=0;i<ls.length;i=i+1) {
                if (ls[i]==l) {
                    unique=false;
                    break;
                }
            }
            if (unique) {
                ls.push(l);
            }
        }
    }
})();

gCjs.register("gCjs", gCjs);