/*
#####################################
# Image Fade By EJL
# 12/20/06
# v.01
# v.02
# v.10 03/15/07
# v.20 03/20/07
# v.20.01 03/28/07
# v.30 04/06/07
# v.40 05/22/07
# v.40.1 05/31/07
# v.41 06/05/07
# v.50 06/07/07
# v.50.1 06/11/07
# v.50.5 06/14/07
# v.60 06/29/07
#####################################
*NOTE: THIS SCRIPT REQUIRES jQuery*
http://www.jquery.com

Instructions

1) Download the newest version of jQuery from www.jquery.com and include it in
   the page.
   
2) Include this script AFTER jquery.

3) Use either jquery or window.onload to detect when the page is ready. I would
   recommend jQuerys method.
   
   jQuery(document).ready
   (
        function()
        {
            //place your code here
        }
   )
   
   This method is better because you don't have to place all the code that will
   run when the browser is ready in one spot.
   
4) You will need to set the height and width of the slide show container area. 
   You can also change the background color the images fade against
   Here are the property names and their default values
   
   table_width: 550
   table_height: 400
   table_background: 000000 //DO NOT place a # infront of the color 
   
5) Start the slideshow with this line.
   
   jQuery("#NAME_OF_DIV_ID").slide_show(array_of_images,[time_delay_for_start],[time_delay_between_images]);
   
   Place all the images in an array and pass in the array name
   ie: 
        var images = new Array('path/image.jpg','path/image.jpg');
        jQuery("#NAME_OF_DIV_ID").slide_show(images);
    
   You can also pass in the time delay for the show to start in milliseconds.
   So if you want it to start 5 seconds after the page loads enter 5000
   
   Same goes for time delay between images.
   
6) If you would like some copy to run along with the slide show you can pass it in with this method
   jQuery("#NAME_OF_DIV_ID").slide_show_titles("#ID_NAME_OF_TITLE_AREA",ARRAY_OF_COPY)
   
7) If you want to wrap the slides in a url use this method
   jQuery("#NAME_OF_DIV_ID").slide_show_urls(ARRAY_OF_URLS)
   
02/16/07
Restructured the way the images are displayed. The _layer divs have a contain
a table that is used to vertically center the image. It also has a background
color now so that smaller images will have something to fade against. Updated
the documentation 

v0.10 3/15/07
Added a previous and next method to the object. Restructured the way the start slideshow
works. Added a new method to safely access the settings for the slideshow
jQuery("#[DIV_NAME]").setting("property","value");

Restructured the way values are returned from external methods for stop_show, and next and previous
Placed more control on the timers. Now they're cleared when the slide show is stopped

v0.20 3/20/07
I'm now using the properties passed in for the table size to properly set up the container div.
YOU MUST PASS IN THE TABLE HEIGHT AND WIDTH BEFORE STARTING THE SHOW

It can also accept copy for a slideshow title area. 

v0.20.01 3/28/07
Made a small update to the number of pictures required to start the show. It's now two. It used
to be three.

v0.30 04/06/07
Cleaned up the variables stored in jQuery.slide_show
Found a small bug when passing in urls with no titles. Needed to init the slide_div and array or it will throw an error
Removed one if depth in init_slide show.
Changed the way images are updated. Now is starts with a blank img that is populated instead of written every time.
Also added a new method.
.slide_show_urls()
Pass in an array of urls and it will wraps the slides in them

v.0.40 05/22/07
Added a image loader so I can control the size of the images shown in the slideshow
Now everything is resized for the window 
Updated the stop show method to register the request and stop when the transition has ended

v0.40.1 05/31/07
Tweaked the preloader to only load the first two images. It was taking to long for the show to start.

v0.41 06/05/07
Totally re-wrote the preloader method to work in safari. It's now a queue and works in safari

v0.50 06/07/07
Localized the settings. Made the image and layer names dynamic. Updated wrap_slide and pop_title
to take a position instead of reading it from the current settings object. It should also be
chainable now.

v.50.1 06/11/07
Fixed a small issue with the next and previous buttons not populating the slide with a correct url

v.50.5 6/14/07
Created a new method to redirect the browser to the url of the current slide

v.60 6/29/07
Added a callback method to the start_show, next and previous slide
#####################################
# Future Plans
#####################################
- More effects (cross fade)
*/

