//JAVASCRIPT OPACITY AND FADING IMAGE GALLERY CLASSES
// @author Alec Hill

// NB - must include Base.js

/*
// must include placeholder class in stylesheet

.placeholder {
  position:absolute;
  top:0px;
  left:0px;
}

*/

/*****************************************************************************************/
//Opacity class

// required arguments:
//						el - a string id or object reference to element to be made into opacity object
//						initialOpacity - 0 to 100 value, initial opacity to set object to
// optional arguments:
//						object with optional properties:
//										steps - number of steps in fade
//										interval - time of interval in fade (ms)
									

var Opacity = ah.Class.extend({}, {
	
	initialize: function(el,initialOpacity,options){
		this.el	= this.getElement(el); //string id or object reference to element to be Opacity - required
		this.setOptions(options); //sets defaults then optional properties
		this.setOpacity(initialOpacity);//sets to initial opacity - initialOpacity required
	},
	
	// sets the defualts and then overides them if they are properties of the options object
	setOptions: function(options){
		this.options = {
						steps: 20, //default steps in fade
						interval: 30 //defualt interval in fade
						};
		ah.extend(this.options, options || {});
	},
	
	//returns a reference to an element when passed string id, or reference, defualting to the opacity object element itself if no argument passed
	getElement: function(el){
		var element = this.el;
		if(el) element = el;
		if(el && typeof el == 'string') element = document.getElementById(el);
		return element;
	},
	
	//gets the opacity of an element, (el not required - defualts to this)
	getOpacity: function(el){
		var element = this.getElement(el);
		if(element.style.opacity){
			var currentOpacity = Math.round(element.style.opacity*100);
		}else if(element.style.MozOpacity){
			var currentOpacity = Math.round(element.style.MozOpacity*100);
		}else if(element.style.KhtmlOpacity){
			var currentOpacity = Math.round(element.style.KhtmlOpacity*100);
		}else if(element.filters){
			currentOpacity = element.filters.alpha.opacity;
		}
		return currentOpacity;
	},
	
	//set the opacity of an element, (el not required - defualts to this)
	setOpacity: function(opacity,el){
		var element = this.getElement(el);
		element.style.opacity = (opacity / 100);
		element.style.MozOpacity = (opacity / 100);
		element.style.KhtmlOpacity = (opacity / 100);
		element.style.filter = "alpha(opacity=" + opacity + ")";
	},

	//calculates the ease in and out
	easeInOut: function(opacStart, opacEnd, totalSteps, currentStep, degree) {
		var delta = opacEnd - opacStart; 
		var step = opacStart+(Math.pow(((1 / totalSteps) * currentStep), degree) * delta); 
		return Math.ceil(step) 
	},
	
	//Changes the opacity at set intervals.
	changeOpacity: function(opacStart, opacEnd, totalSteps, intervals, degree, element){
		if(element.opacChange) window.clearInterval(element.opacChange);
		var currentStep = 0;
		element.opacChange = window.setInterval(
			function(){
				element.currentOpacity = this.easeInOut(opacStart, opacEnd, totalSteps, currentStep, degree);
				this.setOpacity(element.currentOpacity, element);
				currentStep++;
				if(currentStep > totalSteps) window.clearInterval(element.opacChange);
			}.bind(this)
			,intervals);
	},
	
	//fades element to a specified opacity, (el not required - defualts to this)
	fadeTo: function(to,el){	
		var element = this.getElement(el);
		var currentOpacity = this.getOpacity(element);
		this.changeOpacity(currentOpacity,to,this.options.steps,this.options.interval,1.5, element);			 
	},	
	
	//Fades element in to 100% opacity, (el not required - defualts to this)
	fadeIn: function(el) { 
		var element = this.getElement(el);
		this.fadeTo(100,element);
	},
	
	//Fades element out to 0% opacity, (el not required - defualts to this)
	fadeOut: function(el) { 
		var element = this.getElement(el);
		this.fadeTo(0,element); 
	},
	
	//Determines if opacity closer to 0 or 100 and fades the opposite way, (el not required - defualts to this)
	toggle: function(el){
		var element = this.el;
		if(el) element = el;
		var state = Math.round(this.getOpacity(element)/100);
		if(state == 0){
			this.fadeIn(element);
		}else if(state == 1){
			this.fadeOut(element);
		}
	}
	
});

