Source: resource/Requester.js

//------------------------------------------------------------------------------
// Constructor scope
//------------------------------------------------------------------------------

/**
 * Creates a new instance of the Requester class.
 *
 * @constructor
 *
 * @class
 * @classdesc
 * 
 * The Requester class uses URLLoader to download resource files. Once a file 
 * is downloaded, it is automatically added to a resource library and thus 
 * made available during runtime.
 */
rune.resource.Requester = function(resources) {
    
    /**
     * Request options.
     *
     * @type {rune.resource.RequesterOptions}
     * @private
     */
    this.m_arguments = null;
    
    /**
     * The URLLoader used to retrieve requested files.
     *
     * @type {rune.net.URLLoader}
     * @private
     */
    this.m_loader = null;
    
    /**
     * The number of files that have been requested.
     *
     * @type {number}
     * @private
     */
    this.m_numRequests = 0;
    
    /**
     * Reference to the resource library to which downloaded files should 
     * be added.
     *
     * @type {rune.resource.Resources}
     * @private
     */
    this.m_resources = resources;
};

//------------------------------------------------------------------------------
// Public prototype getter and setter methods
//------------------------------------------------------------------------------

/**
 * The download progression represented by a floating point number between 
 * 0 and 1.
 *
 * @member {number} progress
 * @memberof rune.resource.Requester
 * @instance
 * @readonly
 */
Object.defineProperty(rune.resource.Requester.prototype, "progress", {
    /**
     * @this rune.resource.Requester
     * @ignore
     */
    get : function() {
        if (this.m_arguments) {
            return 1 - (this.m_arguments['batch']['length'] / this.m_numRequests);
        }
        
        return 0;
    }
});

//------------------------------------------------------------------------------
// Public prototype methods (API)
//------------------------------------------------------------------------------

/**
 * Cancels file downloads.
 *
 * @returns {undefined}
 */
rune.resource.Requester.prototype.abort = function() {
    this.m_disposeLoader();
    if (this.m_arguments) {
        this.m_arguments.exec("onAbort");
    }
};

/**
 * Begins downloading a batch of requested files.
 *
 * @param {Object} options Loader options.
 *
 * @returns {undefined}
 */
rune.resource.Requester.prototype.load = function(options) {
    this.m_constructArguments(options);
    this.m_constructLoader();
    this.m_processRequests();
};

//------------------------------------------------------------------------------
// Internal prototype methods
//------------------------------------------------------------------------------

/**
 * Clears this object from memory.
 *
 * @returns {undefined}
 * @package
 * @ignore
 */
rune.resource.Requester.prototype.dispose = function() {
    this.m_disposeLoader();
    this.m_disposeArguments();
    
    this.m_resources = null;
};

//------------------------------------------------------------------------------
// Private prototype methods
//------------------------------------------------------------------------------

/**
 * Creates the RequesterOptions object.
 *
 * @returns {undefined}
 * @private
 */
rune.resource.Requester.prototype.m_constructArguments = function(options) {
    this.m_disposeArguments();
    if (this.m_arguments == null) {
        this.m_arguments = new rune.resource.RequesterOptions(options);
        this.m_numRequests = this.m_arguments['batch']['length'];
    }
};

/**
 * Creates the URLLoader object.
 *
 * @returns {undefined}
 * @private
 */
rune.resource.Requester.prototype.m_constructLoader = function() {
    this.m_disposeLoader();
    if (this.m_loader == null) {
        this.m_loader = new rune.net.URLLoader();
    }
};

/**
 * Deletes the RequesterOptions object.
 *
 * @returns {undefined}
 * @private
 */
rune.resource.Requester.prototype.m_disposeArguments = function() {
    if (this.m_arguments instanceof rune.resource.RequesterOptions) {
        this.m_arguments.dispose();
        this.m_arguments = null;
    }
};

/**
 * Deletes the URLLoader object.
 *
 * @returns {undefined}
 * @private
 */
rune.resource.Requester.prototype.m_disposeLoader = function() {
    if (this.m_loader instanceof rune.net.URLLoader) {
        this.m_loader.abort();
        this.m_loader = null;
    }
};

/**
 * Processes available requests. If the initial number of requests is zero, 
 * the callback is executed from the event loop. This is so that all callback 
 * calls are executed "asynchronously".
 *
 * @returns {undefined}
 * @private
 */
rune.resource.Requester.prototype.m_processRequests = function() {
    if (this.m_arguments) {
        var request = this.m_arguments['batch'].shift();
        if (request) {
            this.m_processRequest(request);
        } else {
            if (this.m_numRequests == 0) {
                var m_this = this;
                window.setTimeout(function() {
                    m_this.m_arguments.exec("onComplete");
                }, 0);
            } else {
                this.m_arguments.exec("onComplete");
            }
        }
    } else throw new Error();
};

/**
 * Processing a specific request.
 *
 * @param {rune.resource.Request} request Request to process.
 *
 * @returns {undefined}
 * @private
 */
rune.resource.Requester.prototype.m_processRequest = function(request) {
    if (this.m_loader) {
        this.m_loader.load({
            url: request['path'],
            onComplete: function(response) {
                response.asEncodedResource(function(obj) {
                    this.m_resources.add(request['name'], obj);
                    this.m_arguments.exec("onProgress", [
                        this['progress'], 
                        request['name'], 
                        response['size'],
                        response['type'],
                        obj
                    ]);
                    
                    request.dispose();
                    request = null;
                    
                    this.m_processRequests();
                }, this);
            },
            onError: function() {
                this.m_arguments.exec("onError", [
                    request['name']
                ]);
            },
            scope: this
        });   
    } else throw new Error();
};