/*
  ImagePreloadQueue - Controls the loading order of images in HTML documents

      This code is released under the GPL
      see preloader.txt for details and documentation

  March 4th 2007 - revision II
*/

function ImagePreloadQueue( maxConcurrency ) {
	if( !maxConcurrency ) maxConcurrency = 2;
	var loadedImageUrls = [];
	var loadingImageUrls = [];
	var imageQueue = [];

	// return the index of the first element for which the function pred(el) returns true, return null if none
	function findFirst( ar, pred ) {
		for( var i = 0; i < ar.length; i++ ) {
			if( pred( ar[i] ) ) {
				return i;
			}
		}
		return null;
	}
	
	// remove and return the first element for which the function pred(el) returns true, return null if none
	function removeFirst( ar, pred ) {
		var i = findFirst( ar, pred );
		return( i != null ? ar.splice( i, 1 )[0] : null );
	}

	function removeUrlFromArray( ar, imageUrl ) {
		return removeFirst( ar, function(x) {return( x == imageUrl );} );
	}

	function removeImageFromArray( ar, imageUrl ) {
		return removeFirst( ar, function(x) {return( x.src == imageUrl );} );
	}

	function busy() {
		return( loadingImageUrls.length >= maxConcurrency );
	}

	function imageLoaded( imageUrl ) {
		loadedImageUrls.push( imageUrl );
		return( removeUrlFromArray( loadingImageUrls, imageUrl ) );
	}

	function isLoaded( imageObj ) {
		return( null != findFirst( loadedImageUrls, function(x) {return( x == imageObj.src );} ) );
	}

	function isLoading( imageObj ) {
		return( null != findFirst( loadingImageUrls, function(x) {return( x == imageObj.src );} ) );
	}

	function addToQueue( imageObj, adder ) {
		if( !isLoaded( imageObj ) && !isLoading( imageObj ) ) {
			removeImageFromArray( imageQueue, imageObj.src ); // if the image is already in the queue remove it.
			adder.call( imageQueue, imageObj );
			if( !busy() )
				loadNext();
		}
	}
	
	function loadNext() {
		if( imageQueue.length == 0 ) {
			return;
		}
		loadingImageUrls.push( imageQueue[0].src );
		var pseudoImage = imageQueue.shift();
		var realImage = new Image();
		function removeEvents( obj ) {
			obj.onload = null;
			obj.onerror = null;
			obj.onabort = null;
		}
		realImage.onload = function() {
			removeEvents( this );
			imageLoaded( pseudoImage.src );
			if( pseudoImage.onload )
				pseudoImage.onload();
			loadNext();
		}
		realImage.onerror = function() {
			removeEvents( this );
			if( pseudoImage.onerror )
				pseudoImage.onerror();
			removeUrlFromArray( loadingImageUrls, pseudoImage.src );
			loadNext();
		}
		realImage.onabort = function() {
			removeEvents( this );
			if( pseudoImage.onabort )
				pseudoImage.onabort();
			removeUrlFromArray( loadingImageUrls, pseudoImage.src );
			loadNext();
		}
		realImage.src = pseudoImage.src;
	}

	// Public functions
	this.addToFront = function( imageObj ) {
		addToQueue( imageObj, Array.prototype.unshift );
	}
	
	this.addToBack = function( imageObj ) {
		addToQueue( imageObj, Array.prototype.push );
	}
	
	this.addArrayToBack = function( imageObjArray ) {
		for( var i = 0; i < imageObjArray.length; i++ ) {
			this.addToBack( imageObjArray[i] );
		}
	}
}

// Utility

ImagePreloadQueue.prototype.backgroundReplacer = function( el, imageUrl ) {
	return( {
		src: imageUrl,
		onload: function () {
			el.style.backgroundImage = "url('" + imageUrl + "')";
		}
	} );
}
