if(!Nibynic) {
	var Nibynic = {};
}

Nibynic.Slides = Class.create(Enumerable, {
	defaultOptions: {
		duration: 1,
		interval: 10,
		allowDeselect: false,
		queueEffects: false,
		autoStart: true,
		animateFirst: true,
		hashParamName: false
	},
	
	initialize: function(photosContainerId, descriptionsContainerId, menuContainerId, options) 
	{
		this.photosContainer = $(photosContainerId);
		this.descriptionsContainer = $(descriptionsContainerId);
		this.menuContainer = $(menuContainerId);

		this.options = this.options = Object.extend(Object.extend({ },this.defaultOptions), options || { });;

		this.timeoutId = null;
		this.selectedSlideIndex = null;
		
		if(this.options.queueEffects) {
			this.queueScope = this.photosContainer.id;
			
			while(Effect.Queues.instances.get(this.queueScope) != undefined) {
				this.queueScope = this.queueScope + '_';
			}
		}
		
		if(!this.options.hashParamName) {
			this.options.hashParamName = this.photosContainer.id;
		}
		
		photos = $$('#'+this.photosContainer.id+' .slidePhoto');
		descriptions = $$('#'+this.descriptionsContainer.id+' .slideDescription');
		buttons = $$('#'+this.menuContainer.id+' .slideButton');
		// alert(photos.length + ' ' + descriptions.length + ' ' + buttons.length);
		this.slides = new Array();
		
		for (var i = 0; i < photos.length; i++) {
			this.slides[i] = new Nibynic.Slide(this, i,
			  photos[i], descriptions[i], buttons[i],
			  Object.extend({duration: this.options.duration}, this.options.effects || {}));
		}

		this.initializeZIndex();
		
		if(this.options.autoStart) {
			var immediately = false;
			if(!this.options.animateFirst) {
				immediately = true;
			}
			this.selectSlide(0, immediately);
		}
	},
	
	selectSlide: function(newSlideIndex, immediately)
	{
		if(newSlideIndex == this.selectedSlideIndex && !this.options.allowDeselect) {
			return;
		}
		
		if(this.selectedSlideIndex != null) {
			this.slides[this.selectedSlideIndex].hide(immediately);
		}
		
		if(newSlideIndex != this.selectedSlideIndex) {
			this.slides[newSlideIndex].show(immediately);
			this.selectedSlideIndex = newSlideIndex;

			this.rearrangeZIndex();
		} else {
			this.selectedSlideIndex = null;
		}
		
		if(this.options.interval > 0) {
			if(this.timeoutId != null) {
				clearTimeout(this.timeoutId);
			}
			this.timeoutId = setTimeout(this.nextSlide.bind(this), this.options.interval*1000);
		}
	},
	
	nextSlide: function(immediately)
	{
		var newIndex = this.selectedSlideIndex + 1;
		if(newIndex >= this.slides.length) {
			newIndex = 0;
		}
		this.selectSlide(newIndex, immediately);
	},
	
	initializeZIndex: function() {
		for(var i = 0; i < this.slides.length; i++) {
			this.slides[i].setZIndex(i);
		}
	},
	
	rearrangeZIndex: function()
	{
		var zGap = this.slides[this.selectedSlideIndex].getZIndex();
		this.slides[this.selectedSlideIndex].setZIndex(this.slides.length);
		
		for(var i = 0; i < this.slides.length; i++) {
			var slideZ = this.slides[i].getZIndex();
			if(slideZ > zGap) {
				this.slides[i].setZIndex(slideZ-1);
			}
		}
	},
	
	clearQueue: function()
	{
		var queue = Effect.Queues.get(this.queueScope);
		queue.each(function(effect) { effect.cancel(); });
	}
});

