/**

 * IMAGE REFLECTION
 *
 * Description: This script will allow images to have reflections if you specify it
 * to have them by saying class="reflect" along with some options
 *
 * Researched and Composed By Eric Fisher
 *
 * References: http://developer.apple.com/documentation/AppleApplications/Reference/SafariJSRef/Classes/Canvas.html
 */


/**
* HELPER METHOD
*
* DEFINE a function called getElementsByClassName
* This takes the className as a parameter and gets a list of all the tags in the HTML page.
* It then creates a new blank array and runs through all the tags and adds only those that are named className
* Then it returns the array
*/

document.getElementsByClassName = function(className) {
	var children = document.getElementsByTagName('*') || document.all; //children is a list of all the tags
	var elements = new Array();    //new blank array to be filled
	for (var i = 0; i < children.length; i++) {
		var child = children[i];
		var classNames = child.className.split(' ');  //split up the class name of this tag (in case there are multiple classes)
		for (var j = 0; j < classNames.length; j++) {
			if (classNames[j] == className) {    //if we've found the className we're looking for, add it to our blank array and break
				elements.push(child);
				break;
			}
		}
	}
	return elements;
}

/**
* DEFINE A CLASS CALLED REFLECTION
* with two variables: defaultHeight and defaultOpacitiy, initialized to a default value
*/

