/*
 This file is part of JonDesign's SmoothGallery v2.0.

 JonDesign's SmoothGallery is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 3 of the License, or
 (at your option) any later version.

 JonDesign's SmoothGallery is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with JonDesign's SmoothGallery; if not, write to the Free Software
 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA

 Main Developer: Jonathan Schemoul (JonDesign: http://www.jondesign.net/)
 Contributed code by:
 - Christian Ehret (bugfix)
 - Nitrix (bugfix)
 - Valerio from Mad4Milk for his great help with the carousel scrolling and many other things.
 - Archie Cowan for helping me find a bugfix on carousel inner width problem.
 - Tomocchino from #mootools for the preloader class
 Many thanks to:
 - The mootools team for the great mootools lib, and it's help and support throughout the project.
*/

// declaring the class
var gallery = {
 initialize: function(element, options) {
 this.setOptions({
 showArrows: true,
 showCarousel: true,
 showInfopane: true,
 showPlay: true,
 playState: true,
 embedLinks: true,
 fadeDuration: 500,
 timed: false,
 delay: 9000,
 preloader: true,
 preloaderImage: true,
 preloaderErrorImage: true,
 /* Data retrieval */
 manualData: [],
 populateFrom: false,
 populateData: true,
 destroyAfterPopulate: true,
 elementSelector: "div.imageElement",
 titleSelector: "h3",
 subtitleSelector: "p",
 linkSelector: "a.open",
 imageSelector: "img.full",
 thumbnailSelector: "img.thumbnail",
 defaultTransition: "fade",
 /* InfoPane options */
 slideInfoZoneOpacity: 0.7,
 slideInfoZoneSlide: true,
 /* Carousel options */
 carouselMinimizedOpacity: 0.6,
 carouselMinimizedHeight: 20,
 carouselMaximizedOpacity: 0.6,
 thumbHeight: 75,
 thumbWidth: 80,
 thumbSpacing: 5,
 thumbIdleOpacity: 0.6,
 textShowCarousel: 'Pictures',
 showCarouselLabel: false,
 thumbCloseCarousel: true,
 useThumbGenerator: false,
 thumbGenerator: 'resizer.php',
 useExternalCarousel: true,
 carouselElement: $('thumbs'),
 carouselHorizontal: false,
 activateCarouselScroller: true,
 carouselPreloader: true,
 textPreloadingCarousel: 'Loading...',
 /* CSS Classes */
 baseClass: 'jdGallery',
 withArrowsClass: 'withArrows',
 /* Plugins: HistoryManager */
 useHistoryManager: false,
 customHistoryKey: false
 }, options);
 this.fireEvent('onInit');
 this.currentIter = 0;
 this.lastIter = 0;
 this.maxIter = 0;
 this.galleryElement = element;
 this.galleryData = this.options.manualData;
 this.galleryInit = 1;
 this.galleryElements = Array();
 this.thumbnailElements = Array();
 this.galleryElement.addClass(this.options.baseClass);

 this.populateFrom = element;
 if (this.options.populateFrom)
 this.populateFrom = this.options.populateFrom;
 if (this.options.populateData)
 this.populateData();
 element.style.display="block";

 if (this.options.useHistoryManager)
 this.initHistory();



 this.constructElements();

 if ((this.galleryData.length>1)&&(this.options.showArrows))
 {
 var leftArrow = new Element('a').addClass('left').addEvent(
 'click',
 this.prevItem.bind(this)
 ).injectInside(element);
 var rightArrow = new Element('a').addClass('right').addEvent(
 'click',
 this.nextItem.bind(this)
 ).injectInside(element);
 this.galleryElement.addClass(this.options.withArrowsClass);
 }
 
 /**
* Author 2008, Thinkc2 (fritz at thinkc2.net)
* Added 2008-01-22
* Adds markup for slideshow toggle button
**/
if (this.options.showPlay)
{
var playBtn = new Element('a').addClass('pause').setProperties({
id: 'showControl'
}).addEvent(
'click',
this.playPauseShow.bind(this)
).injectInside(element);
this.galleryElement.addClass(this.options.withArrowsClass);
}

 this.loadingElement = new Element('div').addClass('loadingElement').injectInside(element);
 if (this.options.showInfopane) this.initInfoSlideshow();
 if (this.options.embedLinks)
 {
 this.currentLink = new Element('a').addClass('open').setProperties({
 href: '#',
 title: ''
 }).injectInside(element);

///MOD for IE 6 bug with link not floating correctly
 this.linkImage = new Element('img').setProperties({
 src: 'images/pixel.gif',
 width: '167',
 height: '39'
 }).injectInside(this.currentLink);
 if ((!this.options.showArrows) && (!this.options.showCarousel))
 this.galleryElement = element = this.currentLink;
 else
 this.currentLink.setStyle('display', 'none');
 }
 if (this.options.showCarousel) this.initCarousel();
 this.doSlideShow(1);
 },
 populateData: function() {
 currentArrayPlace = this.galleryData.length;
 options = this.options;
 var data = $A(this.galleryData);
 data.extend(this.populateGallery(this.populateFrom, currentArrayPlace));
 this.galleryData = data;
 this.fireEvent('onPopulated');
 },
 populateGallery: function(element, startNumber) {
 var data = [];
 options = this.options;
 currentArrayPlace = startNumber;
 element.getElements(options.elementSelector).each(function(el) {
 elementDict = {
 image: el.getElement(options.imageSelector).getProperty('src'),
 number: currentArrayPlace,
 transition: this.options.defaultTransition
 };
 elementDict.extend = $extend;
 if ((options.showInfopane) | (options.showCarousel))
 elementDict.extend({
 title: el.getElement(options.titleSelector).innerHTML,
 description: el.getElement(options.subtitleSelector).innerHTML
 });
 if (options.embedLinks)
 elementDict.extend({
 link: el.getElement(options.linkSelector).href||false,
 linkTitle: el.getElement(options.linkSelector).title||false,
 linkTarget: el.getElement(options.linkSelector).getProperty('target')||false
 }); if ((!options.useThumbGenerator) && (options.showCarousel))
 elementDict.extend({
 thumbnail: el.getElement(options.thumbnailSelector).getProperty('src')
 });
 else if (options.useThumbGenerator)
 elementDict.extend({
 thumbnail: options.thumbGenerator + '?imgfile=' + elementDict.image + '&max_width=' + options.thumbWidth + '&max_height=' + options.thumbHeight
 });

 data.extend([elementDict]);
 currentArrayPlace++;
 if (this.options.destroyAfterPopulate)
 el.remove();
 });
 return data;
 },
 constructElements: function() {
 el = this.galleryElement;
 this.maxIter = this.galleryData.length;
 var currentImg;
 for(i=0;i<this.galleryData.length;i++)
 {
 var currentImg = new Fx.Styles(
 new Element('div').addClass('slideElement').setStyles({
 'position':'absolute',
 'left':'0px',
 'right':'0px',
 'margin':'0px',
 'padding':'0px',
 'backgroundPosition':"center center",
 'opacity':'0'
 }).injectInside(el),
 'opacity',
 {duration: this.options.fadeDuration}
 );
 if (this.options.preloader)
 {
 currentImg.source = this.galleryData[i].image;
 currentImg.loaded = false;
 currentImg.load = function(imageStyle) {
 if (!imageStyle.loaded) {
 new Asset.image(imageStyle.source, {
 'onload' : function(img){
 img.element.setStyle(
 'backgroundImage',
 "url('" + img.source + "')")
 img.loaded = true;
 }.bind(this, imageStyle)
 });
 }
 }.pass(currentImg, this);
 } else {
 currentImg.element.setStyle('backgroundImage',
 "url('" + this.galleryData[i].image + "')");
 }
 this.galleryElements[parseInt(i)] = currentImg;
 }
 },
 destroySlideShow: function(element) {
 var myClassName = element.className;
 var newElement = new Element('div').addClass('myClassName');
 element.parentNode.replaceChild(newElement, element);
 },
 startSlideShow: function() {
 this.fireEvent('onStart');
 this.loadingElement.style.display = "none";
 this.lastIter = this.maxIter - 1;
 this.currentIter = 0;
 this.galleryInit = 0;
 this.galleryElements[parseInt(this.currentIter)].set({opacity: 1});
 if (this.options.showInfopane)
 this.showInfoSlideShow.delay(500, this);
 var textShowCarousel = formatString(this.options.textShowCarousel, this.currentIter+1, this.maxIter);
 if (this.options.showCarousel&&(!this.options.carouselPreloader))
 this.carouselBtn.setHTML(textShowCarousel).setProperty('title', textShowCarousel);
 this.prepareTimer();
 if (this.options.embedLinks)
 this.makeLink(this.currentIter);
 },
 playPauseShow: function() {

/**
* Author 2008, Thinkc2 (fritz at thinkc2.net)
* Added 2008-01-22
* Controls slideshow toggle (play/pause)
**/

if($('showControl').hasClass('pause')) {
//pause
this.options.playState = false;
this.clearTimer();
$('showControl').removeClass('pause');
$('showControl').addClass('play');
//alert('pause');

} else if($('showControl').hasClass('play')) {
//start
this.options.playState = true;
this.nextItem();
$('showControl').removeClass('play');
$('showControl').addClass('pause');
//alert('play');
}
}, 
 nextItem: function() {
 this.fireEvent('onNextCalled');
 this.nextIter = this.currentIter+1;
 if (this.nextIter >= this.maxIter)
 this.nextIter = 0;
 this.galleryInit = 0;
 this.goTo(this.nextIter);
 },
 prevItem: function() {
 this.fireEvent('onPreviousCalled');
 this.nextIter = this.currentIter-1;
 if (this.nextIter <= -1)
 this.nextIter = this.maxIter - 1;
 this.galleryInit = 0;
 this.goTo(this.nextIter);
 },
 goTo: function(num) {
 this.clearTimer();
 if(this.options.preloader)
 {
 this.galleryElements[num].load();
 if (num==0)
 this.galleryElements[this.maxIter - 1].load();
 else
 this.galleryElements[num - 1].load();
 if (num==(this.maxIter - 1))
 this.galleryElements[0].load();
 else
 this.galleryElements[num + 1].load();

 }
 if (this.options.embedLinks)
 this.clearLink();
 if (this.options.showInfopane)
 {
 this.slideInfoZone.clearChain();
 this.hideInfoSlideShow().chain(this.changeItem.pass(num, this));
 } else
 this.currentChangeDelay = this.changeItem.delay(500, this, num);
 if (this.options.embedLinks)
 this.makeLink(num);
 
 if (this.options.playState)
 this.prepareTimer();
 /*if (this.options.showCarousel)
 this.clearThumbnailsHighlights();*/
 },
 changeItem: function(num) {
 this.fireEvent('onStartChanging');
 this.galleryInit = 0;
 if (this.currentIter != num)
 {
 for(i=0;i<this.maxIter;i++)
 {
 if ((i != this.currentIter)) this.galleryElements[i].set({opacity: 0});
 }
 gallery.Transitions[this.galleryData[num].transition].pass([
 this.galleryElements[this.currentIter],
 this.galleryElements[num],
 this.currentIter,
 num], this)();
 this.currentIter = num;
 }
 var textShowCarousel = formatString(this.options.textShowCarousel, num+1, this.maxIter);

// if (this.options.showCarousel)
 if (this.options.showCarousel && this.carouselBtn)
 this.carouselBtn.setHTML(textShowCarousel).setProperty('title', textShowCarousel);
 this.doSlideShow.bind(this)();
 this.fireEvent('onChanged');
 },
 clearTimer: function() {
 if (this.options.timed)
 $clear(this.timer);
 },
 prepareTimer: function() {
 if (this.options.timed)
 this.timer = this.nextItem.delay(this.options.delay, this);
 },
 doSlideShow: function(position) {
 if (this.galleryInit == 1)
 {
 imgPreloader = new Image();
 imgPreloader.onload=function(){
 this.startSlideShow.delay(10, this);
 }.bind(this);
 imgPreloader.src = this.galleryData[0].image;
 if(this.options.preloader)
 this.galleryElements[0].load();
 } else {
 if (this.options.showInfopane)
 {
 if (this.options.showInfopane)
 {
 this.showInfoSlideShow.delay((500 + this.options.fadeDuration), this);
 } else
 if ((this.options.showCarousel)&&(this.options.activateCarouselScroller))
 this.centerCarouselOn(position);
 }
 }
 },
 createCarousel: function() {
 var carouselElement;
 if (!this.options.useExternalCarousel)
 {
 var carouselContainerElement = new Element('div').addClass('carouselContainer').injectInside(this.galleryElement);
 this.carouselContainer = new Fx.Styles(carouselContainerElement, {transition: Fx.Transitions.expoOut});
 this.carouselContainer.normalHeight = carouselContainerElement.offsetHeight;
 this.carouselContainer.set({'opacity': this.options.carouselMinimizedOpacity, 'top': (this.options.carouselMinimizedHeight - this.carouselContainer.normalHeight)});
 this.carouselBtn = new Element('a').addClass('carouselBtn').setProperties({
 title: this.options.textShowCarousel
 }).injectInside(carouselContainerElement);
 if(this.options.carouselPreloader)
 this.carouselBtn.setHTML(this.options.textPreloadingCarousel);
 else
 this.carouselBtn.setHTML(this.options.textShowCarousel);
 this.carouselBtn.addEvent(
 'click',
 function () {
 this.carouselContainer.clearTimer();
 this.toggleCarousel();
 }.bind(this)
 );
 this.carouselActive = false;

 carouselElement = new Element('div').addClass('carousel').injectInside(carouselContainerElement);
 this.carousel = new Fx.Styles(carouselElement);
 } else {
 carouselElement = $(this.options.carouselElement).addClass('jdExtCarousel');
 }
 this.carouselElement = new Fx.Styles(carouselElement, {transition: Fx.Transitions.expoOut});
 this.carouselElement.normalHeight = carouselElement.offsetHeight;
 if (this.options.showCarouselLabel)
 this.carouselLabel = new Element('p').addClass('label').injectInside(carouselElement);
 carouselWrapper = new Element('div').addClass('carouselWrapper').injectInside(carouselElement);
 this.carouselWrapper = new Fx.Styles(carouselWrapper, {transition: Fx.Transitions.expoOut});
 this.carouselWrapper.normalHeight = carouselWrapper.offsetHeight;
 this.carouselInner = new Element('div').addClass('carouselInner').injectInside(carouselWrapper);
 if (this.options.activateCarouselScroller)
 {
 this.carouselWrapper.scroller = new Scroller(carouselWrapper, {
 area: 100,
 velocity: 0.2
 })

 this.carouselWrapper.elementScroller = new Fx.Scroll(carouselWrapper, {
 duration: 400,
 onStart: this.carouselWrapper.scroller.stop.bind(this.carouselWrapper.scroller),
 onComplete: this.carouselWrapper.scroller.start.bind(this.carouselWrapper.scroller)
 });
 }
 },
 fillCarousel: function() {
 this.constructThumbnails();
 },
 initCarousel: function () {
 this.createCarousel();
 this.fillCarousel();
 if (this.options.carouselPreloader)
 this.preloadThumbnails();
 },
 flushCarousel: function() {
 this.thumbnailElements.each(function(myFx) {
 myFx.element.remove();
 myFx = myFx.element = null;
 });
 this.thumbnailElements = [];
 },
 toggleCarousel: function() {
 if (this.carouselActive)
 this.hideCarousel();
 else
 this.showCarousel();
 },
 showCarousel: function () {
 this.fireEvent('onShowCarousel');
 this.carouselContainer.start({
 'opacity': this.options.carouselMaximizedOpacity,
 'top': 0
 }).chain(function() {
 this.carouselActive = true;
 this.carouselWrapper.scroller.start();
 this.fireEvent('onCarouselShown');
 this.carouselContainer.options.onComplete = null;
 }.bind(this));
 },
 hideCarousel: function () {
 this.fireEvent('onHideCarousel');
 var targetTop = this.options.carouselMinimizedHeight - this.carouselContainer.normalHeight;
 this.carouselContainer.start({
 'opacity': this.options.carouselMinimizedOpacity,
 'top': targetTop
 }).chain(function() {
 this.carouselActive = false;
 this.carouselWrapper.scroller.stop();
 this.fireEvent('onCarouselHidden');
 this.carouselContainer.options.onComplete = null;
 }.bind(this));
 },
 constructThumbnails: function () {
 element = this.carouselInner;
 for(i=0;i<this.galleryData.length;i++)
 {
 var currentImg = new Fx.Style(new Element ('div').addClass("thumbnail").setStyles({
 backgroundImage: "url('" + this.galleryData[i].thumbnail + "')",
 backgroundPosition: "center center",
 backgroundRepeat: 'no-repeat',
 marginLeft: this.options.thumbSpacing + "px",
 width: this.options.thumbWidth + "px",
 height: this.options.thumbHeight + "px"
 }).injectInside(element), "opacity", {duration: 200}).set(this.options.thumbIdleOpacity);
 currentImg.element.addEvents({
 'mouseover': function (myself) {
 myself.clearTimer();
 myself.start(0.99);
 if (this.options.showCarouselLabel)
 $(this.carouselLabel).setHTML('<span class="number">' + (myself.relatedImage.number + 1) + "/" + this.maxIter + ":</span> " + myself.relatedImage.title);
 }.pass(currentImg, this),
 'mouseout': function (myself) {
 myself.clearTimer();
 myself.start(this.options.thumbIdleOpacity);
 }.pass(currentImg, this),
 'click': function (myself) {
 this.goTo(myself.relatedImage.number);
 if (this.options.thumbCloseCarousel)
 this.hideCarousel();
 }.pass(currentImg, this)
 });

 currentImg.relatedImage = this.galleryData[i];
 this.thumbnailElements[parseInt(i)] = currentImg;
 }
 },
 log: function(value) {
 if(console.log)
 console.log(value);
 },
 preloadThumbnails: function() {
 var thumbnails = [];
 for(i=0;i<this.galleryData.length;i++)
 {
 thumbnails[parseInt(i)] = this.galleryData[i].thumbnail;
 }
 this.thumbnailPreloader = new Preloader();
 this.thumbnailPreloader.addEvent('onComplete', function() {
 var textShowCarousel = formatString(this.options.textShowCarousel, this.currentIter+1, this.maxIter);
// this.carouselBtn.setHTML(textShowCarousel).setProperty('title', textShowCarousel);
 }.bind(this));
 this.thumbnailPreloader.load(thumbnails);
 },
 clearThumbnailsHighlights: function()
 {
 for(i=0;i<this.galleryData.length;i++)
 {
 this.thumbnailElements[i].clearTimer();
 this.thumbnailElements[i].start(0.5);
 }
 },
 changeThumbnailsSize: function(width, height)
 {
 for(i=0;i<this.galleryData.length;i++)
 {
 this.thumbnailElements[i].clearTimer();
 this.thumbnailElements[i].element.setStyles({
 'width': width + "px",
 'height': height + "px"
 });
 }
 },
 centerCarouselOn: function(num) {
 if (!this.carouselWallMode)
 {
 var carouselElement = this.thumbnailElements[num];
 this.clearThumbnailsHighlights();
 carouselElement.clearTimer();
 carouselElement.custom(.99);
 var position = carouselElement.element.offsetLeft + (carouselElement.element.offsetWidth / 2);
 var carouselWidth = this.carouselWrapper.element.offsetWidth;
 var carouselInnerWidth = this.carouselInner.offsetWidth;
 var diffWidth = carouselWidth / 2;
 var scrollPos = position-diffWidth;
 this.carouselWrapper.elementScroller.scrollTo = (scrollPos,0);
 }
 },
 initInfoSlideshow: function() {
 /*if (this.slideInfoZone.element)
 this.slideInfoZone.element.remove();*/
 this.slideInfoZone = new Fx.Styles(new Element('div').addClass('slideInfoZone').injectInside($(this.galleryElement))).set({'opacity':0});
 var slideInfoZoneTitle = new Element('h2').injectInside(this.slideInfoZone.element);
 var slideInfoZoneDescription = new Element('p').injectInside(this.slideInfoZone.element);
 this.slideInfoZone.normalHeight = this.slideInfoZone.element.offsetHeight;
 this.slideInfoZone.element.setStyle('opacity',0);
 },
 changeInfoSlideShow: function()
 {
 this.hideInfoSlideShow.delay(10, this);
 this.showInfoSlideShow.delay(500, this);
 },
 showInfoSlideShow: function() {
 this.fireEvent('onShowInfopane');
 this.slideInfoZone.clearTimer();
 element = this.slideInfoZone.element;
 element.getElement('h2').setHTML(this.galleryData[this.currentIter].title);
 element.getElement('p').setHTML(this.galleryData[this.currentIter].description);
 if(this.options.slideInfoZoneSlide)
 this.slideInfoZone.start({'opacity': [0, this.options.slideInfoZoneOpacity], 'height': [0, this.slideInfoZone.normalHeight]});
 else
 this.slideInfoZone.start({'opacity': [0, this.options.slideInfoZoneOpacity]});
 if (this.options.showCarousel)
 this.slideInfoZone.chain(this.centerCarouselOn.pass(this.currentIter, this));
 return this.slideInfoZone;
 },
 hideInfoSlideShow: function() {
 this.fireEvent('onHideInfopane');
 this.slideInfoZone.clearTimer();
 if(this.options.slideInfoZoneSlide)
 this.slideInfoZone.start({'opacity': 0, 'height': 0});
 else
 this.slideInfoZone.start({'opacity': 0});
 return this.slideInfoZone;
 },
 makeLink: function(num) {
 this.currentLink.setProperties({
 href: this.galleryData[num].link,
 title: this.galleryData[num].linkTitle
 })
 if (!((this.options.embedLinks) && (!this.options.showArrows) && (!this.options.showCarousel)))
 this.currentLink.setStyle('display', 'block');
 },
 clearLink: function() {
 this.currentLink.setProperties({href: '', title: ''});
 if (!((this.options.embedLinks) && (!this.options.showArrows) && (!this.options.showCarousel)))
 this.currentLink.setStyle('display', 'none');
 },
 /* To change the gallery data, those two functions : */
 flushGallery: function() {
 this.galleryElements.each(function(myFx) {
 myFx.element.remove();
 myFx = myFx.element = null;
 });
 this.galleryElements = [];
 },
 changeData: function(data) {
 this.galleryData = data;
 this.clearTimer();
 this.flushGallery();
 if (this.options.showCarousel) this.flushCarousel();
 this.constructElements();
 if (this.options.showCarousel) this.fillCarousel();
 if (this.options.showInfopane) this.hideInfoSlideShow();
 this.galleryInit=1;
 this.lastIter=0;
 this.currentIter=0;
 this.doSlideShow(1);
 },
 /* Plugins: HistoryManager */
 initHistory: function() {
 this.fireEvent('onHistoryInit');
 this.historyKey = this.galleryElement.id + '-picture';
 if (this.options.customHistoryKey)
 this.historyKey = this.options.customHistoryKey();
 this.history = HistoryManager.register(
 this.historyKey,
 [1],
 function(values) {
 if (parseInt(values[0])-1 < this.maxIter)
 this.goTo(parseInt(values[0])-1);
 }.bind(this),
 function(values) {
 return [this.historyKey, '(', values[0], ')'].join('');
 }.bind(this),
 this.historyKey + '\\((\\d+)\\)');
 this.addEvent('onChanged', function(){
 this.history.setValue(0, this.currentIter+1);
 }.bind(this));
 this.fireEvent('onHistoryInited');
 }
};
gallery = new Class(gallery);
gallery.implement(new Events);
gallery.implement(new Options);

