/**
 * @version 0.0.2
 * @since 0.0.1
 * @author Shaun Chyxion
 * date created: 9/11/2012 9:49:18
 * support: chyxion@163.com
 * date modified: Nov 03, 2014 11:50:07
 */

var JSON;
JSON || (JSON = {
    // JSON.stringify(obj); // obj -> str
    stringify: Ext.JSON.encode,
    // JSON.parse(str); // str -> obj
    parse: Ext.JSON.decode
});
/**
 * URL params tool:
 * http://foobar.net/foo.html?bar=1&foobar=xyz
 * ->
 * params.base_path == 'http://foobar.net/'
 * params.bar == '1'
 * params.foobar == 'xyz'
 */
(function() {
    var w = window,
        l = w.location;
    w.console || (w.console = {log: function(){}, error: function(msg){
        alert(JSON.stringify(msg));
    }});
    w.params = {
        base_path: window.__base_path__ =
            l.protocol + '//' + l.host + '/' +
            l.pathname.split('/')[1] + '/'
    };
    // find params in url
    l.search.replace(/([^\?=\&]+)(=([^\&]*))?/g,
        function($0, $1, $2, $3){
            window.params[$1] = $3;
        }); // end of replace
})(); // end

/**
 * Ext Dialog
 */
var Dialog = {
    /**
     * @param {String} msg 
     * @param {Function} fn
     */
    alert: function(msg, fn) {
        Ext.MessageBox.show({
            title: 'Alert',
            msg: msg,
            autoWidth : true,
            minWidth : 200,
            maxWidth : 500,
            buttons : Ext.MessageBox.OK,
            icon : Ext.MessageBox.INFO,
            fn: fn
        });
    },
    /**
     * @param {String} msg
     * @param {Function} fn
     */
    warn: function(msg, fn) {
        Ext.MessageBox.show({
            title : 'Warn',
            msg : msg,
            autoWidth : true,
            minWidth : 200,
            maxWidth : 500,
            buttons : Ext.MessageBox.OK,
            icon : Ext.MessageBox.WARNING,
            fn: fn
        });
    },
    /**
     * @param {String} msg
     * @param {Function} fn_ok
     * @param {Function} fn_no
     */
    confirm: function(msg, fn_ok, fn_no) {
        Ext.MessageBox.confirm('Alert', msg || 'Are You Sure?', function(btn) {
            if (btn == 'yes') {
                fn_ok && fn_ok();
            }
            else {
                fn_no && fn_no();
            }
        });
    },
    ync: function(msg, fn_y, fn_n, fn_c) {
        Ext.MessageBox.show({
            title: 'Alert',
            msg: msg || 'Are You Sure?',
            buttons: Ext.MessageBox.YESNOCANCEL,
            fn: function(btn) {
                if (btn == 'yes') {
                    fn_y && fn_y();
                }
                else if (btn == 'no') {
                    fn_n && fn_n();
                }
                else {
                    fn_c && fn_c();
                }
            },
            icon: Ext.MessageBox.QUESTION
        });
    },
    /**
     * @param {String} title
     * @param {String} msg
     * @param {Function} fn_ok
     * @param {Function} fn_no
     */
    prompt: function(title, msg, fn_ok, fn_no) {
        Ext.MessageBox.prompt(title, msg, function(btn, text) {
            if (btn == 'ok') {
                fn_ok && fn_ok(text);
            }
            else {
                fn_no && fn_no();
            }
        });
    },
    error: function(msg) {
        Ext.MessageBox.show({
            title : 'Error',
            msg : msg || 'Error Caused.',
            autoWidth : true,
            minWidth : 200,
            maxWidth : 500,
            buttons : Ext.MessageBox.OK,
            icon : Ext.MessageBox.ERROR
        });
    },
    success : function(msg) {
        Ext.MessageBox.show({
            title: 'Success',
            msg: msg || 'Success!',
            autoWidth: true,
            minWidth: 200,
            maxWidth: 500,
            buttons: Ext.MessageBox.OK,
            icon: Ext.MessageBox.INFO
        });
    },
    fail : function(msg) {
        Ext.MessageBox.show( {
            title: 'Fail',
            msg: msg || 'Operate Failed.',
            autoWidth: true,
            minWidth: 200,
            maxWidth: 500,
            buttons: Ext.MessageBox.OK,
            icon: Ext.MessageBox.ERROR
        });
    },
    waiting : function(msg) {
        Ext.MessageBox.show( {
            title : 'Waiting...',
            msg : msg || 'Please Wait...',
            width : 300,
            wait : true,
            waitConfig : {
                interval : 200
            },
            animEl : 'mb7'
        });
    },
    saving : function(msg) {
        Ext.MessageBox.show( {
            title: 'Save...',
            msg: msg || 'Saving, Please Wait...',
            width: 300,
            wait: true,
            waitConfig: {
                interval: 200
            },
            icon: 'ext-mb-download',
            animEl: 'mb7'
        });
    },
    loading : function(msg) {
        Ext.MessageBox.show( {
            title: 'Loading...',
            msg: msg || 'Loading, Please Wait...',
            width: 300,
            wait: true,
            icon: 'loading',
            waitConfig: {
                interval : 80
            },
            animEl : 'mb7'
        });
    },
    /**
     * hide dialog
     */
    hide: function() {
        Ext.MessageBox.hide();
    }
},
/**
 * Message box
 */
