// index = 1...2...3..4

// REMEMBER : YOU CAN USE .html INSTEAD OF JUST IMAGES

/*
EVENTS
--------------------------
. loadProgress
. loadComplete
. change
. next
. previous
. play
. stop
. addSlide
. addSlides
. remove
. error
*/
var Slideshow = new Class({
	options: {
		interval		: 8000, 	// Interval for play
		width			: null, 	// if missing stretch to parent.width
		height			: null, 	// if missing stretch to parent.height
		fitImg			: false,	// If set to true, autoFits image to given placeholder
		gravity			: 'center',	// Default = center
		autoPlay		: false,
	/*	preload			: false, 	// Start when preloaded OBSOLETE */
		preloadAsync	: true,		// Preload one by one
		
		// Displays loading stuff
		dumpLoader			: function(slide) {
			return 'Φόρτωση εικόνας  #'+slide.index;
		}
	},
	
	initialize : function(slides, placeholder, options) {
		var args  = $A(arguments);
		if(!window.DOMContentLoaded) {
			window.addEvent('DOMContentLoaded', function() {
				this.initialize.apply(this, args);
			}.bind(this));
			return this;
		}
	
		this.setOptions(options);
		this.placeholder 	= $(placeholder || document.body);
		this.total 			= 0;
		this.totalLoaded	= 0;
		this.identifier 	= 'core-slideshow-' + $uniqueID(this);
		this.slides			= slides;
		this.isPlaying		= false;

		// Element
		this.element = $C('div').
		setStyle('text-align', 'center').
		addClass('slideshow').
		makePositioned().
		injectIn(this.placeholder);

	
		// Also create an image container
		// The primary reason we have this is when fitImg != true to apply some hidden overflow properly
		this.imgContainer = $C('div').
		injectIn(this.element).
		makePositioned().
		setStyle('width', '100%'). // Needed for IE
		setStyle('height', '100%').// Needed for IE
		setStyle('overflow', 'hidden');
		

		// Render containers
		// TODO: Make it way betteρ
		var bg, parent = this.element;

		// In order to properly set the size
		// We need to hold on some millsecs
		(function() {
			// Init size
			this.setSize();

			while(parent && (bg = $(parent).getStyle('background-color')) === 'transparent') {
				parent = parent.getParent();	
			}		
			if (bg === 'transparent') {
				bg = '#fff';		
			}
			this.bg = bg;
			
			var container 	= $C('div', {
				 'styles' : {
					'position' 			: 'absolute',
					'top'				: 0,
					'left'				: 0,
					'z-index'			: 10,
					'background-color' 	: bg,
					'width'				: this.size.width,
					'height'			: this.size.height
				}
			});		
			this.containers = {
				'fg'			: container.clone().injectIn(this.imgContainer),
				'bg'			: container.clone().injectIn(this.imgContainer)
			};
			
		
			// Setup resize event
			window.addEvent('resize', this.setSize.bind(this));
			
			
			// Store it
			Slideshow.instances[this.identifier] = this;
				
			// This semes to cause problems in extensions like Slideshow.Extended
			if(this.slides && this.slides.length > 0) {
				this.addSlides(slides)
				
				// In case we have already assigned a gotoSlide command
				// Dont do that again pls :-)
				if(!this.__skipGoto1stSlide) {
					this.gotoSlide(1, this.isPlaying);
				}				
			} 	
		}).delay(250, this);
		
		/*
		// This seems to cause problems in extensions like Slideshow.Extended
		if(this.slides && this.slides.length > 0) {
			this.addSlides(slides).gotoSlide(1);
			// Start playing if not autoPlay and not preload is set
			if(this.options.autoPlay && !this.options.preload && !this.isPlaying) {
				this.timer = this.play.delay(this.options.interval,this, 2);	
				return this;
			}
		} else {
			return this;	
		}
		*/
		
		return this;
	},
	
	getSize	: function() {
		var size = new Abstract();
		
		if(this.options.height !== null && this.options.width !==null) {
			return {'width' : this.options.width, 'height' : this.options.height };
		}

		var cssSize = {
			width 	: this.placeholder.getStyle('width'),
			height	: this.placeholder.getStyle('height')
		};

		return size.extend({
			width 	: this.options.width 	|| cssSize.width.contains('px') ? cssSize.width.toInt() : this.placeholder.offsetWidth,
			height	: this.options.height 	|| cssSize.height.contains('px') ? cssSize.height.toInt() : this.placeholder.offsetHeight
		});
	},
	
	setSize		: function(event) {
		// Store it here for later
		this.size = this.getSize();
		(function() {
			this.element.setStyles(this.size);
			this.imgContainer.setStyles(this.size);
			if(this.current && this.options.fitImg) {
				this.fitImg();
			}
		}).delay(10, this);
	},
	
	fitImg	: function(slide) {
		slide = slide || this.current;		
		// HTML slide
		if(slide.html) {
			return this;	
		}
		
		var size = this.size, ratio, s = {};					

		
		// no data yet, bail out
		if(!size.width || !slide.width) {
			return;	
		}
		
		// This peace of code actually works
		// Resizes an image to givven dimensiions
		s.height 	= Math.min(slide.height,size.height);
		s.width	 	= Math.min(slide.width, size.width);
		ratio 		= Math.max(slide.width/s.width, slide.height/s.height);
		s.width 	= slide.width/ ratio;	
		s.height 	= slide.height/ ratio;	

		var margins = {
			'top' 	: s.height/2,
			'left' 	: s.width/2
		}

	
		$(slide.img).setStyles({
			'width' 			: s.width,
			'height'			: s.height,
			'margin-top' 		: -margins.top,
			'margin-left' 		: -margins.left
		});
		
		return this;
	},
	
	nextSlide	: function(play){
		var index = this.getSlideIndex() + 1;
		if (index > this.slides.length)  {
			index = 1;
		}
		
		if(this.isPlaying) {
			$clear(this.timer); // Needed
			this.timer = (function()  {
				this.nextSlide(true);
			}).
			delay(this.options.interval, this);	
		}		
		
		return this.invokeEvent('next', index, this.slides[index-1]).gotoSlide(index, play);
	},
	
	previousSlide : function() {
		var index = this.getSlideIndex() - 1;
		if (index < 1) {
			index = this.slides.length;
		}
		return this.invokeEvent('previous', index).gotoSlide(index);
	},
	
	gotoSlide	: function(index, play){
		this.__skipGoto1stSlide = true;
		
		if (play !== true)  { 
			this.stop();
		}
		if (this.current && this.current.index == index) {
			return this;
		}
		
		//  This is what makes the thing work
		this.show(this.getSlideByIndex(index));
		
		return this.invokeEvent('change', index, this.slides[index-1]);		
	},
		
	show: function(slide) {
		
		// Not yet defined containers - delay a bit
		if(!this.containers) {
			this.show.delay(260, this, slide);
			return;
		}
						
		this.previous 	= this.current;
		this.current 	= slide;
		if(this.options.fitImg) {
			this.fitImg();	
		}
		this.containers.fg.style.zIndex 		= 1000;
		this.containers.bg.style.zIndex 		= 1001;
		
		// We had issues with empty() here. This works better
		if (this.containers['bg'].getFirst() ) {
			this.containers['bg'].getFirst().remove();
		}

		this.containers['bg'].adopt(this.slides[slide.index-1].element);	
		return slide;		
	},
	
	play		: function(slide, skipEvent){
		//this.nextSlide(true);		
		// CHANGED: Periodical is buggy!!
		// if for some reson the interval is missed  then it executes the code again
		// CHECKOUT: http://ejohn.org/blog/how-javascript-timers-work/
		if(this.timer) {
			$clear(this.timer);		
		}
		
		this.timer 			= (function()  { this.nextSlide(true); }).delay(this.options.interval, this);
		this.isPlaying	 	= true;			
		
		if(!skipEvent) {
			this.invokeEvent('play');			
		}
		
		return this;
	},
	
	stop		: function() {
		this.timer 		= $clear(this.timer);
		this.isPlaying 	= false;
		return this.invokeEvent('stop');
	},
	
	togglePlay : function() {
		this.invokeEvent('togglePlay', !this.isPlaying);
		return this.timer ? this.stop() : this.play();	
	},
	
	addSlide	: function(slide, index) {	
		// Sanity check
		// 10.11.09
		if(!this.size) {
			this.size =	this.getSize();
		}
		
		index				= index || this.total;
		this.slides 		= this.slides || [];
		// HTML slide
		if(slide.toLowerCase) {
			slide = {
				'html' : slide	
			}
		}
	
		slide.index		 	= $is(index) ? (index + 1) : this.slides.length  +1;		
		

		if(!slide.caption) {
			slide.caption = '';	
		} else {
			slide.caption = slide.caption.stripSlashes(true);	
		}
	
		slide.element		= $C('div', {
			'styles' : {
				'position' 			: 'absolute',
				'top'				: 0,
				'left'				: 0,	
				'width'				: this.size.width,
				'height'			: this.size.height,
				'z-index'			: 10000
			},
			'title'				: slide.caption
		});
	
			
		// HTML		
		if(!slide.html) {
			// We use innerHTML here cause
			// 1. its faster
			// 2. works okay with IE
			// 3. we dont need to use cloning 
			// 4. less memory hog
			var _html = '';
			if(slide.url) { 
				_html += '<a ' + (this.options.clicky ? ' title="'+(slide.caption || slide.descr || '')+'"class="clicky_log" ' : '') + 'href="'+slide.url+'">';
			}
			
			_html += '<img class="slideshow-img" style="display: none;" src="'+slide.img+'" title="'+ ( slide.caption || slide.descr || '').unescapeHTML()+'" alt="'+ ( slide.caption || slide.descr || '').unescapeHTML()+'" galleryimg="no" />';
		
			if(slide.url) { 
				_html += '</a>';
			}		
			
			_html += '<span class="slideshow-loader" style="display: block;margin-top: 30%;">' + this.options.dumpLoader(slide)  + '</span>';		
			
			slide.element.innerHTML = _html;
		} else {
			slide.element.innerHTML = slide.html;	
		}

		
		// Increase total
		this.total++;	
		
		// Preload
		this.preload(slide);

		//this.slides.push(slide);
		this.slides[this.total -1] = slide;
		this.invokeEvent('add', slide);			
		
		// get the slide image
		if(!slide.html) {
			slide.img = slide.element.getElement('img.slideshow-img');
		}

		return slide;
	},

	
	preload		: function(slide) {
		// No given slide
		if(slide && slide.html) {
			slide.loaded = true;
			// Start playing if autoPlay
			if(this.options.autoPlay && !this.isPlaying) {
				this.invokeEvent('play'); // Fire it once
				if(this.timer) {
					$clear(this.timer);	
				}
				this.play();
			}
			
			return this;
		}
		
		this.preloadQueue 	= this.preloadQueue || [];
		var bailOut			= this.preloadQueue.length !== 0;
		var src				= slide ? slide.img : null;

		// Force stands for force :)
		// preloadAsync way
		if(this.options.preloadAsync) {
			if(slide !== undefined ) {
				if(!slide.loaded) {
					this.preloadQueue.push(slide);	
				} 		
				if(bailOut) {
					return this;	
				}
			} else {
				slide = this.preloadQueue[0];	
				if(!slide) {
					return this;	
				}
				src 	= slide.img.src;
			}
		}
		


		new Preloader(src, {
			onStart		: function() {	
				this.invokeEvent('loadStart');
			},
			
			onComplete : function(el) {
				$(slide.element.getElement('span.slideshow-loader')).hide().remove();
				
				slide.width 	= el.width;
				slide.height 	= el.height;

				var margins		= {
					'top' 	: slide.height  / 2,
					'left' 	: slide.width / 2
				}

				// ADDED: 07.07.2009
				// Handle gravity
				// Applicable only when options.fitImage = true
				// TODO: Implement other directions
				if(this.options.gravity !== 'center') {
					if(this.options.gravity.contains('n') && el.height >= this.size.height) {
						margins.top = this.size.height/2;	
					} 					
				}
				
				//console.log(margins.top, slide.height, this.size.height);
			
				slide.img.setStyles({
					'position'		: 'absolute',
					'top' 			: '50%',
					'left' 			: '50%',
					'margin-top' 	: -margins.top,
					'margin-left' 	: -margins.left
				});
			
				if(this.options.fitImg) {
					this.fitImg(slide);
				}
				slide.img.show();

				
				this.totalLoaded++;
				this.invokeEvent('loadProgress', slide, this.totalLoaded);
				
				// Completed
				if(this.totalLoaded == this.total) {
					// Start playing if autoPlay
					if(this.options.autoPlay && !this.isPlaying) {
						this.invokeEvent('play'); // Fire it once
						if(this.timer) {
							$clear(this.timer);	
						}
						this.play();
					}					
					this.invokeEvent('loadComplete');	
				}
				
				// Set loaded to true
				slide.loaded = true;
				this.preloadQueue.remove(slide);
			
				
				// More and more
				if(this.options.preloadAsync && this.preloadQueue.length !== 0) {
					this.preload();	
				}
				
				if(this.totalLoaded === 1) {
					// Start playing if not autoPlay and not preload is set
					if(this.options.autoPlay && !this.isPlaying) {
						this.timer = this.play.delay(this.options.interval,this);	
					}
				}
			}.bind(this)
		});		
	},
	
	addSlides : function(slides){
		// TODO: slides as RSS|XML feed 
		if(!slides) { 
			return this;
		}
		slides.each(this.addSlide,this);
		return this.invokeEvent('addSlides');		
	},
	
	removeSlide	: function(index) {
		if(this.isPlaying) {
			this.stop();	
		}
		if( this.slides.length == 1 ) return this.invokeEvent('error', "last slide");
		
		var slide = this.getSlideByIndex(index);
		if(slide.element.parentNode) {
			slide.element.remove();
		}
		slide.element = null;
		this.slides.remove(slide);
		
		// TODO: make it better
		this.slides.each( function(slide, index) { slide.index = index + 1; });
		
		if(this.slides[this.current.index -1] ) {
			this.current = this.slides[this.current.index -1];
		}
		
		return this.invokeEvent('remove', index);
	},
	
	removeAllSlides : function() {
		for( var i = this.total; i > 0; i-- ) {
			this.removeSlide(i);	
		}
		this.total 		= this.totalLoaded = 0;
		this.current 	= this.previous = null;
		this.slides 	= [];
		return this;
	},
	
	getSlideByIndex	: function(index) {
		return this.slides[index-1];
	},
	
	getSlideIndex	: function(slide) {
		slide = this.slides[slide] || this.current;
		return slide.index;
	}

});
Slideshow.implement(new Options, new Events);
Slideshow.instances = {};




