﻿/// <reference path="../../jquery-1.3.2.js" />

(function($) {
	//Media streamer plugin
	//moduleId [string] - guid of the selected module
	//dataUrl [string] - web service request query
	$.fn.mediaStreamer = function(moduleId, dataUrl, options) {
		//if specified, merge with default configuration
		var options = $.extend({}, $.fn.mediaStreamer.defaults, options);

		//check configuration
		if (options.bufferSize < 2)
			options.bufferSize = 2; //it must be equal or higher than reserve				

		//how many items are readed in advance
		var readAhead = options.scrollSize * options.bufferSize;
		//when there is equal or less items in the buffer, the new buffer is created
		var bufferReserve = options.scrollSize * 2;

		//setup elements selectors
		var controlId = $(this).attr("id"); //temporary

		//view frame over the buffer
		var scroller = $("#" + controlId + " .thumbStreamerScroller");

		//contains all items in the buffer
		var wrapper = $("#" + controlId + " .thumbStreamerWrapper");

		//next button
		var nextImage = $("#" + controlId + " .thumbStreamerNavImgNext");

		//previous button
		var prevImage = $("#" + controlId + " .thumbStreamerNavImgPrev");

		var itemRealWidth = options.itemWidth + 2 * (options.itemLeftRightMargin + options.itemLeftRightBorder);
		var itemRealHeight = options.itemHeight + 2 * (options.itemTopBottomMargin + options.itemTopBottomBorder) + options.bottomOffset;

		//setup width of the scroller to the size of the view frame
		scroller.css("width", options.pageSize * itemRealWidth + options.leftOffset + options.rightOffset);

		//setup width of the buffer to the size of the buffer
		wrapper.css("width", (options.pageSize + 2 * readAhead) * itemRealWidth + options.leftOffset + options.rightOffset);

		wrapper.css("height", itemRealHeight);
		scroller.css("height", itemRealHeight);
		nextImage.css("height", itemRealHeight);
		prevImage.css("height", itemRealHeight);

		//how many items are displayed right to the center item		
		var rightExtent = Math.floor(options.pageSize / 2);

		//how many items are displayed left to the center item
		var leftExtent = rightExtent;

		//if the count is even, than the first item on left from center is "center"
		if (options.pageSize % 2 == 0)
			leftExtent -= 1;

		//object template - holds information about one image/link
		function imageLink() {
			this.title;
			this.thumbnailUrl;
			this.url;
		}

		//object template - holds information about the buffer
		//centerIndex [int] - index of the item in center of the view frame
		function bufferInfo(centerIndex) {
			//index of the leftmos item in the buffer
			this.leftIndex = centerIndex - leftExtent - readAhead;

			//index of the rightmos item in the buffer
			this.rightIndex = centerIndex + rightExtent + readAhead;

			//returns true if the center index reaches one of the buffer border (or is near when reserve > 0)
			//centerIndex [int] - index of the item in center of the view frame
			this.needRefresh = function(centerIndex) {
				//test left border limit
				if ((centerIndex - leftExtent) - this.leftIndex < bufferReserve)
					return true; //refresh buffer for current center index

				//test right border limit
				if (this.rightIndex - (centerIndex + rightExtent) < bufferReserve)
					return true; //refresh buffer for current center index

				//the center index is within buffer limits
				return false;
			}
		}

		//index of the center displayed image
		var centerIndex;

		//index of the selected image (for rendering hilighted frame)
		var selectedIndex = -1;

		//index of the rightmos image for testing limit
		var rightmostIndex;

		//array of all image links
		var linkArray = new Array();

		//buffer info
		var buffer = null;
		var scrollBy = 0;

		//media streamer core functions
		var functions = {
			//move view frame one item right
			next: function() {
				var possibleScroll = rightmostIndex - rightExtent - centerIndex;
				if (possibleScroll < 0)
					scrollBy = 0;

				if (possibleScroll > options.scrollSize)
					scrollBy = options.scrollSize;
				else
					scrollBy = possibleScroll;

				centerIndex = centerIndex + scrollBy;

				functions.updateNavControls();
				functions.renderImages(false, 1);
			},
			//move view frame one item left
			previous: function() {
				var possibleScroll = centerIndex - leftExtent;
				if (possibleScroll < 0)
					scrollBy = 0;

				if (possibleScroll > options.scrollSize)
					scrollBy = options.scrollSize;
				else
					scrollBy = possibleScroll;

				centerIndex = centerIndex - scrollBy;

				functions.updateNavControls();
				functions.renderImages(false, -1);
			},
			//shows available buttons				
			updateNavControls: function updateNavControls() {
				var showNext = rightmostIndex - rightExtent - centerIndex > 0;
				var showPrev = centerIndex - leftExtent > 0;

				if (showNext) {
					nextImage.click(functions.next);
					nextImage.attr("src", "/Scripts/jQuery/MediaStreamer/StreamRight.jpg");
					nextImage.css("cursor", "pointer");
				} else {
					nextImage.unbind("click");
					nextImage.attr("src", "/Scripts/jQuery/MediaStreamer/StreamRightDisabled.jpg");
					nextImage.css("cursor", "default");
				}

				if (showPrev) {
					prevImage.click(functions.previous);
					prevImage.attr("src", "/Scripts/jQuery/MediaStreamer/StreamLeft.jpg");
					prevImage.css("cursor", "pointer");
				} else {
					prevImage.unbind("click");
					prevImage.attr("src", "/Scripts/jQuery/MediaStreamer/StreamLeftDisabled.jpg");
					prevImage.css("cursor", "default");
				}
			},
			//setup view frame positon for init or animate move after next/prev button click
			//direction [int] - 0 no move, -1 move to the left, 1 move to the right
			//startIndex [int] - index of the leftmos item in the buffer
			moveView: function(direction, startIndex) {
				//offset of view frame - index of the leftmos displayed item
				var leftOffset = centerIndex - leftExtent - startIndex;
				if (leftOffset < 0) leftOffset = 0;

				//no animation for control init or when buffer may not contain next item
				if (direction == 0 || bufferReserve == 0) {
					scroller.attr("scrollLeft", leftOffset * itemRealWidth);
				}

				//animate move to the left
				if (direction == -1) {
					var previousIndex = leftOffset + scrollBy;

					scroller.attr("scrollLeft", previousIndex * itemRealWidth); //set previous position
					scroller.animate({ "scrollLeft": leftOffset * itemRealWidth }, "800", "linear"); //move to the current
				}

				//animate move to the right
				if (direction == 1) {
					var previousIndex = leftOffset - scrollBy;

					scroller.attr("scrollLeft", previousIndex * itemRealWidth); //set previous position
					scroller.animate({ "scrollLeft": leftOffset * itemRealWidth }, "800", "linear"); //move to the current
				}
			},
			//render all images in buffer
			//init [bool] - create new buffer when true
			//direction [int] - forwarded to the moveView function, 0 by default
			renderImages: function(init, direction) {
				if (direction == undefined)
					direction = 0;

				var newBuffer = false;

				if (init) {
					buffer = new bufferInfo(centerIndex);
					newBuffer = true;
				}
				else //create new buffer if center index is close/reaches its border
					if (buffer.needRefresh(centerIndex)) {
					{
						buffer = new bufferInfo(centerIndex);
						newBuffer = true;
					}
				}

				//index of the leftmos item in the buffer
				var startIndex = (buffer.leftIndex < 0) ? 0 : buffer.leftIndex;

				//index of the rightmos item in the buffer
				var endIndex = (buffer.rightIndex > rightmostIndex) ? rightmostIndex : buffer.rightIndex;

				//is there any item in the array?
				if (linkArray.length > 0 && newBuffer) {
					//render all images in buffer into a table					
					var divItems = "";
					for (i = startIndex; i <= endIndex; i++) {
						//use different css class for selected image (hilighted border etc.)
						var imgClassName;
						if (i == selectedIndex) {
							imgClassName = "thumbSelectedStreamerImg";
						} else {
							imgClassName = "thumbStreamerImg";
						}

						var divId = "";
						if (i == startIndex)
							divId = "id=\"startDiv\"";

						divItems += "<div " + divId + " class=\"thumbStreamerImgDiv\"><a href=\"" + linkArray[i].url + "\"><img class=\"" + imgClassName + "\" src=\"";
						divItems += linkArray[i].thumbnailUrl + "\" title=\"" + linkArray[i].title + "\"";

						if (i != selectedIndex) {
							divItems += " onmouseover=\"this.className='thumbStreamerImgMouseOver';\" onmouseout=\"this.className='thumbStreamerImg';\"";
						}

						divItems += "/></a></div>";
					}

					//set wrapper control content
					wrapper.html(divItems);

					var itemCss = {
						"width": options.itemWidth,
						"height": options.itemHeight,
						"margin-left": options.itemLeftRightMargin,
						"margin-right": options.itemLeftRightMargin,
						"margin-top": options.itemTopBottomMargin,
						"margin-bottom": options.itemTopBottomMargin + options.bottomOffset
					}

					var selectedItemCss = {
						"width": options.itemWidth,
						"height": options.itemHeight,
						"margin-left": options.itemLeftRightMargin - 2, //because of hilighted border
						"margin-right": options.itemLeftRightMargin - 2, //because of hilighted border
						"margin-top": options.itemTopBottomMargin - 2,
						"margin-bottom": options.itemTopBottomMargin - 2 + options.bottomOffset
					}

					$("#startDiv").css("margin-left", options.leftOffset);

					$(".thumbSelectedStreamerImg").css(selectedItemCss);
					$(".thumbStreamerImg").css(itemCss);
					$(".thumbStreamerImgMouseOver").css(itemCss);
				}

				//animate movement or setup inititial for direction = 0
				functions.moveView(direction, startIndex);
			}
		};

		//plugin method
		return this.each(function() {
			//get data
			if (dataUrl != "") {
				$.get(dataUrl, function(data) {
					var rx = null; //regexp for search item when module id is specified					
					if (moduleId != "")
						rx = new RegExp(moduleId.toLowerCase());

					$(data).find("ArrayOfItem").find("item").each(function() {
						//new object instance
						var link = new imageLink;
						//parse elements
						link.title = $(this).find("title").text();
						link.thumbnailUrl = options.urlPrefix + $(this).find("thumbnailurl").text();
						link.url = options.urlPrefix + $(this).find("url").text();
						//append link to the array
						linkArray[linkArray.length] = link;
						//is it selected item - match module id?
						if (rx != null && selectedIndex == -1) {
							{
							    if (rx.test(link.url.toLowerCase()))
									selectedIndex = linkArray.length - 1; //yes, it is selected item
							}
						}
					});

					//set the index of the rightmos item
					rightmostIndex = (linkArray.length == 0) ? 0 : linkArray.length - 1;

					if (selectedIndex == -1) {
						//no item is selected, set the center of leftmos view frame (0..pageSize)
						centerIndex = leftExtent;

						if (centerIndex > rightmostIndex) //limit, too low count of items
							centerIndex = rightmostIndex;
					}
					else {
						centerIndex = selectedIndex; //set center index to the selected item

						//the selected item is too on the left of the center of the leftmos view frame
						//move it right to the center, or close to it
						if (centerIndex < leftExtent && centerIndex < rightmostIndex) {
							if (leftExtent >= rightmostIndex)
								centerIndex = rightmostIndex; //cannot move more to the right than is the last item
							else
								centerIndex = leftExtent; //exactly to the center
						}
					}

					//eliminate right gap by moving view frame to the left - decrement center index if it is possible
					var rightGap = (centerIndex + rightExtent) - rightmostIndex;
					if (rightGap > 0) { //yes, there is a gap
						var leftReserve = (centerIndex - leftExtent);
						if (leftReserve > 0) { //yes, there is a reserve, there are some non displayed items on the left
							if (leftReserve >= rightGap) {
								//fill exactly the gap
								centerIndex -= rightGap;
							} else {
								//fill gap with all available items in the left reserver
								centerIndex -= leftReserve;
							}
						}
					}

					functions.renderImages(true);
					functions.updateNavControls();

					//the control is ready, display it now
					$(".thumbStreamerOuter").css("visibility", "visible");
				}); //end get
			}; //end if
		});
	};

	$.fn.mediaStreamer.defaults = {
		itemWidth: 65,
		pageSize: 5,
		urlPrefix: "", //when the url links are relative to another server (debug purpose)
		srollSize: 1,
		bufferSize: 5, //how many steps are buffered
		itemLeftRightMargin: 5,
		itemTopBottomMargin: 5,
		leftOffset: 0,
		rightOffset: 0,
		itemHeight: 65,
		itemLeftRightBorder: 1, //border + padding
		itemTopBottomBorder: 1, //border + padding + top/down margin
		bottomOffset: 0
	};

})(jQuery);

function jQueryMediaStreamer_Init(moduleId, dataUrl, options) {
	jQuery(".thumbStreamerOuter").each(function() {
		jQuery(this).mediaStreamer(moduleId, dataUrl, options);
	});
}