/**
 * MooFlow - Image gallery
 *
 * Dependencies: MooTools 1.2
 *
 * @version			0.2.1
 *
 * @license			MIT-style license
 * @author			Tobias Wetzel <info [at] outcut.de>
 * @copyright		Author
 * @docmentation	http://outcut.de/MooFlow/Docmentation.html
 */ 

var MooFlow = new Class({

	Implements: [Events, Options],
	
	options: {
		onStart: $empty,
		onClickView: $empty,
		onAutoPlay: $empty,
		onAutoStop: $empty,
		onRequest: $empty,
		onResized: $empty,
		onEmptyinit: $empty,
		reflection: 0.4,
		heightRatio: 0.6,
		offsetY: 0,
		startIndex: 0,
		interval: 3000,
		factor: 115,
		bgColor: '#000',
		useCaption: false,
		useResize: false,
		useSlider: false,
		useWindowResize: false,
		useMouseWheel: true,
		useKeyInput: false,
		useViewer: false
	},
	
	initialize: function(element, options){
		this.MooFlow = element;
		this.setOptions(options);
		this.foc = 150;
		this.factor = this.options.factor;
		this.offY = this.options.offsetY;
		this.isFull = false;
		this.isAutoPlay = false;
		this.isLoading = false;
		this.inMotion = false;
		
		this.MooFlow.addClass('mf').setStyles({
			'overflow':'hidden',
			'background-color':this.options.bgColor,
			'position':'relative',
			'height':this.MooFlow.getSize().x*this.options.heightRatio,
			'opacity':0
		});
		
		if(this.options.useWindowResize) window.addEvent('resize', this.update.bind(this, 'init'));
		if(this.options.useMouseWheel || this.options.useSlider) this.MooFlow.addEvent('mousewheel', this.wheelTo.bind(this));
		if(this.options.useKeyInput) document.addEvent('keydown', this.keyTo.bind(this));
		
		this.getElements(this.MooFlow);
	},
	
	clearInit: function(){
		this.fireEvent('emptyinit');
	},
	
	getElements: function(el){
		this.master = {'images':[]};
		var els = el.getChildren();
		if(!els.length) {this.clearInit(); return;}
		$$(els).each(function(el){
			var hash = $H(el.getElement('img').getProperties('src','title','alt','longdesc'));
			if(el.get('tag') == 'a') hash.combine(el.getProperties('href','rel','target'));
			this.master['images'].push(hash.getClean());
			el.dispose();
		}, this);
		this.clearMain();
	},
	
	clearMain: function(){
		if(this.cap){this.cap.fade(0);}
		if(this.nav){
			new Fx.Tween(this.nav, {
				'onComplete': function(){
					this.MooFlow.empty();
					this.createAniObj();
				}.bind(this)
			}).start('bottom', -50);
		}
		if(!this.nav && !this.cap){
			this.MooFlow.empty();
			this.createAniObj();
		}
	},
	
	getMooFlowElements: function(key){
		var els = [];
		this.master.images.each(function(el){ 
			els.push(el[key]); 
		});
		return els;
	},
	
	createAniObj: function(){
		this.aniFx = new Fx.Value({
			'transition': Fx.Transitions.Expo.easeOut,
			'link': 'cancel',
			'duration': 750,
			onMotion: this.process.bind(this),
			'onStart': this.flowStart.bind(this),
			'onComplete': this.flowComplete.bind(this)
		});
		this.addLoader();
	},
	
	addLoader: function(){
		this.MooFlow.store('height', this.MooFlow.getSize().y);
		this.loader = new Element('div',{'class':'loader'}).inject(this.MooFlow);
		new Fx.Tween(this.MooFlow, {
			'duration': 800,
			'onComplete': this.preloadImg.bind(this)
		}).start('opacity', 1);
	},
	
	preloadImg: function(){
		this.loadedImages = new Asset.images(this.getMooFlowElements('src'), {
			'onComplete': this.loaded.bind(this),
			'onProgress': this.createMooFlowElement.bind(this)
		});
	},
	
	createMooFlowElement: function(counter, i){
		var obj = this.getCurrent(i);
		var img = this.loadedImages[i];
		obj['width'] = img.width;
		obj['height'] = img.height;
		img.removeProperties('width','height');

		obj['div'] = new Element('div').setStyles({
			'position':'absolute',
			'display':'none',
			'height': this.MooFlow.getSize().y
		}).inject(this.MooFlow);
		obj['con'] = new Element('div').inject(obj['div']);
		img.setStyles({'vertical-align':'bottom', 'width':'100%', 'height':'50%'});
		img.addEvents({'click': this.clickTo.bind(this, i), 'dblclick': this.viewCallBack.bind(this, i)});
		img.inject(obj['con']);
		
		new Element('div').reflect({ 'img': img,
			'ref': this.options.reflection,
			'height': obj.height,
			'width': obj.width,
			'color': this.options.bgColor
		}).setStyles({'width':'100%','height':'50%','background-color': this.options.bgColor}).inject(obj['con']);
		
		this.loader.set('text', (counter+1) + ' / ' + this.loadedImages.length);
	},
	
	loaded: function(){
		this.index = this.options.startIndex;
		this.iL = this.master.images.length-1;
		new Fx.Tween(this.loader, {
			'duration': 800,
			'onComplete': this.createUI.bind(this)
		}).start('opacity', 0);
	},
	
	createUI: function(){
		this.loader.dispose();
		if(this.options.useCaption){
			this.cap = new Element('div').addClass('caption').set('opacity',0).inject(this.MooFlow);
		}	
		this.nav = new Element('div').addClass('mfNav').setStyle('bottom','-50px');
		this.autoPlayCon = new Element('div').addClass('autoPlayCon');
		this.sliderCon = new Element('div').addClass('sliderCon');
		this.resizeCon = new Element('div').addClass('resizeCon');		
		if(this.options.useAutoPlay){
			this.autoPlayCon.adopt(
				new Element('a',{'class':'stop','events': {'click':this.stop.bind(this)}}), 
				new Element('a',{'class':'play','events': {'click':this.play.bind(this)}})
			);
		}
		if(this.options.useSlider){
			this.sliPrev = new Element('a',{'class':'sliderNext','events': {'click':this.prev.bind(this)}});
			this.sliNext = new Element('a',{'class':'sliderPrev','events': {'click':this.next.bind(this)}});
			this.knob = new Element('div',{'class':'knob'});
			this.knob.adopt(new Element('div',{'class':'knobleft'}));
			this.slider = new Element('div',{'class':'slider'}).adopt(this.knob);
			this.sliderCon.adopt(this.sliPrev,this.slider,this.sliNext);
			this.slider.store('parentWidth', this.sliderCon.getSize().x-this.sliPrev.getSize().x-this.sliNext.getSize().x);
		}
		if(this.options.useResize){
			this.resizeCon.adopt(new Element('a',{'class':'resize','events': {'click':this.setScreen.bind(this)}}));
		}		
		this.MooFlow.adopt(this.nav.adopt(this.autoPlayCon, this.sliderCon, this.resizeCon));	
		this.showUI();
	},
	
	showUI: function(){
		if(this.cap) this.cap.fade(1);
		this.nav.tween('bottom', 20);
		this.fireEvent('start');
		this.update();
	},
	
	update: function(e){
		if(e == 'init') return;
		this.oW = this.MooFlow.getSize().x;
		this.sz = this.oW * 0.5;
		if(this.options.useSlider){	
			this.slider.setStyle('width',this.slider.getParent().getSize().x-this.sliPrev.getSize().x-this.sliNext.getSize().x-1);
			this.knob.setStyle('width',(this.slider.getSize().x/this.iL));
			this.sli = new SliderEx(this.slider, this.knob, {steps: this.iL}).set(this.index);
			this.sli.addEvent('onChange', this.glideTo.bind(this));
		}
		this.glideTo(this.index);
		this.isLoading = false;
	},
	
	setScreen: function(){
		if(this.isFull = !this.isFull){
			this.holder = new Element('div').inject(this.MooFlow,'after');
			this.MooFlow.wraps(new Element('div').inject(document.body));
			this.MooFlow.setStyles({'position':'absolute','z-index':'100','top':'0','left':'0','width':window.getSize().x,'height':window.getSize().y});
			if(this.options.useWindowResize){
				this._initResize = this.initResize.bind(this);
				window.addEvent('resize', this._initResize);
			}
		} else {
			this.MooFlow.wraps(this.holder);
			window.removeEvent('resize', this._initResize);
			delete this.holder, this._initResize;
			this.MooFlow.setStyles({'position':'relative','z-index':'','top':'','left':'','width':'','height':this.MooFlow.retrieve('height')});
			this.slider.setStyle('width',this.slider.retrieve('parentWidth'));
		}
		this.fireEvent('resized', this.isFull);
		this.update();
	},
	
	initResize: function(){
		this.MooFlow.setStyles({'width':window.getSize().x,'height':window.getSize().y});
		this.update();
	},
	
	getCurrent: function(index){
		return this.master.images[$chk(index) ? index : this.index];
	},
	
	loadJSON: function(url){
		if(!url || this.isLoading) return;
		this.isLoading = true;
		new Request.JSON({
			'onComplete': function(data){
				if($chk(data)){
					this.master = data;
					this.clearMain();
					this.fireEvent('request', data);
				}
			}.bind(this)
		}, this).get(url);
	},
	
	loadHTML: function(url, filter){
		if(!url || !filter || this.isLoading) return;
		this.isLoading = true;
		new Request.HTML({
			'onSuccess': function(tree, els, htm){
				var result = new Element('div', {'html': htm}).getChildren(filter);
				this.getElements(result);
				this.fireEvent('request', result);
			}.bind(this)
		}, this).get(url);
	},
	
	flowStart: function(){
		this.inMotion = true;
	},
	
	flowComplete: function(){
		this.inMotion = false;
	},
	
	viewCallBack: function(index){
		if(this.index != index || this.inMotion) return;
		var el = $H(this.getCurrent());
		var returnObj = {};
		returnObj['coords'] = el.div.getElement('img').getCoordinates();
		el.each(function(v, k){
			if($type(v) == 'number' || $type(v) == 'string') returnObj[k] = v;
		}, this);
		this.fireEvent('clickView', returnObj);
	},
	prev: function(){
		if(this.index > 0) this.clickTo(this.index-1);
	},
	next: function(){
		if(this.index < this.iL) this.clickTo(this.index+1);
	},
	stop: function(){
		$clear(this.autoPlay);
		this.isAutoPlay = false;
		this.fireEvent('autoStop');
	},
	play: function(){
		this.autoPlay = this.auto.periodical(this.options.interval, this);
		this.isAutoPlay = true;
		this.fireEvent('autoPlay');
	},
	auto: function(){
		if(this.index < this.iL) this.next();
		else if(this.index == this.iL) this.clickTo(0);
	},
	keyTo: function(e){
		switch (e.code){
			case 37: e.stop(); this.prev();	break;
			case 39: e.stop(); this.next();
		}
	},
	wheelTo: function(e){
		if(e.wheel > 0) this.prev();
		if(e.wheel < 0) this.next();
		e.stop().preventDefault();
	},
	clickTo: function(index){
		if(this.index == index) return;
		//this.aniFx.cancel();
		if(this.sli) this.sli.set(index);
		this.glideTo(index);
	},
	glideTo: function(index){
		this.index = index;
		this.aniFx.start(this.aniFx.get(), index*-this.foc);
		if(this.cap) this.cap.set('html', this.getCurrent().title);
	},
	process: function(x){
		var z,W,H,zI=this.iL,foc=this.foc,f=this.factor,sz=this.sz,oW=this.oW,offY=this.offY,div,elh,elw;
		this.master.images.each(function(el){
			div = el.div.style;
			elw = el.width;
			elh = el.height;
			if(x>-foc*6 && x<foc*6){
				with (Math) {
					z = sqrt(10000 + x * x) + 100;
					H = round((elh / elw * f) / z * sz);
					W = round(elw * H / elh);
					if(H >= elw * 0.5) {W = round(f / z * sz);}
					div.left = round(((x / z * sz) + sz) - (f * 0.5) / z * sz) + 'px';
					div.top = round(oW * 0.4 - H) + offY + 'px';
				}	
				el.con.style.height = H*2 + 'px';		
				div.width = W + 'px';
				div.zIndex = x < 0 ? zI++ : zI--;
				div.display = 'block';
			} else {
				div.display = 'none';
			}
			x += foc;
		});
	}
});