// Slideshow.Fade
// Extends to slideshow providing fade effects
Slideshow.Fade = Slideshow.extend({
	options 	: {
		useWheel			: false,
		duration			: 300 		// Duration for fade
	},
	
	show 	: function(slide, invert) {
		// Not yet defined containers - delay a bit
		if(!this.containers) {
			this.show.delay(260, this, slide, invert);
			return;
		}
		
		this.previous 	= this.current;
		this.current 	= slide;
		
		this.containers[this.isSwapped ? 'bg' : 'fg'].style.zIndex 		= 10;
		this.containers[this.isSwapped ? 'fg' : 'bg'].style.zIndex 		= 100;
		
		// CHANGED: was && invert, switched to || invert
		if(this.isSwapped === undefined || invert ) {
			this.containers[this.isSwapped ? 'bg' : 'fg'].style.zIndex = 1000;
		}

		// TODO: innerHTML (?)
		// FIXME: window.ie needs to have a clone instead of the regular object here. find out why
		//var element = window.ie  ? slide.element.clone() : slide.element;
		var element = slide.element;
		
		if (this.containers[this.isSwapped ? 'bg' : 'fg'].getFirst() ) {
			this.containers[this.isSwapped ? 'bg' : 'fg'].getFirst().remove();
		}
		this.containers[this.isSwapped  ? 'bg' : 'fg'].adopt(this.slides[slide.index-1].element);	
			
		if(this.current && this.options.fitImg) {
			this.fitImg();	
		}			
		
		// Swap containers
		this.isSwapped = !this.isSwapped;	
		return slide;
	},
	
	gotoSlide	: function(index, play) {
		this.__skipGoto1stSlide = true;
		
		if (play !== true)  { 
			this.stop();
		}
		
		if (this.current && this.current.index == index) {
			return this;
		}
		
		var to 			= this.getSlideByIndex(index);		
		var complete 	= function() {
			var container = this.containers[this.isSwapped ? 'bg' : 'fg'].setStyle('z-index', 1);
			container.fx.start(1);
		}
		
		if(this.current){		
			var container = this.containers[this.isSwapped ? 'fg' : 'bg'];
			var otherContainer = this.containers[this.isSwapped ? 'bg' : 'fg'];
			
			container.fx 		= (container.fx || container.effect('opacity', {'duration': this.options.duration})).stop();
			otherContainer.fx 	= (otherContainer.fx || otherContainer.effect('opacity', {'duration': this.options.duration})).set(0).stop();
			
			
			if(otherContainer.fx) 	{
				//otherContainer.fx.stop();
				complete.apply(this);					
			}
			this.show(to, true);
			container.fx.start(0).chain( complete.bind(this));
			otherContainer.fx.start(1);	
		} else  {
			this.show(to, true);				
		}

		return this.invokeEvent('change', index, this.slides[index-1]);	
	},
	
	
	removeAllSlides : function() {
		this.parent();
		if(this.containers && this.containers.fg) {
			this.containers['fg'].empty();
			this.containers['bg'].empty();	
		}
		// This is must :)
		this.isSwapped = undefined;
		
		
		return this;
	}
});







