﻿/// <reference path="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.5-vsdoc.js" />
/// <reference path="http://ajax.microsoft.com/ajax/jquery.templates/beta1/jquery.tmpl.js" />
/// <reference path="/Scripts/jquery.ba-hashchange.js" />
/// <reference path="/Scripts/underscore.js" />
/// <reference path="/Scripts/BondiTouch.Core.js" />
/// <reference path="/Scripts/BondiTouch.Events.js" />
/// <reference path="Scripts/Utility.js" />

_b.Carousel = {
	blinderFadeInDur: 500, 
	blinderFadeOutDur: 1000,
	blinderOpacity: 0.1
};

_b.Carousel.Page = function (data, imgIdx) {
	///<summary>Instance a new Carousel.Page object with properties</summary>
	///<param name="data" type="anonymous">Page object from controller/data store.</param>
	///<param name="imgIdx" type="integer">Index of this image in the parent pageListing ignoring spreads.</param>
	this.$image = undefined;
	this.index = imgIdx;
	this.x = 0;
	this.duration = 0;
	this.height = 0;
	this.width = 0;
	this.left = 0;
	this.centerX = 0;
	this.pageKey = data.PageKey;
	this.issueKey = data.IssueKey;
	this.sequenceNumber = data.SequenceNumber;
	this.spreadNumber = data.SpreadNumber;
	this.spreadLocation = data.SpreadLocation;
	this.imageWidth = data.ImageWidth;
	this.imageHeight = data.ImageHeight;
	this.pageNames = data.PageNames;
	this.imageFileName = data.ImageFileName;
	this.base64Thumbnail = data.Base64Thumbnail;
	this.aspectRatio = data.AspectRatio;
	
	// multi-res format:
	// - thumb-res, roughly 66x90, base-64 data URL
	// - spread-res, roughly 512x768, zoomed out spread mode (landscape)
	// - page-res, roughly 768x1024, zoomed out page mode (portrait), roughly 1.33x spread-res
	// - high-res, roughly 1024x1536, zoomed in either more, 2x spread-res, roughly 1.5x page-res
	
	this.spreadResWidth = 0;
	this.spreadResHeight = 0;
	this.spreadResUrl = "";
	
	this.pageResWidth = 0;
	this.pageResHeight = 0;
	this.pageResUrl = "";
	
	this.highResWidth = 0;
	this.highResHeight = 0;
	this.highResUrl = "";
	
	this.$thumbResDiv = null;
	this.$spreadResDiv = null;
	this.$pageResDiv = null;
	this.$highResDiv = null;
	
	this.$pageDiv = null;
	
	this.imgID = "p" + data.PageNames;
	this.topMargin = 0;
	this.isLast = false;
	this.parent = undefined;
};