function exec_callback(call_back)
{
    eval("var test_function = "+call_back);
    test_function();
}

function load_image(img,src)
{
    //we need to make this a queue instead of a function you feed items into
    var queue_layer = img.split(",");
    var queue_src = src.split(",");
    
    //this is the special preloader for safari
    if(jQuery.browser.safari)
    {
        //re-associate the pointer to the object in the body
        var img_large = document.getElementById('safari_preloader');
    }
    else
    {
        //create a new image obj
        var img_large = new Image;
    }
    
    //save the this reference
    var this_ref = this;
    
    img_large.onload = function()
    {
        var height = this.height;
        var width = this.width;
        
        //make sure it's not too tall
        if(height > this_ref['table_height'])
		{
            height = this_ref['table_height'];
            width *= (this_ref['table_height']/this.height);
		}
		
        //make sure the new width isn't too wide
        if(width > this_ref['table_width'])
		{
            width = this_ref['table_width'];
            height *= (this_ref['table_width']/width);
		}
        
        //place the main image on the page
        jQuery('#'+queue_layer[0]).attr({width: width, height: height, src: this.src});
        
        //now check the queue
        //remove the first element from the array
        queue_layer.shift();
        queue_src.shift();
        
        //call the init if the first two images have loaded
        if(queue_layer.length != 0)
        {
            //load the next element
            this.src = queue_src[0];
        }
    }
    img_large.src = queue_src[0];
}


function preload_images()
{
    //preload the first two images
    if(jQuery.browser.safari)
    {
        /*
        we'll have to wrap the image in a div and then hide the div so it doesnt
        make the page any longer.
        */
        var img_obj = document.createElement('img');
        
        var hidden_div = document.createElement('div');
        hidden_div.style.height = 0;
        hidden_div.style.width = 0;
        hidden_div.style.overflow = "hidden";
    
        img_obj.id = "safari_preloader";
        img_obj.style.visibility = "hidden";
        
        //add the image to the div
        hidden_div.appendChild(img_obj);
        
        //add the div to the body
        document.body.appendChild(hidden_div);
        
        //re-associate the pointer to the image in the body
        img_obj = document.getElementById('safari_preloader');
    }
    else
    {
        //create a new image obj
        var img_obj = new Image;
    }
    
    //copy the first two elements into the queue
    var queue = new Array(this['images'][0], this['images'][1]);
    
    //set a reference to the current this object no the image
    var this_ref = this;
    
    //set up some methods for the image obj
    img_obj.onerror = img_obj.onload;
    img_obj.onload = function()
    {
        if(this_ref['images'].length == 0) return;
    
        //remove the first element from the array
        queue.shift();
        
        //call the init if the first two images have loaded
        if(queue.length == 0)
        {
            this_ref.init_slideshow();
        }
        else
        {
            //load the next element
            this.src = queue[0];
        }
    }
    
    //load the image
    img_obj.src = queue[0];
}

function init_slideshow()
{
    //make sure we have at least two images
    if(this['images'].length < 2) return;
    
    //create our layers
    jQuery("#"+this['div']).html("\n<div id='"+this['layer_1']+"' style='position:absolute;z-index:2'><table border='0' bgcolor='#"+this['table_background']+"' cellspacing='0' cellpadding='0' height='"+this['table_height']+"' width='"+this['table_width']+"'><tr><td align='center' valign='middle'><img id='"+this['img_1']+"' border='0'></div></td></tr></table></div>\n<div id='"+this['layer_2']+"' style='position:absolute;z-index:1;'><table border='0' bgcolor='#"+this['table_background']+"' cellspacing='0' cellpadding='0' height='"+this['table_height']+"' width='"+this['table_width']+"'><tr><td align='center' valign='middle'><img id='"+this['img_2']+"' border='0'></div></td></tr></table></div>\n");
    
    load_image(this['img_1']+","+this['img_2'] ,this['images'][++this['current_position']]+","+this['images'][++this['current_position']]);
    
    //wrap the image in a url
    this.wrap_slide(0);
    
    //if there is a title populate the div
    this.pop_title(0);
    
    //pass in the reference to this
    var this_ref = this;
    
    //set timeout for show to start
    this['time_out'] = setTimeout(function()
    {
    	this_ref.start_show_internal();
    },this['wait_to_start']);
}


