// JavaScript Document

//this function will load a file and return an array of the lines read
//It works by using an XMLHttpRequest then parsing the returned file into lines.

function debug(debugtext) {
	if (document.getElementById("debugObj")){
	  debugObj = document.getElementById("debugObj");
	}
	else {
      debugObj = document.createElement("textarea");
	  debugObj.id="debugObj";
	  debugObj.style.backgroundColor="black";
	  debugObj.style.color="white";
	  debugObj.style.position="absolute";
	  debugObj.style.top = "20px";
	  debugObj.style.left = "20px";
	  debugObj.style.width = "200px";
	  debugObj.style.height = "100px";
	  document.body.appendChild(debugObj);
	}
	debugObj.innerHTML = debugObj.innerHTML + "\r" + debugtext;
}



function fileLoad(filename) {
  xmlRequest=new XMLHttpRequest();                                                          // Create a new requestor
  xmlRequest.open('GET',filename,false);                                                    // Prepare a SYNCHRONOUS get request (so careful, this is blocking!);
  xmlRequest.send("");                                                                      // Send the request
  tempArray=xmlRequest.responseText.split(new RegExp(/\r/));
  returnArray = new Array;
  for (x=0; x<tempArray.length; x++) {
	 if (tempArray[x] != "") {
	   returnArray.push(tempArray[x]);
	 }
  }
  return returnArray;                                                        // Split the retrieved lines into an array
}











function testCallback(){
	this.counter = 0;
	
	this.callback = function(){
		alert(this.counter);
		if (this.counter < 10) {
		  this.counter++;
		  var _this = this;
		  var f = function() {_this.callback();};
		  setTimeout(f,3000);	
		}
	}
}




// This class uses an array to create an animation 'timeline'. Each element in the array represents a single animation frame
// So... element[0] = frame 0 and element [20] = frame 20.....so far so good.
// It has a method called 'addTransition' which will interpolate a position between two key frames....
// So... addTransition("top",10,110,0,1000) will create an animation timeline where the 'top' of an object will move between 10 and 110
// between 0 and 1000 milliseconds. The function will automatically convert milliseconds to frames. i.e. 100ms at 20 frames per second would be frame 2
function AnimPath() {
   this.top = new Array();
   this.left = new Array();
   this.width = new Array();
   this.height = new Array();
   this.opacity = new Array();

   this.addTransition = function(param,startValue,endValue,startTime,endTime){
     fps = 20;
	 startFrame = (startTime/1000)*fps;
	 endFrame = (endTime/1000)*fps;
	 totalFrames = endFrame - startFrame;
	 stepValue = (endValue - startValue)/(totalFrames-1);
	 for (i = 0; i < totalFrames; i++) {
		switch (param) {
		  case "top": this.top[startFrame+i] = startValue + Math.round((i*stepValue)); break;
		  case "left": this.left[startFrame+i] = startValue + Math.round((i*stepValue)); break;
		  case "width": this.width[startFrame+i] = startValue + Math.round((i*stepValue)); break;
		  case "height": this.height[startFrame+i] = startValue + Math.round((i*stepValue)); break;
		  case "opacity": this.opacity[startFrame+i] = startValue + Math.round((i*stepValue)); break;
		}
	 }
   }
   
   this.show = function(){
	   var msgStr= "";
	  for (i = 0; i < this.top.length; i++) {
		 msgStr = msgStr + "t[" + i + "]=" + this.top[i] + " l[" + i + "]=" + this.left[i] +" w[" + i + "]=" + this.width[i] + " h[" + i + "]=" + this.height[i] + " o[" + i + "] = " + this.opacity[i] +"\n";
	  }
	  alert(msgStr);
   }
}







