/**
 * ImageScroll.js: An ImageScroll class for scrolling a series of images
 *
 * Constructor Arguments: 
 *   divId:     the id of the <div> tag which will be animated
 *   sps:       the number of scroll movements to display per second
 *	 offset:	the number of pixels to offset the scroll in X direction each frame
 *   frameURLs: an array of URLs, one for each frame not present in the divId division
 *   normalize: normalize the images to fit within the div height
 *
 * Public Methods: 
 *   start():   start the scroll (but wait for all frames to load first)
 *   stop():    stop the scroll
 * 
 * Public Properties:
 *   loaded:    true if all frames of the scroll have loaded,
 *              false otherwise
 *
 * Requirements:
 *	  The division containing the images must be have styles:
 *	       id: aUniqueId; position: relative; overflow: hidden;
 *
 *	  It contains the initial images that will be shown which are then
 *	  added to the list of images scrolled.
 */
function ImageScroll(divId, sps, offset, gap, frameURLs, normalize) {
    // Remember the division id. Don't look it up yet since this constructor
    // may be called before the document is loaded.
    // The division must have style position: relative | absolute | fixed 
    // in order for the sizing to work correctly.  It must also specify height
    // and width. The overflow must be specified as hidden to show only the 
    // portions of the images within the division.
    this.divId = divId;
    // Compute the time to wait between frames of the animation
    this.frameInterval = 1000/sps;
    // Save the movement offsets
    this.offset = offset;
    this.gap = gap;
    // An array for holding Image objects for each frame
    this.frames = new Array(frameURLs.length);
    // Determine how to normalize images based on original divId
    this.normalize = true;
    if (normalize === false)
    	this.normalize = false;
	
    this.div = null;               // The <div> element, looked up by id
    this.height = 0;		   	   // The maximum <img> element height
    this.middle = 0;
    this.loaded = false;           // Whether all frames have loaded
    this.loadedFrames = 0;         // How many frames have loaded
    this.startOnLoad = false;      // Start animating when done loading?
    this.frameNumber = -1;         // What frame is currently displayed in initial position
    this.timer = null;             // The return value of setInterval()
    
    // Initialize the frames[] array and preload the images
    for(var i = 0; i < frameURLs.length; i++) {
        //this.frames[i] = new Image();      // Create Image object
        this.frames[i] = document.createElement("img");  // Create Image object
        // Register an event handler so we know when the frame is loaded
        this.frames[i].onload = countLoadedFrames; // defined later
        this.frames[i].src = frameURLs[i]; // Preload the frame's image
    }

    // This nested function is an event handler that counts how many 
    // frames have finished loading.  When all are loaded, it sets a flag,
    // and starts the animation if it has been requested to do so.
    var loop = this;
    function countLoadedFrames() {
        loop.loadedFrames++;
        if (loop.loadedFrames == loop.frames.length) {
            loop.loaded = true;
            if (loop.startOnLoad) loop.start();
        }
    }

    // Here we define a function that performs the next scroll of the
    // image container.  This function can't be an ordinary instance method because
    // setInterval() can only invoke functions, not methods.  So we make
    // it a closure that includes a reference to the ImageLoop object
    this._scrollImages = function() {
  		// This function is different from the displayNextFrame function
  		// For now just set the reference of images to this.frames
  		var images = loop.frames;
  		for (var i = 0; i < images.length; i++) {
  			var left = (images[i].offsetLeft-loop.offset);
  			if (left + images[i].offsetWidth >= 0) {
  				images[i].style.left = left+"px";
  			} else {
  				// This will happen when the image scrolls off the screen
  				var j = i > 0 ? i-1 : images.length-1;
  				left = images[j].offsetLeft + images[j].offsetWidth + loop.gap;
  				images[i].style.left = left + "px";
  				//alert("i = "+i+"; j = "+j+"; left = "+left);
  			}
  		}
  	};
}

/**
 * This method starts an ImageScroll scrolling.  If the frame images have not
 * finished loading, it instead sets a flag so that the scrolling will 
 * automatically be started when loading completes
 */
ImageScroll.prototype.start = function() {
    if (this.timer != null) return;   // Already started
    // If loading is not complete, set a flag to start when it is
    if (!this.loaded) 
    	this.startOnLoad = true;
    else {
        // If we haven't looked up the division by id yet, do so now
        if (!this.div)  {
        	var lastRight = 0;
        	
       		this.div = document.getElementById(this.divId);
        	this.middle = this.div.offsetHeight/2.0;
        	this.height = this.div.offsetHeight;
        	var totalPaddingHeight = parseInt(getStyle(this.div,"paddingTop")) +
        		parseInt(getStyle(this.div,"paddingBottom"));
        	this.height -= totalPaddingHeight;
        	
         	var images = this.div.getElementsByTagName("img");
        	for (var i = images.length-1; i >= 0; i--) {
        		// Image cannot stay in domain when changing dimensions
        		// It does not do change correctly
        		//this.frames.unshift(images[i]);
        		this.div.removeChild(images[i]);
        	}
        		
        	// Now we do normalizing
        	// We only normalize down scale; we do not try to expand the scale
        	if (this.normalize) {
        		for (var i = 0; i < this.frames.length; i++) {
        			if ( this.frames[i].height > this.height) {
        				// Scale down this image
        				var image = this.frames[i];
        				var ratio = image.height/this.height;
        				image.height = this.height;
        				image.width = image.width/ratio;
        			}
        		}
        	}
        	
         	// Use document fragment to hold all images for now
        	var fragment = document.createDocumentFragment();
       		// Now append the new images
        	// Set position to absolute and set location
        	for (var i = 0; i < this.frames.length; i++) {
        		this.frames[i].style.position = "absolute";
        		this.frames[i].style.left = (lastRight + this.gap)+"px";
        		this.frames[i].style.top = (this.middle - this.frames[i].height/2.0)+"px";
        		lastRight = lastRight + this.gap + this.frames[i].width;
        		fragment.appendChild(this.frames[i]);
        	}
        	// now put into the div
        	this.div.appendChild(fragment);
        }
         
        // Display the first frame immediately
        this._scrollImages();
        // And set a timer to display subsequent frames
        this.timer = setInterval(this._scrollImages, this.frameInterval);
    }
};

/** Stop an ImageLoop animation */
ImageScroll.prototype.stop = function() {
    if (this.timer) clearInterval(this.timer);
    this.timer = null;
};

/** Get a style element */
function getStyle( ele, styleId) {
	if (typeof ele === "string")
		ele = document.getElementById(ele);
	if (ele.currentStyle)	// For internet explorer
		var style = ele.currentStyle[styleId];
	else if (window.getComputedStyle)	// For firefox, safari, opera
		var style = window.getComputedStyle(ele, null)[styleId];
	return style;
};
