/*
    sw.scriptaculous.gallery
    Author: Sven Wappler (http://www.wappler.eu)
    Version: 0.8

    This gallery script is based on JonDesign's SmoothGallery, but this works with prototype and scriptaculous

    Copyright (C) 2007  Sven Wappler

	This program 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 2
	of the License, or (at your option) any later version.

	This program 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 this program; if not, write to the Free Software
	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA


*/

Function.prototype.create = function(options) {

	var fn = this;
	options = $H({
		'bind': fn,
		'event': false,
		'arguments': null,
		'delay': false,
		'periodical': false,
		'attempt': false
	}).merge(options);

	if (options.get('arguments') != null && typeof options.get('arguments') != 'undefined' && !(options.get('arguments') instanceof Array))
		options.set('arguments',[options.get('arguments')]);
		/* not sure */
	return function(event){
		var args = options.get('arguments') || arguments;
		if (options.get('event')){
			event = (options.get('event') === true) ? event || window.event : new options.event(event);
			args = [event].concat(args);
		}
		var returns = function(){
			return fn.apply(options.get('bind'), args);
		};
		if (options.get('delay')) return setTimeout(returns, options.get('delay'));
		if (options.get('periodical')) return setInterval(returns, options.get('periodical'));
		if (options.get('attempt')){
			try {
				var result = returns();
			} catch(err){
				result = err;
			} finally {
				return result;
			}
		} else return returns();
	}
}

Function.prototype.delay = function(ms, bind, args) {
	return this.create({'delay': ms, 'bind': bind, 'arguments': args})();
}

var Scroller = Class.create();
Scroller.prototype = {

	initialize : function(owner,wrapper) {
		this.owner = owner;
		this.wrapper = wrapper;
		this.direction = 0;
		this.running = false;
		this.mousex = 0;
		this.mousey = 0;
		this.position = 0;
		this.element = this.wrapper.childNodes[0];
		this.speed = 0.006;

		this.timeoutdelay = 40;

		Event.observe(document,'mousemove', this.mousemove.bindAsEventListener(this));

		this.originalLeft = parseFloat(this.element.getStyle('left') || '0');
   		this.originalTop  = parseFloat(this.element.getStyle('top')  || '0');

	},
	mousemove : function(e) {
		this.mousex = Event.pointerX(e);
		this.mousey = Event.pointerY(e);
	},
	start : function() {
		this.running = true;

		this.run();
	},
	stop : function() {
		this.running = false;
	},
	moveLeft : function() {
		this.direction = 1;
	},
	moveRight : function() {
		this.direction = -1;
	},
	run : function() {

		var p = this.mousex-Position.cumulativeOffset(this.wrapper)[0];
		var p1 = p/Element.getDimensions(this.wrapper).width;

		var p = this.mousey-Position.cumulativeOffset(this.wrapper)[1];
		var p2 = p/(Element.getDimensions(this.wrapper).height+20);

		if (p2 > 1.4 && this.owner.carouselContainer.style.top === "0px") {
			this.owner.toggleCarousel();
			this.stop();
		}

		if (p1 > 0.8 && this.position <= 1-this.speed && p2 >= 0 && p2 <= 1) {
			this.position += this.speed;
		} else if (p1 < 0.2 && this.position >= this.speed && p2 >= 0 && p2 <= 1) {
			this.position -= this.speed;
		} else {

		}
		this.position = Math.round(this.position*100)/100;

		Element.setStyle(this.element,{
	      left: Math.round((Element.getDimensions(this.element).width - Element.getDimensions(this.wrapper).width )  * -this.position + this.originalLeft) + 'px'
	    });

		if (!this.running) return;

		setTimeout(function(){ this.run() }.bind(this) , this.timeoutdelay);
	}

}


var Gallery = Class.create();

