/*
 Carousel (30-December-2010)
 by Vic Phillips http://www.vicsjavascripts.org.uk/

 An animated carousel which scrolls content across a parent DIV.
 With 'Horizontal' and 'Vertical' modes of display and execution.
 Mouseover the parent DIV stops the scroll, mouseout starts the scroll.
 Options allow a sliding panel to be slid in displaying left and right controls
 and element captions on mouseover of the elements.

 There may be as many applications on a page as required.

 The script utilises my animation script 'Animate' http://www.vicsjavascripts.org.uk/Animate/Animate.htm


 ****** Application Notes.

 **** The HTML and CSS Code.

 ** The Slide DIV.
  The carousel elements are nested in a 'slide' DIV.
  This 'slide' DIV must have a CSS stye position of or 'absolute'.
  The 'slide' DIV is duplicated by the script to achieve the continuous carousel
  and MUST HAVE the width for Horizontal Mode or height for Vertical Mode
  specified accurately by CSS class name or inline style to achieve the seamless carousel effect.

 ** The Parent DIV.
  The 'slide' DIV is nested in a parent DIV.
  This parent DIV must be assigned a unique ID name and have a CSS stye position of 'relative' or 'absolute'
  and width and height defined by CSS class name or inline style.
  The parent DIV be assigned a style overflow of 'hidden' during initialization.

 ** The Carousel Panel.
  The carousel panel option allows a DIV element to be side into the carousel on mouseover of the carousel parent DIV.
  This DIV element must be defined a unique ID name.
  The carousel panel must have a CSS style position of 'absolute'.
  If required the 'forward' and 'back' controls must be assigned a common class name,
  the first element will change the scroll direction to 'forward' the second to 'back'
  If captions are required an element must be defined and assigned a class name.


 **** Initialising the Script.
  Each instance of the script is initialise by creating a new instance of 'zxcCarousel' passing script options as an object.
  Where the instance is to be controlled by inline event calls the instance must be assigned to a global variable.
  e.g.
   S1=new zxcCarousel({
    ID:'tst',                      // the unique ID name of the carousel parent node.                     (string)
    CarouselMode:'Horizontal',     //(optional) the carousel mode, 'Horizontal' or 'Vertical'.            (string, default = 'Horizontal')
    CarouselDirection:-1,          //(optional) the slide direction, <0 = left, >0 = right.               (digits, default = -1)
    CarouselDuration:8000,         //(optional) the time to slide the slider div in milliseconds.         (digits, default = the slider div width*10)
    AutoStart:true,                //(optional) true = start scroll, false = no auto start of the scroll. (boolean, default = true)
    CarouselPanel:{                //(optional) carousel caption and control panel options.               (object, default = no panel)
     ID:'panel',               //(optional) the unique ID name of the panel to slide in on mouseover. (string, default = no panel)
     Mode:'bottom',            //(optional) the panel slide in mode, 'top' or 'bottom'.               (string, default = 'top')
     AnimationSpeed:500,       //(optional) the time to slide the panel in milliseconds.              (digits, default = 500)
     ButtonClassName:'button', //(optional) the common class name of the panel buttons.               (string, default = no buttons)
     CaptionClassName:'title', //(optional) the class name of the element to display the captions.    (string, default = no captions)
     Captions:[                //(optional) the element captions to be displayed on mouseover.        (array, default = the element titles)
     'Egypt 1',
     'Egypt 2',
     '',
     'Egypt 4'
    ]
   }
  });


 **** Controlling the Script by InLine Event calls.

  The script may be controlling by inline event calls to functions 'Next', 'Pause' and 'Auto'.

 ** Function 'Pause'.
  An event call to function 'Pause' will pause auto rotation.
  example:
   <input type="button" name="" value="Pause" onclick="S1.Pause();"/>
  where:
   S1 = the global variable referencing the script instance. (global variable)

 ** Function 'Auto'.
  An event call to function 'Auto' will start auto rotation and may be used to change the scroll speed.
  example:
   <input type="button" name="" value="Auto" onclick="S1.Auto(7000);"/>
  where:
   S1          = the global variable referencing the script instance.   (global variable)
   parameter 0 = (optional) the carousel scroll speed in milli seconds. (digits, default = no change)

 ** Function 'Direction'.
  An event call to function 'Direction' will change the scroll direction.
  example:
   <input type="button" name="" value="Auto" onclick="S1.Direction(7000);"/>
  where:
   S1          = the global variable referencing the script instance. (global variable)
   parameter 0 =  <1 = forward, <1 = back.                            (digits)

*/

// ****** Functional Code(2.91 - 3.79K) - NO NEED to Change.

