////////////////////////////////////////////////////////////////////
// Animation routines // 2007/08/05, author kitchin, http://lapage.com
// Uses an opacity routine from http://lists.evolt.org/archive/Week-of-Mon-20070115/187466.html
// 2007/11/14: "variable widths mod"
////////////////////////////////////////////////////////////////////
// Multiple slide shows with fade-in, controlled by this script (anim.js).
// Does not use absolute positioning, negative margin-top instead.
// Tested in Opera9, Firefox2, IE7, Safari on WinXP.
// NN4 degrades to static cleanly, since the hidden frames are not in the HTML, they are added by JS instead.
// Konqueror degrades to a slide shows without fading (KHTMLOpacity seems to have been dropped).
////////////////////////////////////////////////////////////////////
// For each slide show, stack up some hidden frames on top of its main image, $imgs[0].
// JS will loop through and fade them in, and then return to $imgs[0].
// If fading is not available, it's a simple slide show.
// The return to 0 could work by keeping $imgs[0] visible and fading back
// the last $img (and hiding the $img's in the middle).
// But if fading is not available, fading back the last $img won't look right because it flips
// at the end of the fade while the others flip at the beginning. Another way, setting z-index=1
// temporarily on $imgs[0] won't work without absolute positioning.
// So we stack up an extra frame at the end.  It is a copy of $imgs[0].
// At the end of the loop, JS hides all the frames in the stack, leaving the
// main image visible, which matches the last image that has just faded in.
// That fixes the look when fading is not available.
////////////////////////////////////////////////////////////////////
// The main image $imgs[0] is in HTML, as are empty <div>'s for the frame stack.
// The frame stack images, ($imgs[1] ... $imgs[count($imgs)-1], $imgs[0])
// are in JS strings which are later written into the empty <div>'s.
// The JS strings are in a 2-dimensional Array animsts[k][j], k=slideshow number, j=frame number.
// The index j for the JS Array is off by one from the PHP index $i for $imgs (see comment above).
/////////////////////////////////////////////////////////
// usage:
// # <html><head>...
// # <script src="anim.js"></script>
// # <script language="javascript"><!--
// #   var animsts= new Array();
// # --></script>
// # </head><body onLoad="if (document.animok) startanim();">
// # ...
// # <script language="javascript"><!--
// #   animsts[0]= new Array();
// #   animsts[0][0]= '<img id="anim0-frame0" style="visibility: hidden; margin-top: -99px;" src="a1.jpg" height="99">';
// #   animsts[0][1]= '<img id="anim0-frame1" style="visibility: hidden; margin-top: -99px;" src="a2.jpg" height="99">';
// #   animsts[0][2]= '<img id="anim0-frame2" style="visibility: hidden; margin-top: -99px;" src="a0.jpg" height="99">';
// # // --></script>
// # <div><img src="a0.jpg" height="99"></div><div id="animdiv0-frame0"></div><div id="animdiv0-frame1"></div><div id="animdiv0-frame2"></div>
// # ...
// # <script language="javascript"><!--
// #   animsts[1]= new Array();
// #   animsts[1][0]= '<img id="anim1-frame0" style="visibility: hidden; margin-top: -77px;" src="b1.jpg" height="77">';
// #   animsts[1][1]= '<img id="anim1-frame1" style="visibility: hidden; margin-top: -77px;" src="b0.jpg" height="77">';
// # // --></script>
// # <div><img src="b0.jpg" height="77"></div><div id="animdiv1-frame0"></div><div id="animdiv1-frame1"></div>
// # ...
// # <div id="animcontrol" style="visibility: hidden;"><form action=".">
// # <nobr><input type="checkbox" onClick="setanimate(this.checked)" CHECKED name="x" value="x">
// # Slide Show</nobr></form></div><!-- form action, input name, value: not used, for standards -->
// # ...</html>
/////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////
// globals
/////////////////////////////////////////////////////////
try{
var animfaderate= 100 // msec, time between steps when fading in a frame.
var animframerate= 7000 // msec, hold each frame once faded in.
var animlag= 590 // msec, lag between frame groups.  Increase if framerate increased.
var animstate=0 // 0 not started, 1 running, 2 paused.

// These Arrays are 2-dim, indexed by [slide show number][frame number], and elements are...
var anims= new Array() // ...DOM <img> objects,
// animsts= new Array() // ...strings '<img id=...>, set in the HTML.

// These Arrays are 1-dim, indexed by slide show number, and elements are...
var animframe= new Array() //  ...frame numbers 0,1,2...,
var animstep= new Array() // ...fade step numbers 0,1,2..., which index the sines Array below,
var animtimeoutids= new Array() // ...and TimeOut ids. 

// This fades in faster than (0,10,20,...,100):
var sines= new Array(0,16,31,45,59,71,81,89,95,99,100) // round(100*Math.sin(i*PI/2))

// Signal to the HTML page that the script has loaded and the browser is capable...
// Used in: <body onLoad="if (document.animok) startanim();">
if (document.getElementById) document.animok= true;
} catch(e){}
/////////////////////////////////////////////////////////

//////////////////////////////////////////////
// Allow user control, from a checkbox
//////////////////////////////////////////////
function setanimate(seton) {try {
  if (animstate==1 && !seton) {
	animstate=2 // stop animation
	for (var i=0; i<animtimeoutids.length; i++) {
		clearTimeout(animtimeoutids[i]) // should not cause error on fail
	}
  } else if (animstate==2 && seton) {
	startanim() // resume.
	// Really start over completely, since it is hard to keep track when each setTimeout started.
	// Also, starting over cleans up any synchy errors.  IE is sorta buggy.
  }
} catch(e){}}