Gallery.prototype	= {

	initialize: function(element, options) {
		this.options = $H({
			showArrows: true,
			showCarousel: true,
			showInfopane: true,
			thumbHeight: 75,
			thumbWidth: 100,
			thumbSpacing: 10,
			embedLinks: true,
			fadeDuration: 0.5,
			timed: false,
			delay: 9000,
			preloader: true,
			manualData: [],
			populateData: true,
			elementSelector: "div.imageElement",
			titleSelector: "h3",
			subtitleSelector: "p",
			linkSelector: "a.open",
			imageSelector: "img.full",
			thumbnailSelector: "img.thumbnail",
			slideInfoZoneOpacity: 0.7,
			carouselMinimizedOpacity: 0.4,
			carouselMinimizedHeight: 20,
			carouselMaximizedOpacity: 0.6,
			destroyAfterPopulate: true,
			baseClass: 'swGallery',
			withArrowsClass: 'withArrows',
			useThumbGenerator: false,
			thumbGenerator: 'resizer.php',
			lang : 'en'
        }).merge(options);

		this.msg_opener = $H({
		  'fr'	: 'alle projekte',
		  'en'	: 'alle projekte',
		  'sp'	: 'alle projekte',
		  'it'	: 'alle projekte',
		  'de'	: 'alle projekte'
		 });

		this.currentIter = 0;
		this.lastIter = 0;
		this.maxIter = 0;
		this.galleryElement = element;
		this.galleryData = this.options.get('manualData');
		this.galleryInit = 1;
		this.galleryElements = Array();
		this.thumbnailElements = Array();
		
		Element.addClassName(this.galleryElement,this.options.get('baseClass'));

		if (this.options.get('populateData'))
			this.populateData();
		element.style.display="block";

		if (this.options.get('embedLinks')) {
			this.currentLink = Builder.node('a', { className : 'open' , href: '#' , target: '_blank', title: '' });
			element.appendChild(this.currentLink);

			if ((!this.options.get('showArrows')) && (!this.options.get('showCarousel')))
				this.galleryElement = element = this.currentLink;
			else
				Element.setStyle(this.currentLink,{'display' : 'none'});
		}

		this.constructElements();
		if ((data.length>1) && (this.options.get('showArrows'))) {
			var leftArrow = Builder.node('a',{className : 'left' });
			element.appendChild(leftArrow);
			Event.observe(leftArrow,'click', this.prevItem.bindAsEventListener(this), false);

			var rightArrow = Builder.node('a',{className : 'right' });
			element.appendChild(rightArrow);
			Event.observe(rightArrow,'click', this.nextItem.bindAsEventListener(this), false);

			Element.addClassName(this.galleryElement,this.options.get('withArrowsClass'));
		}
		this.loadingElement = Builder.node('div',{className : 'loadingElement' });
		element.appendChild(this.loadingElement);

		if (this.options.get('showInfopane')) this.initInfoSlideshow();
		if (this.options.get('showCarousel')) this.initCarousel();
		this.doSlideShow(1);
	},

	populateData: function() {
		currentArrayPlace = this.galleryData.length;
		options = this.options;
		data = this.galleryData;
		this.galleryElement.getElementsBySelector(options.get('elementSelector')).each(function(el) {
			elementDict = {
				image: (el.getElementsBySelector(options.get('imageSelector'))[0]).getAttribute('src'),
				number: currentArrayPlace
			};
			if ((options.get('showInfopane')) | (options.get('showCarousel')))
				Object.extend(elementDict, {
					title: el.getElementsBySelector(options.get('titleSelector'))[0].innerHTML,
					description: el.getElementsBySelector(options.get('subtitleSelector'))[0].innerHTML
				});
			if (options.get('embedLinks'))
				Object.extend(elementDict, {
					link: el.getElementsBySelector(options.get('linkSelector'))[0].href||false,
					linkTitle: el.getElementsBySelector(options.get('linkSelector'))[0].title||false
				});
			if ((!options.get('useThumbGenerator')) && (options.get('showCarousel')))
				Object.extend(elementDict, {
					thumbnail: el.getElementsBySelector(options.get('thumbnailSelector'))[0].src
				});
			else if (options.get('useThumbGenerator'))
				Object.extend(elementDict, {
					thumbnail: options.get('thumbGenerator')+'?imgfile=' + elementDict.image + '&max_width=' + options.get('thumbWidth') + '&max_height=' + options.get('thumbHeight')
				});

			data[currentArrayPlace] = elementDict;
			currentArrayPlace++;
			if (this.options.get('destroyAfterPopulate'))
				el.remove();
		});
		this.galleryData = data;
	},
	constructElements: function() {
		el = this.galleryElement;
		this.maxIter = this.galleryData.length;
		var currentImg;
		for(i=0;i<this.galleryData.length;i++) {
			var currentImg = Builder.node('div',{className : 'slideElement'});
			Element.setStyle(currentImg,{
					'position':'absolute',
					'left':'0px',
					'right':'0px',
					'margin':'0px',
					'padding':'0px',
					'backgroundImage':"url('" + this.galleryData[i].image + "')",
					'backgroundPosition':"center center",
					'opacity':'0'
				});
			el.appendChild(currentImg);
			this.galleryElements[parseInt(i)] = currentImg;
		}
	},
	goTo : function(num) {
		this.clearTimer();
		if (this.options.get('embedLinks'))
			this.clearLink();
		if (this.options.get('showInfopane')) {
			this.changeItem(num);
		} else
			this.changeItem.delay(500, this, num);
		if (this.options.get('embedLinks'))
			this.makeLink(num);
		this.prepareTimer();
	},
	startSlideShow : function() {
		this.loadingElement.style.display = "none";
		this.lastIter = this.maxIter - 1;
		this.currentIter = 0;
		this.galleryInit = 0;
		Element.setStyle(this.galleryElements[parseInt(this.currentIter)],{'opacity' : 100});
		if (this.options.get('showInfopane'))
			this.showInfoSlideShow.delay(1000, this);
		this.prepareTimer();
		if (this.options.get('embedLinks'))
			this.makeLink(this.currentIter);
	},
	nextItem: function() {
		this.nextIter = this.currentIter+1;
		if (this.nextIter >= this.maxIter)
			this.nextIter = 0;
		this.galleryInit = 0;
		this.goTo(this.nextIter);
	},
	prevItem: function() {
		this.nextIter = this.currentIter-1;
		if (this.nextIter <= -1)
			this.nextIter = this.maxIter - 1;
		this.galleryInit = 0;
		this.goTo(this.nextIter);
	},
	changeItem: function(num) {
		this.galleryInit = 0;
		if (this.currentIter != num) {
			for(i=0;i<this.maxIter;i++) {
				if ((i != this.currentIter)) Element.setStyle( this.galleryElements[i],{'opacity' : 0});
			}
			if (num > this.currentIter) {
				new Effect.Opacity(this.galleryElements[num], {duration: this.options.get('fadeDuration'), from:0, to: 1});
			}
			else {
				Element.setStyle( this.galleryElements[num] ,{'opacity' : 100});
				new Effect.Opacity(this.galleryElements[this.currentIter], {duration: this.options.get('fadeDuration'), from:1, to: 0});
			}
			this.currentIter = num;
		}
		this.doSlideShow.bind(this)();
	},
	clearTimer: function() {
		if (this.options.get('timed'))
			$clear(this.timer);
	},
	prepareTimer: function() {
		if (this.options.get('timed'))
			this.timer = this.nextItem.delay(this.options.get('delay'), this);
	},
	doSlideShow: function(position) {
		if (this.galleryInit == 1) {
			imgPreloader = new Image();
			imgPreloader.onload=function(){
				this.startSlideShow();
			}.bind(this);
			imgPreloader.src = this.galleryData[0].image;
		} else {
			if (this.options.get('showInfopane')) {
				this.showInfoSlideShow.delay((500 + this.options.get('fadeDuration')), this);
			}
		}
	},
	initCarousel: function () {
		this.carouselContainer = Builder.node('div', {id : 'carouselContainer', className : 'carouselContainer'});
		//Element.setStyle(this.carouselContainer,{'opacity' : this.options.carouselMinimizedOpacity});


		this.galleryElement.appendChild(this.carouselContainer);
		this.carouselContainer.normalHeight = this.carouselContainer.offsetHeight;
		Element.setStyle(this.carouselContainer,{'top': (this.options.get('carouselMinimizedHeight') - this.carouselContainer.normalHeight)});

		this.carouselBtn = Builder.node('a', {className : 'carouselBtn', title: this.msg_opener.get([this.options.get('lang')])});
		this.carouselBtn.innerHTML = this.msg_opener.get([this.options.get('lang')]);
		this.carouselContainer.appendChild(this.carouselBtn);

		Event.observe(this.carouselBtn,'click', function () {
				this.toggleCarousel();
			}.bindAsEventListener(this), false);

		this.carouselActive = false;

		this.carousel = Builder.node('div', { className : 'carousel' } );
		this.carouselContainer.appendChild(this.carousel);

		this.carouselInner = Builder.node('div', { className : 'carouselInner' });
		this.carouselWrapper = Builder.node('div', { className : 'carouselWrapper' }, [ this.carouselInner ] );
		this.carouselLabel = Builder.node('p', { className : 'label' });
		this.carousel.appendChild(this.carouselLabel );
		this.carousel.appendChild(this.carouselWrapper );

		Element.setStyle(this.carouselContainer.id,{'top' : '-'+Element.getDimensions(this.carousel).height+'px'});

		Element.setStyle(this.carouselInner,{'overflow' : "hidden", "position" : "absolute"});

		this.scroller = new Scroller(this,this.carouselWrapper);

		this.constructThumbnails();

		this.carouselInner.style.width = ((this.maxIter * (this.options.get('thumbWidth') + this.options.get('thumbSpacing'))) - this.options.get('thumbSpacing') + this.options.get('thumbWidth')) + "px";
	},
	toggleCarousel: function() {
		if (this.carouselActive)
			this.hideCarousel();
		else
			this.showCarousel();
	},
	showCarousel: function () {
		new Effect.Move(this.carouselContainer,{ x: 0, y: this.carousel.getDimensions().height, mode: 'relative'});
		this.carouselActive = true;
		this.scroller.start();
	},
	hideCarousel: function () {

		new Effect.Move(this.carouselContainer,{ x: 0, y: -this.carousel.getDimensions().height, mode: 'relative'});
		this.carouselActive = false;
		this.scroller.stop();
	},
	thumbnailMousOver : function(e,thumbnail) {
		this.carouselLabel.innerHTML = '<span class="number">' + (thumbnail.relatedImage.number + 1) + "/" + this.maxIter + ":</span> " + thumbnail.relatedImage.title;
		new Effect.Opacity(thumbnail.id, {duration:0.5, from: this.options.get('carouselMinimizedOpacity'), to:1.0});
	},
	thumbnailMousOut : function(e,thumbnail) {
		this.carouselLabel.innerHTML = '';
		new Effect.Opacity(thumbnail.id, {duration:0.5, from: 1.0, to: this.options.get('carouselMinimizedOpacity')});
	},
	thumbnailClick : function(e,thumbnail) {

		this.goTo(thumbnail.relatedImage.number);
	},
	constructThumbnails: function () {
		for(i=0;i<this.galleryData.length;i++) {
			var currentImg = Builder.node('div', { className : 'thumbnail' , id : "thumbnail_"+i });
			Element.setStyle(currentImg,{
					backgroundImage: "url('" + this.galleryData[i].thumbnail + "')",
					backgroundPosition: "center center",
					backgroundRepeat: 'no-repeat',
					marginLeft: this.options.get('thumbSpacing') + "px",
					width: this.options.get('thumbWidth') + "px",
					height: this.options.get('thumbHeight') + "px"
			});
			Element.setStyle(currentImg,{'opacity' : this.options.get('carouselMinimizedOpacity')});
			this.carouselInner.appendChild(currentImg);

			Event.observe(currentImg,'mouseover', this.thumbnailMousOver.bindAsEventListener(this,currentImg));
			Event.observe(currentImg,'mouseout', this.thumbnailMousOut.bindAsEventListener(this,currentImg));
			Event.observe(currentImg,'click', this.thumbnailClick.bindAsEventListener(this,currentImg));

			currentImg.relatedImage = this.galleryData[i];
			this.thumbnailElements[parseInt(i)] = currentImg;
		}
	},
	centerCarouselOn: function(num) {
		var carouselElement = this.thumbnailElements[num];
		var position = carouselElement.element.offsetLeft + (carouselElement.element.offsetWidth / 2);
		var carouselWidth = this.carouselWrapper.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)
			this.slideInfoZone.remove();
		this.slideInfoZone = Builder.node('div', { className : 'slideInfoZone' } );
		this.galleryElement.appendChild(this.slideInfoZone);
		var slideInfoZoneTitle = Builder.node('h2', {} );
		this.slideInfoZone.appendChild(slideInfoZoneTitle);
		var slideInfoZoneDescription = Builder.node('p', {} );
		this.slideInfoZone.appendChild(slideInfoZoneDescription);
		this.slideInfoZone.normalHeight = this.slideInfoZone.offsetHeight;
		Element.setStyle(this.slideInfoZone,{'opacity' : 0});
	},
	changeInfoSlideShow: function() {
		this.hideInfoSlideShow.delay(10, this);
		this.showInfoSlideShow.delay(500, this);
	},
	showInfoSlideShow: function() {
		element = this.slideInfoZone;
		element.getElementsBySelector('h2')[0].innerHTML = this.galleryData[this.currentIter].title;
		element.getElementsBySelector('p')[0].innerHTML = this.galleryData[this.currentIter].description;
		Effect.Appear(element,{'to' : this.options.get('slideInfoZoneOpacity')});
		return this.slideInfoZone;
	},
	hideInfoSlideShow: function() {
		this.slideInfoZone.custom({'opacity': 0, 'height': 0});
		return this.slideInfoZone;
	},
	makeLink: function(num) {
		this.currentLink.setAttribute('href', this.galleryData[num].link);
		this.currentLink.setAttribute('title', this.galleryData[num].linkTitle);

		if (!((this.options.get('embedLinks')) && (!this.options.get('showArrows')) && (!this.options.get('showCarousel'))))
			Element.setStyle(this.currentLink,{ 'display' : 'block'});
	},
	clearLink: function() {
		this.currentLink.setAttribute('href', '');
		this.currentLink.setAttribute('title', '');
		if (!((this.options.get('embedLinks')) && (!this.options.get('showArrows')) && (!this.options.get('showCarousel'))))
			Element.setStyle(this.currentLink,{ 'display' : 'none'});
	}
};
