/**
 * A-ram-o-pan class
 */
function PanHandler (handlerId) {
	
	this.init = function (handlerId)
	{
		this.doctype = this.getDocType();
		
		this.handlerId = handlerId;
		this.obj = handlerId+'PanHandler';
		eval(this.obj+' = this;');
		
		this.elements = [];
		this.panElements = [];
		this.panTimers = [];
		this.panPositions = [];
		this.panSpeeds = [];
		this.panDirections = [];
		this.panWidths = [];
		
		this.windowClassName = 'pan-window';
		this.controlsClassName = 'pan-controls';
		this.containerClassName = 'pan-container';
		this.selectedClass = 'selected';
		this.defaultSpeed = 'medium';
		this.defaultDirection = 'forward';
		
		this.intervals = { // in ms
			'slow'   : 150,
			'medium' : 50,
			'fast'   : 5
		};
		this.increments = { // in pixels
			'slow'   : 1,
			'medium' : 1,
			'fast'   : 1
		};
	}
	
	this.convert = function (className)
	{
		this.elements = this.getElementsByClass(className,'img');
		
		for (elementIndex in this.elements) {
			if (!this.elements[elementIndex]) continue;
			imageSrc = this.elements[elementIndex].src;
			imageAlt = this.elements[elementIndex].alt;
			//imageWidth = this.elements[elementIndex].width;
			//imageHeight = this.elements[elementIndex].height;
			
			/*IE7 is a big steamy piece of shit so im hardcoding this mo-fo*/
			imageWidth = 2056;
			imageHeight = 500;			
			
			panElement = this.appendPanElement(elementIndex, imageSrc, imageWidth, imageHeight, imageAlt);
			
			this.elements[elementIndex].style.display = 'none';
			
			if (this.hasClass(this.elements[elementIndex], 'pause')) {
				this.pause(elementIndex);
			} else {
				this.play(elementIndex);
			}
		}
	}
	
	this.pan = function (elementIndex)
	{
		//console.debug(this.panElements[elementIndex].className);
		
		// Opera will only display backgrounds offset by a certain number of pixels (~9999).
		// this shouldn't matter for our purposes, we will just reset once we reach the end of the image.
		// This should appear seemless, as we jump the position back the width of the entire image.
		// Seems to produce a flicker on Opera as it resets (damn Opera! can't please it).
		// see *Opera Fix*
		
		if (this.panDirections[elementIndex] == 'forward') {
			this.panPositions[elementIndex] = this.panPositions[elementIndex]+this.getIncrement(elementIndex);
			// *Opera Fix*
			if (this.panPositions[elementIndex] > this.panWidths[elementIndex]) {
				this.panPositions[elementIndex] = this.panPositions[elementIndex]-this.panWidths[elementIndex];
			}
		} else {
			this.panPositions[elementIndex] = this.panPositions[elementIndex]-this.getIncrement(elementIndex);
			// *Opera Fix*
			if (this.panPositions[elementIndex] < this.panWidths[elementIndex]) {
				this.panPositions[elementIndex] = this.panPositions[elementIndex]+this.panWidths[elementIndex];
			}
		}
		
		this.panElements[elementIndex].style.backgroundPosition = this.panPositions[elementIndex]+'px top';
		
		// ensure that this pan window has only one timer on it.
		window.clearTimeout(this.panTimers[elementIndex]);
		this.panTimers[elementIndex] = window.setTimeout(this.obj+'.pan('+elementIndex+')', this.getInterval(elementIndex));
	}
	this.play = function (elementIndex)
	{
		this.pan(elementIndex);
		this.removeControlsSelected (elementIndex);
		currentObj = this.findObj(this.controlsClassName+'-'+elementIndex+'-play');
		//if (!currentObj) return;
		this.addClass(currentObj, this.selectedClass);
	}
	this.pause = function (elementIndex)
	{
		window.clearTimeout(this.panTimers[elementIndex]);
		this.removeControlsSelected (elementIndex);
		currentObj = this.findObj(this.controlsClassName+'-'+elementIndex+'-pause');
		//if (!currentObj) return;
		this.addClass(currentObj, this.selectedClass);
	}
	
	
	this.removeControlsSelected = function (elementIndex)
	{
		currentObj = this.findObj(this.controlsClassName+'-'+elementIndex+'-play');
		if (currentObj)
			this.removeClass(currentObj, this.selectedClass);
		
		currentObj = this.findObj(this.controlsClassName+'-'+elementIndex+'-pause');
		if (currentObj)
			this.removeClass(currentObj, this.selectedClass);
	}
	
	this.setSpeed = function (elementIndex, speed)
	{
		this.panSpeeds[elementIndex] = speed;
		
		for(id in this.intervals) {
			currentObj = this.findObj(this.controlsClassName+'-'+elementIndex+'-'+id);
			if (!currentObj) continue;
			this.removeClass(currentObj, this.selectedClass);
		}
		currentObj = this.findObj(this.controlsClassName+'-'+elementIndex+'-'+speed);
		if (!currentObj) return;
		this.addClass(currentObj, this.selectedClass);
	}
	
	this.setDirection = function (elementIndex, direction)
	{
		this.panDirections[elementIndex] = direction;
		
		
		currentObj = this.findObj(this.controlsClassName+'-'+elementIndex+'-forward');
		if (currentObj) this.removeClass(currentObj, this.selectedClass);
		
		currentObj = this.findObj(this.controlsClassName+'-'+elementIndex+'-reverse');
		if (currentObj) this.removeClass(currentObj, this.selectedClass);

		//alert(this.controlsClassName+'-'+elementIndex+'-'+direction);
		currentObj = this.findObj(this.controlsClassName+'-'+elementIndex+'-'+direction);
		if (currentObj) this.addClass(currentObj, this.selectedClass);
	}
	
	this.getIncrement = function (elementIndex)
	{
		speed = this.panSpeeds[elementIndex];
		return this.increments[speed];
	}
	
	this.getInterval = function (elementIndex)
	{
		speed = this.panSpeeds[elementIndex];
		return this.intervals[speed];
	}
	
	this.getDocType = function ()
	{
		/*
			alert(document.doctype.entities);
			alert(document.doctype.notation);
			alert(document.doctype.publicId);
			alert(document.doctype.systemId);
			return;
		*/
		if (!document.doctype || !document.doctype.systemId) return 'html';
		if (document.doctype.systemId.indexOf('xhtml1') != -1) return 'xhtml1';
		if (document.doctype.systemId.indexOf('xhtml2') != -1) return 'xhtml2';
		return 'html';
	}
	
	this.appendPanElement = function (elementIndex, imageSrc, imageWidth, imageHeight, imageAlt)
	{
		panWindow = document.createElement('div');
		panWindow.className = this.windowClassName;
		panWindow.style.height = imageHeight+'px';
		panWindow.style.backgroundImage = 'url('+imageSrc+')';
		panWindow.style.backgroundRepeat = 'repeat-x';
		panWindow.style.backgroundPosition = '0px top';
				
		// use a <h> tag for xhtml 2 :) - or a <h3> tag for html and xhtml 1 :(
		panTitle = (this.doctype == 'xhtml2') ?document.createElement('h'):document.createElement('h3');
		panTitleText = document.createTextNode(imageAlt);
		//panTitle.appendChild(panTitleText);
		
		panControlsDiv = document.createElement('div');
		panControlsDiv.className = this.controlsClassName;
		
			// CONTROLS
			panControlsDl = document.createElement('dl');
			panControlsDiv.appendChild(panControlsDl);
			panContDt = document.createElement('dt');
			panContDt.className = this.controlsClassName+'-controls';
			panContDt.setAttribute('id',this.controlsClassName+'-'+elementIndex+'-controls');
				panContDtText = document.createTextNode('controls');
			panContDt.appendChild(panContDtText);
			
				playContDd = document.createElement('dd');
					playControl = document.createElement('a');
					playControl.className = this.controlsClassName+'-play';
					playControl.setAttribute('id',this.controlsClassName+'-'+elementIndex+'-play');
					this.setEvent(playControl, 'click',this.obj+'.play("'+elementIndex+'")');
						playText = document.createTextNode('play');
					playControl.appendChild(playText);
				playContDd.appendChild(playControl);
				
				pauseContDd = document.createElement('dd');
					pauseControl = document.createElement('a');
					pauseControl.className = this.controlsClassName+'-pause last-control';
					pauseControl.setAttribute('id',this.controlsClassName+'-'+elementIndex+'-pause');
					this.setEvent(pauseControl, 'click', this.obj+'.pause("'+elementIndex+'")');
						pauseText = document.createTextNode('pause');
					pauseControl.appendChild(pauseText);
				pauseContDd.appendChild(pauseControl);
				
				panControlsDl.appendChild(panContDt);
				panControlsDl.appendChild(playContDd);
				panControlsDl.appendChild(pauseContDd);
			
			
			// SPEED
			panSpeedDl = document.createElement('dl');
			panControlsDiv.appendChild(panSpeedDl);
			panSpeedDt = document.createElement('dt');
			panSpeedDt.setAttribute('id',this.controlsClassName+'-speed');
			panSpeedDt.setAttribute('id',this.controlsClassName+'-'+elementIndex+'-speed');
				panSpeedDtText = document.createTextNode('speed');
			panSpeedDt.appendChild(panSpeedDtText);
				
				
				slowSpeedDd = document.createElement('dd');
					slowSpeedA = document.createElement('a');
					slowSpeedA.className = this.controlsClassName+'-slow';
					slowSpeedA.setAttribute('id',this.controlsClassName+'-'+elementIndex+'-slow');
					this.setEvent(slowSpeedA, 'click', this.obj+'.setSpeed("'+elementIndex+'","slow")');
						slowSpeedText = document.createTextNode('slow');
					slowSpeedA.appendChild(slowSpeedText);
				slowSpeedDd.appendChild(slowSpeedA);
				
				medSpeedDd = document.createElement('dd');
					medSpeedA = document.createElement('a');
					medSpeedA.className = this.controlsClassName+'-medium';
					medSpeedA.setAttribute('id',this.controlsClassName+'-'+elementIndex+'-medium');
					this.setEvent(medSpeedA, 'click', this.obj+'.setSpeed("'+elementIndex+'","medium")');
						medSpeedText = document.createTextNode('medium');
					medSpeedA.appendChild(medSpeedText);
				medSpeedDd.appendChild(medSpeedA);
				
				fastSpeedDd = document.createElement('dd');
					fastSpeedA = document.createElement('a');
					fastSpeedA.className = this.controlsClassName+'-fast last-control';
					fastSpeedA.setAttribute('id',this.controlsClassName+'-'+elementIndex+'-fast');
					this.setEvent(fastSpeedA, 'click', this.obj+'.setSpeed("'+elementIndex+'","fast")');
						fastSpeedText = document.createTextNode('fast');
					fastSpeedA.appendChild(fastSpeedText);
				fastSpeedDd.appendChild(fastSpeedA);
				
				
				//panSpeedDl.appendChild(panSpeedDt);
				//panSpeedDl.appendChild(slowSpeedDd);
				//panSpeedDl.appendChild(medSpeedDd);
				//panSpeedDl.appendChild(fastSpeedDd);
			
			
			// DIRECTION
			panDirectionDl = document.createElement('dl');
			panControlsDiv.appendChild(panDirectionDl);
			panDirectionDt = document.createElement('dt');
			panDirectionDt.className = this.controlsClassName+'-direction';
			panDirectionDt.setAttribute('id',this.controlsClassName+'-'+elementIndex+'-direction');
				panDirectionDtText = document.createTextNode('direction');
			panDirectionDt.appendChild(panDirectionDtText);
			
				forwardDirectionDd = document.createElement('dd');
					forwardDirectionA = document.createElement('a');
					forwardDirectionA.className = this.controlsClassName+'-forward';
					forwardDirectionA.setAttribute('id',this.controlsClassName+'-'+elementIndex+'-forward');
					this.setEvent(forwardDirectionA, 'click', this.obj+'.setDirection("'+elementIndex+'","forward")');
						forwardDirectionText = document.createTextNode('forward');
					forwardDirectionA.appendChild(forwardDirectionText);
				forwardDirectionDd.appendChild(forwardDirectionA);
				
				reverseDirectionDd = document.createElement('dd');
					reverseDirectionA = document.createElement('a');
					reverseDirectionA.className = this.controlsClassName+'-reverse last-control';
					reverseDirectionA.setAttribute('id',this.controlsClassName+'-'+elementIndex+'-reverse');
					this.setEvent(reverseDirectionA, 'click', this.obj+'.setDirection("'+elementIndex+'","reverse")');
						reverseDirectionText = document.createTextNode('reverse');
					reverseDirectionA.appendChild(reverseDirectionText);
				reverseDirectionDd.appendChild(reverseDirectionA);
				
				panDirectionDl.appendChild(panDirectionDt);
				panDirectionDl.appendChild(forwardDirectionDd);
				panDirectionDl.appendChild(reverseDirectionDd);
		
		
		
		
		
		panContClearingElement = document.createElement('span');
		panContClearingElement.className = 'clear';
		panControlsDiv.appendChild(panContClearingElement);
		
		panContainer = document.createElement('div');
		panContainer.className = this.containerClassName;
		
		panContainer.appendChild(panTitle);
		panContainer.appendChild(panWindow);
		panContainer.appendChild(panControlsDiv);
		
		
		this.elements[elementIndex].parentNode.appendChild(panContainer);
		this.panElements[elementIndex] = panWindow;
		this.panPositions[elementIndex] = 0;
		this.panWidths[elementIndex] = imageWidth;
		
		this.setSpeed(elementIndex, this.getInitialSpeed(elementIndex));
		this.setDirection(elementIndex, this.getInitialDirection(elementIndex));
		
		return true;
	}
	
	/**
	 * cross-browser function to set a string as an event on an element
	 */
	this.setEvent = function (element, eventType, actionStr)
	{
		if (!element) return false;
		eval("action = function () { "+actionStr+"; };");
		eval('element.on'+eventType+'=action;');
	}
	
	this.getInitialSpeed = function (elementIndex)
	{
		if (this.hasClass(this.elements[elementIndex], 'slow')) {
			return 'slow';
		} else if (this.hasClass(this.elements[elementIndex], 'medium')) {
			return 'medium';
		} else if (this.hasClass(this.elements[elementIndex], 'fast')) {
			return 'fast';
		} else {
			return this.defaultSpeed;
		}
	}
	
	this.getInitialDirection = function (elementIndex)
	{
		if (this.hasClass(this.elements[elementIndex], 'forward')) {
			return 'forward';
		} else if (this.hasClass(this.elements[elementIndex], 'reverse')) {
			return 'reverse';
		} else {
			return this.defaultDirection;
		}
	}
	
	this.hasClass = function (el, className)
	{
		if (!(el && el.className)) {
			return;
		}
		var cls = el.className.split(" ");
		var ar = new Array();
		for (var i = cls.length; i > 0;) {
			if (cls[--i] == className) {
				return true;
				//ar[ar.length] = cls[i];
			}
		}
		//el.className = ar.join(" ");
		return false;
	}
	
	this.removeClass = function (el, className)
	{
		if (!(el && el.className)) {
			return;
		}
		var cls = el.className.split(" ");
		var ar = new Array();
		for (var i = cls.length; i > 0;) {
			if (cls[--i] != className) {
				ar[ar.length] = cls[i];
			}
		}
		el.className = ar.join(" ");
	}
	
	this.addClass = function (el, className)
	{
		this.removeClass(el, className);
		el.className += " " + className;
	}
	
	// http://www.dustindiaz.com/getelementsbyclass/
	this.getElementsByClass = function (searchClass,tag,node)
	{
		var classElements = new Array();
		if ( node == null )
			node = document;
		if ( tag == null )
			tag = '*';
		var els = node.getElementsByTagName(tag);
		var elsLen = els.length;
		var pattern = new RegExp("(^|\\s)"+searchClass+"(\\s|$)");
		for (i = 0, j = 0; i < elsLen; i++) {
			if ( pattern.test(els[i].className) ) {
				classElements[j] = els[i];
				j++;
			}
		}
		return classElements;
	}
	
	this.findObj = function (n, d) { //v4.01
	  var p,i,x;  if(!d) d=document; if((p=n.indexOf("?"))>0&&parent.frames.length) {
		d=parent.frames[n.substring(p+1)].document; n=n.substring(0,p);}
	  if(!(x=d[n])&&d.all) x=d.all[n]; for (i=0;!x&&i<d.forms.length;i++) x=d.forms[i][n];
	  for(i=0;!x&&d.layers&&i<d.layers.length;i++) x=this.findObj(n,d.layers[i].document);
	  if(!x && d.getElementById) x=d.getElementById(n); return x;
	}	
	
	this.init(handlerId);
}
