﻿/*slide projector
version 11 12/14/08 added step play
version 10 10/17/08 added check for loaded slide to show
version 9 10/2/08 dc
	- added saving of the slide list text.  -->imageListText
	uses shuffled slidelist, rather than basic random advance (requires megalo-scripts.js for array shuffle function)
	adds reversePlay and paused
		
version 8 10/29/07 dc - derived from version 7 of SlideShow.js. Added block play and one time only play. Removed file read functionality/.
version 7  2/9/07 - appendItemNumberToIDs option to fill a table from the projector - IDs in the destination should be the imageID and captionID with the slide number appended
	version 6  2/7/07 - Init: improved blank last line search. Added useFilenameAsCaption
	version 5  2/1/07 dc - added added skip first line and add image file extension (for use with straight Aperture metadata. Need to add keyword parsing later
	version 4  1/29/07 dc - added optional manual slide advance (including 1st) by repeated calls to ShowCurrentAndPrepareNext ().
*/ 
	
/* 
Slide object
*/
	function slide(){
		this.imageURL='';
		this.imageOBJ='';
		this.caption='';
		this.keywords='';

		this.downloadSlide = downloadSlide;
		
		function downloadSlide (   ){
			if (!this.imageObj){this.imageOBJ=new Image();}
			this.imageOBJ.src= this.imageURL;
		};
	}

/*slide projector

	MAIN slideProjector OBJECT
	 startup sequence:
	 
	 	start (called on page load) ->loadTextFile (via XMLHTTP object)
	 	PosFileReady (callback)
	 	loadAndStart...
	 
	*/ 