Message = {
    alert: function(title, msg) {
        if (!msg) {
            msg = title;
            title = null;
        }
        this._msg(title, msg, 'bg-alert');
    },
    warn: function(title, msg) {
        if (!msg) {
            msg = title;
            title = null;
        }
        this._msg(title, msg, 'bg-warn');
    },
    _create_box: function(title, msg, cls) { 
    	var c = ['<div class="msg ', cls, '">'];
    	if (title) {
    		c = c.concat(['<h3>', title, '</h3>'])
    	}
    	return c.concat(['<p>', msg, '</p></div>']).join('');
     },
    _msg: function(t, msg, type) {
        var me = this,
        // message div
        msg_div = Ext.get('commons-message-div') || 
        Ext.DomHelper.insertFirst(document.body, 
                {id: 'commons-message-div', style: 'z-index: 30240'});
        Ext.DomHelper.append(msg_div,
                me._create_box(t, msg, type), true)
            .hide()
            .slideIn('t')
            .ghost('t', {delay: 1500, remove: true});
    }
},
/**
 * Ajax
 * get:
 * Ajax.get('this/is/a/url', function(data){
 *  console.log(data.users);
 * });
 * Ajax.get('this/is/a/url', {
 *    user_id: '2008110101'
 *  }, function(user){
 *    console.log(user.name);
 * });
 * post:
 * Ajax.post('this/is/a/url', {
 *    user: {
 *        name: 'chyxion',
 *        id: '2008110101'
 *      };
 *  }, function(){
 *    Dialog.alert('保存成功!');
 * });
 * Ajax.post(form, function(){
 *    Dialog.alert('保存成功!');
 * });
 */
