// slideSpeed is measured in pixels per second
var ImageScroller = function( scrollingElem, interImageSpace, slideSpeed, debugBox ) {
	ImageScroller.haltAllInstances();
	this.instanceNumber = ImageScroller.numInstances++;
	ImageScroller.instances[ this.instanceNumber ] = this;

	this.scrollingElem = scrollingElem;
	this.debugBox = debugBox;

	this.interImageSpace = (interImageSpace?interImageSpace:0);
	this.slideSpeed = (slideSpeed?slideSpeed:ImageScroller.DEFAULT_SLIDE_SPEED);
	this.heartrate = ImageScroller.DEFAULT_HEARTRATE;
	this.pixelsPerBeat = ( this.slideSpeed * this.heartrate ) / 1000 ;

	//this.containedImages = [];
	this.loopbackPosition;
	this.processImages();
	this.currentImage = 0;
	this.currentXOffset = 0;
	this.targetXOffset = 0;

	this.intervalCallbackString = "ImageScroller." +
		"instances[" + this.instanceNumber + "].nextAnimFrame()";

	this.mode = IS_MODE.STOPPED;

	this.locked = false;
	this.numLocks = 0;
	this.locks = {};
	
	var thisA = this;
	if( window.DragTracker ) {
		var dragCallback = function( x, y ) { thisA.updateFromDrag( x, y ); };
		this.dragTracker = new DragTracker( this.scrollingElem, dragCallback );
	}

	this.attachEventMethodsToElem();
};


ImageScroller.numInstances = 0;
ImageScroller.instances = new Array();

ImageScroller.DEFAULT_SLIDE_SPEED = 40;
ImageScroller.DEFAULT_HEARTRATE = 50;

IS_MODE = { STOPPED: 0, SCROLLING: 1, PAUSED: 2 };

ImageScroller.haltAllInstances = function() {
	for( var i = 0; i < ImageScroller.instances.length; i++ ) {
		ImageScroller.instances[ i ].halt();
	}
};

ImageScroller.prototype.processImages = function() {
	var containerElem = this.scrollingElem.getElementsByTagName( "div" )[0];
	
	var containedElems = containerElem.getElementsByTagName( "*" );
	var loopbackPosition = 0;
	var containedImages = [];
	var imagesFound = 0;
	for( var i = 0; i < containedElems.length; i++ ) {
		if( containedElems[ i ].parentNode != containerElem ) continue;

		if( containedElems[ i ].tagName.toLowerCase() == "img" ) {
			loopbackPosition += parseInt( containedElems[ i ].width ) + 
				this.interImageSpace;
			containedImages[ imagesFound++ ] = containedElems[ i ];
		}
		else if( containedElems[ i ].tagName.toLowerCase() == "a" ) {
			var insideLink = containedElems[ i ].getElementsByTagName( "*" )[ 0 ];
			if( insideLink.tagName.toLowerCase() == "img" ) {
				loopbackPosition += parseInt( insideLink.width ) + 
					this.interImageSpace;
				containedElems[ i ].width = insideLink.width;
				containedImages[ imagesFound++ ] = containedElems[ i ];
			}
		}
	}

	this.loopbackPosition = loopbackPosition;

	// Add the first image to the end of the list 
	containerElem.appendChild( containedImages[ 0 ].cloneNode( true ) );

	// Pad right side with duplicates of images from beginning of row
	// so there's no blank space to the right of the last image in the row
	var emptySpace = this.scrollingElem.offsetWidth - 
		containedImages[ containedImages.length - 1 ].offsetWidth - 
		this.interImageSpace;

	var imagesUsed = 1;

	while( emptySpace > 0 ) {
		containerElem.appendChild( containedImages[ imagesUsed ].cloneNode( true ) );
		emptySpace -= containedImages[ imagesUsed ].width - this.interImageSpace;
		imagesUsed++;
		if( imagesUsed >= containedImages.length ) imagesUsed = 0;
	}

};

ImageScroller.prototype.attachEventMethodsToElem = function() {
	var _this = this;
	this.scrollingElem.onmouseover = function() { _this.pause(); };
	this.scrollingElem.onmouseout = function() { _this.resume(); };
};

ImageScroller.prototype.allowDragging = function() {
	this.dragTracker.enable();
	this.draggingAllowed = true;
};

ImageScroller.prototype.disallowDragging = function() {
	this.dragTracker.disable();
	this.draggingAllowed = false;
};

ImageScroller.prototype.updateFromDrag = function( x, y ) {
	if( ! this.draggingAllowed ) return;
	var newXOffset = this.currentXOffset - x;
	//if( newXOffset > this.loopbackPosition ) 
	//	newXOffset -= this.loopbackPosition;

	this.currentXOffset = newXOffset;
	this.scrollingElem.scrollLeft = newXOffset;
};


ImageScroller.prototype.start = function() {
	this.startScrolling();
};

ImageScroller.prototype.stop = function() {
	clearInterval( this.heartbeatHandle );
	this.mode = IS_MODE.STOPPED;
};

ImageScroller.prototype.halt = function() {
	this.stop();
	this.halted = true;
};

ImageScroller.prototype.pauseAndLock = function() {
	this.pause();
	return this.lock();
};

ImageScroller.prototype.lock = function() {
	this.debugBox.value += "locking...\n";
	this.locked = true;
	var key = this.makeKey();
	this.locks[ key ] = true;
	this.numLocks++;
	return key;
};

ImageScroller.prototype.makeKey = function() {
	return (new Date()).getTime();
};

ImageScroller.prototype.unlock = function( key ) {
	if( this.locks[ key ] ) {
		delete this.locks[ key ];
		this.numLocks--;
		if( this.numLocks == 0 )
			this.locked = false;
	}
};

ImageScroller.prototype.pause = function() {
	if( this.locked ) return;
	if( this.mode == IS_MODE.SCROLLING ) {
		clearInterval( this.heartbeatHandle );
		this.mode = IS_MODE.PAUSED;
	}
};

ImageScroller.prototype.resume = function() {
	if( this.halted || this.locked ) return;
	if( this.mode == IS_MODE.SCROLLING ) return;

	if( this.scrollingElem.scrollLeft != this.currentXOffset ) {
		var actualXOffset = this.scrollingElem.scrollLeft;
		if( actualXOffset > this.loopbackPosition ) 
			actualXOffset -= this.loopbackPosition;

		this.currentXOffset = actualXOffset;
	}
	this.heartbeatHandle = setInterval( 
		this.intervalCallbackString, 
		this.heartrate );

	this.mode = IS_MODE.SCROLLING;
};	

ImageScroller.prototype.startScrolling = function() {	
	if( this.halted || this.locked ) return;

	this.mode = IS_MODE.SCROLLING;

	var actualXOffset = this.scrollingElem.scrollLeft;
	if( actualXOffset > this.loopbackPosition ) 
		actualXOffset -= this.loopbackPosition;

	this.currentXOffset = actualXOffset;
	
	clearInterval( this.heartbeatHandle );
	this.heartbeatHandle = setInterval( 
		this.intervalCallbackString, 
		this.heartrate );
};

ImageScroller.prototype.nextAnimFrame = function() {
	if( this.locked ) return;
	if( this.mode == IS_MODE.STOPPED ) {
		clearInterval( this.heartbeatHandle );
		return;
	}
	else if( this.mode == IS_MODE.SCROLLING ) {
		if( this.currentXOffset >= this.loopbackPosition )
			this.currentXOffset -= this.loopbackPosition;

		this.currentXOffset += this.pixelsPerBeat;
		this.scrollingElem.scrollLeft = this.currentXOffset;
	}
};