function slideProjector (   ) {
	
 	this.supported =   ( document.getElementById || document.all  );
 	if  ( !this.supported  ){return false;}
	this.playstate = "running"; //paused, stepping_backward, stepping_fwd
	this.autoAdvance=true;
	this.going_forward=true;// marker to show current dir - set by 

	this.screenID="";// the ID (or root) of the image tag on the page.
	this.captionID="";//...
	
	//special caption handling for creating file listings
	this.useFilenameAsCaption=false;// override any caption data in slide
	// following 2 only apply if useFilenameAsCaption is true:
	this.overrideExistingCaption=true;//ignore existing caption in the field
	this.replaceCaptionDashesWithSpaces=true;//allows wrap
	
	this.appendItemNumberToIDs = false;// adds the current ImageNum to the ID, for filling tables
	this.numberedIdOffset = 0;//if filling ids numbered sequentialloy from zero with slides starting at some arbitrary point
	this.startingNum = 0;
	this.blockPlaySize = 0;
	this.blockCounter=0;
	this.playThroughOnceOnly=false;
	this.slideShowImageDirectory="";// this can be left empty if you supply full filename and path for each slide.
	
	this.slideListURL="";//must be a text file
	this.skipFirstLine = true;//for handling text files with headings (like Aperture metadata)
	this.imageFileExtension="";//ext to add if needed to each slide name 
	this.imageListText="";//where you keep the text passed in from "load"
	
	this.slideDelimiter='\n';//newlne for each slide
	this.fieldDelimiter="\t";//tab delimited fields:  Name Caption Keywords
	this.itemDelimiter=",";// for comma-delimited keywords
	
	this.random_start=false;// allows start at random slide, but regular advance
	this.random_adv=false; //  random advance
	this.dwellTime=1500;//milliseconds, can be overruled by the slideDwellTime of an individual slide  ( if 

	this.slideList=new Array (   );//will be filled up with slide objects
	
	
	this.ImageNum=0;
	this.next_number = 1;
	
	this.timerID = 0;
	
	this.remove = remove;
	function remove(){
	
		if(this.autoAdvance){
			window.clearTimeout(this.timerID);
		}
	
	};
	

	this.getNextSlideNumber = getNextSlideNumber;
	function getNextSlideNumber (   ) {
	//new random function scrambles the list, so just sequential is fine
		
			this.ImageNum =  ( this.ImageNum+1  ) %  ( this.number_of_slides  );
			this.next_number =  ( this.ImageNum+1  ) %  ( this.number_of_slides  );
	
	};
	
	this.showSlide = showSlide;
		function showSlide ( whichOne ){
			var IdNum = whichOne-this.numberedIdOffset;
			var id = this.screenID;
			if(this.appendItemNumberToIDs){id=id+IdNum;}
			document.images[ id ].src = this.slideList[ whichOne ].imageURL;
			if(!this.captionID==''){
				id = this.captionID;
				if(this.appendItemNumberToIDs){id=id+IdNum;}
				document.getElementById ( id ).innerHTML=this.slideList[ whichOne ].caption;	
		}
		
	};
	
	this.setStartingSlideNumAndBlockSize = setStartingSlideNumAndBlockSize;
	function setStartingSlideNumAndBlockSize( aNum, aSize ){
		
		this.ImageNum = anum;
		this.blockPlaySize = aSize;
		this.blockCounter=1;
		
		
	};


// fill up the slideList with new slide objects
	this.loadAndStart = loadAndStart;
	function loadAndStart ( slidelisttext  ){
		this.imageListText=slidelisttext;
		var NameArray = new Array (   );
		NameArray=slidelisttext.split ( this.slideDelimiter );
		
		if(this.skipFirstLine){NameArray.shift();}//remove first line
       
		this.number_of_slides = NameArray.length
		//test for ws at char 0 of last element
		if((/\s/.test(((NameArray[NameArray.length-1]).charAt(0))))||(NameArray[NameArray.length-1])==''){
			this.number_of_slides=this.number_of_slides-1;
			}

       	for  ( var i=0; i<this.number_of_slides;i++  ){

					ParamArray=NameArray[ i ].split ( this.fieldDelimiter );					
		
		 			this.slideList[ i ] = new slide (   );
		 			this.slideList[ i ].imageURL=this.slideShowImageDirectory+ParamArray[ 0 ]+this.imageFileExtension;
		 			
		 			if(this.useFilenameAsCaption){
				 		this.slideList[ i ].caption=ParamArray[ 0 ];//use filename
				 		if(this.replaceCaptionDashesWithSpaces){
				 			this.slideList[ i ].caption = (this.slideList[ i ].caption).replace(/-/g," ");
				 			}
			 			
			 			
			 			if(!this.overrideExistingCaption){
			 			// check for any non-whitespace
			 				if((/\S/g.test(ParamArray[1]))){this.slideList[ i ].caption=ParamArray[ 1 ];}
			 				}	
			 			
			 		}
			 		else{
			 			this.slideList[ i ].caption=ParamArray[ 1 ];//caption as usual
			 			}
		 		}
		 		
		 		
		if(this.random_adv){fisherYatesShuffle(this.slideList);}//randomize it (requires megalo-scripts.js)
		this.ImageNum=0;
		if(this.random_start){this.ImageNum = randNum ( 0, this.number_of_slides-1  );}
       
		this.slideList[ this.ImageNum ].downloadSlide();// for next time

		if(this.autoAdvance){
			this.ShowCurrentAndPrepareNext (   );
		}
	};
	
	
	
	this.reverseDirection = reverseDirection;
	function reverseDirection() {
		this.slideList.reverse();
		this.going_forward = !this.going_forward;
		this.ImageNum = (this.slideList.length - this.ImageNum - 1);
		this.getNextSlideNumber (   );
		};

	this.ShowCurrentAndPrepareNext=ShowCurrentAndPrepareNext;
	function ShowCurrentAndPrepareNext (  aplaystate ) {
		
		window.clearTimeout(this.timerID);
		
		if((typeof aplaystate) != undefined){
			this.playstate = aplaystate;}
		
		switch (this.playstate)
		{
		 case "paused":
		 	this.autoAdvance=false;
			break;
			
		 case "stepping_backward":
		 	if(this.going_forward) {this.reverseDirection();this.ShowCurrentAndPrepareNext("stepping_backward");}
		 	this.autoAdvance=false;
			this.going_forward=false;// marker to show current dir - set by 
			break;
			
		 case "stepping_fwd":
		 	if(!this.going_forward) {this.reverseDirection();this.ShowCurrentAndPrepareNext("stepping_fwd");}
		 	this.autoAdvance=false;
			this.going_forward=true;// marker to show current dir - set by 
			break;
			
		 case "running":
		 	if(this.autoAdvance){
				this.ShowCurrentAndPrepareNext("paused");// this not really working yet
				return;
				}
		 //need to cover no arg use from elsewhere and treat as std running
		 default:
		 	if(!this.going_forward) {this.reverseDirection();}
			this.playstate = "running"; 
			this.going_forward=true;// marker to show current dir - set by 
			this.autoAdvance=true;
			break;
		}
		
		if (this.playstate != "paused"){
			if(this.slideList[ this.ImageNum ].imageOBJ.complete){
				this.showSlide ( this.ImageNum );
			}		
			this.getNextSlideNumber (   );
			this.slideList[ this.next_number ].downloadSlide ();
		}
		
		if (this.playstate == "running"){
			var _this=this;
			var recur_call = function (   ){_this.ShowCurrentAndPrepareNext ();};
			this.timerID = window.setTimeout ( recur_call, this.dwellTime  );
			
			if(this.blockPlaySize>0){this.blockCounter++;}
			if ( this.blockCounter>this.blockPlaySize ){
				this.blockCounter=0;
				if(this.playThroughOnceOnly){this.autoAdvance=false;}//stop playback after this slide if so
				}
			}
		

	};


	function randNum ( x, y  ) {
		var range = y - x + 1;
		return Math.floor ( Math.random() * range  ) + x;
	};
	


}// end of slide projector