var DESFancyScroller = {

	scrollableContentWidth: 0,
	scrollableContentVisibleWidth: 0,
	scrollerWidth: 0,
	scrollerControllerWidth: 0,
	leftArrowWidth: 0,
	rightArrowWidth: 0,
	numItems: 0,
	scrollerStepSize: 0,
	dragStartClickX: 0,
	dragStartControllerX: 0,
	dragScroller: false,
	moreLeftAndRightVisualIndicatorsOpacity: 1,
	moreRightStatic: new Image(56, 194),
	moreLeftStatic: new Image(56, 194),
	tallestCatLinkHeight: 0,
	catLinkWidth: 0,

	initialise: function() {

		this.moreRightStatic.src = '/images/moreRightStatic.gif';
		this.moreLeftStatic.src = '/images/moreLeftStatic.gif';

		$("scrollingContentContainer").style.overflow = 'hidden';
		$("scroller").style.display = 'block';

		this.scrollableContentWidth = parseInt($("scrollableList").getStyle('width'));

		this.scrollableContentVisibleWidth = parseInt( $("scrollingContentContainer").getStyle("width") ); // returns inner width whereas getWidth() includes borders
		this.leftArrowWidth = parseInt($("scrollerLeftArrow").getStyle('width'));
		this.rightArrowWidth = parseInt($("scrollerRightArrow").getStyle('width'));
		this.scrollerWidth = parseInt( $("scroller").getStyle("width") ) - this.leftArrowWidth - this.rightArrowWidth;
		this.scrollerControllerWidth = parseInt($('scrollerController').getStyle("width") );
		this.numItems = $('scrollableList').select("li").length;
		this.scrollerStepSize = 2 * Math.ceil(  this.scrollerWidth    /     (this.numItems - Math.round( this.scrollableContentVisibleWidth / ( this.scrollableContentWidth / this.numItems ) ))  );

		/* BEGIN IE6 FLOATED-DIV-WIDTH BUGFIX */
		if (this.scrollableContentWidth == parseInt( $('scrollableList').down('div.scrollableListCategory').getWidth() ) ) {

			$('scrollableList').select('div.scrollableListCategory').each(function(catDiv){

				var catWidth = 0;

				catDiv.select('li').each(function(li){
					catWidth += li.getWidth();
				});

				catDiv.setStyle({width: catWidth + 'px'});

			});

		}
		/* END IE6 FLOATED-DIV-WIDTH BUGFIX */

		$('scrollerController').style.left = this.leftArrowWidth + "px";

		$("scroller").observe('click', this.onClickOnScroller.bindAsEventListener(this));
		$("scrollerLeftArrow").observe('click', this.onClickOnArrow.curry("left").bindAsEventListener(this));
		$("scrollerRightArrow").observe('click', this.onClickOnArrow.curry("right").bindAsEventListener(this));

		$("scrollerController").observe('click', Event.stop);
		$("scrollerController").observe('mousedown', this.onControllerMouseDown.bindAsEventListener(this));

		/*  Create visual indicator elements  */

		$('scrollingContentContainer').appendChild(
			new Element('div', {id: 'moreToTheRightVisualIndicator', style: 'display: none'})
		);
		$('scrollingContentContainer').appendChild(
			new Element('div', {id: 'moreToTheLeftVisualIndicator', style: 'display: none'})
		);

		$("moreToTheLeftVisualIndicator").observe('click', this.onClickOnArrow.curry("left").bindAsEventListener(this));
		$("moreToTheRightVisualIndicator").observe('click', this.onClickOnArrow.curry("right").bindAsEventListener(this));


		/*  show the animated gif visual indicator to the right  */
		$('moreToTheRightVisualIndicator').appear({to: this.moreLeftAndRightVisualIndicatorsOpacity});
		
		/* fix alignments of images/text in links  */
		$('scrollableList').select('img').each(function(img){

			if (img.hasClassName('verticalSeparator') || img.hasClassName('nomargin')) {
				return; // skip vertical separator bars
			}

			img.style.marginBottom = ( 130 - $(img).getHeight() ) + "px";

		});

		/* position the arrow tails */
		$('scrollerRightArrowTail').style.right = ( this.rightArrowWidth - 1 ) + "px";
		$('scrollerLeftArrowTail').style.left = ( this.leftArrowWidth - 1 ) + "px";


		/* create category links */

		var catHeaders = $A(  $('scrollableList').getElementsByTagName('h3')  );

		this.catLinkWidth = Math.floor(this.scrollableContentVisibleWidth / catHeaders.length) - 10;

		catHeaders.each(function(cat){

			$(cat); // add prototype extensions to the cat Element object

			var link = new Element('a', {
				style: 'width: ' + this.catLinkWidth + 'px',
				href: '#'
			});
			link.appendChild(
				new Element('span').update(cat.title)
			);

			$('categoryLinks').appendChild(link);

			if (parseInt(link.getStyle('height')) > this.tallestCatLinkHeight) {
				this.tallestCatLinkHeight = parseInt(link.getStyle('height'));
			}

			link.observe('click', this.autoScrollTo.curry(cat.positionedOffset().left).bindAsEventListener(this));


		}, this);

		$('categoryLinks').setStyle({height: (8 + this.tallestCatLinkHeight) + 'px'}); // plus 8 for padding

	},

	onClickOnScroller: function(event) {

		$('moreToTheRightVisualIndicator').style.background = 'url("' + this.moreRightStatic.src + '")';

		// firstly, get the horizontal distance of the click from the left-most possible possition of the draggable controller
		var xPos = event.pointerX() - $("scroller").cumulativeOffset().left - this.leftArrowWidth - 2; // minus 2 for the element's border

		// because we want the controller button to be centered around our click point, subtract half the width of the controller
		xPos -= (this.scrollerControllerWidth/2);
		
		// adjust for minimum/maximum locations
		if (xPos < 0) xPos = 0;
		if (xPos > this.scrollerWidth - this.scrollerControllerWidth) xPos = this.scrollerWidth - this.scrollerControllerWidth;

		//  calculate new location for the content, according to the % along the possible length of the bar that the scroller has been positioned
		var contentXPos = 0 - Math.round( ( xPos / (this.scrollerWidth - this.scrollerControllerWidth) ) * ( this.scrollableContentWidth - this.scrollableContentVisibleWidth ) );

		// set new position of scroller & content
		new Effect.Move('scrollerController', {x: xPos + this.leftArrowWidth, mode: 'absolute'});
		new Effect.Move('scrollableList', {x: contentXPos, mode: 'absolute'});

		/* show/hide the visual indicators as required */
		if ( xPos == this.scrollerWidth - this.scrollerControllerWidth   &&  $('moreToTheRightVisualIndicator').getStyle('display') != 'none' ) {
			$('moreToTheRightVisualIndicator').fade({from: this.moreLeftAndRightVisualIndicatorsOpacity, duration: 0.4});
		} else if (xPos < this.scrollerWidth - this.scrollerControllerWidth   &&  $('moreToTheRightVisualIndicator').getStyle('display') == 'none' ) {
			$('moreToTheRightVisualIndicator').appear({to: this.moreLeftAndRightVisualIndicatorsOpacity, duration: 0.4});
		}

		if ( xPos == 0   &&  $('moreToTheLeftVisualIndicator').getStyle('display') != 'none' ) {
			$('moreToTheLeftVisualIndicator').fade({from: this.moreLeftAndRightVisualIndicatorsOpacity, duration: 0.4});
		} else if ( xPos > 0   &&  $('moreToTheLeftVisualIndicator').getStyle('display') == 'none' ) {
			$('moreToTheLeftVisualIndicator').appear({to: this.moreLeftAndRightVisualIndicatorsOpacity, duration: 0.4});
		}

	},

	onClickOnArrow: function(direction, event) {

		// get current left position
		var xPos = parseInt( $("scrollerController").getStyle("left") ) - this.leftArrowWidth;


		switch (direction) {
			case "left":
				xPos -= this.scrollerStepSize;
				break;
			case "right":
				xPos += this.scrollerStepSize;
				$('moreToTheRightVisualIndicator').style.background = 'url("' + this.moreRightStatic.src + '")';
				break;
		}

		// adjust for minimum/maximum locations
		if (xPos < 0) xPos = 0;
		if (xPos > this.scrollerWidth - this.scrollerControllerWidth) xPos = this.scrollerWidth - this.scrollerControllerWidth;

		//  calculate new location for the content, according to the % along the possible length of the bar that the scroller has been positioned
		var contentXPos = 0 - Math.round( ( xPos / (this.scrollerWidth - this.scrollerControllerWidth) ) * ( this.scrollableContentWidth - this.scrollableContentVisibleWidth ) );

		// set new position of scroller & content
		new Effect.Move('scrollerController', {x: xPos + this.leftArrowWidth, mode: 'absolute'});
		new Effect.Move('scrollableList', {x: contentXPos, mode: 'absolute'});

		/* show/hide the visual indicators as required */
		if ( xPos == this.scrollerWidth - this.scrollerControllerWidth   &&  $('moreToTheRightVisualIndicator').getStyle('display') != 'none' ) {
			$('moreToTheRightVisualIndicator').fade({from: this.moreLeftAndRightVisualIndicatorsOpacity, duration: 0.4});
		} else if (xPos < this.scrollerWidth - this.scrollerControllerWidth   &&  $('moreToTheRightVisualIndicator').getStyle('display') == 'none' ) {
			$('moreToTheRightVisualIndicator').appear({to: this.moreLeftAndRightVisualIndicatorsOpacity, duration: 0.4});
		}

		if ( xPos == 0   &&  $('moreToTheLeftVisualIndicator').getStyle('display') != 'none' ) {
			$('moreToTheLeftVisualIndicator').fade({from: this.moreLeftAndRightVisualIndicatorsOpacity, duration: 0.4});
		} else if ( xPos > 0   &&  $('moreToTheLeftVisualIndicator').getStyle('display') == 'none' ) {
			$('moreToTheLeftVisualIndicator').appear({to: this.moreLeftAndRightVisualIndicatorsOpacity, duration: 0.4});
		}

		Event.stop(event); // stop bubbling

	},

	onDragController: function(event) {

		var offset = event.pointerX() - this.dragStartClickX;
		var dragTo = this.dragStartControllerX + offset;

		// adjust for minimum/maximum locations
		if (dragTo < this.leftArrowWidth) dragTo = this.leftArrowWidth;
		if (dragTo > this.leftArrowWidth + this.scrollerWidth - this.scrollerControllerWidth) dragTo = this.leftArrowWidth + this.scrollerWidth - this.scrollerControllerWidth;

		// set new position of scroller
		$('scrollerController').style.left = dragTo + "px";

		//  now scroll content according to the % along the possible length of the bar that the scroller has been positioned
		$("scrollableList").style.left = "-" + Math.round( ( (dragTo - this.leftArrowWidth) / (this.scrollerWidth - this.scrollerControllerWidth) ) * ( this.scrollableContentWidth - this.scrollableContentVisibleWidth ) ) + "px";

		Event.stop(event); // stop bubbling

	},
	onControllerMouseUp: function(event){
		DESFancyScroller.dragScroller = false;
		document.stopObserving('mouseup', this.boundOnControllerMouseUp);
		document.stopObserving('mousemove', this.boundOnDragController);

		/* redisplay the visual indicators if required */

		$('moreToTheRightVisualIndicator').style.background = 'url("' + this.moreRightStatic.src + '")';

		if ( parseInt( $('scrollerController').style.left ) < this.leftArrowWidth + this.scrollerWidth - this.scrollerControllerWidth ) {
			$('moreToTheRightVisualIndicator').appear({to: this.moreLeftAndRightVisualIndicatorsOpacity, duration: 0.6});
		}
		if ( parseInt( $('scrollerController').style.left ) > this.leftArrowWidth ) {
			$('moreToTheLeftVisualIndicator').appear({to: this.moreLeftAndRightVisualIndicatorsOpacity, duration: 0.6});
		}

		Event.stop(event); // stop bubbling
	},
	onControllerMouseDown: function(event){
		this.dragStartClickX = event.pointerX();
		this.dragStartControllerX = parseInt( $("scrollerController").getStyle("left") );
		this.dragScroller = true;
		document.observe('mouseup', this.boundOnControllerMouseUp);
		document.observe('mousemove', this.boundOnDragController);

		/* fade out the visual indicators */
		$('moreToTheRightVisualIndicator').setStyle({display: 'none'});
		$('moreToTheLeftVisualIndicator').setStyle({display: 'none'});

		Event.stop(event); // stop bubbling
	},
	autoScrollTo: function(point, event){

		$('moreToTheRightVisualIndicator').style.background = 'url("' + this.moreRightStatic.src + '")';

		point -= 40; // so content is not obscured by lhs visual indicator
		if (point < 0) {
			point = 0;
		} else if (point > this.scrollableContentWidth - this.scrollableContentVisibleWidth) {
			point = this.scrollableContentWidth - this.scrollableContentVisibleWidth;
		}
		
		// convert location of point to scroll to to xPos of scrollerController
		var xPos = Math.round(  (point / ( this.scrollableContentWidth - this.scrollableContentVisibleWidth ) ) * (this.scrollerWidth - this.scrollerControllerWidth)  );

		//  calculate new location for the content, 
		var contentXPos = 0 - point;

		// set new position of scroller & content
		new Effect.Move('scrollerController', {x: xPos + this.leftArrowWidth, mode: 'absolute'});
		new Effect.Move('scrollableList', {x: contentXPos, mode: 'absolute'});

		/* show/hide the visual indicators as required */
		if ( xPos == this.scrollerWidth - this.scrollerControllerWidth   &&  $('moreToTheRightVisualIndicator').getStyle('display') != 'none' ) {
			$('moreToTheRightVisualIndicator').fade({from: this.moreLeftAndRightVisualIndicatorsOpacity, duration: 0.4});
		} else if (xPos < this.scrollerWidth - this.scrollerControllerWidth   &&  $('moreToTheRightVisualIndicator').getStyle('display') == 'none' ) {
			$('moreToTheRightVisualIndicator').appear({to: this.moreLeftAndRightVisualIndicatorsOpacity, duration: 0.4});
		}

		if ( xPos == 0   &&  $('moreToTheLeftVisualIndicator').getStyle('display') != 'none' ) {
			$('moreToTheLeftVisualIndicator').fade({from: this.moreLeftAndRightVisualIndicatorsOpacity, duration: 0.4});
		} else if ( xPos > 0   &&  $('moreToTheLeftVisualIndicator').getStyle('display') == 'none' ) {
			$('moreToTheLeftVisualIndicator').appear({to: this.moreLeftAndRightVisualIndicatorsOpacity, duration: 0.4});
		}

		Event.stop(event);

	}

};

DESFancyScroller.boundOnControllerMouseUp = DESFancyScroller.onControllerMouseUp.bindAsEventListener(DESFancyScroller);
DESFancyScroller.boundOnDragController = DESFancyScroller.onDragController.bindAsEventListener(DESFancyScroller);