// **********************************************************************
// Written by Iain A. Smith April 2008
//
// Based on 'Image cross-fade' script written by James Edwards
// See http://www.brothercake.com
//
// **********************************************************************

//global object
var ixf = { 'clock' : null, 'count' : 1, 'isRandom' : false };

// additional variables
ixf.imgs = new Array();

var imgsFile = new Array();
var imgsText = new Array();
var imgsLink = new Array();

this.htmlImageSrc = '';
this.newImageIdx = 0;
this.seqIdx = 0;
this.preloadImages = "FALSE"; // required for Firefox else cache images

this.id;
this.speed;
this.secCalibaration = 1000; // 1000 = max, lower will quicken transition
this.procId; // var to hold 'id' of loop process (loop clock)
this.isRunning = true;

/************************************************************************
*  Functions
************************************************************************/
function cacheImages()
{
	ixf.cache = [];
	for(var i=0; i<ixf.imgs.length; i++)
	{
		ixf.cache[i] = new Image;
		ixf.cache[i].src = ixf.imgs[i];
	}
};


function initTransformation()
{
    id_base = arguments[0];

    ixf.obj = document.getElementById(id_base);
	
	// this just simplifies the data file (slightly)
	ixf.imgs = imgsFile;

	//store the supported form of opacity
	if(typeof ixf.obj.style.opacity != 'undefined')
	{
		ixf.type = 'w3c';
	}
	else if(typeof ixf.obj.style.MozOpacity != 'undefined')
	{
		ixf.type = 'moz';
	}
	else if(typeof ixf.obj.style.KhtmlOpacity != 'undefined')
	{
		ixf.type = 'khtml';
	}
	else if(typeof ixf.obj.filters == 'object')
	{
		//weed out win/ie5.0 by testing the length of the filters collection (where filters is an object with no data)
		//then weed out mac/ie5 by testing first the existence of the alpha object (to prevent errors in win/ie5.0)
		//then the returned value type, which should be a number, but in mac/ie5 is an empty string
		ixf.type = (ixf.obj.filters.length > 0 && typeof ixf.obj.filters.alpha == 'object' 
						&& typeof ixf.obj.filters.alpha.opacity == 'number') ? 'ie' : 'none';
	}
	else {
		ixf.type = 'none';
	}

	// Set slideshow order - if random
	if(ixf.isRandom)
	{
		ixf.sequence = new Array();
			
		while(ixf.sequence.length < ixf.imgs.length)
		{
			idxNew = Math.floor(Math.random()*ixf.imgs.length);
		
			// check that index has not already been shuffled
			isShuffled = "FALSE";
			var i = 0;
			while(isShuffled == "FALSE" && i < ixf.sequence.length) 
			{
				if(ixf.sequence[i] == idxNew)
				{
					isShuffled = "TRUE";
				}
				i++;
			}
			
			if(isShuffled == "FALSE")
			{
				ixf.sequence[ixf.sequence.length] = idxNew;
			}
		}
	}
	
	// For Firefox we need to add (preload) the images to the page as soon as it is opened
	if(ixf.type == 'w3c')
	{
		this.preloadImages = "TRUE";
	}

	if(this.preloadImages == "TRUE")
	{
		// insert an empty img tag into the html for each image
		//document.write("<img id='t_img0'><img id='t_img1'><img id='t_img2'><img id='t_img3'>");

		// add the images, placing them in the same position as the image in the html
		for(var i=0; i<ixf.imgs.length; i++)
		{
			// insert an empty img tag with the respective id attribute into the html
			document.write("<img id='" + id_base + i +"'>");

			// copy the new img obj
			ixf.newimg = document.getElementById(id_base + i);

			// set style - this hides the image
			ixf.newimg.className = 'idupe';

			// set src to new image src
			ixf.src = ixf.imgs[i];
			ixf.newimg.src = ixf.src

			// position new image in the same place on the page
			ixf.newimg.style.left = ixf.getRealPosition(ixf.obj, 'x') + 'px';
			ixf.newimg.style.top = ixf.getRealPosition(ixf.obj, 'y') + 'px';
		}
	}
	else {
		cacheImages()
	}
};


