/**
 * ReMooz - Zoomer
 * Inspired by so many boxes and zooms
 *
 * @version		1.0
 * @modified	Mar 11, 2008
 *
 * @license		MIT-style license
 * @author		Harald Kirschner <mail [at] digitarald.de>, Alvis Tang <alvis.sty [at] gmail.com>
 * @copyright	Author
 */
 
 //this version was modified in a dirty hack(s) by jossele :)
 
var ReMooz = new Class({
	Implements: [Events, Options, Chain],
	options: {
		caption: true, /* Enable caption */
		centered: true, /* Center the box */
		className: null, /* Extra class applied to ReMooz box */
		closer: true, /* Display closer icon on the box (Note: No transition applies on IE since it has problem on handling opacity) */
		closeOnClick: true, /* Close box by click */
		closeOnDblClick: false, /* Close box by double click */
		container: null, /* Box container */
		dragging: true, /* Enable box dragging */
		size: false, /* Size of the box e.g. {x: 640, y: 640} */
		hideSource: true, /* Hide source element after opening the box */
		loadingOpacity: 0.7, /* Opacity applied on source element */
		margin: 20, /* Margin of the box */
		openOnClick: true, /* Enable click to open */
		openOnDblClick: false, /* Enable click to open */
		resize: true, /* Shrink oversize picture */
		resizeFactor: 0.9, /* Fraction of the screen for displaying the box */
		resizeLimit: false, /* Maximum size of the box e.g. {x: 640, y: 640}*/
		resizeOptions: {
			transition: Fx.Transitions.Back.easeOut
		}, /* Options applied during resize */
		shadow: true, /* Enable shadow */
		type: 'image', /* Type of the box. (element/flash/iframe/image) */
		title: false, /* Caption title */
		content: false, /* Caption content */
		source: false, /* Source of which the box would load (Usually set in 'rel' or by default from 'src' or 'href' of parent) */
		onLoad: $empty,
		onOpen: $empty,
		onOpenEnd: $empty,
		onClose: $empty,
		onCloseEnd: $empty,
		onError: $empty,
		generateCaption: function(el){
			if (!$defined(el)) return;
			return false; /*jossele modified*/
			var title = this.options.title || el.getProperty('alt') || el.getProperty('title');
			var content = this.options.content;
			if (!title && !content) return false;
			var head = new Element('h6', {
				'text': title
			});
			return (content) ? [head, new Element('p', {
				'text': content
			})] : head;
		},
		generateElement: $empty
	},
	initialize: function(element, options){
		this.elements = $(element) || $$(element);
		if ($type((this.elements)) == 'element') this.elements = [this.elements];
		this.setOptions(options);
		this.defaultOptions = this.options;
		this.container = $(this.options.container) || document;
		
		if (this.options.openOnClick) this.elements.each((function(element){
			var open = (function(e){
				var e = new Event(e);
				if (!e.control && !e.shift && !e.meta) {
					this.open.delay(1, this, element);
					return false;
				}
				return true;
			}).bind(this);
			
			element.addClass('remooz-element')
			
			if (this.options.openOnClick && this.options.type == 'image') element.addClass('remooz-box-zoom-in');
			if (this.options.openOnClick) element.addEvent('click', open);
			if (this.options.openOnDblClick) element.addEvent('dblclick', open);
		}).bind(this));
	},
	open: function(element, options){
		if (this.loading) return;
		
		if (this.opened) {
			this.close();
			this.chain(this.open.pass(element, this));
			this.loading = true;
			
			return;
		}
		
		this.element = element;
		this.options = this.defaultOptions;
		try {
			var elOptions = JSON.decode(this.element.get('rel'));
		} catch (e) {
			var elOptions = {};
		}
		this.setOptions(elOptions);
		this.setOptions(options);
		
		this.loading = true;
		this.fireEvent('onLoad');
		
		this.options.source = this.options.source || this.element.getParent().get('href') || this.element.get('href') || this.element.get('src');
		
		if (!this.box) this.build();
		var classes = ['remooz-box', 'remooz-type-' + this.options.type, 'remooz-engine-' + Browser.Engine.name, 'remooz-engine-' + Browser.Engine.name + Browser.Engine.version];
		if (this.options.className) classes.push(this.options.className);
		
		this.styles = $merge(this.getElementCoordinates(), {
			opacity: this.options.loadingOpacity
		});
		// bug: sometimes the a element is not as high as the img (when vertical-align: middle is applied)
		var img = this.element.getElement("img"), cor;
		if (img && (cor = img.getCoordinates()) && cor.height>this.styles.height) {
			this.styles = $merge(this.styles,cor);
		}
		this.box.set({
			'class': classes.join(' '),
			styles: $merge(this.styles, {
				display: ''
			})
		}).addClass('remooz-loading');
		this.body.empty();
		this.openImage();
		
		window.addEvent('keydown', (function(e){
			if (e.key == 'esc') this.close();
		}).bind(this));
		
		return this;
	},
	close: function(){
		if (this.loading) this.box.set('styles', {
			display: 'none'
		});
		this.fireEvent('onClose');
		window.removeEvents('keydown');
		this.box.removeEvents('click');
		this.box.removeEvents('dblclick');
		if (this.content) this.content.removeClass('remooz-box-zoom-out');
		if (this.drag) this.drag.detach();
		
		var fadeCloser = this.options.closer ? (function(){
				this.closer.fade('hide');
				this.callChain();
		}).bind(this) : this.callChain;
		var fadeFull = this.options.closer ? (function(){
				this.full.fade('hide');
				this.callChain();
		}).bind(this) : this.callChain;
		var fadeCaption = this.options.caption ? (function(){
			this.caption.set('tween', {
				duration: 'short',
				onComplete: this.callChain.bind(this)
			}).fade('out');
		}).bind(this) : this.callChain;
		var fadeBox = (function(){
			if (!this.options.type.test('image|flash') && this.content) {
				this.content.destroy();
				this.content = null;
			}
			this.caption.getElement('.remooz-caption-content').empty();
			this.box.set('morph', {
				onComplete: this.callChain.bind(this)
			}).morph(this.styles);
		}).bind(this);
		
		var fadeShadow = (function(){
			 this.shadow.fade('out');
			 this.bgborder.fade('out');
			 this.callChain();
		}).bind(this);
		
		var hideBox = (function(){
			this.box.set('styles', {
				display: 'none'
			});
			if (this.content){
				this.content.destroy();
				this.content = null;
			}
			if (this.element) this.element.fade('show');
			this.callChain();
		}).bind(this);
		
		var onCloseEnd = (function(){
			this.fireEvent('onCloseEnd');
			this.loading = false;
			this.opened = false;
			this.callChain();
		}).bind(this)
		
		var emptyChain = this.$chain ? !this.$chain.length : true;
		this.chain(fadeShadow, fadeCloser, fadeFull, fadeCaption, fadeBox, hideBox, onCloseEnd);
		if (emptyChain) this.callChain();
		
		return this;
	},
	openImage: function(){
		var prefetch = new Image();
		
		prefetch.onload = (function(fast){
			prefetch.onload = prefetch.onabort = prefetch.onerror = null;
			var size = {
				x: prefetch.width,
				y: prefetch.height
			};
			this.content = $(prefetch).inject(this.body);
			this[(this.options.resize) ? 'zoomRelative' : 'zoom'](size);
		}).bind(this);
		
		prefetch.onabort = prefetch.onerror = (function(){
			prefetch.onload = prefetch.onabort = prefetch.onerror = null;
			this.fireEvent('onError', 'File unreachable').close();
		}).bind(this)
		
		prefetch.src = this.options.source;
		
		if (prefetch && prefetch.complete && prefetch.onload) prefetch.onload(true);
	},
	zoomRelative: function(size){
		size = size || this.container.getSize();
		var scale = this.options.resizeLimit;
		if (!scale) {
			scale = this.container.getSize();
			//opera 9.2 bug
			if (scale.y<300 && window.innerHeight)
				scale.y = window.innerHeight;
			scale = {
				x: (scale.x * this.options.resizeFactor).toInt(),
				y: (scale.y * this.options.resizeFactor).toInt()
			}
			
		}
		
		var oversize = scale && (size.x > scale.x || size.y > scale.y)
		var xDominant = scale && size.x / size.y > scale.x / scale.y;
		
		if (oversize) {
			size = xDominant ? {
				x: scale.x,
				y: (size.y * scale.x / size.x).toInt()
			} : {
				x: (size.x * scale.y / size.y).toInt(),
				y: scale.y
			}
		}
		
		return this.zoom(size);
	},
	zoom: function(size){
		size = this.options.size || size;
		var container = this.container.getSize(), scroll = this.container.getScroll();
		//opera 9.2 bug
		if (container.y<300 && window.innerHeight)
			container.y = window.innerHeight;
		//safari bug
		if (!scroll.x && this.container==document) scroll.x=window.pageXOffset;
		if (!scroll.y && this.container==document) scroll.y=window.pageYOffset;
		
		var position = (this.options.centered) ? {
			x: scroll.x + ((container.x - size.x) / 2).toInt(),
			y: scroll.y + ((container.y - size.y) / 2).toInt()
		} : {
			x: (this.styles.left + (this.styles.width / 2) - size.x / 2).toInt().limit(scroll.x + this.options.margin, scroll.x + container.x - this.options.margin - size.x),
			y: (this.styles.top + (this.styles.height / 2) - size.y / 2).toInt().limit(scroll.y + this.options.margin, scroll.y + container.y - this.options.margin - size.y)
		};
		var to = {
			left: position.x,
			top: position.y,
			width: size.x,
			height: size.y,
			opacity: 1
		};
		
		this.fireEvent('onOpen');
		if (this.options.closeOnClick) this.box.addEvent('click', this.close.bind(this));
		if (this.options.closeOnDblClick) this.box.addEvent('dblclick', this.close.bind(this));
		if (this.options.hideSource && this.element) this.element.fade('hide');
		if (this.options.closeOnClick && this.options.type == 'image') this.content.addClass('remooz-box-zoom-out');
		if (this.element && this.element.get('tag') != 'img') this.box.set('opacity', 0);
		this.box.removeClass('remooz-loading');
		
		this.full.setAttribute("href", this.options.source);
		
		var fadeShadow = (function(){
			 this.shadow.fade('in');
			 this.bgborder.fade('in');
			 this.callChain();
		}).bind(this);;
		var fadeBox = (function(){
			this.box.set('morph', $merge(this.options.resizeOptions, {
				onComplete: this.callChain.bind(this)
			})).morph(to);
		}).bind(this)
		var fadeCloser = this.options.closer ? (function(){
			if (!Browser.Engine.trident) {
				this.closer.set('tween', {
					duration: 'short',
					onComplete: this.callChain.bind(this)
				}).fade('in');
			} else {
				this.closer.fade('show');
				this.callChain();
			}
		}).bind(this) : this.callChain;
		var fadeFull = this.options.closer ? (function(){
			if (!Browser.Engine.trident) {
				this.full.set('tween', {
					duration: 'short',
					onComplete: this.callChain.bind(this)
				}).fade('in');
			} else {
				this.full.fade('show');
				this.callChain();
			}
		}).bind(this) : this.callChain;
		var fadeCaption = this.options.caption && this.options.type == 'image' ? (function(){
			var caption = this.options.generateCaption.apply(this, [this.element]);
			if (caption) {
				this.caption.getElement('.remooz-caption-content').adopt(caption);
				this.caption.set('tween', {
					duration: 'short',
					onComplete: this.callChain.bind(this)
				}).fade('in');
			} else this.callChain();
		}).bind(this) : this.callChain;
		var onOpenEnd = (function(){
			this.fireEvent('onOpenEnd');
			this.loading = false;
			this.opened = true;
			this.callChain();
		}).bind(this);
		
		
		
		var emptyChain = this.$chain ? !this.$chain.length : true;
		this.chain(fadeBox, fadeShadow, fadeCloser, fadeFull, fadeCaption, onOpenEnd);
		if (emptyChain) this.callChain();
	},
	build: function(){
		this.box = new Element('div', {
			styles: {
				display: 'none'
			}
		}).inject(document.body);
		
		this.caption = new Element('div', {
			'class': 'remooz-caption',
			opacity: 0
		}).adopt(new Element('div', {
			'class': 'remooz-caption-bg',
			opacity: 0.75
		}), new Element('div', {
			'class': 'remooz-caption-content'
		})).inject(this.box);
		
		this.closer = new Element('a', {
			'class': 'remooz-btn-close',
			opacity: 0,
			title: 'Schließen',
			events: {
				click: this.close.bind(this)
			}
		}).inject(this.box);
		this.full = new Element('a', {
			'class': 'remooz-btn-full',
			opacity: 0,
			title: 'Nur Bild zeigen'
		}).inject(this.box);
		
		if (!Browser.Engine.trident || Browser.Engine.trident5) {
			this.shadow = new Element('div', {
				'class': 'remooz-bg-wrap',
				opacity: 0
			}).inject(this.box);
			this.bgborder = new Element('div', {'class': 'remooz-bg-border', opacity: 0}).inject(this.box);
			['n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw'].each(function(direction){
				new Element('div', {
					'class': 'remooz-bg remooz-bg-' + direction
				}).inject(this.shadow);
			}, this);
			
		}
		
		this.body = new Element('div', {
			'class': 'remooz-body'
		}).inject(this.box);
	},
	getElementCoordinates: function(){
		if (this.element) {
			var coords = this.element.getCoordinates();
			delete coords.right;
			delete coords.bottom;
		} else {
			var container = this.container.getSize(), scroll = this.container.getScroll();
			var coords = {
				x: scroll.x + (container.x / 2).toInt(),
				y: scroll.y + (container.y / 2).toInt(),
				height: 0,
				width: 0
			};
		}
		
		return coords;
	}
});
