var Josephine = {
	conventions: {
		thumb: 'thumb',
		hoverThumb: 'thumb',
		activeThumb: 'thumb',
		full: 'big',
		zoom: 'zoom'
	},

	stageLayout: 'sideArrows',	
	fadeTime: .5,
	slideTime: .25,
	zoomTime: .4,
	zoomFactor: 1.5,
	preloadFullImagesOnDocumentLoad: true,
	preloadHoverImagesOnDocumentLoad: true,	
	preloadZoomImagesOnDocumentLoad: true,
	enableZoomr: true,
	enableSpinr: true,

	swapWait: false,
	panning: false,
	zoomIn: true,
	currentDiv: 'showcase2',
	reserveDiv: 'showcase1',

	images: [],
	current: null,
	currentThumb: null,
	offsets: null,	
	primaryImage: 0,

	zoomOutHook: function(){},
	zoomInHook: function(){},
	swapHook: function(){},
	postEffectSwapHook: function(){},
	nextPrevHook: function(){},

	swapToCurrent: function(thumb, effect, option) {

		if(Josephine.swapWait || Element.hasClassName(thumb,'current')){
			return false;
		}
				
		Josephine.swapWait = true;
		
		//remove the 'current' class from all the thumbs
		Josephine.images.each(function(t){
			Element.removeClassName(t,'current');
		});
		
		//add the 'current' class to the current thumb
		Element.addClassName(thumb,'current');

		//apply the active thumb image to the active thumb
		thumb.src = thumb.src.replace(Josephine.conventions.thumb,Josephine.conventions.activeThumb);

		//Replace all active thumb images with inactive thumb images
		Josephine.images.each(function(t){
	   		if(t!=thumb){
				var activeFind = new RegExp(Josephine.conventions.activeThumb,"gi");
				t.src = t.src.replace(activeFind,Josephine.conventions.thumb);
			}
		});
		
		//get the big image by replacing the 'find' in the thumb src with the 'full'
		var thumbFind = new RegExp(Josephine.conventions.activeThumb,"gi");
		var url = $(thumb).readAttribute('src').replace(thumbFind, Josephine.conventions.full);

		var preloadImg = new Image();
		preloadImg.onload = function(){
			$(Josephine.reserveDiv).innerHTML = '<img id="'+Josephine.reserveDiv+'_img" src="'+url+'"/>';
			Josephine.doSwapEffect(effect, option);
		}
	
		preloadImg.src = url;
		Josephine.currentThumb = thumb;
	},

	doSwapEffect: function(effect, option) {

		Josephine.swapHook();

		var rd = Josephine.reserveDiv;
		var cd = Josephine.currentDiv;

		$(rd+'_img').style.position='absolute';
		$(rd+'_img').style.left = (option.coords)? option.coords[0] : '0px';
		$(rd+'_img').style.top = (option.coords)? option.coords[1] : '0px';

		if(effect=='fade'){
			
			$(rd).style.left = '0px';
			$(rd).style.top = '0px';

			$(rd).style.display = 'none';
			$(rd).style.zIndex = '1';
			$(cd).style.zIndex = '0';

			new Effect.Appear(rd, {
				duration:Josephine.fadeTime,
				afterFinish:function(){
					Josephine.swapCurrent();				
					Josephine.togglePanning();
					Josephine.pan();
					Josephine.postEffectSwapHook();
					Josephine.swapWait=false;
				}
			});
			
		}

		if(effect=='slide'){

			if(!Josephine.zoomIn){
				Josephine.toggleZoom();
				Josephine.stopPanning();
			}
			
			var isNext = (option.direction == 'right' || option.direction == 'down' );
			
			var containerWidth = $('showcase-container').getWidth();
			var containerHeight = $('showcase-container').getHeight();
			var newX = 0;
			var newY = 0;

			if(option.direction == 'up' || option.direction == 'down'){
				$(rd).style.left = 0;
				$(rd).style.top = (isNext? '' : '-' ) + containerHeight + 'px';
				newY = (isNext? containerHeight*-1 : containerHeight );
			}else{
				$(rd).style.top = 0;
				$(rd).style.left = (isNext? '-' : '' ) + containerWidth + 'px';
				newX = (isNext? containerWidth : containerWidth*-1 );
			}
			$(rd).style.display = 'block';
			
			new Effect.Parallel(
				[ 
					new Effect.MoveBy(cd, newY, newX, { sync: true}), 
					new Effect.MoveBy(rd, newY, newX, { sync: true})
				], 
				{ 
					duration: Josephine.slideTime, 
					afterFinish:function(){
						
						Josephine.swapCurrent();
						Josephine.postEffectSwapHook();
						
						Josephine.swapWait=false;
					
					}
				}
			);
		}
	},
	
	swapCurrent: function(){
		//swap the current showcase div
		var tmpDiv = Josephine.reserveDiv;
		Josephine.reserveDiv = Josephine.currentDiv;
		Josephine.currentDiv = tmpDiv;
		
		//empty the reserve div
		$(Josephine.reserveDiv).innerHTML = '';
		
	},
	
	toggleZoom: function(){

		if(Josephine.enableZoomr){

			Josephine.zoomIn = !Josephine.zoomIn;
	
			var ps = $('positionSensor');
			
			if(Josephine.zoomIn){
				ps.removeClassName('zoomout');
				ps.addClassName('zoomin');
				Josephine.zoomOutHook();
			}else{
				ps.removeClassName('zoomin');
				ps.addClassName('zoomout');
				Josephine.zoomInHook();
			}
		}
	},
	
	zoom: function(coords){
		
		if(Josephine.swapWait){ return false; }		
		var ps = $('positionSensor');
		Josephine.swapWait = true;
				
		if(Josephine.zoomIn){

			//Zoom In

			Josephine.toggleZoom();

			var t = $(Josephine.currentDiv + '_img');
			var zf = Josephine.zoomFactor;
		
			var moveCoords = [ coords[0] - coords[0] * zf, coords[1] - coords[1] * zf ];
			if(!(/MSIE/.test(navigator.userAgent))){
				moveCoords = [ Math.floor(moveCoords[0]) , Math.floor(moveCoords[1]) ];
			}
			
			var effects = [
				new Effect.Scale(t, zf * 100,{sync:true,scaleContent:false}),
				new Effect.Move(t,{x:moveCoords[0],y:moveCoords[1],sync:true})
			]
			
			new Effect.Parallel(effects,{duration:Josephine.zoomTime, transition:Effect.Transitions.sinoidal, afterFinish:function(t){

				var fullFind = new RegExp(Josephine.conventions.full,"gi");
				
				var t = $(Josephine.currentDiv + '_img');
					
				var url = t.src.replace(fullFind,Josephine.conventions.zoom);
					
				var preloadImg = new Image();
				preloadImg.onload = function(){
					$(Josephine.reserveDiv).innerHTML = '<img id="'+Josephine.reserveDiv+'_img" src="'+url+'"/>';
					Josephine.doSwapEffect('fade', {coords: [t.style.left,t.style.top]});
				}

				preloadImg.src = url;

	
			}});
				
		}else{
		
			//Zoom Out
		
			Josephine.toggleZoom();
			Josephine.stopPanning();

			var t = $(Josephine.currentDiv + '_img');
			var zf = Josephine.zoomFactor;

			var moveCoords = [ (coords[0] * zf - coords[0]) , (coords[1] * zf - coords[1])  ];

			if(/MSIE/.test(navigator.userAgent)){
				moveCoords = [ Math.floor(moveCoords[0]) , Math.floor(moveCoords[1]) ];
			}

			var effects = [
				new Effect.Scale(t, 100 / zf,{sync:true,scaleContent:false}),
				new Effect.Move(t,{x:moveCoords[0],y:moveCoords[1],sync:true})
			]
			
			new Effect.Parallel(effects,{duration:Josephine.zoomTime, transition:Effect.Transitions.sinoidal, afterFinish:function(t){
	
				var zoomFind = new RegExp(Josephine.conventions.zoom,"gi");
					
				var t = $(Josephine.currentDiv + '_img');
						
				var url = t.src.replace(zoomFind,Josephine.conventions.full);
				
				var preloadImg = new Image();
				preloadImg.onload = function(){
					$(Josephine.reserveDiv).innerHTML = '<img id="'+Josephine.reserveDiv+'_img" src="'+url+'"/>';
					Josephine.doSwapEffect('fade', {coords: [0,0]});
				}

				preloadImg.src = url;
				Josephine.swapWait = true;
		
			}});
		}	
	},
	
	
	startPanning: function(){		
		Josephine.panning = true;
	},
	
	stopPanning: function(){
		Josephine.panning = false;
	},
	
	togglePanning: function(){
		if(Josephine.zoomIn){
			Josephine.stopPanning();	
		}else{
			Josephine.startPanning();
		}
	},
	
	
	followMouse: function(){
				
		$('positionSensor').observe('mousemove', function(event) {
			
			var ps = $('positionSensor');
			var element = $(Josephine.currentDiv);

			var totalOffset = Position.cumulativeOffset(element);
			var pointers = [Event.pointerX(event), Event.pointerY(event)];
			var offsets = [pointers[0] - totalOffset[0], pointers[1] - totalOffset[1] ];
				
			Josephine.offsets = offsets;
			Josephine.pan();
				
		});	
	},
	
	pan: function(){
		if(Josephine.panning){
			var img = $(Josephine.currentDiv+'_img');				
			img.style.left = -Josephine.offsets[0] * Josephine.zoomFactor + Josephine.offsets[0]  + 'px'; 
			img.style.top = -Josephine.offsets[1] * Josephine.zoomFactor + Josephine.offsets[1]  + 'px'; 
		}
	},
	
	nextPrev: function(linkObj){
			
		var direction = '';

		if( Element.hasClassName(linkObj,'prev')){direction = 'right';}
		if( Element.hasClassName(linkObj,'next')){direction = 'left';}

		if( Element.hasClassName(linkObj,'up')){direction = 'down';}
		if( Element.hasClassName(linkObj,'down')){direction = 'up';}

		var designated = 0;
		
		Josephine.images.each(function(img,imgIndex){
			if(img == Josephine.currentThumb){designated = imgIndex;}
		});
		
		if(direction=='up' || direction=='left'){
			designated++;
		}else{
			designated--;
		}
		
		if (!Josephine.images[designated]) {
			designated = (designated > 0) ? 0 : Josephine.images.length - 1;
		}
		
		designated = Josephine.images[designated];
		Josephine.swapToCurrent.apply(Josephine, [designated, 'slide', {direction: direction}]);

		Josephine.nextPrevHook();

	},
	
	
	init: function(){
		
		if(!$('stage')){ return false; }
		
		//Build the stage area 
		var stageHTML = '';	
		if(Josephine.stageLayout == 'sideArrows'){		
			stageHTML = '' + 
			'<table border="0" id="stage-container" class="sideArrows"><tr>' + 
				'<td class="prev-next prev-cell"><a href="#" class="prev">Previous</a></td>' + 
					'<td>'+
						'<div id="showcase-container">' + 
							'<div id="showcase1"></div><div id="showcase2"></div>' +
							'<div id="positionSensor">'+
								'<img src="images/spacer.gif" border="0" galleryimg="no" />' + 
							'</div>' +
						'</div>' +
					'</td>' + 
				'<td class="prev-next next-cell"><a href="#" class="next">Next</a></td>' + 
			'</tr></table>';
	
			$('stage').innerHTML = stageHTML;
		}
		
		if(Josephine.stageLayout == 'vertArrows'){		
			stageHTML = '' + 
			'<table border="0" id="stage-container" class="vertArrows">' +
				'<tr>' + 
					'<td class="prev-next"><a href="#" class="up">Previous</a></td>' + 
				'</tr>' +
				'<tr>' +
					'<td>'+
						'<div id="showcase-container">' + 
							'<div id="showcase1"></div><div id="showcase2"></div>' +
							'<div id="positionSensor">'+
								'<img src="images/spacer.gif" border="0" galleryimg="no" />' + 
							'</div>' +
						'</div>' +
					'</td>' + 
				'</tr>' +
				'<tr>' +
					'<td class="prev-next"><a href="#" class="down">Next</a></td>' + 
				'</tr>' +
			'</table>';
	
			$('stage').innerHTML = stageHTML;
		}
		
		if(Josephine.stageLayout == 'noArrows'){		
			stageHTML = '' + 
			'<div id="stage-container" class="noArrows">' +
				'<div id="showcase-container">' + 
					'<div id="showcase1"></div><div id="showcase2"></div>' +
					'<div id="positionSensor">'+
						'<img src="images/spacer.gif" border="0" galleryimg="no" />' + 
					'</div>' +
				'</div>' +
			'</div>';
	
			$('stage').innerHTML = stageHTML;
		}
		
		//Copy the width and height styles from 'showcase-container' to other divs that are the same size
		$('showcase-container', 'showcase1', 'showcase2', 'positionSensor').invoke('setStyle', {
			width: $('showcase-container').getWidth() + 'px', 
			height: $('showcase-container').getHeight() + 'px'
		});
	
		//Set up the behaviors for the thumbnails
		Josephine.images = $$('.thumbs li img').each(function(t,index){
			Element.addClassName(t,'thumb');
			Event.observe(t,'mouseover',function() {
				Element.addClassName(t,'hover');
				
				if(t != Josephine.currentThumb){
					var thumbFind = new RegExp(Josephine.conventions.thumb+'|'+Josephine.conventions.hoverThumb,"gi");
					var hoverURL = t.src.replace(thumbFind, Josephine.conventions.hoverThumb);
					t.src = hoverURL;
				}
			});
		
			Event.observe(t,'mouseout', function() {
				Element.removeClassName(t,'hover');
				
				if(t != Josephine.currentThumb){
					var hoverFind = new RegExp(Josephine.conventions.hoverThumb,"gi");
					var inactiveURL = t.src.replace(hoverFind, Josephine.conventions.thumb);
					t.src = inactiveURL;
				}
			});
			
			Event.observe(t,'click', function() {
				if(!Josephine.zoomIn){
					Josephine.stopPanning();
					Josephine.toggleZoom();
				}			
				Josephine.swapToCurrent.apply(Josephine, [t,'fade',{}]);
			});
			
			if (t.hasClassName('primary')){Josephine.primaryImage=index;}
			
		});
	  
		// load the first image
		Josephine.swapToCurrent.apply(Josephine, [Josephine.images[Josephine.primaryImage],'fade',{direction: 'none'}]);

		// preload full-size and zoom images
		Josephine.images.invoke('readAttribute', 'src').each(function(src) {
			//get the big image by replacing the 'find' in the thumb src with the 'full'
			var thumbFind = new RegExp(Josephine.conventions.thumb,"gi");

			if(Josephine.preloadFullImagesOnDocumentLoad){
				var fullURL = src.replace(thumbFind, Josephine.conventions.full);
				var preloadImg = new Image()
				preloadImg.src = fullURL;
				preloadImg.style.display='none';
				document.body.appendChild(preloadImg);
			}
			
			if(Josephine.preloadHoverImagesOnDocumentLoad){
				var hoverURL = src.replace(thumbFind, Josephine.conventions.hoverThumb);
				var preloadImg = new Image()
				preloadImg.src = hoverURL;
				preloadImg.style.display='none';
				document.body.appendChild(preloadImg);
			}
									
			if(Josephine.enableZoomr && Josephine.preloadZoomImagesOnDocumentLoad){
				var zoomURL = src.replace(thumbFind, Josephine.conventions.zoom);
				var preloadImg = new Image()
				preloadImg.src = zoomURL;
				preloadImg.style.display='none';
				document.body.appendChild(preloadImg);
			}
		});
		
		//Find the previous and next buttons and assign the nextPrev function to their click events
		$$('#stage a.prev', '#stage a.next','#stage a.up','#stage a.down').each(function(linkObj){
			Event.observe(linkObj,'click', function(event) {
				Event.stop(event);
				Josephine.nextPrev(linkObj);
			});
		});	
			
		//Set click event to zoom
		if(Josephine.enableZoomr){
			Event.observe('positionSensor','click', function(event) {
				Josephine.zoom(Josephine.offsets);
			});	
			
			$('positionSensor').addClassName('zoomin');
		}
		
		//Set mouse move event to update coords	
		Josephine.followMouse();	
	}
};

Event.onDOMReady(Josephine.init);
