/**
 * Site class
 * 
 * General site functionality class
 * Handles:
 *     - adding load events with support for passing arguments and binding
 *     - preloading images
 *     
 * NOTE - singleton class - use Site.getInstance to instantiate and get a handle on it
 * 
 * @author alec hill
 */

/**
 * constructor
 */
function Site(){
    // check that this is being instatiated from getInstance by checking the static INSTANTIATING flag
    if(!Site.INSTANTIATING) throw new Error('Site::constructor - you must use Site.getInstance() to instatiate a Site object')
    this.initialize();
}

/**
 * getInstance static method - sets up or gets the current instance of site
 */
Site.getInstance = function(){
    if(!Site._instance){
        Site.INSTANTIATING = true;
        Site._instance = new Site();
        Site.INSTANTIATING = false;
    }
    return Site._instance;
}

/**
 * Site prototype
 */
Site.prototype = {
    
    _loadEvents: null,
    _preloadedImages: null,
    
    /**
     *
     * initialize
     *
     * performs initial setup of the object
     */
    initialize: function(){
        // initialise properties that cannot be initialised in the prototype
        this._loadEvents = [];
        this._preloadedImages = [];
        // add current window.onload event if previously defined
        if( typeof window.onload == 'function' ) this.addLoadEvent(window.onload);
        // set up the new window.onload
        var self = this;
        window.onload = function(e){ self._onWindowLoad(e); }
    },
    
    /**
     * _onWindowLoad
     *
     * Called when the window has loaded. 
     * Executes the functions that have been added to the _loadEvents array
     * 
     * @var e {Event}
     */
    _onWindowLoad: function(e){
        for( var i = 0, len = this._loadEvents.length; i < len; i++ ){
            var obj = this._loadEvents[i];
            obj.func.apply( obj.bind, obj.args );
        }
    },
    
    /**
     * addLoadEvent
     *
     * adds a function to run on the window.onload event
     *
     * @var func {Function} - reference to function to add
     * @var args {Array} - an array of arguments to be passed to the function
     * @var bind {Object} - the object to to which 'this' will refer to within the scope of the function
     */
    addLoadEvent: function(func, args, bind){
        if( typeof func != 'function' ) throw new Error('Site::addLoadEvent - supplied argument must be a function!'); 
        this._loadEvents.push( { func: func, args: args || [], bind: bind || window } );
    },
    
    /**
     * preload
     *
     * preloads an image
     *
     * @var src {String} - the src of the image to preload
     */
    preload: function(src){
        var image = new Image();
        image.src = src;
        this._preloadedImages.push( image ); 
    },
    
    /**
     * preloadImages
     *
     * preloads multiple images
     *
     * @var srcArray {Array} - array of the src strings of the images to preload
     */
    preloadImages: function(srcArray){
        for( var i = 0, len = srcArray.length; i < len; i++ ){
            this.preload( srcArray[i] );
        } 
    }

}