var SliderEx = new Class({
	Extends: Slider,
	set: function(step){
		this.step = Math.round(step);
		this.fireEvent('tick', this.toPosition(this.step));
		return this;
    },
	clickedElement: function(event){
		var dir = this.range < 0 ? -1 : 1;
		var position = event.page[this.axis] - this.element.getPosition()[this.axis] - this.half;
		position = position.limit(-this.options.offset, this.full -this.options.offset);
		this.step = Math.round(this.min + dir * this.toStep(position));
		this.checkStep();
		this.fireEvent('tick', position);
	}
});

Fx.Value = new Class({
	Extends: Fx,
	compute: function(from, to, delta){
		this.value = Fx.compute(from, to, delta);
		this.fireEvent('motion', this.value);
		return this.value;
	},
	get: function(){
		return this.value || 0;
	}
});

Element.implement({
	reflect: function(arg){
		i = arg.img.clone();
		if(Browser.Engine.trident){
			i.style.filter = 'flipv progid:DXImageTransform.Microsoft.Alpha(opacity=20, style=1, finishOpacity=0, startx=0, starty=0, finishx=0, finishy='+100*arg.ref+')';
			i.setStyles({'width':'100%', 'height':'100%'});
			return new Element('div').adopt(i);
		} else {
			var can = new Element('canvas').setProperties({'width':arg.width, 'height':arg.height});
			if(can.getContext){
				var ctx = can.getContext("2d");
				ctx.save();
				ctx.translate(0,arg.height-1);
				ctx.scale(1,-1);
				try {
				  ctx.drawImage(i, 0, 0, arg.width, arg.height);
				} catch(err) {}
				ctx.restore();
				ctx.globalCompositeOperation = "destination-out";
				ctx.fillStyle = arg.color;
				ctx.fillRect(0, arg.height*0.5, arg.width, arg.height);
				var gra = ctx.createLinearGradient(0, 0, 0, arg.height*arg.ref);					
				gra.addColorStop(1, "rgba(255, 255, 255, 1.0)");
				gra.addColorStop(0, "rgba(255, 255, 255, "+(1-arg.ref)+")");
				ctx.fillStyle = gra;
				ctx.rect(0, 0, arg.width, arg.height);
				ctx.fill();
				delete ctx, gra;
			}
			return can;
		}
	}
});