function zxcCarousel(o){
 var mde=typeof(o.CarouselMode)=='string'&&o.CarouselMode.charAt(0).toUpperCase()=='V'?['top','left','height','offsetHeight']:['left','top','width','offsetWidth'];
 var oop=this,obj=document.getElementById(o.ID),slide=obj.getElementsByTagName('DIV')[0],ssz=slide[mde[3]],panel,ary=[],z0=0,z0a,cnt,imgs,objh,ph,slider,captions=[];
 obj.style.overflow='hidden';
 this.panel=false;
 this.text=false;
 if (typeof(o.CarouselPanel)=='object'&&this.carouselpanel){
  captions=this.carouselpanel(o.CarouselPanel,obj);
 }
 this.nu=Math.max(Math.ceil(obj[mde[3]]/ssz+2),4);
 var slider=document.createElement('DIV');
 slider.style.position='absolute';
 slider.style[mde[0]]=-ssz+'px';
 slider.style[mde[1]]='0px';
 slider.style[mde[2]]=this.nu*ssz+'px';
 obj.appendChild(slider);
 this.slides=[];
 for (;z0<this.nu;z0++){
  slide=z0>0?slide.cloneNode(true):slide;
  slide.style[mde[0]]=(ssz*z0)+'px';
  slider.appendChild(slide);
  imgs=slide.childNodes;
  for (cnt=0,z0a=0;z0a<imgs.length;z0a++){
   if (imgs[z0a].nodeType==1&&this.title){
    this.addevt(imgs[z0a],'mouseover','title',captions[cnt++]||imgs[z0a].title||'');
    this.addevt(imgs[z0a],'mouseout','title','');
   }
  }
 }
 this.slide=new zxcAnimate(mde[0],slider,-ssz);
 this.slide.Complete=function(){
   oop.Pause(false);
   oop.rotate();
  }
 this.ssz=ssz;
 this.to=null;
 this.ms=typeof(o.CarouselDuration)=='number'?ssz*o.CarouselDuration:ssz*10;
 this.ud=typeof(o.CarouselDirection)=='number'&&o.CarouselDirection>0?1:-1;
 this.addevt(obj,'mouseover','Pause',true);
 this.addevt(obj,'mouseout','Auto');
 if (typeof(o.AutoStart)!='boolean'||o.AutoStart){
  this.Auto(false);
 }
}

zxcCarousel.prototype={

 Auto:function(ms){
  this.Pause(false);
  this.ms=typeof(ms)=='number'?ms:this.ms;
  var oop=this;
  this.to=setTimeout(function(){ if (this.text){ oop.text.innerHTML=''; } oop.rotate(); },150);
 },

 Pause:function(p){
  clearTimeout(this.slide.to);
  clearTimeout(this.to);
  if (this.panel){
   this.panel.animate(this.panel.data[0],this.panelpos[p?1:0],this.panelms,this.panelpos);
  }
 },

 Direction:function(ud){
  if (typeof(ud)=='number'){
   this.ud=Math.abs(this.ud)*(ud>0?1:-1);
  }
 },

 rotate:function(){
   var data=this.slide.data[0];
   if ((this.ud<0&&data<-this.ssz)||(this.ud>0&&data>-this.ssz)){
    data+=this.ssz*(this.ud<0?1:-1);
   }
   this.slide.animate(data,data+(this.ssz*this.ud),this.ms,[0,this.ssz]);
 },

 bycls:function(nme,el,tag){
  for (var tag=tag||'*',reg=new RegExp('\\b'+nme+'\\b'),els=el.getElementsByTagName(tag),ary=[],z0=0; z0<els.length;z0++){
   if(reg.test(els[z0].className)) ary.push(els[z0]);
  }
  return ary;
 },

 addevt:function(o,t,f,p){
  var oop=this;
  if (o.addEventListener) o.addEventListener(t,function(e){ return oop[f](p,e);}, false);
  else if (o.attachEvent) o.attachEvent('on'+t,function(e){ return oop[f](p,e); });
 },

// Optional Carousel Panel Code
 carouselpanel:function(o,obj){
  var panel=document.getElementById(o.ID),buts,z0=0;
  if (panel){
   objh=obj.offsetHeight;
   ph=panel.offsetHeight;
   this.panelpos=typeof(o.Mode)=='string'&&o.Mode.charAt(0).toUpperCase()=='B'?[objh+2,objh-ph]:[-ph-2,0];
   this.panelms=o.AnimationSpeed||500;
   panel.style.top=this.panelpos[0]+'px';
   this.panel=new zxcAnimate('top',panel,this.panelpos[0]);
   buts=this.bycls(o.ButtonClassName,panel);
   if (buts[0]){
    this.addevt(buts[0],'mouseup','Direction',-1);
   }
   if (buts[1]){
    this.addevt(buts[1],'mouseup','Direction',1);
   }
   buts=this.bycls(o.CaptionClassName,panel)[0];
   if (buts){
    this.text=buts;
   }
  }
  return typeof(o.Captions)=='object'&&o.Captions.constructor==Array?o.Captions:[];
 },

 title:function(caption){
  this.text.innerHTML=caption;
 }


}