// Slideshoow.Extended was renamed to Slideshow.Technologin and was
// Transfered on technologin.pathfinder.gr/js/src/js.js




// Slideshow.Content
// Extendign .Fade, used for content mainly
Slideshow.Content = Slideshow.Fade.extend({										  
	initialize : function() {		
		this.parent.parent.apply(this, arguments);		
		
		(function() {
			this.controls = $C('div',{
				'styles' : {
					'padding'	: '20px 0',
					'background': 'black',
					'margin'	: '60px 0 0 0',
					'opacity'	: 0.8,
					'text-align' : 'center',
					'color'		: 'white',
					'float'		: 'left',
					'position'	: 'absolute',
					'width'		: this.size.width,
					'z-index'	: '9999999'
				}
			}).setClass('slideshow-controls').makeUnselectable().
			injectIn(this.placeholder);
	
			if(this.options.dumpControls) {
				this.controls.setHTML(this.options.dumpControls());
			}
		
		}).delay(700, this);
		
		return this;			
	},
	
	addSlide : function(slide, index) {
		this.parent.parent.apply(this, arguments);		
		$C('p').setHTML(slide.caption).injectIn(slide.element).
		setStyles({
			'text-align': 'left',
			'padding' : '10px 0',
			'margin'	: 0,
			'position' : 'absolute',
			'top'	: '100%',
			'background' : '#fff',
			'width' : '100%',
			'height'	: 30,
			'margin-top' : '2px'
		});
	}
});