gallery.Transitions = new Abstract ({
 fade: function(oldFx, newFx, oldPos, newPos){
 oldFx.options.transition = newFx.options.transition = Fx.Transitions.linear;
 oldFx.options.duration = newFx.options.duration = this.options.fadeDuration;
 if (newPos > oldPos) newFx.start({opacity: 1});
 else
 {
 newFx.set({opacity: 1});
 oldFx.start({opacity: 0});
 }
 },
 crossfade: function(oldFx, newFx, oldPos, newPos){
 oldFx.options.transition = newFx.options.transition = Fx.Transitions.linear;
 oldFx.options.duration = newFx.options.duration = this.options.fadeDuration;
 newFx.start({opacity: 1});
 oldFx.start({opacity: 0});
 },
 fadebg: function(oldFx, newFx, oldPos, newPos){
 oldFx.options.transition = newFx.options.transition = Fx.Transitions.linear;
 oldFx.options.duration = newFx.options.duration = this.options.fadeDuration / 2;
 oldFx.start({opacity: 0}).chain(newFx.start.pass([{opacity: 1}], newFx));
 }
});

/* All code copyright 2007 Jonathan Schemoul */

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * Follows: Preloader (class)
 * Simple class for preloading images with support for progress reporting
 * Copyright 2007 Tomocchino.
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