//////////////////////////////////////////////
// Start, called from <body onLoad="...">
//////////////////////////////////////////////
function startanim() {try{
  // alert(animsts.length)
  // if (document.fdebug) document.fdebug.t3.value= '';
  var temp, elem, elem2;
  for (var i=0; i<animsts.length; i++) {
	temp= new Array();
	for (var j=0; j<animsts[i].length; j++) {
		elem= document.getElementById('animdiv'+i+'-frame'+j) // This is a <div>.
		if (!elem || !animsts[i] || !animsts[i][j]) break;
		elem.innerHTML= animsts[i][j] // This is a string <img id="anim{i}-frame{j}" src=...>.

		// Get the element just inserted into the DOM.  Seems to work.
		elem= document.getElementById('anim'+i+'-frame'+j)
		if (!elem) break;
		temp[j]= elem;

		// We could set the magic styles on all but the first frame...
			// setOpacity(elem, 0)
			// elem.style.visibility= 'visible'
		// But to allow incapable browsers to degrade cleanly (Konqueror),
		// set visibilty below whenever opacity set to 0.
	}
	if (temp.length==0) break;
	anims[i]= temp
  }
  if (anims.length==0) return;

  // enable control box
  elem= document.getElementById('animcontrol'); // div
  elem2= document.getElementById('animcontrol2'); // checkbox
  if (elem && elem2) {
	elem.style.visibility= 'visible';
	elem2.checked= true;
  }
  animstate=1; // global, started
  var interval= animlag
  for (var i=0; i<anims.length; i++) {
	animframe[i]= 0
	animstep[i]= 0
	interval+= animlag // Add a increasing lag
	animtimeoutids[i]= setTimeout('anim3(' + i + ')', interval)
  }
} catch(e){}}


/////////////////////////////////////////////////////////
// Increment animframe[i], animstep[i].
// Called from anim3, recursively.
/////////////////////////////////////////////////////////
function anim2(i) {try{
  // if (document.fdebug) document.fdebug.t1.value= 'i='+i
  if (!anims[i] || animstate!=1) return;
  var interval= animfaderate;
  if (++animstep[i] >= sines.length) {  // Fades increment and rotate through sines array.
	animstep[i]= 0  // Back to zero.
	if (++animframe[i] >= anims[i].length) {  // Rotate to the next frame.
		animframe[i]= 0  // First frame.
	}
	interval+= animframerate // Delay the fade after switching to a fresh frame.
  }
  animtimeoutids[i]= setTimeout('anim3(' + i + ')', interval)
} catch(e){}}


/////////////////////////////////////////////////////////
// Set opacities, based on animstep[i], animframe[i].
// Called from animstart(), and anim2, recursively.
/////////////////////////////////////////////////////////
function anim3(i) {try{
  if (!anims[i] || animstate!=1) return;
  var elem, elem2, x;
  var aframe= animframe[i];
  var astep= animstep[i];
  var numframes= anims[i].length;
  // if (document.fdebug && i<8) eval('document.fdebug.t'+i).value= i + ': [fr='+aframe+',s='+astep+',n='+numframes+']';

  elem= anims[i][aframe]
  if (!elem) return;

  if (astep==0) { // starting new frame
	setOpacity(elem, 0); // before making it 'visible'
	elem.style.visibility= 'visible'
	if (aframe==0) { // All later frames are still 'visible' and faded-in, so cover the new frame.
		// Hide them all.  The last frame is the one showing, but it matches the main image,
		// which precedes them all and is not part of the frame stack, so let it show. 
		for (var j=1; j<numframes; j++) { // All except the new frame.
			elem2= anims[i][j]
			if (elem2) {
				// setOpacity(elem2, 0);  // later
				elem2.style.visibility= 'hidden'
			}
		}
	}
  } else {
	x= sines[astep]  // Apply the sine*100 lookup.

////////////////////////////////////////////////
//////// variable widths mod ///////////////////
////////////////////////////////////////////////
// This mod allows frames with variable widths, by fading out the underlying frame as the new frame
// fades in.  But for simplicty, it does have one bug: the last frame in the array must be *wider*
// than frame 0.  The last frame in the array is the same as the static frame that is dispayed by default
// and is under all the frames in the array.  We have no way to fade it.
////////////////////////////////////////////////
	if (aframe!=0)  {
		setOpacity(anims[i][aframe-1], 100-x);
	}
////////////////////////////////////////////////

	setOpacity(elem, x);
  }
  anim2(i) // Recurse back into anim2/setTimeout(anim3)
} catch(e){}}


/////////////////////////////////////////////////////////
// opacity setter, from: http://lists.evolt.org/archive/Week-of-Mon-20070115/187466.html
/////////////////////////////////////////////////////////
function setOpacity(obj, opacity) {try{
  // opacity= (opacity==100) ? 99.999 : opacity;  // why?
  if (!obj) return;
  // IE/Win
  obj.style.filter="progid:DXImageTransform.Microsoft.Alpha(opacity=" + opacity + ");";
  opacity= (opacity==0) ? 0 : round2(opacity/100);
  // Safari 1.2, newer Firefox and Mozilla, CSS3
  obj.style.opacity = opacity;
  // Safari<1.2, Konqueror
  // obj.style.KHTMLOpacity = opacity;
  // Older Mozilla and Firefox
  // obj.style.MozOpacity = opacity;
} catch(e){}}


//////////////////////////////////////////////
// like sprintf('%.2f', x)
//////////////////////////////////////////////
function round2(x) {try{
  if (Number.prototype.toFixed) {
	x= x.toFixed(2)
  } else {
	x= Math.round(x*100)
	x= x/100
  }
  if (x<0.001) return 0;
  if (x>0.999) return 1;
  return x;
} catch(e){}}
