/*
 * j2 Library 0.1
 *
 * Copyright (c) 2008 CNJUN (9dsoft.com)
 */

/**
 * The j2 Global Object
 * 
 * The j2 global object lives at the top of the namespace tree for all j2 components. 
 * It also include some utility methods for type checking, user agent detection, and module extension.
 *
 * Type-Checking Your Data: Use the j2.lang type checking methods to deal with unpredictable data.
 * User Agent Detection: j2.env.ua can tell you with some accuracy which brower your page is being viewed in.
 * Creating Class Hierarchies with j2.lang.extend: Leverage class inheritance in an object-oriented architecture.
 * Creating a Composition-Based Class Structure Using j2.lang.augmentProto: Use j2.lang.augmentProto to help modularize class behaviors.
 * Add Behavior to Objects or Static Classes with j2.lang.augmentObject: Use augmentObject to extend static classes, object literals, or class instances.
 * Combining Simple Data Sets with j2.lang.merge: Merge several objects, creating a unique set.
 */

if (typeof j2 == "undefined" || !j2) {
    /**
     * 如果j2对象不存在,则创建一个空的对象
     */
    var j2 = {};
}

/*
 * 创建命名空间
 * 
 * @method namespace
 * @static
 * @param  {String}  要创建的命名空间, 只有同时创建多个
 * @return {Object}  最后一个创建的命名空间对象
 */
j2.namespace = function() {
    var a = arguments, o = null, i, j, d;
    for (i=0; i<a.length; i=i+1) {
        d = a[i].split(".");
        o = j2;
        
        //j2是默认的, 如果在参数中包含了,则进行忽略
        for (j=(d[0] == "j2") ? 1 : 0; j<d.length; j=j+1) {
            o[d[j]] = o[d[j]] || {};
            o = o[d[j]];
        }
    }
    
    return o;
};

/*
 * 日志
 * 
 * @method log
 * @static
 * @param  {String}  msg  日志信息
 * @param  {String}  cat  日志类型 默认有: info, warn, error, time, 用户自定义类型. (opt)
 * @param  {String}  src  日志来源 (opt)
 * @return {Boolean} 日志操作成功返回true, 否则返回false
 */
j2.log = function(msg, cat, src) {
    var l = j2.widget.Logger;
    if (l && l.log) {
        return l.log(msg, cat, src);
    } else {
        return false;
    }
}

/*
 * 注册一个j2模块
 *
 * @method register
 * @static
 * @param {String}   name      要注册模块的名称 (例如: event, dom等)
 * @param {Function} mainClass 要注册模块的类引用,该类包含有版本信息,因此当有多个版本加载时,可以判定使用指定的版本
 * @param {Object}   data      要注册模块的元数据对象,当前包含version,build两个属性
 */
j2.register = function(name, mainClass, data) {
    var mods = j2.env.modules;
    if (!mods[name]) {
        mods[name] = { versions:[], builds:[] };
    }
    var m = mods[name], v = data.version, b = data.build, ls = j2.env.listeners;
    m.name = name;
    m.version = v;
    m.build = b;
    m.versions.push(v);
    m.builds.push(b);
    m.mainClass = mainClass;
    
    //
    for (var i = 0; i < ls.length; i = i + 1) {
        ls[i](m);
    }
    //
    if (mainClass) {
        mainClass.VERSION = v;
        mainClass.BUILD = b;
    } else {
        j2.log("mainClass is undefied for module " + name, "warn");
    }
}

/*
 * 浏览器,J2类的环境跟踪类
 * 
 * @class j2.env
 * @static
 */
j2.env = j2.env || {
    /**
     * 保存所有模块的版本信息
     */
    modules: [],
    /**
     * 模块的监听事件列表
     */
    listeners: []
}

/*
 * 获取指取模块的版本信息
 * 
 * @method getVersion
 * @static
 * @param  {String} 模块的名称
 * @return {Object} 模块版本信息对象
 */
 j2.env.getVersion = function(name) {
     return j2.env.modules[name] || null;
 }
 
 /**
  * 浏览器引擎类型
  * 
  * @class j2.env.ua
  * @static
  */
j2.env.ua = function() {
    var o = {
        ie: 0,
        opera: 0,
        gecko: 0,
        webkit: 0,
        mobile: null,
        air: 0
    };
    
    var ua = navigator.userAgent, m;
    
    // Modern KHTML browsers should qualify as Safari X-Grade
    if ((/KHTML/).test(ua)) {
        o.webkit=1;
    }
    // Modern WebKit browsers are at least X-Grade
    m=ua.match(/AppleWebKit\/([^\s]*)/);
    if (m&&m[1]) {
        o.webkit=parseFloat(m[1]);

        // Mobile browser check
        if (/ Mobile\//.test(ua)) {
            o.mobile = "Apple"; // iPhone or iPod Touch
        } else {
            m=ua.match(/NokiaN[^\/]*/);
            if (m) {
                o.mobile = m[0]; // Nokia N-series, ex: NokiaN95
            }
        }

        m=ua.match(/AdobeAIR\/([^\s]*)/);
        if (m) {
            o.air = m[0]; // Adobe AIR 1.0 or better
        }

    }

    if (!o.webkit) { // not webkit
        // @todo check Opera/8.01 (J2ME/MIDP; Opera Mini/2.0.4509/1316; fi; U; ssr)
        m=ua.match(/Opera[\s\/]([^\s]*)/);
        if (m&&m[1]) {
            o.opera=parseFloat(m[1]);
            m=ua.match(/Opera Mini[^;]*/);
            if (m) {
                o.mobile = m[0]; // ex: Opera Mini/2.0.4509/1316
            }
        } else { // not opera or webkit
            m=ua.match(/MSIE\s([^;]*)/);
            if (m&&m[1]) {
                o.ie=parseFloat(m[1]);
            } else { // not opera, webkit, or ie
                m=ua.match(/Gecko\/([^\s]*)/);
                if (m) {
                    o.gecko=1; // Gecko detected, look for revision
                    m=ua.match(/rv:([^\s\)]*)/);
                    if (m&&m[1]) {
                        o.gecko=parseFloat(m[1]);
                    }
                }
            }
        }
    }
    
    return o;
}();