/*______________________________________________________________________________________________________________________________________________________________________________________*/
_b.Carousel.Page.prototype = {

	/*______________________________________________________________________________________________________________________________________________________________________________________*/
	sizeToScreen: function () {
		///<summary>Set image element size and internal properties based on screen size and orientation.</summary>
		// console.log("sizeToScreen: " + this.imgID);
		var aspectWidth, aspectHeight, scaleAdjustment;
		
		if (_b.Core.navState.mode === _b.Core.constants.pageMode) {
			aspectWidth = this.imageWidth;
			aspectHeight = this.imageHeight;
		} else {
			aspectWidth = this.parent.spreadWidth;
			aspectHeight = this.parent.tallestPage;
		}
		
		// TODO this code can definitely be simplified...
		var heightConstrainedAspect = (_b.Core.navState.windowH / aspectHeight);
		var testNewWidth = (heightConstrainedAspect * aspectWidth);
		// Is the new test width too wide?
		if (testNewWidth > _b.Core.navState.windowW) {
			scaleAdjustment = (_b.Core.navState.windowW / aspectWidth);
		}
		else {
			scaleAdjustment = heightConstrainedAspect;
		};
		
		this.width = Math.floor(this.imageWidth * scaleAdjustment);
		this.height = Math.floor(this.imageHeight * scaleAdjustment);
		this.centerX = Math.floor(this.width / 2);
		this.topMargin = Math.floor((_b.Core.navState.windowH - this.height) / 2);
		
		// only calculate spread-res or page-res when we're in that mode
		if (_b.Core.navState.mode === _b.Core.constants.pageMode) {
			this.pageResWidth = this.width;
			this.pageResHeight = this.height;
			this.pageResUrl = this.makeImageUrl(this.pageResWidth, this.pageResHeight);
		} else {
			this.spreadResWidth = this.width;
			this.spreadResHeight = this.height;
			this.spreadResUrl = this.makeImageUrl(this.spreadResWidth, this.spreadResHeight);
		}
		
		// calculate high-res dimensions only once to prevent inconsistencies
		if (this.highResWidth && this.highResHeight) {
			return;
		}
		
		// 2x spread mode if spread size is available, otherwise 1.5x page size.
		// these numbers were picked to make sure we never exceed iOS 2MP limit.
		this.highResWidth = (this.spreadResWidth * 2.0) || Math.floor(this.pageResWidth * 1.5);
		this.highResHeight = (this.spreadResHeight * 2.0) || Math.floor(this.pageResHeight * 1.5);
		this.highResUrl = this.makeImageUrl(this.highResWidth, this.highResHeight);
	},
	
	/*______________________________________________________________________________________________________________________________________________________________________________________*/
	makeImageUrl: function (width, height) {
		return _.template(_b.Uri.collection, {
			issueKey: _b.Core.navState.issueKey,
			pageName: this.pageNames,
			maxHeight: height,
			maxWidth: width
		});
	},
	
	/*______________________________________________________________________________________________________________________________________________________________________________________*/
	createUIObject: function () {
		if (this.$pageDiv) {
			return;
		};
		
		var $pageDiv = this.$pageDiv = $("#pageTemplate").tmpl(this);
		
		// TEMP wanted to smoothly animate size changes to this on re-orient,
		// but this doesn't quite work -- causes only a delayed change. ???
//		$pageDiv.css({
//			// TEMP hardcoding in 500ms, trying it out. should it be variable?
//			webkitTransition: "left, width, height, margin-top 500ms, 500ms, 500ms, 500ms"
//		});
		
		this.$thumbResDiv = $pageDiv.find(".thumb-res");
		this.$spreadResDiv = $pageDiv.find(".spread-res");
		this.$pageResDiv = $pageDiv.find(".page-res");
		this.$highResDiv = $pageDiv.find(".high-res"); 
	},

	/*______________________________________________________________________________________________________________________________________________________________________________________*/
	updateUIObject: function (loadImagery) {
		if (!this.$pageDiv) {
			return;
		};
		
		this.$pageDiv.css({
			left: this.left,
			width: this.width,
			height: this.height,
			marginTop: this.topMargin
		});
		
		// always show thumb res if it's available, nice low-res placeholder.
		var $thumbImg = _b.Core.getThumbImg$(this.pageNames);
		if ($thumbImg) {
			// no explicit sizing necessary, default 100% width/height upscales.
			_b.Utility.setBgImageOnce(this.$thumbResDiv, $thumbImg.attr("src"));
		}
		
		// always show spread res if it's available, even in page mode,
		// because it's a lower-res placeholder in that case.
		// update: but only if we're loading imagery beyond thumb-res.
		if (loadImagery && this.spreadResUrl) {
			// no explicit sizing necessary, default 100% width/height upscales.
			_b.Utility.setBgImageOnce(this.$spreadResDiv, this.spreadResUrl).show();
		} else {
			_b.Utility.clearBgImage(this.$spreadResDiv).hide();
		}
		
		// only show page res if we're in page mode, because it's higher-res
		// than spread-res, so not needed in spread mode.
		// update: and only if we're loading imagery beyond thumb-res.
		if (loadImagery && this.pageResUrl && _b.Core.navState.mode === _b.Core.constants.pageMode) {
			// TEMP hardcoding webkit, TODO support others
			_b.Utility.setBgImageOnce(this.$pageResDiv, this.pageResUrl).show().css({
				width: this.pageResWidth,
				height: this.pageResHeight,
				webkitTransform: "scale3d(" + (this.width / this.pageResWidth) + ", " + (this.height / this.pageResHeight) + ", 1)"
			});
		} else {
			_b.Utility.clearBgImage(this.$pageResDiv).hide();
		}
	},

	/*______________________________________________________________________________________________________________________________________________________________________________________*/
	loadHighRes: function () {
		if (!this.$highResDiv) {
			return;
		}
		
		_b.Utility.setBgImageOnce(this.$highResDiv, this.highResUrl).show().css({
			width: this.highResWidth,
			height: this.highResHeight,
			webkitTransform: "scale3d(" + (this.width / this.highResWidth) + ", " + (this.height / this.highResHeight) + ", 1)"
		});
	},
	
	showHighRes: function () {
		if (!this.$highResDiv) {
			return;
		}
		
		this.$highResDiv.show();
	},

	/*______________________________________________________________________________________________________________________________________________________________________________________*/
	hideHighRes: function () {
		if (!this.$highResDiv) {
			return;
		}
		
		this.$highResDiv.hide();
	},
	
	/*______________________________________________________________________________________________________________________________________________________________________________________*/
	unloadHighRes: function () {
		if (!this.$highResDiv) {
			return;
		}
		
		_b.Utility.clearBgImage(this.$highResDiv).hide().css({
			width: 0,
			height: 0,
			webkitTransform: ""
		});
	},

	/*______________________________________________________________________________________________________________________________________________________________________________________*/
	clearUIObject: function () {
		if (!this.$pageDiv) {
			return;
		}
		
		this.$pageDiv.empty().remove();
		this.$pageDiv = null;
		
		this.$thumbResDiv = null;
		this.$spreadResDiv = null;
		this.$pageResDiv = null;
		this.$highResDiv = null;
	},
	
	/*______________________________________________________________________________________________________________________________________________________________________________________*/
	obsoleteFunctions: function () {
		///<summary>Holding space to keep old code until it si apparent that it is not needed...</summary>
		//	/*______________________________________________________________________________________________________________________________________________________________________________________*/
		//	createUIObject: function () {
		//		/// <summary>Creates the UI Element that corresponds to the parent page object.
		//		/// <para>Future operations will resize, move or destroy this element but it will not overwrite an existing element.</para>
		//		/// </summary>
		//		// console.log("createUIObject: " + this.imgID);
		//		if (this.$image !== undefined) {
		//			// The image already exists, do nuthin.
		//			return false;
		//		};
		//		var $imgElem = $("#imageTemplate").tmpl(this);
		//		var newX = this.x + _b.Core.navState.currentOffset;
		//		$imgElem.css({ height: this.height, width: this.width });
		//		$imgElem.bind("webkitTransitionEnd", function (event) {
		//			if (_b.Core.navState.itemsInTransition > 0) {
		//				_b.Core.navState.itemsInTransition--;
		//				if (_b.Core.navState.itemsInTransition === 0) {
		//					_b.Core.displayPaging(false);
		//				};
		//			};
		//			console.log("Items in transition: " + _b.Core.navState.itemsInTransition);
		//		});
		//		if (!this.isLast) {
		//			$imgElem.css("background-position", "center right");
		//		}
		//		else {
		//			$imgElem.css("background-position", "center left");
		//		};
		//		this.$image = $imgElem;
		//		console.log("added image to object: " + this.$image.attr("id"));
		//	},

		//	/*______________________________________________________________________________________________________________________________________________________________________________________*/
		//	executePagination: function (offsetX, dur) {
		//		///<summary>Execute pagination of the page element. Create the image element or destroy it as necessary.</summary>
		//		// console.log("executePagination: " + this.imgID);
		//		var newX = this.x + offsetX;
		//		if (newX < _b.Core.constants.leftMax || newX > _b.Core.constants.rightMax) {
		//			if (this.$image !== undefined) {
		//				this.$image.remove();
		//				this.$image = undefined;
		//			};
		//		}
		//		else {
		//			if (this.$image === undefined) {
		//				this.createUIObject();
		//				this.$image.appendTo(_b.Core.constants.imageContainer);
		//			};
		//			this.setScreenLocation(newX, dur);
		//		};
		//	},

		//	/*______________________________________________________________________________________________________________________________________________________________________________________*/
		//	setScreenLocation: function (newX, dur) {
		//		///<summary>
		//		/// Use whatever the appropriate method is to set the parent page's UI element offset based on the current page.
		//		/// <para>** Note: This code should be branched to include other kinds of transitions based on browser compatibilities.</para>
		//		/// <para>** Note: This code should include setting values to indicate when the transition has completed in order to prevent stacking.</para>
		//		/// </summary>
		//		// console.log("setScreenLocation: " + this.imgID);
		//		if (this.$image.length !== 0) {
		//			if (_b.Core.navState.vendorSpec === "webkit") {
		//				if (this.lastTransitDur !== -1) {
		//					// The first assignment of a webkit transition value to an image will not excute a physical movement of the image
		//					// and will not fire the webkitTransitionEnd event. Checking the value of css('-webkit-transform' will automatically
		//					// make the assignment of that value to the element with an empty string, thus placing it at the 0-X location and
		//					// forcing the transition to occur. Each new image placed on the screen will then move across the screen to be
		//					// placed in it's correct location after the transition duration has expired.
		//					// console.log("Bump itemsInTransition for: " + this.$image.attr("id") + " duration: " + dur + ", newX: " + newX);
		//					_b.Core.navState.itemsInTransition++;
		//					_b.Core.displayPaging(true);
		//				};
		//				this.lastTransitDur = dur;
		//				this.$image.css("-webkit-transition", "-webkit-transform " + dur + "ms");
		//				this.$image.css("-webkit-transform", "translate3d(" + newX + "px, 0, 0)");
		//				// _b.Core.backstopPager(dur);
		//			};
		//		};
		//	},
	}

};