/*****************************************************************************************/
// FadeGallery class

// required arguments:
//						srcArray - an array of the source paths to images
//						altArray - an array of alt text for images
//						img_el - the string id or object reference to of the div element holding main image

// optional arguments:
//						object with optional properties:
//										steps - number of steps in fade
//										interval - time of interval in fade (ms)
//										duration - time duration of main image rotation (ms)
//										li_el - string id or object reference to li element holding thumbnails


var FadeGallery = ah.Class.extend(Opacity, {

    initialize: function(srcArray, altArray, img_el, options) {
        this.srcArray = srcArray; //an array of image source strings - required
        this.altArray = altArray; //an array of alt text strings - required
        this.img_el = this.getElement(img_el); //string id or object reference to div element holding main image - required
        this.imageArray = new Array(); //initialized for holding preloaded image objects
        this.delay; //initialized for holding the timeout for rotating images
        this.setOptions(options); //sets defaults then optional properties
        this.duration = 4000; //default image duration
        if (this.options.duration) this.duration = this.options.duration; //if duration option is set overide defualt duration	
        this.current = (this.options.random == true) ? this.randomNumber() : 0; //if random option is set to true,create a random start number  
        //calls to set up functions

        this.preload();
        if (this.options.random) {
            this.delay = setTimeout(function() { this.changeImage() } .bind(this), this.duration);
        } else {
            this.changeImage();
        }
        if (this.options.li_el) this.prepareThumbLinks();
    },

    randomNumber: function() {
        return Math.round((this.srcArray.length - 1) * Math.random());
    },

    preload: function() {
        for (var i = 0; i < this.srcArray.length; i++) {
            var imageObj = new Image();
            imageObj.src = this.srcArray[i];
            this.imageArray.push(imageObj);
        }
    },

    insertAfter: function(newElement, targetElement) {
        var parent = targetElement.parentNode;
        if (parent.lastChild == targetElement) {
            parent.appendChild(newElement);
        } else {
            parent.insertBefore(newElement, targetElement.nextSibling);
        }
    },

    prepareThumbLinks: function() {
        var imageList = this.getElement(this.options.li_el);
        links = imageList.getElementsByTagName("img");
        for (var i = 0; i < links.length; i++) {
            links[i].imageValue = i;
            links[i].onclick = function(e) {
                if (!e) var e = window.event;
                if (e.target) {
                    var targ = e.target;
                } else if (e.srcElement) {
                    var targ = e.srcElement;
                }
                if (targ.nodeType == 3) targ = targ.parentNode;
                var value = targ.imageValue;
                this.changeImage(value);
                return false;
            } .bind(this);
            links[i].onkeypress = links[i].onclick;
        }
    },

    changeImage: function(value) {
        if (undefined != this.delay) clearTimeout(this.delay);
        this.addImage(value);
    },

    addImage: function(user_selection) {
        if (undefined != user_selection) this.current = user_selection;
        if (!this.img_el == null) {
            if (this.img_el.childNodes.length > 1) this.img_el.removeChild(this.img_el.firstChild);
            var lastElement = this.img_el.lastChild;
            var newElement = document.createElement("img");
            newElement.id = "image_" + this.current;
            newElement.src = this.srcArray[this.current];
            newElement.alt = this.altArray[this.current];
            newElement.className = "placeholder";
            this.setOpacity(0, newElement);
            this.insertAfter(newElement, lastElement);
            this.fadeIn(newElement);
            if (this.current == this.srcArray.length - 1) {
                this.current = 0;
            } else {
                this.current++;
            }
            if (user_selection) {
                this.delay = setTimeout(function() { this.changeImage() } .bind(this), this.duration * 2);
            } else {
                this.delay = setTimeout(function() { this.changeImage() } .bind(this), this.duration);
            }
       }
        
    }

});

	
	
/*****************************************************************************************/
// FadeGalleryDescriptions class

//extends FadeGallery - takes a further required argument for the string id /object reference to element that will show description in. this description is taken from the alt text array. In this alt text a '-' will be replaced by a <br /> to suit my needs for this project. 