//this is what does the fade
function start_show_internal()
{
	//bail if the show is stopped
    if(this['bool_stop_show']) return;

    //image will start fading
    this['img_fading'] = true;
    
    //pass a reference to this
    var this_ref = this; 
    
    //fade the image. after it's done switch the layers
    jQuery("#"+this['current_layer']).fadeOut(this['fade_duration'],
    function()
    {
        //change the image fading state
        this_ref['img_fading'] = false;
        
        if(jQuery("#"+this_ref['layer_1']).css("z-index") == "2")
        {
            jQuery("#"+this_ref['layer_1']).css("z-index","1");
            jQuery("#"+this_ref['layer_2']).css("z-index","2");
            this_ref['current_layer'] = this_ref['layer_2'];//set current layer
            
            this_ref.pop_layer(this_ref['img_1'],this_ref['layer_1']);//populate the next image
        }
        else
        {
           jQuery("#"+this_ref['layer_1']).css("z-index","2");
           jQuery("#"+this_ref['layer_2']).css("z-index","1");
           this_ref['current_layer'] = this_ref['layer_1'];//set the current layer
           this_ref.pop_layer(this_ref['img_2'],this_ref['layer_2']);//populate the one behind it
        }
        
        //exec callback here
        if(this_ref['callback']) exec_callback(this_ref['callback']);
        
        //bail if the slideshow has stopped
        if(this_ref['bool_stop_show']) return;
        
        //set timeout for show to start
        this_ref['time_out'] = setTimeout(function(){this_ref.start_show_internal();},this_ref['wait_to_start']);
    });
}

//populate the next layer with an image
function pop_layer(image,layer)
{
    //if there is a title populate the div
    this.pop_title(this['current_position']);
    
    //wrap the image in a url
    this.wrap_slide(this['current_position']);
    
    //set the images to start from the beginning once it reaches the end
    if((this['current_position']+1) == this['images'].length) this['current_position'] = -1;
    
    //populate the layer behind it with the next images
    load_image(image,this['images'][++this['current_position']]);
    
    //turn the layer back on
    jQuery("#"+layer).fadeIn(0);
}

//this is used to populate the title area
function pop_title(index)
{
    //check to see if there are any titles 
    if(this['slide_show_titles'].length == 0) return;
    
    jQuery("#"+this['slide_show_titles_div']).html(this['slide_show_titles'][index]);
}

//this is used to wrap the current slide in a url if one exists
function wrap_slide(index)
{
    //check to see if there are any urls
    if(this['urls'].length == 0) return;
    
    //set the url
    this['current_url'] = this['urls'][index];
    
   	//wrap the current slide with the stated url
    if(this['current_layer'] == this['layer_1'])
    {
        //check for an a tag
        if(jQuery("#"+this['img_1']).parent().is("td"))
        {
            jQuery("#"+this['img_1']).wrap("<a id='"+this['div']+"_href' href='"+this['current_url']+"'></a>");
        }
        else
        {
            jQuery("#"+this['img_1']).parent().attr("href",this['current_url']);
        }
    }
    else
    {
        if(jQuery("#"+this['img_2']).parent().is("td"))
        {
            jQuery("#"+this['img_2']).wrap("<a href='"+this['current_url']+"'></a>");
        }
        else
        {
            jQuery("#"+this['img_2']).parent().attr("href",this['current_url']);   
        }
    }
}

//this will be used to stop the show
//this cannot be chained
jQuery.fn.stop_show = function()
{
	var return_val = "";
	this.each(function()
	{
		//if you can stop the show, do so then return true
		if(this.settings.is_stopped())
		{
			//stop any timer that's in the system
			clearTimeout(this.settings.time_out);
			this.settings.bool_stop_show = true;
			return_val =  true;
		}
		else
		{
			//since it didn't stop we want to register the stop and kill it when the transition is done
			this.settings.bool_stop_show = true;
			return_val = false;
		}
	});
	
	return return_val;
}