// Animate (11-January-2010)
// by Vic Phillips http://www.vicsjavascripts.org.uk

// A light weight animator to progressively change
// the Left, Top, Width, Height or Opacity of an element over a specified period of time.
// With the ability to scale the effect time on specified minimum/maximum values
// and with three types of progression 'sin' and 'cos' and 'liner'.

// **** Application Notes

// **** The HTML Code
//
// when moving an element the inline or class rule style position of the element should be assigned as
// 'position:relative;' or 'position:absolute;'
//
// The element would normally be assigned a unique ID name.
//

// **** Initialising the Script.
//
// The script is initialised by assigning an instance of the script to a variable.
// e.g A = new zxcAnimate('left','id1')
// where:
//  A           = a global variable                                                               (variable)
//  parameter 0 = the mode(see Note 1).                                                           (string)
//  parameter 1 = the unique ID name or element object.                                           (string or element object)
//  parameter 1 = the initial value.                                                              (digits, default = 0)

// **** Executing the Effect
//
// The effect is executed by an event call to function 'A.animate(10,800 ,5000,[10,800]);'
// where:
//  A           = the global referencing the script instance.                                 (variable)
//  parameter 0 = the start value.                                                            (digits, for opacity minimum 0, maximum 100)
//  parameter 1 = the finish value.                                                           (digits, for opacity minimum 0, maximum 100)
//  parameter 2 =  period of time between the start and finish of the effect in milliseconds. (digits or defaults to previous or 0(on first call) milliSeconds)
//  parameter 3 = (optional) to scale the effect time on a specified minimum/maximum.         (array, see Note 3)
//                 field 0 the minimum value. (digits)
//                 field 1 the maximum value. (digits)
//  parameter 3 = (optional) the type of progression, 'sin', 'cos' or 'liner'.                (string, default = 'liner')
//                 'sin' progression starts fast and ends slow.
//                 'cos' progression starts slow and ends fast.
//
//  Note 1:  Examples modes: 'left', 'top', 'width', 'height', 'opacity.
//  Note 2:  The default units(excepting opacity) are 'px'.
//           For hyphenated modes, the first character after the hyphen must be upper case, all others lower case.
//  Note 3:  The scale is of particular use when re-calling the effect
//           in mid progression to retain an constant rate of progression.
//  Note 4:  The current effect value is recorded in A.data[0].
//  Note 5:  A function may be called on completion of the effect by assigning the function
//           to the animator intance property .Complete.
//           e.g. [instance].Complete=function(){ alert(this.data[0]); };
//



// **** Functional Code(1.52K) - NO NEED to Change

function zxcAnimate(mde,obj,srt){
 this.to=null;
 this.obj=typeof(obj)=='object'?obj:document.getElementById(obj);
 this.mde=mde.replace(/\W/g,'');
 this.data=[srt||0];
 return this;
}

zxcAnimate.prototype={

 animate:function(srt,fin,ms,scale,c){
  clearTimeout(this.to);
  this.time=ms||this.time||0;
  this.neg=srt<0||fin<0;
  this.data=[srt,srt,fin];
  this.mS=this.time*(!scale?1:Math.abs((fin-srt)/(scale[1]-scale[0])));
  this.c=typeof(c)=='string'?c.charAt(0).toLowerCase():this.c?this.c:'';
  this.inc=Math.PI/(2*this.mS);
  this.srttime=new Date().getTime();
  this.cng();
 },

 cng:function(){
  var oop=this,ms=new Date().getTime()-this.srttime;
  this.data[0]=Math.floor(this.c=='s'?(this.data[2]-this.data[1])*Math.sin(this.inc*ms)+this.data[1]:this.c=='c'?this.data[2]-(this.data[2]-this.data[1])*Math.cos(this.inc*ms):(this.data[2]-this.data[1])/this.mS*ms+this.data[1]);
  this.apply();
  if (ms<this.mS) this.to=setTimeout(function(){oop.cng()},10);
  else {
   this.data[0]=this.data[2];
   this.apply();
   if (this.Complete) this.Complete(this);
  }
 },

 apply:function(){
  if (isFinite(this.data[0])){
   if (this.data[0]<0&&!this.neg) this.data[0]=0;
   if (this.mde!='opacity') this.obj.style[this.mde]=this.data[0]+'px';
   else zxcOpacity(this.obj,this.data[0]);
  }
 }

}

function zxcOpacity(obj,opc){
 if (opc<0||opc>100) return;
 obj.style.filter='alpha(opacity='+opc+')';
 obj.style.opacity=obj.style.MozOpacity=obj.style.WebkitOpacity=obj.style.KhtmlOpacity=opc/100-.001;
}