// This class takes is passed a target object to animate.
// It contains an AnimPath class that must be used to define an animation path (see the class details on how to use);
// The 'doAnim' method will cause the target object to be animated.
// It works by reading each AnimPath element (one element per frame) and moving the target object based on the values in the AnimPath.
function Animator(newTarget) {
	this.target = this.target = document.getElementById(newTarget);
	this.opacity=100;
	this.animPath = new AnimPath();
    this.currentFrame = 0;
	this.enableOpacity = true; //this is a hack to disable Opacity updates.... for some reason Opacity updates in IE aren't working properly on some items. 
	
	this.setTarget = function (newTarget) {	this.target = document.getElementById(newTarget);}
	this.getTarget = function()           {	return this.target;      }
   
 
    this.getValue = function(param){
          switch (param) {
			case "top":     return parseInt(this.target.style.top.replace("px","")); break;
			case "left":    return parseInt(this.target.style.left.replace("px","")); break;
			case "width":   return parseInt(this.target.style.width.replace("px","")); break;
			case "height":  return parseInt(this.target.style.height.replace("px","")); break;
			case "opacity": return this.opacity;break;
		  }
	}
	
    this.setValue = function(param,desiredVal){
          //alert("setValue:" + param + "," + desiredVal);
          switch (param) {
			case "top":     this.target.style.top = desiredVal + "px"; break;
			
			case "left":    this.target.style.left = desiredVal + "px"; break;
			case "width":   this.target.style.width = desiredVal + "px"; break;
            case "height":  this.target.style.height = desiredVal + "px"; break;
			case "opacity": this.target.style.opacity = desiredVal/100;
             	            this.target.style.filter = "alpha(opacity = " + desiredVal + ")";
	                        this.opacity = desiredVal; break;
		  }
	}
	

	
	this.doAnimation = function() {
		if (this.currentFrame < this.animPath.top.length) {
			this.setValue("top",this.animPath.top[this.currentFrame]);
			this.setValue("left",this.animPath.left[this.currentFrame]);
			this.setValue("width",this.animPath.width[this.currentFrame]);
			this.setValue("height",this.animPath.height[this.currentFrame]);
			if (this.enableOpacity) {
				this.setValue("opacity",this.animPath.opacity[this.currentFrame]);
			}
			this.currentFrame++;
	        var _this = this;
		    var f = function() {_this.doAnimation();};
		    setTimeout(f,50);
   	   }
	}

}









// This class will load a number of image objects into memory
// It has two primary uses... firstly it can be used as an image 'preloader', that is to say, to load
// images at the start of a web surfing session so that the browser caches them locally, and makes the 
// end user surfing experience faster (since there should be much less 'lag' as the browser tries to download
// download the images on demand.
// Secondly, it can be used for slideshow type work, were multiple images are cached for display.
//
// The ImageCache object has four callback functions that tell the observer of the progress of the image loading.
// onload will be called for each individual image that has been successfully loaded
// onerror will occur for each individual image that creates some error 
// onabort will occur for each individual image that has been aborted (stopped by end user clicking)
// oncompleted will occur just once, when ALL the images have been processed (either loaded, or failed)
//
// So, you must be aware that even if 100 images are requested to be loaded, some may fail to load. Therefore
// 'oncompleted' means everything is finished, not that all images loaded.
//
// The observer can see the progress made so far by accessing the member variables, in particular the following:
// imagesProcessed (How many images we have managed to load / fail so far
// imagesLoaded (How many images have been successfully loaded so far
// imagesCount (How many images in total, we are attempting to load
//
// The imageList array will containt the filenames of the images
// The imageObjs array contains the actual image objects