window.addEvent('domready', function(){
	$$('.MooFlowieze').each(function(mooflow){
		new MooFlow(mooflow);
	});
});

/**
 * ReMooz - Zoomer
 *
 * Inspired by so many boxes and zooms
 *
 * @version		1.0
 *
 * @license		MIT-style license
 * @author		Harald Kirschner <mail [at] digitarald.de>
 * @copyright	Author
 */

var ReMooz = new Class({

	Implements: [Events, Options, Chain],

	options: {
		link: null,
		type: 'image',
		container: null,
		className: null,
		centered: false,
		dragging: true,
		closeOnClick: true,
		shadow: (Browser.Engine.trident) ? 'onOpenEnd' : 'onOpen', // performance
		resize: true,
		margin: 20,
		resizeFactor: 0.95,
		resizeLimit: false, // {x: 640, y: 640}
		fixedSize: false,
		cutOut: true,
		addClick: true,
		opacityLoad: 0.6,
		opacityResize: 1,
		opacityTitle: 0.9,
		resizeOptions: {},
		fxOptions: {},
		closer: true,
		parse: false, // 'rel'
		parseSecure: false,
		temporary: false,
		onBuild: $empty,
		onLoad: $empty,
		onOpen: $empty,
		onOpenEnd: $empty,
		onClose: $empty,
		onCloseEnd: $empty,
		generateTitle: function(el) {
			var text = el.get('title');
			if (!text) return false;
			var title = text.split(' :: ');
			var head = new Element('h6', {'html': title[0]});
			return (title[1]) ? [head, new Element('p', {'html': title[1]})] : head;
		}
	},

	initialize: function(element, options) {
		this.element = $(element);
		this.setOptions(options);
		if (this.options.parse) {
			var obj = this.element.getProperty(this.options.parse);
			if (obj && (obj = JSON.decode(obj, this.options.parseSecure))) this.setOptions(obj);
		}
		var origin = this.options.origin;
		this.origin = ((origin) ? $(origin) || this.element.getElement(origin) : null) || this.element;
		this.link = this.options.link || this.element.get('href') || this.element.get('src');
		this.container = $(this.options.container) || this.element.getDocument();
		this.bound = {
			'click': function(e) {
				this.open.delay(1, this);
				return false;
			}.bind(this),
			'close': this.close.bind(this),
			'dragClose': function(e) {
				if (e.rightClick) return;
				this.close();
			}.bind(this)
		};
		if (this.options.addClick) this.bindToElement();
	},

	destroy: function() {
		if (this.box) this.box.destroy();
		this.box = this.tweens = this.body = this.content = null;
	},

	bindToElement: function(element) {
		($(element) || this.element).addClass('remooz-element').addEvent('click', this.bound.click);
		return this;
	},

	getOriginCoordinates: function() {
		var coords = this.origin.getCoordinates();
		delete coords.right;
		delete coords.bottom;
		return coords;
	},

	open: function(e) {
		if (this.opened) return (e) ? this.close() : this;
		this.opened = this.loading = true;
		if (!this.box) this.build();
		this.coords = this.getOriginCoordinates();
		this.coords.opacity = this.options.opacityLoad;
		this.coords.display = '';
		this.tweens.box.set(this.coords);
		this.box.addClass('remooz-loading');
		ReMooz.open(this.fireEvent('onLoad'));
		this['open' + this.options.type.capitalize()]();
		return this;
	},

	finishOpen: function() {
		this.tweens.fade.start(0, 1);
		this.drag.attach();
		this.fireEvent('onOpenEnd').callChain();
	},

	close: function() {
		if (!this.opened) return this;
		this.opened = false;
		ReMooz.close(this.fireEvent('onClose'));
		if (this.loading) {
			this.box.setStyle('display', 'none');
			return this;
		}
		this.drag.detach();
		this.tweens.fade.cancel().set(0).fireEvent('onComplete');
		if (this.tweens.box.timer) this.tweens.box.clearChain();
		var vars = this.getOriginCoordinates();
		if (this.options.opacityResize != 1) vars.opacity = this.options.opacityResize;
		this.tweens.box.start(vars).chain(this.closeEnd.bind(this));
		return this;
	},

	closeEnd: function() {
		if (this.options.cutOut) this.element.setStyle('visibility', 'visible');
		this.box.setStyle('display', 'none');
		this.fireEvent('onCloseEnd').callChain();
		if (this.options.temporary) this.destroy();
	},

	openImage: function() {
		var tmp = new Image();
		tmp.onload = tmp.onabort = tmp.onerror = function(fast) {
			this.loading = tmp.onload = tmp.onabort = tmp.onerror = null;
			if (!tmp.width || !this.opened) {
				this.fireEvent('onError').close();
				return;
			}
			var to = {x: tmp.width, y: tmp.height};
			if (!this.content) this.content = $(tmp).inject(this.body);
			else tmp = null;
			this[(this.options.resize) ? 'zoomRelativeTo' : 'zoomTo'].create({
				'delay': (tmp && fast !== true) ? 1 : null,
				'arguments': [to],
				'bind': this
			})();
		}.bind(this);
		tmp.src = this.link;
		if (tmp && tmp.complete && tmp.onload) tmp.onload(true);
	},

	/**
	 * @todo Test implementation
	 */
	openElement: function() {
		this.content = this.content || $(this.link) || $E(this.link);
		if (!this.content) {
			this.fireEvent('onError').close();
			return;
		}
		this.content.inject(this.body);
		this.zoomTo({x: this.content.scrollWidth, y: this.content.scrollHeight});
	},

	zoomRelativeTo: function(to) {
		var scale = this.options.resizeLimit;
		if (!scale) {
			scale = this.container.getSize();
			scale.x *= this.options.resizeFactor;
			scale.y *= this.options.resizeFactor;
		}
		for (var i = 2; i--;) {
			if (to.x > scale.x) {
				to.y *= scale.x / to.x;
				to.x = scale.x;
			} else if (to.y > scale.y) {
				to.x *= scale.y / to.y;
				to.y = scale.y;
			}
		}
		return this.zoomTo({x: to.x.toInt(), y: to.y.toInt()});
	},

	zoomTo: function(to) {
		to = this.options.fixedSize || to;
		var box = this.container.getSize(), scroll = this.container.getScroll();
		var pos = (!this.options.centered) ? {
			x: (this.coords.left + (this.coords.width / 2) - to.x / 2).toInt()
				.limit(scroll.x + this.options.margin, scroll.x + box.x - this.options.margin - to.x),
			y: (this.coords.top + (this.coords.height / 2) - to.y / 2).toInt()
				.limit(scroll.y + this.options.margin, scroll.y + box.y - this.options.margin - to.y)
		} :  {
			x: scroll.x + ((box.x - to.x) / 2).toInt(),
			y: scroll.y + ((box.y - to.y) / 2).toInt()
		};
		if (this.options.cutOut) this.element.setStyle('visibility', 'hidden');
		this.box.removeClass('remooz-loading');
		var vars = {left: pos.x, top: pos.y, width: to.x, height: to.y};
		if (this.options.opacityResize != 1) vars.opacity = [this.options.opacityResize, 1];
		else this.box.set('opacity', 1);
		this.tweens.box.start(vars).chain(this.finishOpen.bind(this));
		this.fireEvent('onOpen');
	},

	build: function() {
		this.addEvent('onBlur', function() {
			this.focused = false;
			this.box.removeClass('remooz-box-focus').setStyle('z-index', ReMooz.options.zIndex);
		}, true);
		this.addEvent('onFocus', function() {
			this.focused = true;
			this.box.addClass('remooz-box-focus').setStyle('z-index', ReMooz.options.zIndexFocus);
		}, true);

		var classes = ['remooz-box', 'remooz-type-' + this.options.type, 'remooz-engine-' + Browser.Engine.name + Browser.Engine.version];
		if (this.options.className) classes.push(this.options.className);
		this.box = new Element('div', {
			'class': classes.join(' '),
			'styles': {
				'display': 'none',
				'top': 0,
				'left': 0,
				'zIndex': ReMooz.options.zIndex
			}
		});

		this.tweens = {
			'box': new Fx.Morph(this.box, $merge({
					'duration': 400,
					'unit': 'px',
					'transition': Fx.Transitions.Quart.easeOut,
					'chain': 'cancel'
				}, this.options.resizeOptions)
			),
			'fade': new Fx.Tween(null, $merge({
					'property': 'opacity',
					'duration': (Browser.Engine.trident) ? 0 : 300,
					'chain': 'cancel'
				}, this.options.fxOptions)).addEvents({
					'onComplete': function() {
						if (!this.element.get('opacity')) this.element.setStyle('display', 'none');
					},
					'onStart': function() {
						if (!this.element.get('opacity')) this.element.setStyle('display', '');
					}
				}
			)
		};
		this.tweens.fade.element = $$();

		if (this.options.shadow) {
			if (Browser.Engine.webkit420) {
				this.box.setStyle('-webkit-box-shadow', '0 0 10px rgba(0, 0, 0, 0.7)');
			} else if (!Browser.Engine.trident4) {
				var shadow = new Element('div', {'class': 'remooz-bg-wrap'}).inject(this.box);
				['n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw'].each(function(dir) {
					new Element('div', {'class': 'remooz-bg remooz-bg-' + dir}).inject(shadow);
				});
				this.tweens.bg = new Fx.Tween(shadow, {
					'property': 'opacity',
					'chain': 'cancel'
				}).set(0);
				this.addEvent(this.options.shadow, this.tweens.bg.set.bind(this.tweens.bg, 1), true);
				this.addEvent('onClose', this.tweens.bg.set.bind(this.tweens.bg, 0), true);
			}
		}

		if (this.options.closer) {
			var closer = new Element('a', {
				'class': 'remooz-btn-close',
				'events': {'click': this.bound.close}
			}).inject(this.box);
			this.tweens.fade.element.push(closer);
		}
		this.body = new Element('div', {'class': 'remooz-body'}).inject(this.box);

		var title = this.options.title || this.options.generateTitle.call(this, this.element);
		if (title) { // thx ie6
			var title = new Element('div', {'class': 'remooz-title'}).adopt(
				new Element('div', {'class': 'remooz-title-bg', 'opacity': this.options.opacityTitle}),
				new Element('div', {'class': 'remooz-title-content'}).adopt(title)
			).inject(this.box);
			this.tweens.fade.element.push(title);
		}
		this.tweens.fade.set(0).fireEvent('onComplete');

		this.drag = new Drag.Move(this.box, {
			'snap': 15,
			'preventDefault': true,
			'onBeforeStart': function() {
				if (!this.focused && !this.loading) ReMooz.focus(this);
				else if (this.loading || this.options.closeOnClick) this.box.addEvent('mouseup', this.bound.dragClose);
			}.bind(this),
			'onSnap': function() {
				this.box.removeEvent('mouseup', this.bound.dragClose);
				if (!this.options.dragging) this.drag.stop();
				else this.box.addClass('remooz-box-dragging');
			}.bind(this),
			'onComplete': function() {
				this.box.removeClass('remooz-box-dragging');
			}.bind(this)
		});
		this.drag.detach();

		this.fireEvent('onBuild', this.box, this.element);
		this.box.inject(this.element.getDocument().body);
	}

});

ReMooz.factory = function(extended) {
	return $extend(this, extended);
};

ReMooz.factory(new Options).factory({

	options: {
		zIndex: 41,
		zIndexFocus: 42,
		query: 'a.remooz',
		modal: false
	},

	assign: function(elements, options) {
		return $$(elements).map(function(element) {
			return new ReMooz(element, options);
		}, this);
	},

	stack: [],

	open: function(obj) {
		var last = this.stack.getLast();
		this.focus(obj);
		if (last && this.options.modal) last.close();
	},

	close: function(obj) {
		var length = this.stack.length - 1;
		if (length > 1 && this.stack[length] == obj) this.focus(this.stack[length - 1]);
		this.stack.erase(obj);
	},

	focus: function(obj) {
		var last = this.stack.getLast();
		obj.fireEvent('onFocus', [obj]);
		if (last == obj) return;
		if (last) last.fireEvent('onBlur', [last]);
		this.stack.erase(obj).push(obj);
	}

});