/*______________________________________________________________________________________________________________________________________________________________________________________*/
_b.Carousel.Spread = function (startPage, sprdIdx) {
	///<summary>Instance a new spread object.</summary>
	///<param name="startPage" type="Carousel.Page">First page to insert into pages collection. Also used to get spread number.</param>
	///<param name="sprdIdx" type="integer">The index that this spread gets in the overall pageListing scheme.</param>
	this.pages = [];
	this.spreadID = "s" + startPage.spreadNumber;
	this.$spreadDiv = undefined;
	this.index = sprdIdx;
	this.x = startPage.x;
	this.width = 0; 			// width as displayed on screen
	this.spreadWidth = 0; 	// original width used for calculating aspect ratio
	this.height = 0; 			// height as displayed on screen
	this.centerX = 0;
	this.spreadNumber = startPage.spreadNumber;
	this.tallestPage = startPage.imageHeight;
	this.lastTransitDur = -1;
	this.paginationTimeout = null; // used during executePagination
};

/*______________________________________________________________________________________________________________________________________________________________________________________*/
_b.Carousel.Spread.prototype = {

	/*______________________________________________________________________________________________________________________________________________________________________________________*/
	createUIObject: function () {
		/// <summary>Creates the UI Element that corresponds to the spread object.
		/// <para>Future operations will resize, move or destroy this element but it will not overwrite an existing element.</para>
		/// </summary>
		if (this.$spreadDiv) {
			return;
		};
		
		var $spreadDiv = this.$spreadDiv = $("#spreadTemplate").tmpl(this);
		
		_.each(this.pages, function (page) {
			page.createUIObject();
			$spreadDiv.append(page.$pageDiv);
		}, this);
		
		// TEMP hardcoding webkit, TODO support others
		$spreadDiv.css({
			webkitTransition: "-webkit-transform 16ms"
		});
		
		// TEMP hardcoding webkit, TODO support others
		$spreadDiv.bind("webkitTransitionEnd", function (event) {
			if (_b.Core.navState.itemsInTransition > 0) {
				_b.Core.navState.itemsInTransition--;
				if (_b.Core.navState.itemsInTransition === 0) {
					_b.Tasks.hidePaging();
				};
			};
		});
		
		var newX = this.x + _b.Core.navState.currentOffset;
		if (newX > 0) {
			newX += (_b.Core.constants.carouselEdgeRight + 1000);
		} else {
			newX += (_b.Core.constants.carouselEdgeLeft + -1000);
		};
		
		// TEMP hardcoding webkit, TODO support others
		this.$spreadDiv.css({
			height: this.height,
			width: this.width,
			webkitTransform: "translate3d(" + newX + "px, 0, 0)"
		});
	},
	
	// updates the UI object's sizes and URLs 
	updateUIObject: function (loadImagery) {
		if (!this.$spreadDiv) {
			return;
		}
		
		_.each(this.pages, function (page) {
			page.updateUIObject(loadImagery);
		}, this);
	},
	
	loadHighRes: function () {
		_.each(this.pages, function (page) {
			page.loadHighRes();
		}, this);
	},
	
	showHighRes: function () {
		_.each(this.pages, function (page) {
			page.showHighRes();
		}, this);
	},
	
	hideHighRes: function () {
		_.each(this.pages, function (page) {
			page.hideHighRes();
		}, this)
	},
	
	unloadHighRes: function () {
		_.each(this.pages, function (page) {
			page.unloadHighRes();
		}, this)
	},

	/*______________________________________________________________________________________________________________________________________________________________________________________*/
	executePagination: function (offsetX, currentIndex, dur) {
		///<summary>Execute pagination of a spread element.</summary>
		var self = this, 
			constants = _b.Core.constants,
			state = _b.Core.navState,
			newX = this.x + offsetX,
			addToDom = newX >= constants.carouselEdgeLeft && newX <= constants.carouselEdgeRight,
			indexDelta = this.index - currentIndex,
			loadImagery = indexDelta >= constants.imageryEdgeLeft && indexDelta <= constants.imageryEdgeRight;
		
		function updateDom () {
			if (!addToDom) {
				self.clearUIObject();
			} else if (!self.$spreadDiv) {
				self.createUIObject();
				self.$spreadDiv.appendTo(constants.imageContainer);
			}
			
			if (addToDom) {
				self.updateUIObject(loadImagery);
			}
		}
		
		var opacityChange = {
			value: 1, 
			dur: _b.Carousel.blinderFadeInDur
		};
		
		if (!dur) {
			updateDom();
			opacityChange.value = (currentIndex == this.index ? 1 : _b.Carousel.blinderOpacity);
			opacityChange.dur = 0;
		} else {
			if (this.paginationTimeout) {
				clearTimeout(this.paginationTimeout);
				this.paginationTimeout = null;
			} 
			
			this.paginationTimeout = setTimeout(function() {
				updateDom();
				self.setScreenLocation(newX, 0, {
					value: (currentIndex == self.index ? 1 : _b.Carousel.blinderOpacity),
					dur: _b.Carousel.blinderFadeOutDur
				});
			}, dur);
		}
		
		this.setScreenLocation(newX, dur, opacityChange);
	},

	/*______________________________________________________________________________________________________________________________________________________________________________________*/
	setScreenLocation: function (newX, dur, opacityChange) {
		///<summary>
		/// Use whatever the appropriate method is to set the parent page's UI element offset based on the current page.
		/// <para>** Note: This code should be branched to include other kinds of transitions based on browser compatibilities.</para>
		/// <para>** Note: This code should include setting values to indicate when the transition has completed in order to prevent stacking.</para>
		/// </summary>
		// console.log("setScreenLocation: " + this.imgID);
		if (!this.$spreadDiv || this.$spreadDiv.length == 0) { return; }

		var state = _b.Core.navState;
		if (state.vendorSpec === "webkit") {
			if (this.lastTransitDur === -1) {
				// The first assignment of a webkit transition value to an image will not excute a physical movement of the image
				// and will not fire the webkitTransitionEnd event. Checking the value of css('-webkit-transform' will automatically
				// make the assignment of that value to the element with an empty string, thus placing it at the 0-X location and
				// forcing the transition to occur. Each new image placed on the screen will then move across the screen to be
				// placed in it's correct location after the transition duration has expired.

				//	this.$spreadDiv.css("margin-top", ((state.windowH * 2) * -1) + "px");
				//	setTimeout(function (spread) {
				//		spread.$spreadDiv.css("margin-top", "0px");
				//	}, (dur * 1.1), this);
			}
			else {
				state.itemsInTransition++;
				_b.Tasks.displayPaging();
			};
			this.lastTransitDur = dur;
			var bez = "cubic-bezier(0.00, 0.40, 0.80, 1.00)";
			var lastCss = this.$spreadDiv.css("-webkit-transform"),
				transitionSpread = function (spread) {
					var transition = "-webkit-transform " + dur + "ms " + bez
						+ ", opacity " + opacityChange.dur + "ms linear";
						
					spread.$spreadDiv.css({
						"-webkit-transition": transition,
						"-webkit-transform": "translate3d(" + newX + "px, 0, 0)",
						opacity: opacityChange.value
					});
				};

			if (lastCss === "none") {
				var offset = newX;
				if (newX < state.windowCtrX) {
					offset = (state.windowW + this.width) * -1;
				}
				else {
					offset = state.windowW * 2;
				};
				setTimeout(transitionSpread, 300, this);
				this.$spreadDiv.css("-webkit-transform", "translate3d(" + offset + "px, 0, 0)");
			}
			else {
				transitionSpread(this);
			}
			_b.Tasks.backstopPager(undefined, dur);
		} else { /* TBD: handle other browsers */ }
	},

	/*______________________________________________________________________________________________________________________________________________________________________________________*/
	sizeSpreadToScreen: function () {
		///<summary>Set spread size values based on contained image size values.</summary>
		// console.log("sizeSpreadToScreen: " + this.SpreadNumber);
		var totalWidth = 0;
		for (i = 0; i < this.pages.length; i++) {
			totalWidth += this.pages[i].width;
		};
		this.width = parseInt(totalWidth);
		var tallestH = this.pages[0].height;
		for (var iPg = 0; iPg < this.pages.length; iPg++) {
			if (this.pages[iPg].height > tallestH) {
				tallestH = this.pages[iPg].height;
			};
			if (iPg > 0) {
				this.pages[iPg].left = this.pages[iPg - 1].width;
			};
		};
		this.height = tallestH;
		this.centerX = parseInt(totalWidth / 2);
	},

	/*______________________________________________________________________________________________________________________________________________________________________________________*/
	cleanUp: function () {
		///<summary>Assigns the tallestPage, spreadWidth and child page parent objects to all contents.</summary>
		this.pages[this.pages.length - 1].isLast = true;
		for (var i = 0; i < this.pages.length; i++) {
			var pg = this.pages[i];
			pg.parent = this;
			this.spreadWidth += pg.imageWidth;
			if (pg.imageHeight > this.tallestPage) {
				this.tallestPage = pg.imageHeight;
			};
		};
	},

	/*______________________________________________________________________________________________________________________________________________________________________________________*/
	clearUIObject: function () {
		if (!this.$spreadDiv) {
			return;
		}
		
		_.each(this.pages, function (page) {
			page.clearUIObject();
		}, this);
		
		this.$spreadDiv.empty().remove();
		this.$spreadDiv = null;
	},

	/*______________________________________________________________________________________________________________________________________________________________________________________*/
	drag: function (dragDistance, dur, opacityChange) {
		/// <summary>Moves the current spread the appropriate distance from the current offset.</summary>
		if (this.$spreadDiv) {
			dur = dur || 0;
			var ease = (dur ? " ease-out" : "");
			var state = _b.Core.navState;
			if (state.vendorSpec === "webkit") {
				var newX = this.x + dragDistance + state.currentOffset;
				// console.log("spread " + this.spreadID + " is being moved " + newX);
				var transition = "-webkit-transform " + dur + "ms" + ease
						+ ", opacity " + opacityChange.dur + "ms linear";
						
				this.$spreadDiv.css({
					"-webkit-transition": transition,
					"-webkit-transform": "translate3d(" + newX + "px, 0, 0)", 
					opacity: opacityChange.value
				});
			}
			else {
				// Other browsers
			};
		};
	}

};

