/*!
 *
 * Copyright 2011, Davy De Pauw, Marlon bvba
 *
 */
 
(function(global) {
    
    var mjs = {};

    // Logging is enabled by default. This is the logging shown to the
    // developer and not at all noisy.
    mjs._logging = true;
                
    /**
     * Copies things from source into target.
     *
     * @access public
     * @param target    {Object}  the target object where things will be copied
     *                            into
     * @param source    {Object}  the source object where things will be copied
     *                            from
     * @param overwrite {Boolean} indicate if existing items should be
     *                            overwritten
     * @param tranform  {function} [Optional], transformation function for
     *        each item
     */
     
    mjs.copy = function(target, source, overwrite, transform) {
        
        // Iterate each key
        for(var key in source) {
            
            // If key doesn't exist or if it may be overwritten
            if (overwrite || typeof target[key] === 'undefined') {
                
                // Copy source key to target
                target[key] = transform ? transform(source[key]) : source[key];
            }
        }
        
        return target;
        
    };
    
    /**
     * Copy stuff from one object to the specified namespace that
     * is mjs.<target>.
     * If the namespace target doesn't exist, it will be created automatically.
     *
     * @access public
     * @param target    {Object|String}  the target object to copy into
     * @param source    {Object}         the source object to copy from
     * @param overwrite {Boolean}        indicate if we should overwrite
     * @return {Object} the *same* target object back
     *
     * @author Davy De Pauw
     */
    
    mjs.extend = function(target, source, overwrite) {
    
        // a string means a dot separated object that gets appended to, or created
        return mjs.copy(
            typeof target == 'string' ? mjs.namespace(target, true) : target,
            source,
            overwrite
        );
            
    };
    
    
    /**
     * Create a namespaced object or check if an namespace exists
     *
     * @access public
     * @param name {String} full qualified name ('Util.foo', etc.)
     * @param create {Boolean} indicate whether a namespace has to be checked or created
     * @param value {Object} value to set. Default value is {}. [Optional]
     * @return {Object} The created object
     *
     * @since 0.0.2
     * @author Davy De Pauw
     */
     
    mjs.namespace = function(ns, create, value) {
    
        var 
            // The global namespace
            node = global.mjs,                
            
            // Split requestes namespace string
            parts = ns.split('.'),
            
            // Count
            c = parts.length,                
            
            i;
        
        // Iterate the namespace parts
        for(i = 0; i < c; i++)
        {
            var part = parts[i];
            
            // Create a property if it doesn't exist
            // If the object already exists, nothing is done
            if(typeof node[part] === 'undefined' && !node[part])
            {
                // Check whether the namespace has to be created, if not exist
                if(create)
                {
                    // Create a new property 
                    // or assign it the optional value if it's the last in chain
                    node[part] = (value && i + 1 == c) ? value : {};
                }
                else 
                {
                    // Namespace does not exist, but there's no need to create it
                    return false;    
                }
            }
            
            // Assign the current node to the namespace
            node = node[part];
        }
        
        return node;

    };
       
    if(global.mjs) 
    {
        throw new Error('mjs has already been defined');
    } 
    else 
    {
        global.mjs = mjs;
    }
    
}(typeof window === 'undefined' ? this : window));