//changeDescription() method added to do the description
//initialize() method overwritten to reflect new argument
//changeImage() method overwritten to add a call to changeDescription()

var FadeGalleryDescriptions = ah.Class.extend(FadeGallery, {
	
	initialize: function(srcArray,altArray,img_el,desc_el,options){
		this.srcArray = srcArray; //an array of image source strings - required
		this.altArray = altArray; //an array of alt text strings - required
		this.img_el = this.getElement(img_el); //string id or object reference to div element holding main image - required
		this.desc_el = this.getElement(desc_el); //string id or object reference to element you want description text displayed in		
		this.imageArray = new Array(); //initialized for holding preloaded image objects
		this.delay; //initialized for holding the timeout for rotating images
		this.current = this.randomNumber(); //the current image number - set start heren
		this.setOptions(options); //sets defaults then optional properties
		this.duration = 4000; //default image duration
		if(this.options.duration) this.duration = this.options.duration;  //if duration option is set overide defualt duration		
		//calls to set up functions
		this.preload();
		this.changeImage();
		if(this.options.li_el) this.prepareThumbLinks();	
	},
	
	changeImage: function(value){
		if(undefined != this.delay) clearTimeout(this.delay);
		this.changeDescription(value);
		this.addImage(value);
	},
	
	changeDescription: function(value){
		var number = this.current;
		if(value) number = value;
		var text = this.altArray[number];
		var separatedtext = text.split('-');
		if(this.desc_el.firstChild) this.desc_el.removeChild(this.desc_el.firstChild);
		var nodes = new Array();
		for(var i=0;i<separatedtext.length;i++){
			var node = document.createTextNode(separatedtext[i]);
			nodes.push(node);
			if(i != text.length-1){
				var br = document.createElement('br');
				nodes.push(br);
			}
		}
		var span = document.createElement('span');
		for(var i=0;i<nodes.length;i++){
			span.appendChild(nodes[i]);
		}
		span.id = 'thespan';
		span.style.display = 'none';
		this.desc_el.appendChild(span);
		var thespan = new Opacity('thespan',0,{steps: 30});
		var spanel = document.getElementById('thespan');
		spanel.style.display = 'block';
		thespan.fadeIn();
	}
	
});





/*******************************************************************************/


//Generic onload event handler.
function addLoadEvent(func) {
	var oldonload = window.onload;
	if (typeof window.onload != 'function') {
		window.onload = func;
	} else {
		window.onload = function() {
			oldonload();
			func();
		}
	}
}
/***************************************************************************************/	
// set up when page has loaded

				function initiateSlideShow(){
					var srcArr = new Array(
						'images/homeimage2.jpg',
						'images/homeimage3.jpg',
						'images/homeimage4.jpg',
						'images/homeimage5.jpg',
						'images/homeimage6.jpg',
						'images/homeimage1.jpg'
					);
					var altArr = new Array(
						'Quay Holidays',
						'Quay Holidays',
						'Quay Holidays',
						'Quay Holidays',
						'Quay Holidays',
						'Quay Holidays'
					);
					var gal = new FadeGallery(srcArr,altArr,"slideShow",{'duration': 5000, random: true});	
				}
				addLoadEvent(initiateSlideShow);	

				
				function initiateSlideShow3(){
					var srcArr = new Array(
						'images/topbanner2.jpg',
						'images/topbanner.jpg'
					);
					var altArr = new Array(
						'Quay Holidays',
						'Quay Holidays'
					);
					var gal = new FadeGallery(srcArr,altArr,"slideShow3",{'duration': 1000, random: true});	
				}
				addLoadEvent(initiateSlideShow3);

				function initiateSlideShowtest() {
				    var srcArr = new Array(
						'images/quote1.jpg',
						'images/quote2.jpg',
						'images/quote3.jpg'
					);
				    var altArr = new Array(
						'Quay Holidays',
						'Quay Holidays',
						'Quay Holidays'
					);
				    var gal = new FadeGallery(srcArr, altArr, "slideShowTest", { 'duration': 5000, random: true });
				}
				addLoadEvent(initiateSlideShowtest);				