Nibynic.Slide = Class.create({
	defaultOptions: {
		photoInEffect: {
			from: null,
			to: 'opacity: 1'
		},
		photoOutEffect: {
			from: null,
			to: 'opacity: 0'
		},
		descriptionInEffect: {
			from: 'opacity: 0',
			to: 'opacity: 1'
		},
		descriptionOutEffect: {
			from: null,
			to: 'opacity: 0'
		}
	},
	
	initialize: function(parent, index, photoElement, descriptionElement, buttonElement, options)
	{
		this.parent = parent;
		this.index = index;
		this.options = this.options = Object.extend(Object.extend({ },this.defaultOptions), options || { });
		
		this.photo = photoElement;
		this.description = descriptionElement;
		this.button = buttonElement;
		
		this.photoTmpEffect = null;
		this.descrTmpEffect = null;
		
		if(!this.isEffect(this.options.photoOutEffect)) {
			this.photoTmpEffect = this.applyMorph(this.photo, this.options.photoOutEffect.to, 0);
		// } else {
		// 	this.photoTmpEffect = this.applyEffect(this.photo, this.options.photoOutEffect, 0);
		}
		
		if(!this.isEffect(this.options.descriptionOutEffect)) {
			this.descrTmpEffect = this.applyMorph(this.description, this.options.descriptionOutEffect.to, 0);
		} else {
			this.descrTmpEffect = this.applyEffect(this.description, this.options.descriptionOutEffect, 0);
		}

		var thisButton;
		var nextButton;
		if((thisButton = this.button.down('.this')) && (nextButton = this.button.down('.next'))) {
			thisButton.observe('click', function(event) {
				this.parent.selectSlide(this.index);
				event.stop();
			}.bind(this));
			
			nextButton.observe('click', function(event) {
				var index = this.index+1;
				if(index >= this.parent.slides.length) {
					index = 0;
				}
				this.parent.selectSlide(index);
				event.stop();
			}.bind(this));
		} else {
			this.button.observe('click', function(event) {
				this.parent.selectSlide(this.index);
				event.stop();
			}.bind(this));
		}
	},
	
	show: function(immediately)
	{
		if(immediately) {
			var duration = 0;
		} else {
			var duration = undefined;
		}
		
		this.cancelAllEffects();
		
		if(!this.isEffect(this.options.photoInEffect)) {
			this.applyMorph(this.photo, this.options.photoInEffect.from, 0);
		// } else {
		// 	this.applyEffect(this.photo, this.options.photoInEffect, 0);
		}
		
		if(!this.isEffect(this.options.photoInEffect)) {
			this.photoTmpEffect = this.applyMorph(this.photo, this.options.photoInEffect.to, duration);
		} else {
			this.photoTmpEffect = this.applyEffect(this.photo, this.options.photoInEffect, duration);
		}
		
		if(!this.isEffect(this.options.descriptionInEffect)) {
			this.applyMorph(this.description, this.options.descriptionInEffect.from, 0);
		// } else {
		// 	this.applyEffect(this.description, this.options.descriptionInEffect, 0);
		}
		
		if(!this.isEffect(this.options.descriptionInEffect)) {
			this.descrTmpEffect = this.applyMorph(this.description, this.options.descriptionInEffect.to, duration);
		} else {
			this.descrTmpEffect = this.applyEffect(this.description, this.options.descriptionInEffect, duration);
		}
		
		this.button.addClassName('selected');
		if(this.parent.options.rememberLocation) {
			Nibynic.LocationHash.setParam(this.parent.options.hashParamName, this.index);
		}
	},
	
	hide: function(immediately)
	{
		if(immediately) {
			var duration = 0;
		} else {
			var duration = undefined;
		}
		
		this.cancelAllEffects();
		if(this.parent.options.queueEffects) {
			this.parent.clearQueue();
		}
		
		if(!this.isEffect(this.options.photoOutEffect)) {
			this.applyMorph(this.photo, this.options.photoOutEffect.from, 0);
		// } else {
		// 	this.applyEffect(this.photo, this.options.photoOutEffect, 0);
		}
		
		if(!this.isEffect(this.options.photoOutEffect)) {
			this.photoTmpEffect = this.applyMorph(this.photo, this.options.photoOutEffect.to, duration);
		} else {
			this.photoTmpEffect = this.applyEffect(this.photo, this.options.photoOutEffect, duration);
		}
		
		if(!this.isEffect(this.options.descriptionOutEffect)) {
			this.applyMorph(this.description, this.options.descriptionOutEffect.from, 0);
		// } else {
		// 	this.applyEffect(this.description, this.options.descriptionOutEffect, 0);
		}
		
		if(!this.isEffect(this.options.descriptionOutEffect)) {
			this.descrTmpEffect = this.applyMorph(this.description, this.options.descriptionOutEffect.to, duration);
		} else {
			this.descrTmpEffect = this.applyEffect(this.description, this.options.descriptionOutEffect, duration);
		}
		
		this.button.removeClassName('selected');
		if(this.parent.options.rememberLocation) {
			Nibynic.LocationHash.removeParam(this.parent.options.hashParamName);
		}
	},
	
	getZIndex: function()
	{
		return Number(this.photo.getStyle('zIndex'));
	},
	
	setZIndex: function(z)
	{
		this.photo.setStyle({'zIndex': z});
		this.description.setStyle({'zIndex': z});
	},
	
	cancelAllEffects: function()
	{
		if(this.photoTmpEffect != null) {
			this.photoTmpEffect.cancel();
		}
		if(this.descrTmpEffect != null) {
			this.descrTmpEffect.cancel();
		}
	},
	
	isEffect: function(effect)
	{
		switch(effect) {
			case Effect.BlindDown:
			case Effect.BlindUp:
			case Effect.SlideDown:
			case Effect.SlideUp:
				return true;
			default:
				return false;
		}
	},
	
	applyEffect: function(element, effect, duration)
	{
		if(duration == undefined) {
			duration = this.options.duration;
		}

		var options = { duration: duration }
		if(this.parent.options.queueEffects) {
			Object.extend(options, { queue: { position: 'end', scope: this.parent.queueScope } });
		}
		// alert(Object.toJSON(this.parent));

		return new effect(element, options);
	},
	
	applyMorph: function(element, style, duration)
	{
		if(duration == undefined) {
			duration = this.options.duration;
		}
		if (style != null) {
			if(duration == 0) {
				element.setStyle(style)
			} else {
				var options = { style: style, duration: duration }
				if(this.parent.options.queueEffects) {
					Object.extend(options, { queue: { position: 'end', scope: this.parent.queueScope } });
				}
			
				return new Effect.Morph(element, options);
			}
		} else {
			return null;
		}
	}
});