//crossfade timer function
ixf.crossfade = function()
{
    //decrease the counter on a linear scale
    ixf.count -= (1 / ixf.resolution);

    //if the counter has reached the bottom
    if(ixf.count < (1 / ixf.resolution))
    {
        //clear the timer
        clearInterval(ixf.clock);
        ixf.clock = null;

        //reset the counter
        ixf.count = 1;

        //set the original image to the src of the new image
        ixf.obj.src = ixf.src;
	}

    //set new opacity value on both elements
    //using whatever method is supported
    switch(ixf.type)
    {
        case 'ie' :
            ixf.obj.filters.alpha.opacity = ixf.count * 100;
            ixf.newimg.filters.alpha.opacity = (1 - ixf.count) * 100;
            break;

        case 'khtml' :
            ixf.obj.style.KhtmlOpacity = ixf.count;
            ixf.newimg.style.KhtmlOpacity = (1 - ixf.count);
            break;

        case 'moz' :
            //restrict max opacity to prevent a visual popping effect in firefox
            ixf.obj.style.MozOpacity = (ixf.count == 1 ? 0.9999999 : ixf.count);
            ixf.newimg.style.MozOpacity = (1 - ixf.count);
            break;

        default :
            //restrict max opacity to prevent a visual popping effect in firefox
            ixf.obj.style.opacity = (ixf.count == 1 ? 0.9999999 : ixf.count);
            ixf.newimg.style.opacity = (1 - ixf.count);
    }

    //now that we've gone through one fade iteration
    //we can show the image that's fading in
    ixf.newimg.style.visibility = 'visible';

    //keep new image in position with original image
    //in case text size changes mid transition or something
    ixf.newimg.style.left = ixf.getRealPosition(ixf.obj, 'x') + 'px';
    ixf.newimg.style.top = ixf.getRealPosition(ixf.obj, 'y') + 'px';

    //if the counter is at the top, which is just after the timer has finished
    if(ixf.count == 1)
    {
        //remove the duplicate image - depending on browser
        if(preloadImages != "TRUE")
        {
        	ixf.newimg.parentNode.removeChild(ixf.newimg);
        }
    }
};


//get real position method
ixf.getRealPosition = function()
{
    this.pos = (arguments[1] == 'x') ? arguments[0].offsetLeft : arguments[0].offsetTop;
    this.tmp = arguments[0].offsetParent;
    while(this.tmp != null)
    {
        this.pos += (arguments[1] == 'x') ? this.tmp.offsetLeft : this.tmp.offsetTop;
        this.tmp = this.tmp.offsetParent;
    }

    return this.pos;
};


// Main image transformation function
function imgTransition()
{
	//transition may not be required sometimes, eg when first image should be random 
	doTransition = true;
	
    //if the timer is not already going
    if(ixf.clock == null)
    {
		if(ixf.isRandom && this.htmlImageSrc)
		{	
			// ensure any image source in the html is redisplayed last
			// otherwise it may be displayed for twice the normal time
			// if it happens to come up as idx 1 in the random sequence	
			for(var i = 0; i < ixf.imgs.length; i++)
			{
				if(ixf.imgs[i] == this.htmlImageSrc.substring(this.htmlImageSrc.length-ixf.imgs[i].length))
				{			
					for(var k = 0 ; k < ixf.sequence.length; k++)
					{
						if(ixf.sequence[k] == i)
						{
							this.seqIdx = k;
							// break (both loops)
							k = ixf.sequence.length;
							i = ixf.imgs.length;
						}
					}
				}
			}

			// the step above is only required once
			this.htmlImageSrc = null;
		}
		
		getNextImageIdx();
		
		// Set image src, alt/title and link
		setImgAttributes();
				
		//check if transition effect is required or are we simply loading an initial image	
		if(ixf.obj.src == null || ixf.obj.src == '' || ixf.obj.src.substring(ixf.obj.src.length-1) == '/')
		{
			doTransition = false;
		}
 
        //do transition (if any kind of opacity is supported)
        if(ixf.type != 'none' && doTransition == true)
        {
        	if(this.preloadImages != "TRUE")
        	{
				//create a new image object and append it to body
				//detecting support for namespaced element creation, in case we're in the XML DOM
				ixf.newimg = document.getElementsByTagName('body')[0].appendChild((typeof document.createElementNS != 'undefined') ?
								document.createElementNS('http://www.w3.org/1999/xhtml', 'img') : document.createElement('img'));
			}

            //set positioning classname
            ixf.newimg.className = 'idupe';

            //set src to new image src
            ixf.newimg.src = ixf.src

			//set image src, alt/title and link (in case ixf.newimg obj was not previously available - IE)
			setImgAttributes(); 

            //move it to superimpose original image
            ixf.newimg.style.left = ixf.getRealPosition(ixf.obj, 'x') + 'px';
            ixf.newimg.style.top = ixf.getRealPosition(ixf.obj, 'y') + 'px';

            //copy and convert fade duration argument
			ixf.length = parseInt(arguments[1], 10) * 1000;

            //create fade resolution argument as 20 steps per transition
            ixf.resolution = parseInt(arguments[1], 10) * 20;

            //start the timer
			ixf.clock = setInterval('ixf.crossfade()', ixf.length/ixf.resolution);
        }
        //otherwise if opacity is not supported
        else {
            //just do the image swap
	        ixf.obj.src = ixf.src;
        }
    }
};