var Reflection = {
	defaultHeight : 0.5,   //default height
	defaultOpacity: 0.5,   //default opacity
	
	// DEFINE A FUNCTION CALLED "add" which takes two parameters: the image and some options
	
	add: function(image, options) {
	   // so as not to do two reflections, first remove the image
		Reflection.remove(image);
		//create a list of the default height and opacity
		doptions = { "height" : Reflection.defaultHeight, "opacity" : Reflection.defaultOpacity }
        //if options were specified, then replace any that weren't by the default ones
		if (options) {
			for (var i in doptions) {
				if (!options[i]) { options[i] = doptions[i]; }
			}
		}
		//otherwise just set options to the default ones 
		else { options = doptions; }
	   
        // TRY THIS

		try {
			// Create a new <div> tag
			var d = document.createElement('div');
			var p = image;
		
            //Now let's break down the class name to determine what we're doing			
			
			var classes = p.className.split(' ');    //split by white space
			var newClasses = '';
			for (j=0;j<classes.length;j++) {
				if (classes[j] != "reflect") {      //here we're talking about the other values like rheight and ropacity
					if (newClasses) { newClasses += ' ' }  //if this is a second or greater class, make sure to add the space between them!
					newClasses += classes[j];      //add this class
				}
			}

			var reflectionHeight = Math.floor(p.height*options['height']);   //round down, multiply actual image height by our specified height
			var divHeight = Math.floor(p.height*(1+options['height']));      //make the division height similar
			var reflectionWidth = p.width;   //make the reflection span the width of the image
			
			// Set our division class name to all the newClasses
			d.className = newClasses;
			p.className = 'reflected';
			
			// Align any text on the bottom
			d.style.cssText = p.style.cssText;
			p.style.cssText = 'vertical-align: bottom';
			
			//Make sure the division we've created has the same width and height that we want
			d.style.width = reflectionWidth+'px';
			d.style.height = divHeight+'px';
			
			//If there are elements and we're not using Opera

			if (document.all && !window.opera) {
			    
			    //Step 1: Create a new image tag
				var reflection = document.createElement('img');
				//Step 2: Make this image tag's source our original image
				reflection.src = p.src;
				//Step 3: Ensure this new image's width is the same as the reflection width, adding 'px' for pixels
				reflection.style.width = reflectionWidth+'px';

				//Step 4: Set the bottom margin of the reflected image to the negative value of the total height - reflected height.
				//        The value is negative because we're bringing the next line CLOSER to the image as our reflection height gets smaller.
				reflection.style.marginBottom = "-"+(p.height-reflectionHeight)+'px';
				//Step 5: The piece that makes it FADE
				//Set the opacity to the specified opacity, ensure it fades to 0 opacity and set the coordinates to start from y=0 and fade to y=the reflection height
				reflection.style.filter = 'flipv progid:DXImageTransform.Microsoft.Alpha(opacity='+(options['opacity']*100)+', style=1, finishOpacity=0, startx=0, starty=0, finishx=0, finishy='+(options['height']*100)+')';

				// Make whatever is the parent TAG to the image we're talking about replace this image with our newly created division
				p.parentNode.replaceChild(d, p);

				// Now add the image as a child of this division
				d.appendChild(p);
                // And add the reflection also as a child
				d.appendChild(reflection);

			} 
			
			else {
			    //Create a new element <canvas> :: The canvas element is a third party extension to the HTML standard that allows for dynamic rendering of scriptable bitmap images.
				var canvas = document.createElement('canvas');
				//If there's a context (i.e. 2D ...)
				if (canvas.getContext) {
			        //Set our context to 2D (for 2D images)
					var context = canvas.getContext("2d");
				    //Set our height and width both as a CSS style, and as an HTML attribute (just in case!)
					canvas.style.height = reflectionHeight+'px';
					canvas.style.width = reflectionWidth+'px';
					canvas.height = reflectionHeight;
					canvas.width = reflectionWidth;
			
					//Again, replace this tag by our new division
					p.parentNode.replaceChild(d, p);
                    // And add on the image and this new canvas					
					d.appendChild(p);
					d.appendChild(canvas);

                    //SAVE the context					
					context.save();
					
					//FLIP THE IMAGE

					// Translate the reflected image so that it's below the original image
					context.translate(0,image.height-1);
				    // Flip the image upside down
					context.scale(1,-1);
					// Now that we have the context down, DRAW THE REFLECTED IMAGE in our canvas!
					context.drawImage(image, 0, 0, reflectionWidth, image.height);

	                // Restore the canvas to BEFORE we translated and flipped the image
					context.restore();
					context.globalCompositeOperation = "destination-out";

					//Create a gradient on the reflected image now so that it fades out from total opacity to 0 by the time it reaches reflectionHeight
					var gradient = context.createLinearGradient(0, 0, 0, reflectionHeight); //the 4 parameters are X0,y0, x1, y1
					
					// THIS PART MAKES THE IMAGE FADE FROM THE DEFAULT OPACITY TO WHATEVER THE BACKGROUND (ALPHA) COLOR IS
					
					gradient.addColorStop(1, "rgba(255, 255, 255, 1.0)");  //because the offset is 1, we're talking about the END of the image. Make this the alpha channel (aka whatever the background color is)
					gradient.addColorStop(0, "rgba(255, 255, 255, "+(1-options['opacity'])+")");   //at the beginning, make this white plus whatever our opacity is set to

		
		            //now fill the canvas with a gradient
					context.fillStyle = gradient;
					//Version checking
					if (navigator.appVersion.indexOf('WebKit') != -1) { context.fill(); } //if not WebKit 
					else { context.fillRect(0, 0, reflectionWidth, reflectionHeight*2); } //fill the canvax with the specified dimensions
				}
			}
		} catch (e) {} //error checking if try doesn't work. But it will!
	},

    /**
    * DEFINE a function called remove which takes the image as a parameter and removes it from the HTML
    */

	remove : function(image) {
		if (image.className == "reflected") { //first make sure we're only removing an image who has a class="reflect"
			image.className = image.parentNode.className; //now set the class name of this image to whatever the parent's class name is
			image.parentNode.parentNode.replaceChild(image, image.parentNode); //now get the grandparent to replace the parent with the image.
		}
	}
}

//SO, you could just write <img src="something" class="reflect" but if you want to do this dynamically, you can use this method

function addReflections() {
	var rimages = document.getElementsByClassName('reflect');  //get all the images that have class="reflect"
	for (i=0;i<rimages.length;i++) {   //for each image...
		var rheight = null;   //reset rheight to null
		var ropacity = null;  //reset ropacity to null
		
		var classes = rimages[i].className.split(' '); //get all the other classes that this image uses besides reflect
		for (j=0;j<classes.length;j++) {  //go through them all
			if (classes[j].indexOf("rheight") == 0) { var rheight = classes[j].substring(7)/100; }//if it doesn't have rheight already, then set rheight to 'rheight100'
			else if (classes[j].indexOf("ropacity") == 0) { var ropacity = classes[j].substring(8)/100; } //else if it doesn't have ropacity already, then set it to 'ropacity100'
		}
		// Now use the reflection class to add a reflection to this image, which we've added classes to
		Reflection.add(rimages[i], { height: rheight, opacity : ropacity});
	}
}

//Do all of this when the page loads.

var previousOnload = window.onload;
window.onload = function () { 
	if(previousOnload) previousOnload(); 
	addReflections(); 
}

// END SCRIPT