var ByZoomer = new Class({
	Implements: Options,
	
	options: {
		selector: 'a.byzoomer',
		transparentImage: 'transparent.gif',
		loadingIcon: 'wait.gif',
		errorIcon: 'error.png',
		placeholderId: null,
		duration: 500,
		transition: 'linear',
		onZoomInStart: $empty,
		onZoomInComplete: $empty,
		onZoomOutStart: $empty,
		onZoomOutComplete: $empty,
		useOpacity: true
	},
	
	startOpacity: 0,
	index: 0,
	thumbs: null,
	images: null,
	imagesUrl: null,
	loadingMask: null,
	errorMasks: null,
	zoomedImage: null,
	placeholder: null,
	
	initialize: function(options)
	{
		this.setOptions(options);
		this.thumbs = new Array();
		this.images = new Array();
		this.imagesUrl = new Array();
		this.loadingMasks = new Array();
		this.errorMasks = new Array();
		if(!this.detection())
			return;

		this.startOpacity = !this.options.useOpacity + 0;
		
		this.loadingMask = [this.createMask('loading', 0)];
		/*
		// PreLoading images file
		this.loadingMask = new Asset.image(this.options.transparentImage, {
			styles: {
				position: 'absolute', // resolve a bug under Opera
				background: '#ffffff url("' + this.options.loadingIcon + '") no-repeat scroll center',
				opacity: 0.8
			}
		});
		*/
	},
	
	detection: function()
	{
		if(this.options.placeholderId)
			this.placeholder = $(this.options.placeholderId);
		
		var elements = $$(this.options.selector);
		
		if(!elements.length)
			return;

		elements.each(function(element){
			
			var index = this.index++;
			
			var thumb = element.getElement('img');
			if(!thumb)
				thumb = element;
				
			element.store('index', index);
			thumb.store('index', index);
			this.thumbs[index] = thumb;
			this.imagesUrl[index] = element.get('href');
			
			element.addEvent('click', function(event, index){
				event.preventDefault();
				
				this.start(index);

			}.bindWithEvent(this, index));

		}, this);
		
		return true;
	},
	
	show: function(identifier)
	{
		if($type(identifier) == 'number')
			index = identifier;
		else
			index = $(identifier).retrieve('index');
		
		this.start(index);
		
		return false;
	},
	
	start: function(index)
	{
		var image = this.images[index];
		
		if(this.zoomedImage != null && this.zoomedImage == image)
			return this.unZoom();
		
		this.showLoadingMask(index);

		if(!image)
		{
			image = new Asset.image(this.imagesUrl[index], {
				morph: {
					transition: this.options.transition,
					duration: this.options.duration
				},
				styles: {
					position: 'absolute'
				},
				onload: function(image){
						var index = image.retrieve('index');
						this.images[index] = image;
						this.zoom(index);
					}.bind(this),
				onerror: function(){
					this.showErrorMask(index);
				}.bind(this)
			}).store('index', index);
			image.addEvent('click', function(){
				this.unZoom();
			}.bind(this));
		}
		else
			this.zoom(index);
	},
	
	zoom: function(index)
	{
		this.unZoom();
		
		var thumb = this.thumbs[index];
		var image = this.images[index];
		
		var start_width = thumb.getWidth();
		var start_height = thumb.getHeight();
		
		var start_position = thumb.getOffsets();
		
		var end_width = image.width;
		var end_height = image.height;
			
		if(this.placeholder)
		{
			var ph_width = this.placeholder.getWidth();
			var ph_height = this.placeholder.getHeight();

			if(end_width > ph_width)
			{
				end_height = (end_height / end_width) * ph_width;
				end_width = ph_width;
			}
			
			if(end_height > ph_height)
			{
				end_width = (end_width / end_height) * ph_height;
				end_height = ph_height;
			}
			
			var margin_x = ((ph_width - end_width) / 2);
			var margin_y = ((ph_height - end_height) / 2);
			var end_position_x = this.placeholder.getOffsets().x;
			var end_position_y = this.placeholder.getOffsets().y;
			
		}
		else
		{
			var margin_x = 0;
			var margin_y = 0;
			var end_position_x = ((window.getWidth() - end_width) / 2) + window.getScroll().x;
			var end_position_y = ((window.getHeight() - end_height) / 2) + window.getScroll().y;
		}
		
		this.zoomedImage = image;
		
		image.setStyles({
			left: start_position.x,
			top: start_position.y,
			width: start_width,
			height: start_height,
			opacity: this.startOpacity
		});
		
		$(document.body).adopt(image);
		
		this.options.onZoomInStart(image, thumb);
		
		var morph = image.get('morph').start({
			left: end_position_x,
			top: end_position_y,
			width: end_width,
			height: end_height,
			opacity: 1,
			marginLeft: margin_x,
			marginTop: margin_y
		}).chain(function(image, thumb){
			if(this.placeholder)
			{
				image.setStyle('position', 'static');
				this.placeholder.adopt(image);
			}
			this.options.onZoomInComplete(image, thumb);
		}.bind(this, [image, thumb]));

		this.hideLoadingMask(index);
	},
	
	unZoom: function()
	{
		var image = this.zoomedImage;
		this.zoomedImage = null;
		
		if(!image)
			return;

		var index = image.retrieve('index');
		var thumb = this.thumbs[index];

		var end_width = thumb.getWidth();
		var end_height = thumb.getHeight();
		var end_position = thumb.getOffsets();
		
		if(this.placeholder)
		{
			image.setStyles({
				position: 'absolute',
				left: this.placeholder.getOffsets().x,
				top: this.placeholder.getOffsets().y
			});
			$(document.body).adopt(image);
		}
		
		this.options.onZoomOutStart(image, thumb);
		
		image.get('morph').start({
			left: end_position.x,
			top: end_position.y,
			width: end_width,
			height: end_height,
			opacity: this.startOpacity,
			marginLeft: 0,
			marginTop: 0
		}).chain(function(image, thumb){
			this.options.onZoomOutComplete(thumb);
			image.dispose();
			
		}.bind(this, [image, thumb]));
	},
	
	createMask: function(type, index)
	{
		var thumb = this.thumbs[index];
		
		var margin_left = thumb.getWidth();
		var width = thumb.getWidth();
		var height = thumb.getHeight();
		
		if(type == 'loading')
		{
			var icon = this.options.loadingIcon;
			var color = '#ffffff';
		}
		else
		{
			var icon = this.options.errorIcon;
			var color = '#ffd0d0';
		}
		
		mask = new Element('img', {
			src: this.options.transparentImage,
			styles: {
				position: 'absolute', // resolve a bug under Opera
				marginLeft: -margin_left,
				width: width,
				height: height,
				background: color + ' url("' + icon + '") no-repeat scroll center',
				opacity: 0.8
			}
		});
		
		return mask;
	},
	
	showLoadingMask: function(index)
	{
		var mask = this.loadingMask[0];
		var thumb = this.thumbs[index];
		
		var margin_left = thumb.getWidth();
		var width = thumb.getWidth();
		var height = thumb.getHeight();
		
		mask.setStyles({
			marginLeft: -margin_left,
			width: width,
			height: height,
		});

		mask.inject(thumb, 'after');
	},
	
	hideLoadingMask: function(index)
	{
		this.loadingMask[0].dispose();
	},
	
	showErrorMask: function(index)
	{
		var mask = this.errorMasks[index];
		var thumb = this.thumbs[index];
		
		if(!mask)
		{
			mask = this.createMask('error', index);
			this.errorMasks[index] = mask;
		}

		this.hideLoadingMask(index);
		mask.inject(thumb, 'after');
	}
});
