﻿/// <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="debugversions/underscore.js" />
/// <reference path="debugversions/jquery.ba-dotimeout.js" />
/// <reference path="/Scripts/BondiTouch.Utility.js" />
/// <reference path="/Scripts/BondiTouch.Workflow.js" />
/// <reference path="/Scripts/BondiTouch.ClientCache.js" />
/// <reference path="/Scripts/BondiTouch.Core.js" />
/// <reference path="/Scripts/BondiTouch.Search.js" />

_b.Tasks = {
	pageLoadingShown: false, 

	/*______________________________________________________________________________________________________________________________________________________________________________________*/
	returnCall: function (callback, status) {
		if (callback) {
			status = status + "_Done";
			callback(status);
		};
	},

	/*______________________________________________________________________________________________________________________________________________________________________________________*/
	cacheState: function (callback) {
		/// <summary>Caches a shallow copy of the current nav state, removing the page property before caching</summary>
		/// <param name="callback" type="function">Success callback function("state")</param>
		var core = _b.Core,
			simpleState = $.extend({}, core.navState);
		delete simpleState.page;
		_b.ClientCache.cacheObject(core.constants.issueSubCache, "state", simpleState);
		//add secondary cache entry	for use by app loading page (html5 browsers only)
		//_b.ClientCache.cacheObject("app", "urlState", location.href);
		this.setUrlState(null, location.href);
		this.returnCall(callback, "cacheState");
	},

	/*______________________________________________________________________________________________________________________________________________________________________________________*/
	checkIssueState: function (callback) {
		/// <summary> Check if the current issue is different from that stored in the cache, if so clear the issue cache </summary>
		/// <param name="callback" type="function">Success callback function("state")</param>
		var core = _b.Core,
			cachedState = _b.ClientCache.getCachedObject(core.constants.issueSubCache, "state");
		if (cachedState && core.navState.issueKey !== cachedState.issueKey) {
			_b.ClientCache.clearSubCache(core.constants.issueSubCache);
		};
		this.returnCall(callback, "checkIssueState");
	},

	/*______________________________________________________________________________________________________________________________________________________________________________________*/
	resumeToUrlState: function(callback) {
		var urlState = BondiTouch.ClientCache.getCachedObject("app", "urlState");
		if (urlState && !document.referrer.length) {
			location.href = urlState;
		}
		//else
		this.returnCall(callback, "resumeToUrlState");
	},
	/*______________________________________________________________________________________________________________________________________________________________________________________*/
	setUrlState: function(callback, state) {
		BondiTouch.ClientCache.cacheObject("app", "urlState", state);
		this.returnCall(callback, "setUrlState");
	},

	/*______________________________________________________________________________________________________________________________________________________________________________________*/
	loadIssueData: function (callback) {
		/// <summary>Loads issue data from pageListing controller into spread and page objects in the Core.pageListing object.</summary>
		var core = _b.Core,
			issueKey = core.navState.issueKey;
		_b.ClientCache.cachedGetJSON("issue", _b.Utility.makeProxyUrl(_b.Uri.pageListing + "?issueKey=" + issueKey), false,
			function (data, textStatus, XMLHttpRequest) {
				///<summary>This is the actual code that loads page and spread objects into the _b.Core.pageListing object.</summary>
				var spreadNum = -1;
				var sprdIdx = 0;
				var spreadObj = undefined;
				core.pageListing.clearSpreads();
				for (var i = 0; i < data.length; i++) {
					var seedItem = data[i];
					var pg = new _b.Carousel.Page(data[i], i);
					if (spreadNum !== pg.spreadNumber) {
						if (spreadObj !== undefined) {
							spreadObj.cleanUp();
							core.pageListing.spreads.push(spreadObj);
						};
						spreadObj = new _b.Carousel.Spread(pg, sprdIdx);
						sprdIdx++;
					};
					spreadObj.pages.push(pg);
					spreadNum = pg.spreadNumber;
				};
				if (spreadObj !== undefined) {
					spreadObj.cleanUp();
					core.pageListing.spreads.push(spreadObj);
				};
				_b.Tasks.returnCall(callback, "loadIssueData");
			},
			function (XMLHttpRequest, textStatus, errorThrown) { alert("There was an error loading issue data: " + textStatus); }
		);
	},

	/*______________________________________________________________________________________________________________________________________________________________________________________*/
	setScreenSize: function (callback) {
		/// <summary>Assign the screen size to the local properties.</summary>
		var state = _b.Core.navState;
		
		state.windowW = window.innerWidth;
		state.windowCtrX = Math.abs(state.windowW / 2);
		state.windowH = window.innerHeight;
		
		this.returnCall(callback, "setScreenSize");
	},

	/*______________________________________________________________________________________________________________________________________________________________________________________*/
	setScreenMode: function (callback) {
		///<summary>Based on the value in constants.modeRatio, determine whether we are in portrait or landscape mode.</summary>
		var state = _b.Core.navState,
			ratio = state.windowH / state.windowW;
		state.mode = (ratio > _b.Core.constants.modeRatio) ?
			_b.Core.constants.pageMode : _b.Core.constants.spreadMode;
		this.returnCall(callback, "setScreenMode");
	},

	/*______________________________________________________________________________________________________________________________________________________________________________________*/
	resizeFullHeightMenus: function(callback) {
		var h = _b.Core.navState.windowH - $("header").height();
		$(".fullheight").height(h);
		this.returnCall(callback, "resizeFullHeightMenus");
	},

	/*______________________________________________________________________________________________________________________________________________________________________________________*/
	createThumbnails: function (callback) {
		var core = _b.Core,
			$wrapper = $(core.constants.thumbnailContainer),
		// Get margin info
			$ftrItemWrapperDiv = $("<div>").appendTo($wrapper),
			divMarginLeft = parseInt($ftrItemWrapperDiv.css("margin-left")),
			divMarginRight = parseInt($ftrItemWrapperDiv.css("margin-right")),
			margin = divMarginLeft + divMarginRight;
		$ftrItemWrapperDiv.remove();

		// build the html as a string (using optimized string concatination method as determined by Nick Zakas)
		var html = "",
			newNavWidth = (margin + 20),
			spreadNum = 0,
			h = core.constants.thumbnailHeight;

		_.each(core.pageListing.getPages(), function (pageItem) {
			if (spreadNum !== pageItem.spreadNumber) {
				if (spreadNum > 0)
					html = html + '</div>';

				newNavWidth += margin;
				spreadNum = pageItem.spreadNumber;
				html = html + '<div id="sft' + spreadNum + '">';
			}

			var w = pageItem.imageWidth * (h / pageItem.imageHeight);
			newNavWidth += w;

			html = html + '<div><img id="pft'
				+ pageItem.pageNames
				+ '" style="width:'
				+ w
				+ 'px; height:'
				+ h
				+ 'px"><p>'
				+ pageItem.pageNames
				+ '</p></div>';
		});

		core.navState.navWidth = newNavWidth;
		html = html + '</div>';

		// Shove the string into the DOM
		$wrapper.html(html);
		$wrapper.css("width", newNavWidth + "px");
	
		if(BrowserDetect.useTouch) {
			$("#ftrPageBack").hide();
			$("#ftrPageForward").hide();
		}
		
		// Set up iScroll
		new iScroll("pgftr", {
			hScrollbar: false,
			vScrollbar: false,
		});

		// done
		this.returnCall(callback, "createThumbnails");
	},

	/*______________________________________________________________________________________________________________________________________________________________________________________*/
	setCurrentPageIndex: function (callback) {
		var currPageName = _b.Utility.getPageNameFromUrl();
		if (currPageName === "") {
			_b.Core.navState.currentIndex = 0;
		}
		else {
			var pg = _b.Core.pageListing.getPageByName(currPageName);
			if (pg) {
				_b.Core.navState.currentIndex = pg.index;
			}
			else {
				alert("Could not find page name: " + currPageName);
			};
		};
		this.returnCall(callback, "setCurrentPageIndex");
	},
	
	/*______________________________________________________________________________________________________________________________________________________________________________________*/
	resizeImages: function (callback) {
		_b.Core.pageListing.resizeImages();
		this.returnCall(callback, "resizeImages");
	},

	/*______________________________________________________________________________________________________________________________________________________________________________________*/
	transitionScreenToPage: function (callback) {
		var currPage = _b.Core.pageListing.getPageByIndex(_b.Core.navState.currentIndex);
		var currItem = undefined;
		var pageName = currPage.pageNames;
		if (_b.Core.navState.mode === _b.Core.constants.pageMode) {
			currItem = currPage;
		}
		else {	// spread mode
			currItem = currPage.parent;
		};
		if (!currItem) {
			return false;
		};
		var lastOffset = _b.Core.navState.currentOffset;
		_b.Core.navState.currentOffset = ((currItem.x - (_b.Core.navState.windowCtrX - currItem.centerX)) * -1);
		var dist = Math.abs(lastOffset - _b.Core.navState.currentOffset);
		var dur = (dist * 0.5); //.75);
		// TODO is this a bug? only used rightMax, not leftMax.
		// i've only updated it to use carouselEdgeRight for now...
		if (dist > _b.Core.constants.carouselEdgeRight) {
			dur = 0;
		};
		_b.Core.navState.hash = "#!/" + pageName;
		location.hash = _b.Core.navState.hash;
		_b.Core.pageListing.executeIssuePagination(_b.Core.navState.currentOffset, dur);
		this.returnCall(callback, "transitionScreenToPage");
	},

	/*______________________________________________________________________________________________________________________________________________________________________________________*/
	transitionThumbstrip: function (callback) {
		///<summary>Scrolls the navigation thumbnails to center the current page</summary>
		if (!_b.Core.navState.navWidth === 0) // Not yet ready
			return;

		var $backButton = $("#ftrPageBack");
		var leftStop = ($backButton.is(":visible") ? $backButton.width() : 0);
		
		var $pg = _b.Core.getThumbImg$(_b.Core.pageListing.getCurrentPage().pageNames);
		var pgLeft = $pg.position().left;
		var imgWidth = $pg.width();
		var imgOffset = ((_b.Core.navState.windowW - imgWidth) / 2);
		var wrapLeft = $(_b.Core.constants.thumbnailContainer).position().left;
		var finalOffset = ((pgLeft - wrapLeft) - imgOffset);
		finalOffset = finalOffset * -1;
		if (finalOffset > leftStop) {
			finalOffset = leftStop;
		}
		var scrollMax = (_b.Core.navState.navWidth - (_b.Core.navState.windowW - 10));
		scrollMax = scrollMax * -1;
		if (scrollMax > finalOffset) {
			finalOffset = scrollMax;
		}
		var bez = "cubic-bezier(0.20, 0.00, 0.00, 1.00)";
		var slideTranslate = _b.Core.navState.browserTag + "transform 1000ms " + bez;
		$(_b.Core.constants.thumbnailContainer).css(_b.Core.navState.browserTag + "transition", slideTranslate);

		var transformFooter = _b.Core.navState.translateStart + finalOffset + "px, 0" + _b.Core.navState.translateEnd;
		$(_b.Core.constants.thumbnailContainer).css(_b.Core.navState.browserTag + "transform", transformFooter);
		_b.Core.navState.thumbOffset = finalOffset;
		this.returnCall(callback, "transitionThumbstrip");
	},

	/*______________________________________________________________________________________________________________________________________________________________________________________*/
	loadThumbnailsInitial: function (callback) {
		///<summary>Load the first 15 thumbnails or the 15 thumbnails around the current page.</summary>
		var pageCount = 15;
		var start = Math.max(0, (_b.Core.navState.currentIndex - Math.floor(pageCount / 2)));
		this.loadThumbnails(function () {
			_b.Tasks.returnCall(callback, "loadThumbnailsInitial");
		}, start, pageCount);
	},

	/*______________________________________________________________________________________________________________________________________________________________________________________*/
	loadThumbnailsRemaining: function (callback) {
		///<summary>Get all pages that are not currently loaded with base64 thumbnails.</summary>
		if (_b.Core.navState.thumbnailLoadSeq > _.last(_b.Core.pageListing.getPages()).sequenceNumber) {
			this.returnCall(callback, "loadThumbnailsRemaining");
		}
		else {
			this.loadThumbnails(function (state, lastSequenceNumber) {
				_b.Core.navState.thumbnailLoadSeq = lastSequenceNumber + 1;
				_b.Tasks.loadThumbnailsRemaining(callback);
			}, _b.Core.navState.thumbnailLoadSeq, 100);
		};
	},

	/*______________________________________________________________________________________________________________________________________________________________________________________*/
	loadThumbnails: function (callback, startSeq, pageCount) {
		///<summary>Start load of a specific number of thumbnails</summary>
		///<param name="callback" type="function">The callback to execute when complete.
		///<para>Overwritten normally by anonymous method</para></param>
		///<param name="startSeq" type="integer">First thumbnail by sequence to load</param>
		///<param name="pageCount" type="integer">Number of thumbnails to load</param>
		var pageUrl = _.template(_b.Uri.pageThumbs, {
			issueKey: _b.Core.navState.issueKey,
			startSequence: startSeq,
			pageCount: pageCount
		});
		$.ajax({
			url: _b.Utility.makeProxyUrl(pageUrl),
			success: function (data, textStatus, XMLHttpRequest) {
				var lastSequenceNumber = _b.Tasks.loadThumbnailsOnSuccess(data);
				callback("loadThumbnails_Done", lastSequenceNumber);
			},
			error: function (XMLHttpRequest, textStatus, errorThrown) {
				console && console.warn("thumbnails failed to load!");
				// We don't announce this error, as it's usually due to the user navigating away from the page.
				// alert("There was an error loading thumbnails: " + textStatus);
			}
		});
	},

	/*______________________________________________________________________________________________________________________________________________________________________________________*/
	loadThumbnailsOnSuccess: function (data) {
		///<summary>Method  called when a load thumbnail call returns list of data</summary>
		///<param name="data" type="array">Data returned from call. List of thumbnail base64 strings</param>
		if (!data.length)
			return -1;
		var firstItm = data[0];
		var lastItm = _.last(data);
		var storedItems = _.select(_b.Core.pageListing.getPages(), function (pageItem) {
			return pageItem.sequenceNumber >= firstItm.SequenceNumber
				&& pageItem.sequenceNumber <= lastItm.SequenceNumber;
		});
		_.each(data, function (receivedPageItem) {
			_.each(storedItems, function (storedPageItem) {
				if (receivedPageItem.SequenceNumber === storedPageItem.sequenceNumber) {
					storedPageItem.base64Thumbnail = receivedPageItem.Base64Thumbnail;
					_b.ThumbPusher.add(storedPageItem);
					_.breakLoop();
				};
			});
		});
		return lastItm.SequenceNumber;
	},

	/*______________________________________________________________________________________________________________________________________________________________________________________*/
	loadJumpLinks: function (callback) {
		var jumpUrl = _.template(_b.Uri.jumpLinks, { issueKey: _b.Core.navState.issueKey });
		_b.ClientCache.cachedGetJSON("issue", _b.Utility.makeProxyUrl(jumpUrl), false,
			function (data, textStatus, XMLHttpRequest) {
				_b.Core.jumpLinks = data;
				_b.Tasks.returnCall(callback, "loadJumpLinks");
			},
			function (XMLHttpRequest, textStatus, errorThrown) {
				alert("There was an error loading issue jump links: " + textStatus);
			});
	},

	/*______________________________________________________________________________________________________________________________________________________________________________________*/
	displayJumpLinks: function (callback) {
		var sprd = _b.Core.pageListing.getCurrentSpread();
		if (!sprd) {
			return;
		};
		$("em").empty().remove();
		_.each(sprd.pages, function (pageObj) {
			var pgHeight = pageObj.height;
			var pgWidth = pageObj.width;

			var shrinkH = (pgHeight / pageObj.imageHeight);
			var shrinkW = (pgWidth / pageObj.imageWidth);
			var $img = $("#" + pageObj.imgID);
			_.each(_b.Core.jumpLinks, function (linkItem) {
				if (linkItem.SourcePage === pageObj.pageNames) {
					var calcLeft = 0;
					var calcTop = 0;
					var calcWidth = 0;
					var calcHeight = 0;
					calcLeft = (linkItem.L * shrinkW);
					calcTop = (linkItem.T * shrinkH); //  + pageObj.topMargin;
					calcWidth = (linkItem.W * shrinkW);
					calcHeight = (linkItem.H * shrinkH);
					//calcLeft += leftOffset;
					var $em = $("<em />").addClass("link")
						//.addClass("JumpLink")
						.css({
							"width": calcWidth,
							"height": calcHeight,
							"left": calcLeft,
							"top": calcTop,
							"z-index": 500
						}).attr("title", linkItem.TargetPage)
						.fadeTo(1500, 0.4)
						.appendTo("#" + pageObj.imgID)
						.bind("click", _b.Core.navigateToPage)
						.fadeTo(1500, 0.2);
				};
			});
		});
//		$("em").addClass("link").bind("click", _b.Core.navigateToPage);
//		$("em").fadeTo(1500, 0.25);
		this.returnCall(callback, "displayJumpLinks");
	},

	/*______________________________________________________________________________________________________________________________________________________________________________________*/
	hideJumpLinks: function (callback) {
		$("#filmStrip").find("em.link").remove();
		this.returnCall(callback, "hideJumpLinks");
	},

	/*______________________________________________________________________________________________________________________________________________________________________________________*/
	displayChrome: function (callback) {
		//display Header and Footer (without callbacks)
		this.displayHeader()
		this.displayFooter();
		this.returnCall(callback, "displayChrome");
	},

	/*______________________________________________________________________________________________________________________________________________________________________________________*/
	displayHeader: function (callback) {
		var transformHeader = _b.Core.navState.translateStart + "0px, 0px " + _b.Core.navState.translateEnd;
		$("header").css(_b.Core.navState.browserTag + "transform", transformHeader);
		_b.Core.navState.headerVisible = true;
		this.returnCall(callback, "displayHeader");
	},

	/*______________________________________________________________________________________________________________________________________________________________________________________*/
	displayFooter: function (callback) {
		var transformFooter = _b.Core.navState.translateStart + "0px, 0px" + _b.Core.navState.translateEnd;
		$("footer").css(_b.Core.navState.browserTag + "transform", transformFooter);
		_b.Core.navState.footerVisible = true;
		this.returnCall(callback, "displayFooter");
	},

	/*______________________________________________________________________________________________________________________________________________________________________________________*/
	hideChrome: function (callback) {
		this.hideHeader();
		this.hideFooter();
		this.hideOverlays();
		this.returnCall(callback, "hideChrome");
	},

	/*______________________________________________________________________________________________________________________________________________________________________________________*/
	hideHeader: function (callback) {
		var $header = $("header"), hideHeaderY = ($header.height() * -1.5);
		var transformHeader = _b.Core.navState.translateStart + "0px, " + hideHeaderY + "px" + _b.Core.navState.translateEnd;
		$header.css(_b.Core.navState.browserTag + "transform", transformHeader);
		$("#searchText").blur();

		_b.Core.navState.headerVisible = false;
		this.returnCall(callback, "hideHeader");
	},

	/*______________________________________________________________________________________________________________________________________________________________________________________*/
	hideFooter: function (callback) {
		var htFtr = $("footer").height() * 1.2;
		var transformFooter = _b.Core.navState.translateStart + "0px, " + htFtr + "px" + _b.Core.navState.translateEnd;
		$("footer").css(_b.Core.navState.browserTag + "transform", transformFooter);

		_b.Core.navState.footerVisible = false;
		this.returnCall(callback, "hideFooter");
	},

	/*______________________________________________________________________________________________________________________________________________________________________________________*/
	hideOverlays: function (callback, except) {
		var $o = $(".overlay");
		if (except) {
			$o = $o.not(except);
		}
		$o.css("display", "none");
		$(".menuButton").removeClass("selected");
		this.returnCall(callback, "hideOverlays");
	},
	
	/*______________________________________________________________________________________________________________________________________________________________________________________*/
	resizeOverlays: function (callback) {
		_b.Toc && _b.Toc.handleResize();
		_b.Search &&_b.Search.handleResize();
		this.returnCall(callback, "resizeOverlays");
	},
	
	/*______________________________________________________________________________________________________________________________________________________________________________________*/
	displayWorking: function (callback) {
		$("#spinner").css("display", "block");
		this.returnCall(callback, "displayWorking");
	},

	/*______________________________________________________________________________________________________________________________________________________________________________________*/
	hideWorking: function (callback) {
		$("#spinner").css("display", "none");
		this.returnCall(callback, "hideWorking");
	},

	/*______________________________________________________________________________________________________________________________________________________________________________________*/
	displayPaging: function (callback) {
		if (this.pageLoadingShown)
			return; 
			
		var $pgDots = $("#pageLoading");
		$pgDots.css("display", "block");
		var pgTop = _b.Core.navState.windowH - 15;
		if (_b.Core.navState.footerVisible) {
			pgTop -= $("footer").height();
		};
		$pgDots.css("top", pgTop);
		$pgDots.css("left", (_b.Core.navState.windowW - 120));

		this.pageLoadingShown = true;
		this.returnCall(callback, "displayPaging");
	},

	/*______________________________________________________________________________________________________________________________________________________________________________________*/
	hidePaging: function (callback) {
		$("#pageLoading").css("display", "none");
		this.pageLoadingShown = false;
		this.returnCall(callback, "hidePaging");
	},

	/*______________________________________________________________________________________________________________________________________________________________________________________*/
	loadTOC: function (callback) {
		_b.Toc.load(_b.Core.navState.issueKey);
		this.returnCall(callback, "loadTOC");
	},

	/*______________________________________________________________________________________________________________________________________________________________________________________*/
	backstopPager: function (callback, duration) {
		/// <summary>Assigns a timer to reset the pagination function.
		/// <para>This will, in the event of an exception, allow pagination to continue by resetting the navState.itemsInTransition value.</para></summary>
		if (_b.Core.navState.backstopTimerID !== -1) {
			clearTimeout(_b.Core.navState.backstopTimerID);
		};
		_b.Core.navState.backstopTimerID = setTimeout(function () {
			if (_b.Core.navState.itemsInTransition > 0) {
				_b.Core.navState.itemsInTransition = 0;
				_b.Tasks.hidePaging();
			};
			_b.Core.navState.backstopTimerID = -1;
		}, (duration * 2));
		this.returnCall(callback, "backstopPager");
	},

	/*______________________________________________________________________________________________________________________________________________________________________________________*/
	displaySearchTermHighlights: function (callback) {
		///<summary>display any search terms for the current spread</summary>
		BondiTouch.Search.displayHighlightTerms();
		this.returnCall(callback, "displaySearchTermHighlights");
	}
};


