﻿/**
 * Custom JavaScript Standard Library
 * depends: webtoolkit.md5.js(optional for MD5 hash)
 * version 2.0
 */

var HasMD5 = true;
if (eval("typeof(MD5)") == 'undefined') {
    HasMD5 = false;
    var MD5 = function() {
        throw({message: '缺少MD5实现'});
    };
}

var HasExtJS = true;

// 如果没有使用ExtJS库，则创建一个模拟Ext对象
if (eval("typeof(Ext)") == 'undefined') {
    HasExtJS = false;

    var Ext = {version: 'fake'};

    // Original from ExtJS (3 lines below)
    var ua = navigator.userAgent.toLowerCase();
    var isOpera = ua.indexOf("opera") > -1;
    var isIE = !isOpera && ua.indexOf("msie") > -1;

    // Original from ExtJS
    Ext.apply = function(o, c, defaults) {
        if (defaults) {
            // no "this" reference for friendly out of scope calls
            Ext.apply(o, defaults);
        }
        if (o && c && typeof c == 'object') {
            for (var p in c) {
                o[p] = c[p];
            }
        }
        return o;
    };

    Ext.applyIf = function(o, c) {
        if (o && c) {
            for (var p in c) {
                if (typeof o[p] == "undefined") {
                    o[p] = c[p];
                }
            }
        }
        return o;
    };

    // Original from ExtJS
    Ext.applyIf(Array.prototype, {
        indexOf : function(o) {
            for (var i = 0, len = this.length; i < len; i++) {
                if (this[i] == o) return i;
            }
            return -1;
        },

        remove : function(o) {
            var index = this.indexOf(o);
            if (index != -1) {
                this.splice(index, 1);
            }
            return this;
        }
    });

    Ext.apply(Ext, {
        // Original from ExtJS
        isIE: isIE,

        // Original from ExtJS
        isEmpty: function(v, allowBlank) {
            return v === null || v === undefined || (!allowBlank ? v === '' : false);
        },

        // Original from ExtJS
        isArray : function(v) {
            return v && typeof v.length == 'number' && typeof v.splice == 'function';
        },

        // Just a fake for typeof
        type: function(o) {
            return typeof o;
        },

        // Original from ExtJS
        extend: function() {
            // inline overrides
            var io = function(o) {
                for (var m in o) {
                    this[m] = o[m];
                }
            };
            var oc = Object.prototype.constructor;

            return function(sb, sp, overrides) {
                if (typeof sp == 'object') {
                    overrides = sp;
                    sp = sb;
                    sb = overrides.constructor != oc ? overrides.constructor : function() {
                        sp.apply(this, arguments);
                    };
                }
                var F = function() {
                }, sbp, spp = sp.prototype;
                F.prototype = spp;
                sbp = sb.prototype = new F();
                sbp.constructor = sb;
                sb.superclass = spp;
                if (spp.constructor == oc) {
                    spp.constructor = sp;
                }
                sb.override = function(o) {
                    Ext.override(sb, o);
                };
                sbp.override = io;
                Ext.override(sb, overrides);
                sb.extend = function(o) {
                    Ext.extend(sb, o);
                };
                return sb;
            };
        }(),

        // Original from ExtJS
        override: function(origclass, overrides) {
            if (overrides) {
                var p = origclass.prototype;
                for (var method in overrides) {
                    p[method] = overrides[method];
                }
                if (Ext.isIE && overrides.toString != origclass.toString) {
                    p.toString = overrides.toString;
                }
            }
        }
    });
}

/**
 * @class BasicListener
 * 基本事件侦听器
 */
function BasicListener() {
    this.scope = null;
    this.fn = null;
    this.passParam = null;
    this.nextListener = null;
}

BasicListener.prototype = {
    /**
     * {Object} [可选] 事件回调函数的调用对象
     */
    scope: null,
    /**
     * {Function} 事件回调函数，参数如下：
     *   passParam {*} 就是BasicListener的可选项passParam
     *   eventData {*} 由事件激发函数给出，详见具体的事件激发函数注释
     */
    fn: null,
    /**
     * {*} [可选] 传递给事件回调函数的参数
     */
    passParam: null,
    /**
     * {BasicListener} [可选] 下一个接收事件的基本事件侦听器
     */
    nextListener: null
};

/**
 * @class SuccessOrNotListener
 * 成功或失败事件侦听器
 */
function SuccessOrNotListener() {
    this.scope = null;
    this.success = null;
    this.failure = null;
    this.passParam = null;
    this.successParam = null;
    this.failureParam = null;
    this.nextListener = null;
}

SuccessOrNotListener.prototype = {
    /**
     * {Object} [可选] 事件回调函数的调用对象
     */
    scope: null,
    /**
     * {Function} 成功时的事件回调函数，参数如下：
     *   passParam {*} 就是SuccessOrNotListener的可选项passParam
     *   successParam {*} 就是SuccessOrNotListener的可选项successParam
     *   eventData {*} 由事件激发函数给出，详见具体的事件激发函数注释
     */
    success: null,
    /**
     * {Function} 失败时的事件回调函数，参数如下：
     *   passParam {*} 就是SuccessOrNotListener的可选项passParam
     *   failureParam {*} 就是SuccessOrNotListener的可选项failureParam
     *   eventData {*} 由事件激发函数给出，详见具体的事件激发函数注释
     */
    failure: null,
    /**
     * {*} [可选] 无论成功还是失败都会传递给回调函数的参数
     */
    passParam: null,
    /**
     * {*} [可选] 成功时传递给回调函数的参数
     */
    successParam: null,
    /**
     * {*} [可选] 失败时传递给回调函数的参数
     */
    failureParam: null,
    /**
     * {SuccessOrNotListener} [可选] 下一个接收事件的成功或失败事件侦听器
     */
    nextListener: null
};

