//Cloud Async Loader
(function() {
    this.CAL = {
        start: function() {
            clearTimeout(CAL.timer);
            if (typeof jQuery !== 'undefined' && CAL.length > 0) {
                CAL.run();
                if (CAL.length > 0) {
                    CAL.timer = setTimeout(CAL.start, CAL.interval);
                }
            } else {
                CAL.timer = setTimeout(CAL.start, CAL.interval);
            }
        },
        run: function() {
            for (var i=0,ii=this.length;i<ii;i++) {
                var callback = this[i];
                if ('dependency' in callback) {
                    var rescursive_dependencies = callback.dependency;
                    for (var j=0,jj=rescursive_dependencies.length;j<jj;j++) {
                        if (rescursive_dependencies[j] in callback.context) {
                            if (j ==  jj - 1) {
                                callback.call();
                                this.splice(i--, 1), ii--;
                            } else {
                                callback.context = callback.context[rescursive_dependencies[j]];
                                rescursive_dependencies.shift();
                                j--, jj--;
                                continue;
                            }
                        } else {
                            break;
                        }
                    }
                } else {
                    callback.call();
                    this.splice(i--, 1), ii--;
                }
            }
        },
        load: function(u) {
            var s = document.createElement('script');
            s.setAttribute('type', 'text/javascript');
            s.setAttribute('async', true);
            s.setAttribute('defer', true);
            s.setAttribute('src', u);
            (document.getElementsByTagName('head')[0] || document.documentElement).appendChild(s);
        },
        loadOnReady: function(u) {
            this.pushOnReady(function(){
                CAL.load(u);
            });
        },
        push: function(callback, dependency) {
            if (typeof callback === 'string') {
                callback = this.predefined_callbacks[callback];
            }
            if (typeof dependency !== 'undefined') {
                callback.dependency = dependency.split('.');
            }
            if (callback) {
                callback.context = window;
                Array.prototype.push.call(this, callback);
                // start it using setTimeout() to put start() in a new stack for prevent rescurive calling
                CAL.timer = setTimeout(CAL.start, CAL.interval);
            }
        },
        pushOnReady: function(callback, dependency) {
            if (typeof callback === 'string') {
                this.push(function(){
                    $(function() {
                        CAL.push(callback);
                    });
                }, dependency);
            } else {
                this.push(function(){
                    $(callback);
                }, dependency);
            }
        },
        splice: function() {
            Array.prototype.splice.apply(this, arguments);
        },
        register: function(name, callback, dependency) {
            this.predefined_callbacks[name] = callback;
            if (typeof dependency !== 'undefined') {
                this.predefined_callbacks[name].dependency = dependency.split('.');
            }
        },
        length: 0,
        interval: 150,
        timer: 0,
        predefined_callbacks: {}
    }
})();