/*
 * 初始化
 * 
 * @method init
 * @static
 * @private
 */
(function() {
    j2.namespace("util", "widget", "example");
})();

/**
 * Provides the language utilites and extensions used by the library
 * @class j2.lang
 */
j2.lang = j2.lang || {
    /**
     * 判断对象是否是数组
     * @method isArray
     * @param  {any} o   被测试的对象
     * @return {boolean} 测试结果
     */
    isArray: function(o) {
        if (o) {
            var l = j2.lang;
            return l.isNumber(o.length) && l.isFunction(o.splice);
        }
        return false;
    },
    
    /**
     * 判断对象是否是Boolean类型
     * @method isBoolean
     * @param  {any} o   被测试的对象
     * @return {boolean} 测试结果
     */
    isBoolean: function(o) {
        return typeof o === 'boolean';
    },
    isFunction: function(o) {
        return typeof o === 'function';
    },
    isNull: function(o) {
        return o === null;
    },
    isNumber: function(o) {
        return typeof o === 'number' && isFinite(o);
    },
    isObject: function(o) {
        return (o && (typeof o === 'object' || j2.lang.isFunction(o))) || false;
    },
    isString: function(o) {
        return typeof o === 'string';
    },
    isUndefined: function(o) {
        return typeof o === 'undefined';
    },
    /**
     * 测试对象是否含有某一属性
     */
    hasOwnProperty: function(o, prop) {
        if (Object.prototype.hasOwnProperty) {
            return o.hasOwnProperty(prop);
        }
        
        return !j2.lang.isUndefined(o[prop]) &&
                o.constructor.prototype[prop] !== o[prop];
    },
    _IEEnumFix: function(r, s) {
        if (j2.env.ua.ie) {
            var add = ["toString", "valueOf"], i;
            for (i = 0; i < add.length; i++) {
                var fname = add[i], f = s[fname];
                if (j2.lang.isFunction(f) && f != Object.prototype[fname]) {
                    r[fname] = f;
                }
            }
        }
    },
    extend: function(subc, superc, overrides) {
        if (!superc || !subc) {
            throw new Error("j2.lang.extend failed, please check that " + 
                            "all dependencies are included.");
        }
        var F = function() {};
        F.prototype = superc.prototype;
        subc.prototype = new F();
        subc.prototype.constructor = subc;
        subc.supperclass = superc.prototype;
        if (superc.prototype.constructor == Object.prototype.constructor) {
            superc.prototype.constructor = superc;
        }
        
        if (overrides) {
            for (var i in overrides) {
                subc.prototpe[i] = overrides[i];
            }
            
            j2.lang._IEEnumFix(subc.prototype, overrides);
        }
    },
    augmentObject: function(r, s) {
        if (!s || !r) {
            throw new Error("Absorb failed, verify dependencies.");
        }
        var a = arguments, i, p, override = a[2];
        if (override && override !== true) {// 仅接收指定属性
            for (i = 2; i < a.length; i++) {
                r[a[i]] = s[a[i]];
            }
        } else {//take everything, overwrite only if the third parameter is true
            for (p in s) {
                if (override || !r[p]) {
                    r[p] = s[p];
                }
            }
            
            j2.lang._IEEnumFix(r, s);
        }
    },
    augmentProto: function(r, s) {
        if (!s || !r) {
            throw new Error("Augment failed, verify dependencies.");
        }
        var a = [r.prototype, s,prototype];
        for (var i=2; i < arguments.length; i++) {
            a.push(arguments[i]);
        }
        j2.lang.augmentObject.apply(this, a);
    },
    trim: function(s) {
        try {
            return s.replace(/^\s+|\s+$/g, "");
        } catch(e) {
            return s;
        }
    },
    merge: function() {
        var o = {}, a = arguments;
        for (var i = 0, l = a.length; i < l; i++) {
            j2.lang.augmentObject(o, a[i], true);
        }
        return o;
    },
    isValue: function(o) {
        var l = j2.lang;
        return (l.isObject(o) || l.isString(o) || l.isNumber(o) || l.isBoolean(o));
    }
};
/**
 * j2.lang别名
 * @class j2.util.lang
 */
j2.util.Lang = j2.lang;

j2.lang.augment = j2.lang.augmentProto;

j2.augment = j2.lang.augmentProto;

j2.extend = j2.lang.extend;

j2.register("j2", j2, {version: "0.1", build: "1"});

String.prototype.trim = function(){
	return this.replace(/(^[ |　]*)|([ |　]*$)/g, "");
}

