define(['config', './browser'], function (config, browser) {
    //import tpl html
    var apiUrl = config.apiUrl;
    var deferConfig = null;
    var tpls = {
        "server_select": "tpls/server_select.html",
        "gift": "tpls/gift.html",
        "info_fill": "tpls/info_fill.html",
        "my_prize": "tpls/my_prize.html",
        "captcha": "tpls/captcha.html"
    };
    var fetchUrl = function (path) {
        var defer = $.Deferred();
        $.ajax({
            url: path,
            dataType: "html",
            success: function (data) {
                defer.resolve(data);
            },
            error: function () {
                defer.reject();
            }
        });
        return defer;
    };

    var keyMirror = function (obj) {
        var ret = {};
        var key;
        if (!(obj instanceof Object && !Array.isArray(obj))) {
            throw new Error('keyMirror(...): Argument must be an object.');
        }
        for (key in obj) {
            if (obj.hasOwnProperty(key)) {
                ret[key] = key;
            }
        }
        return ret;
    };
    var uuid = function (len, radix) {
        var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('');
        var uuid = [], i;
        radix = radix || chars.length;

        if (len) {
            // Compact form
            for (i = 0; i < len; i++) uuid[i] = chars[0 | Math.random() * radix];
        } else {
            // rfc4122, version 4 form
            var r;

            // rfc4122 requires these characters
            uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-';
            uuid[14] = '4';

            // Fill in random data.  At i==19 set the high bits of clock sequence as
            // per rfc4122, sec. 4.1.5
            for (i = 0; i < 36; i++) {
                if (!uuid[i]) {
                    r = 0 | Math.random() * 16;
                    uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r];
                }
            }
        }

        return uuid.join('');
    };

    var getUrlKey = function (url) {
        if (!url)
            return '';
        for (var key in apiUrl) {
            if (url.indexOf(apiUrl[key]) !== -1) {
                return key + url.substring(apiUrl[key].length);
                break;
            }
        }
    };

    var invokeQueue = new SQ.Class();

    invokeQueue.include({
        init: function () {
            SQ.log("执行栈初始化...")
        },

        context: null,
        clock: null,
        interval: 300,
        index: 0,
        queue: [],
        overCall: null,
        options: {
            endCallback: $.noop,
            limit: Number.MAX_VALUE
        },

        config: function (options) {
            this.options = $.extend(this.options, options);
        },

        invoke: function () {
            var that = this;
            this.clock = setTimeout(function () {
                that.runningState = true;
                if (that.index < that.queue.length && that.index < that.options.limit) {
                    that.queue[that.index].func.call(that.queue[that.index].context);
                    that.index++;
                    that.invoke();
                } else {
                    that.index = 0;
                    that.options.endCallback && that.options.endCallback();
                    that.runningState = false;
                }
            }, that.interval);
        },

        push: function (func, context, arguments) {
            this.queue.push({func: func, context: context});
        },

        clear: function () {
            clearTimeout(this.clock);
            this.runningState = false;
            this.queue = [];
        },

        stop: function () {
            clearTimeout(this.clock);
            this.runningState = false;
        },

        _continue: function () {
            this.invoke();
        },

        restart: function () {
            this.index = 0;
            this.invoke();
        },

        isRunning: function () {
            return this.runningState;
        }
    });

    function getKeys(obj) {
        var keys = [];
        for (var key in obj) {
            keys.push(key);
        }
        return keys;
    }


    function _jsonP(url, callback, errorCallback) {
        var settings = {};
        var mock_uuid = '_'+uuid(4,16);

        if (typeof url === "string") {
            settings.url = url;
        }
        if (typeof url === "object") {
            settings = url;
        }

        if (('process.env.NODE_ENV' === 'development')) {
            var keys = getKeys(settings.data);
            var appendUrl = $.map(keys, function (item) {
                return '&' + item + '=' + settings.data[item];
            }).join('');

            settings.url = getUrlKey(settings.url) + appendUrl;
            if (settings.url.indexOf('?') === -1) {
                settings.url = settings.url.replace('&', '?');
            }
            if (settings.url.indexOf('?') === -1) {
                settings.url = settings.url + '?callback=mock_test' + mock_uuid
            } else {
                settings.url = settings.url + '&callback=mock_test'+mock_uuid
            }
            settings.data = null;
        }

        $.ajax({
            url: settings.url,
            data: settings.data || {},
            dataType: ('process.env.NODE_ENV' === 'development') ? "json" : "jsonp",
            jsonpCallback: ('process.env.NODE_ENV' === 'development') ? "" : settings.jsonpCallback,
            success: function (res) {
                callback && callback(res);
            },
            error: function (XMLHttpRequest, textStatus, errorThrown) {
                errorCallback && errorCallback(XMLHttpRequest, textStatus, errorThrown);
            },
            complete: function (XHR, TS) {
                if ('process.env.NODE_ENV' === 'development' && TS === 'parsererror') {
                    var res = XHR.responseText;
                    callback && callback(eval(res.substring(res.indexOf('('), res.indexOf(')') + 1)));

                }
                settings.completeCallback && settings.completeCallback(XHR, TS);
            }
        });
    }

    function initTemplate() {
        var defer = $.Deferred();
        var defers = [];
        for (var key in tpls) {
            defers.push(fetchUrl(tpls[key]).then(function (templateData) {
                $(document.body).append(templateData);
            }));
        }
        $.when.apply(undefined, defers).then(function () {
            defer.resolve();
        });

        return defer;
    };

    function _deferConfig() {
        var defer = $.Deferred();
        _jsonP(apiUrl.default_info, function (res) {
            obj.deferConfig = res;
            defer.resolve(res);
        });
        return defer;
    }

    var obj = $.extend({
        invokeQueue: new invokeQueue(),
        fetchUrl: fetchUrl,
        keyMirror: keyMirror,
        getKeys: getKeys,
        uuid: uuid,
        /*_deferConfig: _deferConfig(),*/
        deferConfig: null,
        _jsonP: _jsonP
    }, browser);

    return obj;
});