var Loader = {
	
	// jLoader
	
	jLoader : null,
	
	// load method
	
	loadingMethod : "singular",
	
	// load boxes
	
	setup : [],
	queue : [],
	loading : [],
	completed : [],
	errored : [],
	
	// load counts
	
	countGlobal : 0,
	countLocal : 0,
	initialCount : 0,
	
	// progress

	weightTotal : 0,
	weightLoaded : 0,

	loadedCountLocal : 0,
	loadedCountGlobal : 0,
	loadedTotalLocal : 0,
	loadedTotalGlobal : 0,
	
	loadedPercentLocal : 0,
	loadedPercentGlobal : 0,
	weightedLoadedPercent : 0,
	
	// last loaded
	
	lastLoaded : null,
	
	// events
	
	COMPLETE : "complete",
	PROGRESS : "progress",
	FILE_COMPLETE : "fileComplete",
	ERROR : "error",
	ESTIMATE : "estimate",
	
	// load methods
	
	SINGULAR : "singular",
	MULTIPLE : "multiple",
	
	// loadBoxes
	
	SETUP : "setup",
	QUEUE : "queue",
	LOADING : "loading",
	COMPLETED : "completed",
	ERRORED : "errored",
	
	////////////////////////////////////////////////////////
	// Private Methods
	////////////////////////////////////////////////////////
	
	loadImage : function(imageDetails)
	{
		var image = new Image();
		var imageObj = $(image);
		Loader.loading.push(Loader.queue.splice(Loader.findIndexInArray(imageDetails, Loader.queue), 1)[0]);
		imageDetails.loadingTime = new Date().getTime();
		imageDetails.content = image;
		imageObj	.load(function() { Loader.imageLoaded(imageDetails); })
					.error(function(e) { Loader.imageErrored(imageDetails, e); })
					.attr("src", imageDetails.url);
	}, // loadImage
		
	completeTest : function()
	{
		if(Loader.loading.length === 0 && Loader.queue.length === 0) {
			Loader.jLoader.trigger(Loader.COMPLETE);
		} else if(Loader.loadingMethod == Loader.SINGULAR) {
			Loader.loadImage(Loader.queue[0]);
		}
	}, // completeTest
	
	////////////////////////////////////////////////////////
	// Data Manipulation
	////////////////////////////////////////////////////////
	
	findIndexInArray : function(toSearch, array)
	{
		for(var i = 0 ; i < array.length ; i ++) if(array[i] === toSearch) return i;
		return -1;
	}, // findIndexInArray
	
	addDefaultProperties : function(obj) // adds all the default properties to a loader
	{
		Loader.countLocal ++;
		Loader.countGlobal ++;
		obj.guid = Loader.countGlobal;
		obj.lid = Loader.countLocal;	
		obj.name = Loader.getNameFromURL(obj.url);
		obj.extension = Loader.getExtensionFromURL(obj.url);
		obj.location = Loader.getLocationFromURL(obj.url);
		obj.priority = obj.priority || 1;
		obj.weight = obj.weight || 1;
	}, // addDefaultProperties
	
	filterItems : function(items) // takes a string/array/object and turns it into a uniform object format
	{
		switch(items.constructor) {
			case Array :
				for(var item in items) Loader.filterItems(items[item]);
				break;
			case String :
				Loader.filterItems({ url:items });
				break;
			case Object :
				if(typeof(items.url) != "undefined" && items.url != "") {
					Loader.addDefaultProperties(items);
					Loader.setup.push(items);
				}
				break;
		}
	}, // filterItems
	
	getLocationFromURL : function(url) // extracts the location path from the url
	{
		return url.slice(0, url.lastIndexOf('/') + 1);
	}, // getLocationFromURL
	
	getNameFromURL : function(url) // extracts the name from the url eg images/image1.jpg will be image1
	{
		return url.lastIndexOf(".") == -1 ? url.slice(url.indexOf("/") + 1) : url.slice(url.lastIndexOf('/') + 1, url.lastIndexOf('.'));
	}, // getNameFromURL
	
	getExtensionFromURL : function(url) // extracts the extension of the file from the url eg images/image1.jpg will be .jpg
	{
		return url.slice(url.lastIndexOf('.') + 1);
	}, // getExtensionFromURL
	
	searchArray : function(value, property, array) // searches an array of objects to match a value on a property, eg search for the value images/image1.jpg on property url in the array loaded
	{
		var result = false;
		property = property.toLowerCase();
		value = value.toLowerCase();
		for(var i in array) {
			if(String(array[i][property]).toLowerCase() == value) {
				result = array[i];
				break;
			}
		}
		return result;
	},

	////////////////////////////////////////////////////////
	// Bind Handlers
	////////////////////////////////////////////////////////

	imageLoaded : function(imageDetails)
	{
		imageDetails.loadedTime = new Date().getTime();
		imageDetails.loadTime = imageDetails.loadedTime - imageDetails.loadingTime;
		Loader.loadedCountLocal ++;
		Loader.loadedCountGlobal ++;
		Loader.weightLoaded += imageDetails.weight;
		
		Loader.loadedPercentLocal = Loader.loadedCountLocal / Loader.loadedTotalLocal;
		Loader.loadedPercentGlobal = Loader.loadedCountGlobal / Loader.loadedTotalGlobal;
		Loader.weightedLoadedPercent = Loader.weightLoaded / Loader.weightTotal;
		
		Loader.lastLoaded = imageDetails;
		Loader.completed.push(Loader.loading.splice(Loader.findIndexInArray(imageDetails, Loader.loading), 1)[0]);
		Loader.jLoader.trigger(Loader.FILE_COMPLETE);
		Loader.completeTest();
	}, // imageLoaded
	
	imageErrored : function(imageDetails, e)
	{
		imageDetails.error = e;
		Loader.errored.push(Loader.loading.splice(Loader.findIndexInArray(imageDetails, Loader.loading), 1)[0]);
		Loader.jLoader.trigger(Loader.ERROR);
	}, // imageErrored
	
	////////////////////////////////////////////////////////
	// Public
	////////////////////////////////////////////////////////
	
	load : function(items)
	{
		if(Loader.jLoader == null) Loader.jLoader = $(Loader);
		Loader.countLocal = 0;
		Loader.filterItems(items);
		return Loader;
	}, // load
	
	start : function()
	{
		Loader.loadedCountLocal = 0;
		Loader.loadedTotalLocal = 0;
		Loader.loadedPercentLocal = 0;
			
		Loader.loadedTotalLocal = Loader.setup.length;
		Loader.loadedTotalGlobal += Loader.setup.length;
		
		Loader.weightLoaded = 0;
		Loader.weightTotal = 0;
		
		for(var loader in Loader.setup) Loader.weightTotal += Loader.setup[loader].weight;
		
		while(Loader.setup.length > 0) Loader.queue.push(Loader.setup.splice(0, 1)[0]);
			
		if(Loader.loadingMethod == Loader.MULTIPLE) {
			while(Loader.queue.length > 0) Loader.loadImage(Loader.queue[0]);
		} else {
			Loader.loadImage(Loader.queue[0]);
		}
		return Loader;
	}, // start
	
	getContent : function(value, property)
	{
		if(!property || typeof(property) == "undefined") property = "url";
		return Loader.searchArray(value, property, Loader.completed).content;
	}, // getContent
	
	getContentAsCopy : function(value, property)
	{
		if(!property || typeof(property) == "undefined") property = "url";
		var img = new Image();
		$(img).attr({ src:Loader.searchArray(value, property, Loader.completed).url });
		return img;
	}
	
} // loader
