/*
 * xLazyLoader 1.3 - Plugin for jQuery
 * 
 * Load js, css and images asynchron and get different callbacks
 *
 * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
 * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
 *
 * Depends:
 *   jquery.js
 *
 *  Copyright (c) 2008 Oleg Slobodskoi (ajaxsoft.de)
 */

;(function($){

$.xLazyLoader =  function ( method, options ) {
    if ( typeof method == 'object' ) {
        options = method;
        method = 'init';
    };
    new xLazyLoader()[method](options);
};

$.xLazyLoader.defaults = {
    js: [], css: [], img: [],
    name: null,
    timeout: 2000000,
    //success callback for all files
    success: function(){}, 
    //error callback - by load errors / timeout
    error: function(){},
    //complete callbck - by success or errors
    complete: function(){},
    //success callback for each file
    each: function(){} 
};

var head = document.getElementsByTagName("head")[0];

function xLazyLoader ()
{

    var self = this,
        s,
        loaded = [],
        errors = [],
        tTimeout,
        cssTimeout,
        toLoad,
        files = []
    ;
    
    this.init = function ( options )
    {
        if ( !options ) return;
        
        s = $.extend({}, $.xLazyLoader.defaults, options);
        toLoad = {js: s.js, css: s.css, img: s.img};
        
        $.each(toLoad, function( type, f ){
            if ( typeof f == 'string' )        
                f = f.split(',');
            files = files.concat(f);    
        });

        if ( !files.length ) {
            dispatchCallbacks('error');
            return;    
        };

        if (s.timeout) {
            tTimeout = setTimeout(function(){
                var handled = loaded.concat(errors);
                /* search for unhandled files */
                $.each(files, function(i, file){
                    $.inArray(file, handled) == -1 && errors.push(file);        
                });
                dispatchCallbacks('error');            
            }, s.timeout);
        };


        $.each(toLoad, function(type, urls){
            if ( $.isArray(urls) )
                $.each( urls, function(i, url){
                    load(type, url);
                });
            else if (typeof urls == 'string')
                load(type, urls);
        });
        


    };

    this.js = function ( src, callback, name )
    {
        var $script = $('script[src*="'+src+'"]');
        if ( $script.length ) {
            $script.attr('pending') ? $script.bind('scriptload',callback) : callback();
            return;
        };
        
        var s = document.createElement('script');
        s.setAttribute("type","text/javascript");
        s.setAttribute("src", src);
        s.setAttribute('id', name);
        s.setAttribute('pending', 1);
        // Mozilla only
        s.onerror = addError;
        
        
        $(s).bind('scriptload',function(){
            $(this).removeAttr('pending');
            callback();
             //unbind load event
             //timeout because of pending callbacks
            setTimeout(function(){
                $(s).unbind('scriptload');
            },10);
        });
        
        // jQuery doesn't handling onload event special for script tag,
        var done = false;
        s.onload = s.onreadystatechange = function() {
            if ( !done && ( !this.readyState || /loaded|complete/.test(this.readyState) ) ) {
                done = true;
                // Handle memory leak in IE
                s.onload = s.onreadystatechange = null;
                $(s).trigger('scriptload'); 
            };
        };
        head.appendChild(s);
    
    };

    this.css = function ( href, callback, name )
    {

        if ( $('link[href*="'+href+'"]').length ) {
            callback();
            return;
        };
        

        var link = $('<link rel="stylesheet" type="text/css" media="all" href="'+href+'" id="'+name+'"></link>')[0];
        if ( $.browser.msie ) {
            link.onreadystatechange = function () {
                /loaded|complete/.test(link.readyState) && callback();
            };
        } else if ( $.browser.opera ) {
            link.onload = callback;
        } else {
            /* 
             * Mozilla, Safari, Chrome 
             * unfortunately it is inpossible to check if the stylesheet is really loaded or it is "HTTP/1.0 400 Bad Request"
             * the only way to do this is to check if some special properties  were set, so there is no error callback for stylesheets -
             * it fires alway success
             * 
             * There is also no access to sheet properties by crossdomain stylesheets, 
             * so we fire callback immediately
             */
            
            var hostname = location.hostname.replace('www.',''),
                hrefHostname = /http:/.test(href) ? /^(\w+:)?\/\/([^\/?#]+)/.exec( href )[2] : hostname;
            hostname != hrefHostname && $.browser.mozilla ?  
                callback()
                :  
                //stylesheet is from the same domain or it is not firefox
                (function(){
                    try {
                        link.sheet.cssRules;
                    } catch (e) {
                        cssTimeout = setTimeout(arguments.callee, 20);
                        return;
                    };
                    callback();
                })();
        };

                
        head.appendChild(link);
    };
    
    this.img = function ( src, callback )
    {
        var img = new Image();
        img.onload = callback;
        img.onerror = addError;
        img.src = src;
    };
    
    /* It works only for css */
    this.disable = function ( name )
    {    
        $('#lazy-loaded-'+name, head).attr('disabled', 'disabled');
    };

    /* It works only for css */
    this.enable = function ( name )
    {    
        $('#lazy-loaded-'+name, head).removeAttr('disabled');
    };
    
    /*
     * By removing js tag, script ist still living in browser memory,
     * css will be really destroyed
     */
    this.destroy = function ( name )
    {
        $('#lazy-loaded-'+name, head).remove();    
    };
    
    function load ( type, url ) {
        self[type](url, function(status) { 
            status == 'error' ? errors.push(url) : loaded.push(url) && s.each(url);
            checkProgress();
        }, 'lazy-loaded-'+ (s.name ? s.name : new Date().getTime()) );
    };
    
    function dispatchCallbacks ( status ) {
        s.complete(status, loaded, errors);
        s[status]( status=='error' ? errors : loaded);
        clearTimeout(tTimeout);
        clearTimeout(cssTimeout);
    };
    
    function checkProgress () {
        if (loaded.length == files.length) dispatchCallbacks('success')
        else if (loaded.length+errors.length == files.length) dispatchCallbacks('error');
    };
    
    function addError () {
        errors.push(this.src);    
        checkProgress();
    };

};

})(jQuery);