function ImageCache() {                                                                                           
  this.onload = null;                                                                                            // Initialise the callback pointers
  this.onerror = null;
  this.onabort = null;
  this.oncompleted= null;
  this.imageList = new Array;                                                                                    // Initialise the imageList and imageObj arrays
  this.imageObjs = new Array;
  this.imagesProcessed = 0;                                                                                      // Initialise our stats / totals
  this.imagesLoaded = 0;
  this.imagesCount = 0;
  var me = this;                                                                                                 // This is quirky, but we need to maintain a pointer to ourself (so we can use callbacks
  
 
  this.loadImages = function(rootDir) {                                                               
    this.imageList = fileLoad('phpscript/dirlist.php?rootDir=' + rootDir + '&recurse=TRUE');                     // Load a text file of all the images requested
    this.imagesCount = this.imageList.length;                                                                    // Update the count of images to the number of images we found
    for (i = 0; i < this.imagesCount; i++) {	                                                                 // For each of those images found
	  this.imageObjs[i] = new Image();                                                                           //   Create a real instance of image
	  this.imageObjs[i].onload = function() {me.incrementLoaded();};                                             //   Add ourself as an observer for the image loading events
	  this.imageObjs[i].onerror = function() {me.incrementError();};                                             //
	  this.imageObjs[i].onAbort = function() {me.incrementAborted();};                                           //
	  this.imageObjs[i].src = this.imageList[i];                                                                 //   Give the image object the filename it needs to load
    }	
  }
  
  this.incrementLoaded = function() {                                                                            // This function is 'called back' by each image object that is loaded
    this.imagesProcessed++;                                                                                      // So increment the number of images processed
    this.imagesLoaded++;                                                                                         // and increment the number of images loaded            
    if (this.onload){
	  this.onload();                                                                                             // then notify those observing US	  
	}
    if (this.imagesProcessed >= this.imagesCount) {                                                              // If we have processed all the images we expected to
	  this.oncompleted();                                                                                        //   notify any observer that we're done
    }
  }
  
  this.incrementError = function() {                                                                             // This function is 'called back' by each image object that encournters an error
    this.imagesProcessed++;                                                                                      // So increment the number of images processed (because it's still processed, even if error)
    if(this.onerror){
	  this.onerror();                                                                                              // Notify any observer that we've encountered an error
	}
  }

  this.incrementAborted = function(){                                                                            // This function is 'called back' by each image object that is aborted
    this.imagesProcessed++;                                                                                      // So increment the number of images processed (because it's still processed, even if aborted)
    if (this.onabort) {
	  this.onabort();                                                                                              // Notify any observer that we've encountered an abort
	}
  }

  return true;                                                                                                   // Classes are supposed to return true  
}







function SlideShow(targetID){
	this.target = document.getElementById(targetID);
    this.width = 100;
	this.height= 100;
	this.transitionTime = 8000;
	this.currentImageIdx = 0;
	
    var me = this;
	var imageCache = new ImageCache();
	

	this.loadImages = function(rootDir) {
		imageCache.oncompleted =  function() { me.imagesLoaded();};
		imageCache.loadImages(rootDir);
	}
	
	this.imagesLoaded = function() {
		//this.target.style.position="relative";
		this.cycleToNextImage();
	}
	
	this.cycleToNextImage = function() {
		imageCache.imageObjs[this.currentImageIdx].style.position = "absolute";
		imageCache.imageObjs[this.currentImageIdx].style.top = "0px";
		imageCache.imageObjs[this.currentImageIdx].style.left = "0px";
		imageCache.imageObjs[this.currentImageIdx].id = "image" + this.currentImageIdx;
        
		this.target.appendChild(imageCache.imageObjs[this.currentImageIdx]);

        iAnim = new Animator(imageCache.imageObjs[this.currentImageIdx].id);
	    iAnim.animPath.addTransition("top",0,0,0,600);
        iAnim.animPath.addTransition("left",0,0,0,600)
        iAnim.animPath.addTransition("width",this.width,this.width,0,600);
        iAnim.animPath.addTransition("height",this.height,this.height,0,600);
        iAnim.animPath.addTransition("opacity",0,100,0,600);
        iAnim.doAnimation();

		this.currentImageIdx++;
		if (this.currentImageIdx >= imageCache.imageObjs.length){
			this.currentImageIdx = 0;
		}


        setTimeout(function() { me.cycleToNextImage();},this.transitionTime);
	}
    		
}
	











