/**
 * ReMooz - Image Zoombox
 * 
 * 
 * Inspired by 
 *  ... *	- 
 * 
 * @version		1.0beta
 * 
 * @license		MIT-style license
 * @author		Harald Kirschner <mail [at] digitarald.de>
 * @copyright	Author
 */
var ReMooz = new Class({

	options: {
		id: null,
		url: null,
		opacityOptions: {},
		resizeOptions: {},
		positionToCenter: false,
		marginBox: 10,
		resize: true,
		resizeFactor: 0.9,
		resizeLimit: {x: 1024, y: 674},
		zIndex: 41,
		zIndexFocus: 42,
		onLoad: $empty,
		onOpen: $empty,
		onBeforeClose: $empty,
		onClose: $empty
	},

	initialize: function(element, options) {
		this.element = $(element);
		this.setOptions(options);
		this.addEvent('onBlur', function() {
			this.focussed = false;
			this.box.setStyle('z-index', this.options.zIndex);
			this.box.removeClass('remo-box-focus');
		}.bind(this));
		this.addEvent('onFocus', function() {
			this.focussed = true;
			this.box.setStyle('z-index', this.options.zIndexFocus);
			this.box.addClass('remo-box-focus');
		}.bind(this));
		this.url = this.options.url || this.element.href;
		this.element.addClass('remo-zoom-in').addEvent('trash', this.destroy.bind(this));
	},

	destroy: function() {
		this.box = this.image = null;
	},

	bindToElement: function(el) {
		($(el) || this.element).addEvent('click', function(e) {
			this.open.delay(1, this);
			return false;
		}.bind(this));
	},

	open: function() {
		if (this.opened) return this;
		this.opened = true;
		if (!this.box) this.build();
		this.coords = this.element.getCoordinates();
		this.boxFx.set({
			opacity: 0,
			top: this.coords.top,
			left: this.coords.left,
			height: this.coords.height,
			width: this.coords.width
		}).start({'opacity': 0.7});
		this.box.setStyle('display', '').addClass('remo-loading');
		if (!this.boxDrag) this.boxDrag = new Drag.Move(this.box, {
			snap: 15,
			onStart: function() {
				if (!this.focussed && !this.loading) {
					ReMooz.focus(this);
					this.focusEvent = true;
				}
			}.bind(this),
			onSnap: function() {
				this.dragging = true;
				this.box.addClass('remo-box-dragging');
			}.bind(this),
			onComplete: function() {
				if (!this.dragging && !this.focusEvent) this.close();
				this.dragging = this.focusEvent = false;
				this.box.removeClass('remo-box-dragging');
			}.bind(this)
		}).detach();
		this.fireEvent('onLoad');
		this.loadImage();
		return this;
	},

	close: function() {
		if (!this.opened) return this;
		this.fireEvent('onBeforeClose');
		this.opened = false;
		ReMooz.close(this);
		if (this.loading) {
			this.box.setStyle('display', 'none');
			return this;
		}
		this.boxDrag.detach();
		this.btnClose.setStyle('display', 'none');
		if (this.boxFx.timer) this.boxFx.clearChain();
		this.coords = this.element.getCoordinates();
		this.boxFx.start({
			top: this.coords.top,
			left: this.coords.left,
			height: this.coords.height,
			width: this.coords.width
		}).chain(function() {
			this.element.setStyle('visibility', 'visible').focus();
			this.box.setStyle('display', 'none');
			this.fireEvent('onClose');
		}.bind(this));
		return this;
	},

	loadImage: function() {
		var loader = new Image();
		this.loading = true;
		loader.onload = loader.onabort = loader.onerror = function() {
			this.loading = loader.onload = loader.onabort = loader.onerror = null;
			if (!loader.width || !this.opened) {
				this.close();
				return;
			}
			var to = {x: loader.width, y: loader.height};
			if (!this.image)
			{
				 this.image = (Client.Engine.webkit419) ? new Element('img', {src: loader.src}) : $(loader);
				 this.image.inject(this.box).addClass('remo-img');
			} else loader = null;
			this.openImage(to);
		}.bind(this);
		loader.src = this.url;
		if (loader && loader.width && loader.onload) loader.onload();
	},

	openImage: function(size) {
		this.element.setStyle('visibility', 'hidden');
		this.relativeResize(size);
	},

	relativeResize: function(to) {
		if (this.options.resize) {
			var max = this.options.resizeLimit || {
				x: window.getWidth() * this.options.resizeFactor,
				y: window.getHeight() * this.options.resizeFactor
			};
			for (var i = 0; i < 2; i++) {
				if (to.x > max.x) {
					to.y *= max.x / to.x;
					to.x = max.x;
				} else if (to.y > max.y) {
					to.x *= max.y / to.y;
					to.y = max.y;
				}
			}
		}
		return this.resizeTo({x: to.x.toInt(),y: to.y.toInt()});
	},

	resizeTo: function(to) {
		var box = window.getSize();
		var pos = {
			x: box.scroll.x + ((box.size.x - to.x) / 2).toInt(),
			y: box.scroll.y + ((box.size.y - to.y) / 2).toInt()
		};
		if (!this.options.positionToCenter) {
			pos.x = (this.coords.left + (this.coords.width / 2) - to.x / 2).toInt()
				.limit(box.scroll.x + this.options.marginBox, box.scroll.x + box.size.x - this.options.marginBox - to.x);
			pos.y = (this.coords.top + (this.coords.height / 2) - to.y / 2).toInt()
				.limit(box.scroll.y + this.options.marginBox, box.scroll.y + box.size.y - this.options.marginBox - to.y);
		}

		this.box.removeClass('remo-loading');
		this.fireEvent('onOpen');
		ReMooz.open(this);

		this.boxFx.set({opacity: 1}).start({
			left: pos.x,
			top: pos.y,
			width: to.x,
			height: to.y
		}).chain(function() {
			this.boxDrag.attach();
			this.btnClose.setStyle('display', '');
		}.bind(this));
	},


	build: function() {
		this.box = new Element('div', {
			'class': 'remo-box',
			styles: {
				display: 'none',
				zIndex: this.options.zIndex
			}
		}).inject(document.body);

		this.boxFx = this.box.effects({
			duration: 500,
			transition: Fx.Transitions.Quint.easeOut,
			wait: false
		});

		this.btnClose = new Element('a', {
			'class': 'remo-btn-close',
			styles: {
				display: 'none'
			},
			events: {
				click: this.close.bind(this)
			}
		}).inject(this.box);
	}

});

ReMooz.implement(new Events, new Options);
ReMooz.extendFactory = $extend;

ReMooz.extendFactory({

	options: {
		zIndex: 41,
		zIndexFocus: 42
	},

	opened: [],

	open: function(obj) {
		this.focus(obj);
	},

	close: function(obj) {
		var last = this.opened.length - 1;
		if (this.opened.indexOf(obj) == last) this.focus(this.opened[last - 1]);
		this.opened.remove(obj);
	},

	focus: function(obj) {
		var last = this.opened.getLast();
		if (!obj || last == obj) return;
		if (last) last.fireEvent('onBlur', [last], 10);
		obj.fireEvent('onFocus', [obj], 10);
		this.opened.remove(obj).push(obj);
	}

});