/**
 * @class CSUtils
 * 常用工具类
 * @singleton
 */
var CSUtils = new (function() {
    /**
     * 模拟生成GUID
     * @param {Boolean} fullMode 是否生成完整模式的GUID，为true时生成的GUID带有花括号和短划线
     * @param {Boolean} lowerCase 是否生成全部字母为小写的GUID，true为是，false为否
     * @return {String} GUID
     */
    this.newGuid = function(fullMode, lowerCase) {
        var guid;
        if (fullMode)
            guid = '{';
        else
            guid = '';
        for (var i = 1; i <= 32; i++) {
            guid += Math.floor(Math.random() * 16.0).toString(16);
            if (((i == 8) || (i == 12) || (i == 16) || (i == 20)) && fullMode)
                guid += '-';
        }
        if (fullMode)
            guid += '}';

        if (lowerCase)
            return guid;
        else
            return guid.toUpperCase();
    };

    /**
     * 返回yyyy-MM-dd格式的当天日期字符串
     */
    this.getToday = function() {
        var date = new Date();
        return date.format('Y-m-d');
    };

    /**
     * 返回当前时间字符串（年月日时分秒毫秒）
     */
    this.getNowFull = function() {
        var date = new Date();
        return date.format('YmdHisu');
    };

    /**
     * 返回当前时间字符串的MD5哈希码
     */
    this.getNowHash = function() {
        var nowFull = this.getNowFull();
        if (HasMD5)
            return MD5(this.getNowFull());
        else
            return nowFull;
    };

    /**
     * 判断一个对象是否为纯字符串数组
     *
     * @param {Object} obj 要判断的独享
     * @param allowEmptyArray 是否允许空数组，默认为false
     * @param allowBlankString 是否允许某个元素为空字符串，默认为false
     */
    this.isStringArray = function(obj, allowEmptyArray, allowBlankString) {
        if (!Ext.isArray(obj))
            return false;
        if ((obj.length == 0) && (!allowEmptyArray))
            return false;
        for (var i = 0; i < obj.length; i ++)
            if ((Ext.type(obj[i]) != 'string') || (Ext.isEmpty(obj[i]) && (!allowBlankString)))
                return false;
        return true;
    };

    /**
     * 从文件的完整路径名中提取文件名
     *
     * @param fullName 文件的完整路径名
     */
    this.extractFileName = function(fullName) {
        if (fullName.indexOf('\\') >= 0)
            return fullName.substring(fullName.lastIndexOf('\\') + 1, fullName.length);
        else if (fullName.indexOf('/') >= 0)
            return fullName.substring(fullName.lastIndexOf('/') + 1, fullName.length);
        else
            return fullName;
    };

    /**
     * 从源对象克隆一个新对象，舍弃源对象所有的函数，不支持嵌套克隆
     *
     * @param source {Object} 源对象
     * @param skipProps {Array} 字符串数组，给出克隆时要跳过的属性名
     */
    this.cloneValueProps = function(source, skipProps) {
        var r = {};
        for (var field in source) {
            if (source[field] instanceof Function)
                continue;
            if ((Ext.isArray(skipProps)) && (skipProps.indexOf(field) >= 0))
                continue;
            if ((!Ext.isEmpty(source[field])) || (Ext.type(source[field]) == 'number'))
                r[field] = source[field];
        }
        return r;
    };

    /**
     * 发布事件给基本事件侦听器
     *
     * @param eventListener {BasicListener} 基本事件侦听器，参见BasicListener
     * @param eventData {*} [可选] 传递给事件回调函数的参数，排在BasicListener的passParam的后面
     */
    this.dispachBasicEvent = function(eventListener, eventData) {
        var scope = eventListener.scope;
        var fn = eventListener.fn;
        var passParam = eventListener.passParam;
        var nextListener = eventListener.nextListener;

        if (fn instanceof Function) {
            var args = [];
            if (!Ext.isEmpty(passParam))
                args.push(passParam);
            if (!Ext.isEmpty(eventData))
                args.push(eventData);
            if (args.length == 0)
                fn.call(scope);
            else
                fn.apply(scope, args);
        }

        if (!Ext.isEmpty(nextListener))
            CSUtils.dispachBasicEvent(nextListener, eventData);
    };

    /**
     * 发布事件给成功或失败事件侦听器
     *
     * @param eventListener {SuccessOrNotListener} 成功或失败事件侦听器，参见SuccessOrNotListener
     * @param eventData {*} [可选] 传递给事件回调函数的参数，排在BasicListener的passParam的后面
     * @param isFailure {boolean} 是否失败事件，默认为false
     */
    this.dispatchSuccessOrNotEvent = function(eventListener, eventData, isFailure) {
        var scope = eventListener.scope;
        var fn;
        if (isFailure)
            fn = eventListener.failure;
        else
            fn = eventListener.success;
        var passParam = eventListener.passParam;
        var exPassParam;
        if (isFailure)
            exPassParam = eventListener.failureParam;
        else
            exPassParam = eventListener.successParam;
        var nextListener = eventListener.nextListener;

        if (fn instanceof Function) {
            var args = [];
            if (!Ext.isEmpty(passParam))
                args.push(passParam);
            if (!Ext.isEmpty(exPassParam))
                args.push(exPassParam);
            if (!Ext.isEmpty(eventData))
                args.push(eventData);
            if (args.length == 0)
                fn.call(scope);
            else
                fn.apply(scope, args);
        }

        if (!Ext.isEmpty(nextListener))
            CSUtils.dispatchSuccessOrNotEvent(nextListener, eventData, isFailure);
    };
});