var Preloader = new Class({

 Implements: [Events, Options],

 options: {
 root : '',
 period : 100
 },

 initialize: function(options){
 this.setOptions(options);
 },

load: function(sources) {
 this.index = 0;
 this.images = [];
 this.sources = this.temps = sources;
 this.total = this. sources.length;

 this.fireEvent('onStart', [this.index, this.total]);
 this.timer = this.progress.periodical(this.options.period, this);

 this.sources.each(function(source, index){
 this.images[index] = new Asset.image(this.options.root + source, {
 'onload' : function(){ this.index++; if(this.images[index]) this.fireEvent('onLoad', [this.images[index], index, source]); }.bind(this),
 'onerror' : function(){ this.index++; this.fireEvent('onError', [this.images.splice(index, 1), index, source]); }.bind(this),
 'onabort' : function(){ this.index++; this.fireEvent('onError', [this.images.splice(index, 1), index, source]); }.bind(this)
 });
 }, this);
 },

 progress: function() {
 this.fireEvent('onProgress', [Math.min(this.index, this.total), this.total]);
 if(this.index >= this.total) this.complete();
 },

 complete: function(){
 $clear(this.timer);
 this.fireEvent('onComplete', [this.images]);
 },

 cancel: function(){
 $clear(this.timer);
 }

});

Preloader.implement(new Events, new Options);

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * Follows: formatString (function)
 * Original name: Yahoo.Tools.printf
 * Copyright Yahoo.
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

function formatString() {
 var num = arguments.length;
 var oStr = arguments[0];
 for (var i = 1; i < num; i++) {
 var pattern = "\\{" + (i-1) + "\\}";
 var re = new RegExp(pattern, "g");
 oStr = oStr.replace(re, arguments[i]);
 }
 return oStr;
}