//this is used to start the show up again
jQuery.fn.start_show = function()
{
	this.each(function()
	{
		this.settings.bool_stop_show = false;
		this.settings.start_show_internal();
	});

	//chaining
	return this;
}

//use this to detect if the show has stopped or is still playing
function is_stopped()
{
	//if the image is fading(true) then the show is in motion. otherwise it can be stopped
	return !this['img_fading'] ? true : false;
}

//this will foward to the next slide
jQuery.fn.next_slide = function(callback)
{
	this.each(function()
	{
		//if its currently fading bail
		if(!jQuery("#"+this.settings.div).stop_show()) return false;
		
		//if there is a title populate the div
		this.settings.pop_title(this.settings.current_position);
		
		if(this.settings.current_layer == this.settings.layer_1)
		{
			//load_image(this.settings.img_1,this.settings.images[this.settings.current_position]);
			var position_1 = this.settings.images[this.settings.current_position];
			
			//wrap the image in a url
			this.settings.wrap_slide(this.settings.current_position);
			
			//if we're at the end wrap to the beginning
			if((this.settings.current_position+1) == this.settings.images.length) this.settings.current_position = -1;

			//load_image(this.settings.img_2,this.settings.images[++this.settings.current_position]);
			var position_2 = this.settings.images[++this.settings.current_position];
			
			load_image(this.settings.img_2+","+this.settings.img_1, position_2+","+position_1);
		}
		else
		{
			//load_image(this.settings.img_2,this.settings.images[this.settings.current_position]);
			var position_2 = this.settings.images[this.settings.current_position];
			
			//wrap the image in a url
			this.settings.wrap_slide(this.settings.current_position);
			
			//if we're at the end wrap to the beginning
			if((this.settings.current_position+1) == this.settings.images.length) this.settings.current_position = -1;

			//load_image(this.settings.img_1,this.settings.images[++this.settings.current_position]);
			var position_1 = this.settings.images[++this.settings.current_position];

			load_image(this.settings.img_1+","+this.settings.img_2, position_1+","+position_2);
		}
        
        //execute callback here
        if(callback) exec_callback(callback);
	});
	
	//chainning
	return this;
    
}

//this will move to the previous slide
jQuery.fn.prev_slide = function(callback)
{
	this.each(function()
	{
		//if its currently fading bail
		if(!jQuery("#"+this.settings.div).stop_show()) return false;
		
		//this is the logic for moving backwards and finding the correct current position
		this.settings.current_position -= (this.settings.current_position == 1 || this.settings.current_position == 0) ? -(this.settings.images.length - 2) : 2; 
		
		//if there is a title populate the div
		this.settings.pop_title(this.settings.current_position);
		
		if(this.settings.current_layer == this.settings.layer_1)
		{
			var position_1 = this.settings.images[this.settings.current_position];
			
			//wrap the image in a url
			this.settings.wrap_slide(this.settings.current_position);
			
			//if we're at the end wrap to the beginning
			if((this.settings.current_position+1) == this.settings.images.length) this.settings.current_position = -1;

			var position_2 = this.settings.images[++this.settings.current_position];
			
			load_image(this.settings.img_1+","+this.settings.img_2, position_1+","+position_2);
		}
		else
		{
			var position_2 = this.settings.images[this.settings.current_position];
			
			//wrap the image in a url
			this.settings.wrap_slide(this.settings.current_position);
			
			//if we're at the end wrap to the beginning
			if((this.settings.current_position+1) == this.settings.images.length) this.settings.current_position = -1;

			var position_1 = this.settings.images[++this.settings.current_position];
			
			load_image(this.settings.img_2+","+this.settings.img_1, position_2+","+position_1);
		}
        //execute callback here
        if(callback) exec_callback(callback);
	});
	
	//chainning
	return this;
}

//this is a safe way for people to change the settings for the slideshow
jQuery.fn.setting = function(name, prop)
{
    //since the settings object doesn't exist yet we'll store these for just a bit
    this.each(function()
    {
        //create the pre_settings object if it doesn't exist
        if(this.pre_settings == null) this.pre_settings = {};
        
        eval("this.pre_settings."+name+" = \""+prop+"\";");
    });
    
    //this is for chaining
    return this;
}

