/*the following line is used for checking source against javascript lint*/
/*global document, duration */

if(!window.Msn){window.Msn={};}	// Future proof in case the framework is released.

Msn.Slideshow = new function() {

  // private fields
  var me = this;
  
  var se = null;
  var t = null;
  var dly = 4;
  var tm = 1;
  var st = 0;
  
  var w = window;
  
  // see if we can grab some parameters from the window object
  if ( w.ipFadeSecs ) {
    tm = w.ipFadeSecs;
  }
  if ( w.ipDelaySecs ) {
    dly = w.ipDelaySecs;
  }

  // shortcut function for getElementById
  function E( i ) {
    return document.getElementById( i );
  }
  
  function init() {
    // get the slideshow object
    var ss = E("slides");
	  if ( ss ) {

	    // IE 5.5 and up get a filter applied
	    if (ss.style && ss.style.filter === "") {
		    ss.style.filter = "progid:DXImageTransform.Microsoft.Fade()";
	    } 

	    // get the first non-empty child
	    se = fc(ss);
	    if ( se ) {
		    // hide all the other slides so the first
		    // round of fades work properly
		    var c = 1, n = ns(se);
		    while( n != se ) {
		      ++c;
		      n.style.display = "none";
		      n = ns(n);
		    }

		    // hook a couple events
	      if ( w.attachEvent ) {
		      // IE has a memory-leak bug when events point to closures,
		      // so we have to hook into the onunload to unhook our events
		      w.attachEvent("onunload", me.ondestroy);
	      }
	      
	      // if we only have one slide, then we don't need to hook into
	      // the mouse or filter event, we don't need to show the next/prev
	      // buttons, and we don't want to start flipping
	      if ( c > 1 ) {
		      ss.onmousemove = pause;
		      ss.onfilterchange = trans;
        	
		      // hook up the next/prev buttons
		      hb();
          
          // kick off a timer until the first flip
          res();
	      }
	    }
    }
  }

	function uninit() {
    // unhook our slideshow events
	  if ( w.detachEvent ) {
	    w.detachEvent("onunload", me.ondestroy);
		}
    
  	// get the slides div
    var sl = E("slides");
	  if ( sl ) {
      sl.onfilterchange = null;
      sl.onmousemove = null;
    }
    
  	// unhook the next/prev buttons
	  hb( true );
	}
  
	this.ondestroy = function() {
	  uninit();
	};
  
	function hb(u) {
	  var f = E("flipper");
	  if ( f ) {
	    var as = f.getElementsByTagName( "a" );
	    for(var n=0; n < as.length; ++n) {
	      var a = as[n];
	      switch( n ) {
	        case 0:
	          a.onclick = (u ? null : fp);
	          a.style.visibility = "visible";
	          break;
    	      
	        case 1:
	          a.onclick = (u ? null : fn);
	          a.style.visibility = "visible";
	          break;
	      }
	    }
	  }
	}
  
  function hide() {
    // we're going to hide the current slide element
    st = 1;
    
    // if we have filters
    var sl = E("slides");
	  if (sl && sl.filters && sl.filters[0]) {
	    // use the filter to hide the slide element
		  f(sl,0);	        
	  }
	  else {
		  h();
	    t = w.setTimeout( trans, tm * 1000 / 4 );
	  }
  }
  
  function trans() {
    if ( st == 1 ) {
      // now we need to show the next slide element
      st = 2;
      se = ns(se);
      
      // if we have filters
	    var sl = E("slides");
	    if (sl && sl.filters && sl.filters[0]) {
	      // use the filter to show the slide element
		    f(sl,1);	        
	    }
	    else {
	      // show the slide element
		    s();
		    // start the timer for the next hide
		    res(tm);
	    }
    }
    else if ( st == 2 ) {
      // go back to display state
      res();
    }
  }
  
  function res(ex) {
    // reset the state to zero and kick off the hide timer
    st = 0;
    t = w.setTimeout( hide, (dly+(ex?ex:0)) * 1000 );
  }
  
  function ct() {
    w.clearTimeout( t );
    return (se !== null);
  }
  
  function f(sl,v) {
		sl.filters[0].apply();
		(v ? s() : h());
	  sl.filters[0].play(duration=tm);	        
  }
  
  // short cut function for showing the slide
  function s() {
    se.style.display = "block";
  }
  
  // shortcut function hiding the slide
  function h() {
    se.style.display = "none";
  }
  
  // called whenever the mouse moves over the slide
  function pause() {
    // if we're in display state
	  if( !st ) {
	    // clear our current timer and reset it
	    if ( ct() ) {
		    res();
		  }
	  }
  }

  // returns the first element child of the given parent
  function fc(p) {
    // get the first non-flipper child
    var n = p.firstChild;
    // if we got something and it isn't an element, we'll
    // keep getting the next sibling until we either run out of
    // siblings or find an element
    while( n && (n.nodeType != 1 || ie(n)) ) {
      n = n.nextSibling;
    }
    return n;
  }
  
  // returns the last element child of the parent element
  function lc(p) {
    // get the last non-flipper child
    var n = p.lastChild;
    // if we got something and it isn't an element, we'll
    // keep getting the previous sibling until we either run out of
    // siblings or find an element
    while ( n && (n.nodeType != 1 || ie(n)) ) {
      n = n.previousSibling;
    }
    return n;
  }
  
  // returns the parent element of the given child
  function pe(n) {
    // get the parent node
    var p = n.parentNode;
    // if we got something and it isn't an element,
    // keep getting the parent until we either run out
    // of parents or find an element
    while( p && p.nodeType != 1 ) {
      p = p.parentNode;
    }
    return p;
  }
  
  // returns the next sibling element of the given node
  function ns(n) {
    // get the next sibling
    var s = n.nextSibling;
    // if we got something and it isn't an element, keep 
    // looping until we either reach the end or find an element
    while( s && (s.nodeType != 1 || ie(s)) ) {
      s = s.nextSibling;
    }
    // if we reached the end...
    if ( !s ) {
      // circle back to the first child element of the parent
      s = fc( pe(n) );
    }
    return s;
  }
  
  function ps(n) {
    // get the previous sibling
    var s = n.previousSibling;
    // if we got something and it isn't an element, keep 
    // looping until we either reach the beginning or find an element
    while( s && (s.nodeType != 1 || ie(s)) ) {
      s = s.previousSibling;
    }
    // if we reached the beginning...
    if ( !s ) {
      // circle back to the last child element of the parent
      s = lc( pe(n) );
    }
    return s;
  }
  
  function ie( n ) {
    // return true if none of our children are elements
    for(var i = 0; i < n.childNodes.length; ++i) {
      // if this child is an element, then we know we're not empty
      if ( n.childNodes[i].nodeType == 1 ) {
        return false;
      }
    }
    // didn't find any elements, then we are empty
    return true;
  }
  
  function fp() {
    return flip(1);
  }
  
  function fn() {
    return flip();
  }

  function flip(r) {
    if ( !st ) {
      // clear the current timer
      if ( ct() ) {
        // hide the current slide element
        h();
        // get the "next" slide element
        se = ( r ? ps(se) : ns(se) );
        // show the current slide element
        s();
        // kick off the new timer
        res();
      }
    }
    // cancel the default action
    if ( w.event ) {
      w.event.returnValue = false;
    }
    return false;
  }
  
  // kick off this slideshow
  init();
};