/*______________________________________________________________________________________________________________________________________________________________________________________*/
_b.Carousel.PageListing = function () {
	///<summary>Instance a new PageListing object.</summary>
	this.spreads = [];
};

/*______________________________________________________________________________________________________________________________________________________________________________________*/
_b.Carousel.PageListing.prototype = {

	/*______________________________________________________________________________________________________________________________________________________________________________________*/
	clearSpreads: function () {
		/// <summary>Empty all spread objects in the current PageListing spreads array. No changes to the UI happen here.</summary>
		this.spreads = [];
	},

	/*______________________________________________________________________________________________________________________________________________________________________________________*/
	resizeImages: function () {
		/// <summary>Resize each spread and image object in pageListing based on current state size values.</summary>	
		// console.log("resizeImages");
		var lastX = 0;
		for (var i = 0; i < this.spreads.length; i++) {
			var sprd = this.spreads[i];
			sprd.x = lastX;
			for (var iPg = 0; iPg < sprd.pages.length; iPg++) {
				var pg = sprd.pages[iPg];
				pg.sizeToScreen();
				pg.x = lastX;
				lastX += pg.width;
				if (pg.isLast) {
					lastX += _b.Core.constants.pageMargin;
				};
			};
			sprd.sizeSpreadToScreen();
		};
	},

	/*______________________________________________________________________________________________________________________________________________________________________________________*/
	getSpreadByIndex: function (idx) {
		///<summary>Cycle through all spreads in the parent object and return the spread object at the appropriate index.</summary>
		return (this.spreads[idx]);
	},

	/*______________________________________________________________________________________________________________________________________________________________________________________*/
	getPageByIndex: function (idx) {
		///<summary>Cycle through all pages in all spreads in the parent object and return the page object at the appropriate index.</summary>
		var currIdx = -1;
		for (var i = 0; i < this.spreads.length; i++) {
			for (var iPg = 0; iPg < this.spreads[i].pages.length; iPg++) {
				currIdx++;
				if (currIdx === idx) {
					return (this.spreads[i].pages[iPg]);
					break;
				};
			};
		};
	},

	/*______________________________________________________________________________________________________________________________________________________________________________________*/
	getCurrentPage: function () {
		var idx = _b.Core.navState.currentIndex;
		return this.getPageByIndex(idx);
	},

	/*______________________________________________________________________________________________________________________________________________________________________________________*/
	getPageByName: function (targetPage) {
		for (var i = 0; i < this.spreads.length; i++) {
			for (var iPg = 0; iPg < this.spreads[i].pages.length; iPg++) {
				if (this.spreads[i].pages[iPg].pageNames === targetPage) {
					return (this.spreads[i].pages[iPg]);
					break;
				};
			};
		};
	},

	/*______________________________________________________________________________________________________________________________________________________________________________________*/
	executeIssuePagination: function (newX, dur) {
		///<summary>Execute pagination functions for all pages in the spreads collection.</summary>
		// console.log("executeIssuePagination: newX: " + newX + ", dur: " + dur);
		//TODO: Make sure we are paginating spreads in the correct order.
		var currentIndex = this.getCurrentSpread().index;
		for (var i = 0; i < this.spreads.length; i++) {
			this.spreads[i].executePagination(newX, currentIndex, dur);
		};
	},

	/*______________________________________________________________________________________________________________________________________________________________________________________*/
	getPages: function () {
		///<summary>Return all pages in the current listing in order.</summary>
		var ret = [];
		for (var i = 0; i < this.spreads.length; i++) {
			for (var iPg = 0; iPg < this.spreads[i].pages.length; iPg++) {
				ret.push(this.spreads[i].pages[iPg]);
			};
		};
		return ret;
	},

	/*______________________________________________________________________________________________________________________________________________________________________________________*/
	getNextIndex: function (increments) {
		if (_b.Core.navState.mode === "p") {
			if (_b.Core.navState.currentIndex >= 0) {
				var nextPageIdx = (_b.Core.navState.currentIndex + increments);
				var pg = this.getPageByIndex(nextPageIdx);
				if (pg) {
					return pg.index;
				}
				else {
					return -1;
				};
			}
			else {
				return -1;
			};
		}
		else {
			var spreadIdx = this.getPageByIndex(_b.Core.navState.currentIndex).parent.index;
			if (spreadIdx >= 0) {
				var nextSpreadIdx = (spreadIdx + increments);
				var spread = this.getSpreadByIndex(nextSpreadIdx);
				if (spread) {
					return spread.pages[0].index;
				}
				else {
					return -1;
				};
			}
			else {
				return -1;
			};
		};
	},

	/*______________________________________________________________________________________________________________________________________________________________________________________*/
	getCurrentSpread: function () {
		return this.getCurrentPage().parent;
	},

	/*______________________________________________________________________________________________________________________________________________________________________________________*/
	clearUIObjects: function () {
		///<summary>Removes all current UI objects </summary>
		_.each(this.spreads, function (spreadObject) {
			spreadObject.clearUIObject();
		});
	},

	/*______________________________________________________________________________________________________________________________________________________________________________________*/
	drag: function (dragDistance, dur, options) {
		/// <summary>Execute drag on all spreads in the pageListing</summary>
		var resetBlinders = (options && options.resetBlinders);
		var opacityChange = {
			value: 1,
			dur: (resetBlinders ? _b.Carousel.blinderFadeOutDur 
				: _b.Carousel.blinderFadeInDur)
		};
		
		var currentSpread = this.getCurrentSpread();
		_.each(this.spreads, function (spreadObject) {
			opacityChange.value = (resetBlinders && spreadObject != currentSpread 
				? _b.Carousel.blinderOpacity : 1);
			spreadObject.drag(dragDistance, dur, opacityChange);
		});
	}

};