//this is where we pass in any copy that might be with the slideshow
jQuery.fn.slide_show_titles = function(div,copy)
{
    this.each(function()
    {
        //create the pre_settings object if it doesn't exist
        if(this.pre_settings == null) this.pre_settings = {};
        
        this.pre_settings.slide_show_titles_div = div;
        this.pre_settings.slide_show_titles = copy;
    });
    
    //chainning
    return this;
}

//this is where we can pass in a url to wrap the image in
jQuery.fn.slide_show_urls = function(urls)
{
    this.each(function()
    {
        //create the pre_settings object if it doesn't exist
        if(this.pre_settings == null) this.pre_settings = {};
        
        this.pre_settings.urls = urls;
    });
    
    //chainning
    return this;
}

/**
* This will redirect the browser to the current slides url
*/
jQuery.fn.current_url = function()
{
    this.each(function()
    {
        //return the url for the current slide
        window.location = this.settings.current_url;
    });
}


jQuery.fn.slide_show = function(pictures, wait, fade, callback)
{
    this.each
    (
        function()
        {
            //move the settings onto the div
            this.settings = 
            {
                init_slideshow: init_slideshow /*function*/
                ,start_show_internal: start_show_internal /*function*/
                ,pop_layer: pop_layer /*function*/
                ,pop_title: pop_title /*function*/
                ,wrap_slide: wrap_slide /*function*/
                ,preload_images: preload_images /*function*/
                ,is_stopped: is_stopped /*function*/
                
                ,callback: (callback ? callback : '') /*this will execute after the slide transition has finished*/
                
                ,images: new Array() /*this is where the images are stored*/
                ,current_position: -1 /*current position in image array*/

                ,current_layer: "" /*the first layer we use*/
                ,layer_1: "" /*this will hold the reference to the first layer*/
                ,layer_2: "" /*this will hold the reference to the second layer*/
                
                ,img_1: "" /*this will hold the reference to the first image*/
                ,img_2: "" /*this will hold the reference to the second image*/
                
                ,img_fading: false /*states wither the images currrently fading*/
                ,bool_stop_show: false /*states wither the show is stopped or not*/
                ,time_out:0 /*this controls the timeout*/
                
                ,slide_show_titles_div: "" /*holds the name of the div to be populated with the copy*/
                ,slide_show_titles: "" /*array of titles*/
                ,urls: new Array() /*array of urls*/
                ,current_url: "" /*holds the reference to the current slides url*/
                
                ,table_width: 550 /*table width, dbls as div width*/
                ,table_height: 400 /*table height, dbls as div height*/
                ,table_background: "000000" /*table background color*/
            };
            
            //check for any presettings
            if(this.pre_settings)
            {
                for(var items in this.pre_settings)
                {
                    eval("this.settings."+items+" = this.pre_settings['"+items+"']");
                }
            }
            
            //set up the proper css for the container
            jQuery("#"+this.id).css("position","relative");
            jQuery("#"+this.id).css("height",this.settings.table_height+"px");
            jQuery("#"+this.id).css("width",this.settings.table_width+"px");
            
            //this if for IE
            if(jQuery.browser.msie)
            {
                jQuery("#"+this.id).css("overflow","hidden");
                jQuery("#"+this.id).css("overflow-x","hidden");
                jQuery("#"+this.id).css("overflow-y","hidden");
                jQuery("#"+this.id).css("position","relative");
            }
            
            this.settings.div = this.id;
            
            //name the layers
            this.settings.layer_1 = this.id+"_layer1";
            this.settings.layer_2 = this.id+"_layer2";
            
            //set our current layer
            this.settings.current_layer = this.settings.layer_1;
            
            //the the name of our image layers
            this.settings.img_1 = this.id+"_image1";
            this.settings.img_2 = this.id+"_image2";
            
            this.settings.images = pictures;
            
            this.settings.wait_to_start = (wait ? wait : 3000);
            this.settings.fade_duration = (fade ? fade : 5000);
            
            //preload the images. once it's done the show will start
            this.settings.preload_images();
        }
    );
    
    //this is for chaining
    return this;
}
