if(detectBrowser.modernBrowser()){

//
// Set of image ranges, each of which has a subset of images.
//

var ImageSet = Class.create();
Object.extend(ImageSet.prototype, Enumerable);
Object.extend(ImageSet.prototype,{
	// construct an image set.
	// @element is an element within which to seek out already-loaded sets in the DOM
	initialize:function(element){

		// parse a range string like startToken_INT_INT
		function parseRange(classNames,startToken){
			var tokens = classNames.find(function(item){ return (typeof(item)=="string" && item.indexOf(startToken)==0); });
			return {'start':parseInt(tokens.split("_")[1]),'end':parseInt(tokens.split("_")[2])};
		}

		// return a set of sets
		this.loadedsets = element.getElementsBySelector("ol.images").map(function(imageList){
			var classnames = $A(imageList.classNames());
			return {
				'range':parseRange(classnames,"range_"),
				'extents':parseRange(classnames,"extents_"),
				'images':imageList.getElementsBySelector("li.image").map(function(imageListElement){
					// if we have a placeholder image, just return a stub
					if ($A(imageListElement.classNames()).include("placeholder")) return {'placeholder':true};
					// return a fully-formed image if we have a real image
					var result = {
						
						'versions':{
							'thumbnail_small':imageListElement.getElementsBySelector("a.thumbnail_small")[0].readAttribute("href").strip()
							
						}
					};
					imageListElement.getElementsBySelector("a").each(function(img){
						var imageKey = $A(img.classNames()).find(function(token){ // find first token matching INTxINT
							return token.split("x").length > 1 && parseInt(token.split("x")[0]) > -1 && parseInt(token.split("x")[1]) > -1;
						});
						// This image fits the pattern and is something like "1024x768". Append to result as another version.
						if(typeof(imageKey)!='undefined') result['versions'][imageKey] = img.readAttribute("href").strip();
					});
					return result;
				})
			};
		});
	},

	isRealImage:function(range,index){ // assumes range exists, assumes it is loaded
		return this.getRange(range)['images'][index]['placeholder']!=true;
	},

	getRangeIndex:function(range){	// assumes range exists
		for(var i=0;i<this.loadedsets.length;i++)
			if(ImageSet.prototype.compareRange(this.loadedsets[i]['range'],range))
				return i;
	},

	getRangeAfter:function(range){
		for(var i=0;i<this.loadedsets.length;i++)
			if(ImageSet.prototype.compareRange(this.loadedsets[i]['range'],range) && (i + 1 < this.loadedsets.length))
				return this.loadedsets[i + 1]['range'];
	},

	getRangeBefore:function(range){
		for(var i=0;i<this.loadedsets.length;i++)
			if(ImageSet.prototype.compareRange(this.loadedsets[i]['range'],range) && (i - 1 >= 0))
				return this.loadedsets[i - 1]['range'];
	},

	findRangeByImage:function(imageItem){
		var result;
		var matchingSet = this.loadedsets.find(function(loadedSet,i){ return loadedSet['images'].include(imageItem); });
		if(matchingSet) result = matchingSet['range'];
		// return undefined if not found
		return result;
	},

	// external code must be able to fetch the "first" range block. Return a range in format {start:int,end:int}
	getFirstRange:function(){
		return this.loadedsets[0]['range'];
	},

	// compare two ranges in format {start:int,end:int}, return true if they are the same
	compareRange:function(range1,range2){
		return typeof(range1)=='object' && typeof(range2)=='object' && range1!=null && range2!=null && parseInt(range1['start'])==parseInt(range2['start']) && parseInt(range1['end'])==parseInt(range2['end']);
	},

	getRange:function(range){
		var result = this.loadedsets.find(function(aSet){
			return ImageSet.prototype.compareRange(aSet.range,range);
		}.bind(this));
		
		if(!result){
			// TODO check if range is within the total extents, and load
		}
		
		return result;
	},

	loadRangeAsync:function(range,url,callbackFunc){
		console.debug("loadRangeAsync: loading range",range);
		// TODO load a range, run a callback function after finish.
		new Ajax.Request(url,{
			method:'get',
			onSuccess:function(transport){
				console.debug("results of query (transport object):",transport);
			}
		});
	},

	rangeLoaded:function(range){
		return typeof(this.loadedsets.find(function(aSet){ return ImageSet.prototype.compareRange(aSet.range,range); }.bind(this)))!='undefined';
	},

	// return all ranges in the entire extent, whether they are loaded or not.
	allRangesInExtent:function(iterator){
		var rangeLength = (parseInt(this.loadedsets[0]['range']['end']) - parseInt(this.loadedsets[0]['range']['start'])) + 1;
		// NB: this might break if rangelength is not a nice number like 10, 20, etc
		var rangeCeiling = Math.ceil(this.loadedsets[0]['extents']['end'] / rangeLength) * rangeLength;
		return $A($R(0,(rangeCeiling / rangeLength) - 1)).map(function(i){
			return {
				'start':(i*(rangeLength)) + 1,
				'end':((i+1)*(rangeLength))
			};
		});
	},

	// _each is a function required by the Enumerable mix-in
	// _each will iterate over each SUBSET of images, not all images
	_each: function(iterator) {
		for (var i = 0, length = this.loadedsets.length; i < length; i++) iterator(this.loadedsets[i]);
	}

});

}// end modern browser check