Ajax = {
    /**
     * private
     */
    _request: function(p) {
        // loading mask
        var me = this, lm;

        if (p.loadmask) {
            lm = Utils.loadmask(p.loadmask);
            lm.show();
        }

        p.before_load && p.before_load(); // 请求前回调
        // if not string, convert to json string
        if (p.params && !Ext.isFunction(p.params)) {
            var a, v;
            for (a in p.params) {
                v = p.params[a];
                Ext.isString(v) || (p.params[a] = JSON.stringify(v));
            }
        }
        else if (p.params && Ext.isFunction(p.params)) {
            p.params = p.params();
        }
        p.params || (p.params = {});
        // add _ajax param
        if (p.method != 'GET') {
            p.params._ajax = 1;
        }
        p.params._method = p.method;
        Ext.Ajax.request({
            method: p.method == 'GET' ? 'GET' : 'POST',
            url: p.url,
            params: p.params,
            disableCachingParam: '_ajax',
            disableCaching: true,
            success: function(r, opt) {
                p.loadmask && top.Ext.destroy(lm);
                if (p.post_request) {
                    if (p.post_request(r)) {
                        return;
                    }
                }
                try {
                    r = JSON.parse(r.responseText);
                }
                catch (e) {
                    // json parse exception
                    Dialog.warn(r.responseText + ' is not valid JSON.');
                    return false;
                }
                if (me.default_callback) {
                    if (me.default_callback(r)) {
                        return;
                    }
                } 
                if (r.success) {
                    // success callback equals false, return
                    if (p.fn_s === false) return;
                    Ext.isFunction(p.fn_s) ? p.fn_s(r.data, r) : Message.alert(r.data || 'Load Success.');
                }
                else {
                    if (p.fn_f === false) return;
                    Ext.isFunction(p.fn_f) ? p.fn_f(r.errmsg, r) : 
                    Dialog.warn(r.errmsg || 
                    	'Error Caused.');
                }
            },
            failure : function(r, opt) {
                p.loadmask && top.Ext.destroy(lm);
                console.log('ERROR: Ajax Request Error.', r, opt);
                if (me.default_callback) {
                    if (me.default_callback(r, r)) {
                        return;
                    }
                } 
                p.post_request && p.post_request(r);
            }
        });
    },
    /**
     * {
     *      [lm], [url], [form], [params], [fn_s], [fn_f]
     * }
     */
    _process_request: function(args, method) {
        var me = this;
        if (args && args.length) {
            // args to array
            args = Array.prototype.slice.call(args);
            var lm = args.shift(), // loadmask
                url,
                form,
                p,
                fn_s,
                fn_f;
            // loadmask
            if (Ext.isBoolean(lm)) {
                url = args.shift();
            }
            else {
                url = lm;
                // default loadmask
                lm = true; 
            }
            // default loadmask
            lm && (lm = 'Loading...');
            // no url
            if (me._is_form(url)) {
                form = url;
                url = null;
            }
            else {
                form = args.shift();
                // not form found
                if (!me._is_form(form)) {
                    args.unshift(form);
                    form = null;
                }
            }
            me._parse_params_and_callbacks(args);
            // params
            p = args.shift();
            // callbacks
            fn_s = args.shift();
            fn_f = args.shift();
            // Form Submit
            if (form) {
                form.getForm && (form = form.getForm());
                //form.isValid() &&
                form.submit({
                    clientValidation: true,
                    method: method == 'GET' ? 'GET' : 'POST',
                    url: url,
                    params: Ext.merge({
                        _method: method,
                    }, p),
                    submitEmptyText: false,
                    waitMsg: lm || null,
                    success: function(form, action) {
                        fn_s ? fn_s(action.result, form, action) : 
                            Message.alert('Submit Success.');
                    },
                    failure: function(form, action) {
                        console.log('Form Submit ERROR.', form, action);
                        var result = action.result; 
                        fn_f ? fn_f(result, form, action) :
                            Dialog.alert('Error Caused, Message [' + 
                            	result.errmsg + 
                            	'], Error Code [' + 
                            	result.errcode + '].');
                    }
                });
            }
            // Ajax Request
            else {
                me._request({
                    loadmask: lm,
                    method: method || 'GET',
                    url: url,
                    params: p,
                    fn_s: fn_s,
                    fn_f: fn_f
                });
            }
        }
    },
    _parse_params_and_callbacks: function(args) {
        // has callbacks
        if (Ext.isFunction(args[1]) && Ext.isFunction(args[2])) {
            Ext.isFunction(args[0]) && (args[0] = args[0]());
        }
        // no params, params is success callback
        else if (Ext.isFunction(args[0])) {
            args[2] = args[1];
            args[1] = args[0];
            args[0] = null;
        }
    },
    _is_form: function(f) {
        return Ext.Array.contains(
            ['Ext.form.Panel', 'Ext.form.Basic'], 
            Ext.getClassName(f));
    },
    /**
     *  Ajax.get('url.get',
     *     {id: 001, name: 'foo'},
     *     function(data) {
     *       // success
     *     }, function(msg) {
     *       // fail
     *     });
     *     no params
     *  Ajax.get('url.get',
     *     function(data) {
     *       // success
     *     }, function(msg){
     *       // fail
     *     });
     * @param {Boolean} [loadmask], option
     * @param {String} url
     * @param {Object} [params]
     * @param {Function} [fn_s]
     * @param {Function} [fn_f]
     */
    get: function() {
        this._process_request(arguments, 'GET');
    },
    /**
     * @see #get
     */
    post: function() {
        this._process_request(arguments, 'POST');
    },
    /**
     * @see #get
     */
    put: function() {
        this._process_request(arguments, 'PUT');
    },
    /**
     * @see #get
     */
    del: function() {
        this._process_request(arguments, 'DELETE');
    },
    download: function(url, params) {
    	var di_id = '__download_iframe__',
    	di = Ext.get(di_id);
    	if (!di) {
    		di = Ext.DomHelper.append(document.body, {
    			tag: 'iframe',
    			id: di_id,
    			name: di_id,
    			width: 0,
    			height: 0,
    			style: 'display: none',
    			src: 'about:blank',
    		}, true);
    	}
    	di.set({src: params ? url + '?' + Ext.Object.toQueryString(params) : url});
    },
    load_script: function(url, fn_s, fn_f) {
        Ext.Loader.loadScript({
            url: url,
            onLoad: fn_s,
            onError: fn_f || function() {Dialog.warn('Load Script Fail.')}
        });
    }
},
Utils = {
    date_renderer: function(fmt) {
        return Ext.util.Format.dateRenderer(fmt || 'Y-m-d H:i:s');
    },
    cell_qt_renderer: function (v, md) {
        var e = Ext.String.htmlEncode;
        md.tdAttr = 'data-qtip="' + e(e(v)) + '"';
        return e(v);
    },
    page_size: 15,
    date_column_width: 136,
    loadmask: function (msg) { // 返回loading mask
        return new top.Ext.LoadMask(top.Ext.getBody(), {msg: msg || 'Loading...'});
    },
    is_ext_view: function (view) {
        return /^(\w+\.)+\w+$/.test(view);
    },
    /**
     * a=1,b=2 --> {a: 1, b: 2}
     */
    parse_args: function (args) {
        var r;
        if (Ext.isString(args)) {
            r = {};
            // remove blank char
            args = args.replace(/\s+/g, '');
            args.replace(/([^,=]+)(=([^,]+))?/g, function($0, $1, $2, $3) {
                    r[$1] = $3;
                }); // end of replace
        }
        else if (Ext.isObject(args)) {
            r = args;
        }
        return r;
    }
},
Store = {
    create: function (s) {
        var me = this,
        s_config = { // store config
            autoLoad: s.auto_load === undefined ? true : s.auto_load,
            store: 'json',
            pageSize: 50,
            proxy: me.ajax_proxy(s),
            listeners: me.listeners()
        };
        return Ext.create('Ext.data.Store', Ext.merge(s_config, s));
    },
    ajax_proxy: function (s) {
        var me = this;
        return {
            type: 'ajax',
            cacheString: '__ajax',
            url: s.url,
            extraParams: s.params || s.extraParams,
            actionMethods: {
                read: s.method || 'GET'
            },
            reader: {
                type: 'json',
                root: 'data',
                idProperty: s.id_property || s.idProperty,
                totalProperty: 'total'
            },
            listeners: {
                exception: function (proxy, op) { // Store Load Exception
                    console.log('Store Load Exception.', op);
                    try {
                        if (op.responseText) {
                            me.default_callback ? me.default_callback(
                                    JSON.parse(op.responseText), op.responseText) :
                                Dialog.alert('Store Load Error: ' + op.responseText);
                        }
                        else {
                            Dialog.alert('Store Load Exception Caused.');
                        }
                    } 
                    catch (e) {
                        op.responseText &&
                            Dialog.alert(op.responseText || 
                                'Store Load Exception Caused.');
                    }
                }
            }
        };
    },
    listeners: function () {
        return {
            beforeload: function (s) {
                var p = s.getProxy().extraParams, i;
                if (p) {
                    for (i in p) {
                        p[i] != null &&
                            !Ext.isString(p[i]) &&
                            (p[i] = JSON.stringify(p[i]));
                    }
                }
            }
        };
    },
    tree: function (s) { // tree store
        var me = this,
        ts = {
            store: 'tree',
            proxy: me.ajax_proxy(s),
            listeners: me.listeners(),
            root: Ext.merge({
                expanded: true,
                id: s.root_id || 'root',
                text: s.root_text || 'root'
            }, s.root)
        };
        return Ext.merge(ts, s);
    }
};