function getNextImageIdx()
{
	if(ixf.isRandom)
	{
		// Increment the random sequence index
		if(this.seqIdx < ixf.imgs.length - 1)
		{
			this.seqIdx++;
		}
		else
		{
			this.seqIdx = 0;	
		}
	
		// Apply sequence to image array
		this.newImageIdx = ixf.sequence[this.seqIdx];		
	}
	else
	{	
		// Increment the image number to go to the next slide
		if(this.newImageIdx < ixf.imgs.length - 1)
		{
			this.newImageIdx++;
		}
		else
		{
			// if last slide reached, restart at the first slide
			this.newImageIdx = 0;
		}
	}	
};

function getLastImageIdx()
{
	for(i = 0; i < ixf.imgs.length - 1; i++)
	{
		getNextImageIdx();
	}
	
};

function setImgAttributes()
{
	ixf.src = ixf.imgs[this.newImageIdx];

	//update the image alt attribute if text provided
	if(imgsText.length > 0)
	{
		if(imgsText[this.newImageIdx] == null)
		{
			ixf.obj.alt = "";
			ixf.obj.title = "";
			if(ixf.newimg)
			{
				ixf.newimg.alt = "";
				ixf.newimg.title = "";
			}
		}
		else {
			ixf.obj.alt = imgsText[this.newImageIdx];
			ixf.obj.title = imgsText[this.newImageIdx];
			if(ixf.newimg)
			{
				ixf.newimg.alt = imgsText[this.newImageIdx];
				ixf.newimg.title = imgsText[this.newImageIdx];
			}
		}
	}

	//update the href attribute if link provided	
	if(imgsLink.length > 0)
	{
		ixf_link = document.getElementById('transitions_link');
		
		//update href is link available
		if(imgsLink[this.newImageIdx] != null && imgsLink[this.newImageIdx] != '')
		{
			ixf_link.href = imgsLink[this.newImageIdx];
		}
	}	
};

function stopTransitionLoop()
{
	if(this.procId)
	{
		this.procId = window.clearInterval(this.procId);
		document.getElementById('button_stop').title = 'Play';
		this.isRunning = false;
	}
	else
	{
		// restart looping through the images
		runTransition();
		this.procId = setInterval('runTransition()', this.delay * this.secCalibaration);
		document.getElementById('button_stop').title = 'Stop';
		this.isRunning = true;
	}
};

function showLastImage()
{
	if(this.isRunning == true)
	{
		stopTransitionLoop();
	}

	getLastImageIdx();
	setImgAttributes();
	ixf.obj.src = ixf.src;
};

function showNextImage()
{
	if(this.isRunning == true)
	{
		stopTransitionLoop();
		
		// only move to next image if we know for sure that current
		// image has been fully displayed otherwise it looks odd!
		if(ixf.clock == null)
		{
			getNextImageIdx();
		}
	}
	else
	{
		getNextImageIdx();
	}
	
	setImgAttributes();
	ixf.obj.src = ixf.src;
};

//Helper function to enable setInterval() to be used by main loop function
function runTransition()
{
	imgTransition(ixf.obj, this.speed);
};

//Main method called when running in a loop
function imgTransitionLoop(id, speed, delay, isRandom)
{
	// delay between cycles must be enough time for transition to complete
	if(speed > delay)
	{
		delay = speed + 1;
	}
	
	// make arguments globally available
	this.id = id;
	this.delay = delay;
	//this.speed = speed+'';	// must be a string! // Not reqd?
	this.speed = speed;

	// make setting available in transition object
	ixf.isRandom = isRandom;

	// run initialisation func
	initTransformation(id);
	
	// switch off transition effect
	//ixf.type = 'none';

	// check if an initial image should be loaded (without transition effect)
	// note: src will be the actual html page if the value is blank
	if(ixf.obj.src == null || ixf.obj.src == '' || ixf.obj.src.substring(ixf.obj.src.length-1) == '/'
			|| ixf.obj.src.substring(ixf.obj.src.length-4) == '.php'
			|| ixf.obj.src.substring(ixf.obj.src.length-4) == '.htm'
			|| ixf.obj.src.substring(ixf.obj.src.length-5) == '.html'
			|| ixf.obj.src.substring(ixf.obj.src.length-5) == '.shtm'
			|| ixf.obj.src.substring(ixf.obj.src.length-6) == '.shtml')
	{
		// use transition process as it will cater for random sequence
		imgTransition(ixf.obj, 0);
	}
	else
	{
		// record which image file is set in the html 
		// so that it is not repeated straight away in the random sequence
		this.htmlImageSrc = ixf.obj.src;
		
		// ensure alt and title attributes are set - if we have values for image
		for(var i = 0; i < ixf.imgs.length; i++)
		{
			if(ixf.imgs[i] == ixf.obj.src.substring(ixf.obj.src.length-ixf.imgs[i].length))
			{
				if(imgsText[i] != null)
				{
					if(!ixf.obj.alt)
					{
						ixf.obj.alt = imgsText[i];
					}
					if(!ixf.obj.title)
					{
						ixf.obj.title = imgsText[i];
					}
				}
			}
		}
		
	}
	
	// start looping through the images
	this.procId = setInterval('runTransition()', this.delay * this.secCalibaration);
};
