/**
 * @author:		Angelo Dini
 * @copyright	CORESHOCK - coreshock.ch
 * @requires	MooTools Core, Mootools More Assets
 */

/*
todo:
- navigation per mouse/keyboard
*/

var LightBox = new Class({
					 
	Implements: [Options, Events],
	
	options: {
		pattern: 'a[rel^={1}]',
		group: 'a[rel={1}]',
		animation: true,
		dimOpacity: 0.6,
		dimDuration: 400,
		dimTransition: 'sine:in:out',
		resDuration: 500,
		resTransition: 'sine:in:out',
		link: 'cancel',
		initWidth: 100,
		initHeight: 100,
		offset: 20,
		navHeight: 40,
		slideshow: false,
		autoplay: false,
		slide: 5000,
		loop: true,
		closeKeys: [27, 88, 67],
		previousKeys: [37, 80],
		nextKeys: [39, 78],
		lang: {
			next: 'Next',
			prev: 'Previous',
			close: 'Close',
			stop: 'Stop',
			play: 'Play',
			status: 'Entry {1} of {2}'
		}
	},
	
	initialize: function (el, options) {
		this.body = $(document.body);
		this.setOptions(options);
		
		// init scan
		this.scan(el);
	},
	
	scan: function (el) {
		// scan document
		var pattern = this.options.pattern.split('{1}');
		var anchors = this.body.getElements(pattern[0] + el + pattern[1]);
		anchors.each(function (item) {
			item.addEvent('click', this.setup.bindWithEvent(this, item));
		}, this);
	},
	
	setup: function (event, anchor) {
		event.stop();

		// handle link setup
		this.group = anchor.get('rel');
		this.link = anchor.get('href');
		this.title = '<strong>' + anchor.getChildren()[0].get('title') + '</strong><br />';
			if(!anchor.getChildren()[0].get('title')) this.title = '';
		this.desc = anchor.getChildren()[0].get('alt');
			if(!anchor.getChildren()[0].get('alt')) this.desc = '';
		
		// handle grouping setup
		var pattern = this.options.group.split('{1}');
		this.elements = this.body.getElements(pattern[0] + this.group + pattern[1]);
		
		// handle loop/slideshow setup
		this.slideshow = (this.elements.length > 1) ? this.options.slideshow : false;
		this.loops = (this.elements.length > 1) ? this.options.loop : false;
		
		// handle index/length setup
		this.length = this.elements.length;
		this.elements.each(function (anchor, index) {
			if(anchor.get('href') == this.link) this.index = index;
		}, this);
		
		// init
		($('lightbox-dim')) ? this.filter(this.link) : this.build();
		
		// dim
		this.dim(true);
	},
	
	build: function () {
		// build html code
		var dim = new Element('div', { id: 'lightbox-dim', events: { click: this.dim.pass(false, this) } });
		var frame = new Element('div', { id: 'lightbox' }).adopt(
			new Element('div', { 'class': 'lightbox-box' }).adopt(
				new Element('a', { 'class': 'lightbox-box-next', events: { click: this.next.bind(this) } }),
				new Element('a', { 'class': 'lightbox-box-prev', events: { click: this.prev.bind(this) } })
			),
			new Element('div', { 'class': 'lightbox-nav' }).adopt(
				new Element('a', { 'class': 'lightbox-close', html: this.options.lang.close, events: { click: this.dim.pass(false, this) } }),
				new Element('a', { 'class': 'lightbox-slideshow' }),
				new Element('a', { 'class': 'lightbox-next', html: this.options.lang.next, events: { click: this.next.bind(this) } }),
				new Element('a', { 'class': 'lightbox-prev', html: this.options.lang.prev, events: { click: this.prev.bind(this) } }),
				new Element('span', { 'class': 'lightbox-caption' }),
				new Element('span', { 'class': 'lightbox-status' })
			)
		);
		
		// inject html code
		frame.inject(this.body, 'top');
		dim.inject(this.body, 'top');
		
		// get dom references
		this.canvas = $('lightbox-dim');
		this.frame = $('lightbox');
		
		this.box = this.frame.getElement('.lightbox-box');
		this.nav = this.frame.getElement('.lightbox-nav');

		// build base animation
		this.animate();
		
		// show at startup
		this.filter(this.link);
	},

	animate: function () {
		var settings = {
			duration: this.options.dimDuration,
			transition: this.options.dimTransition,
			link: this.options.link
		}
		
		this.canvasFx = new Fx.Tween(this.canvas, settings);
		this.canvasFx.set('opacity', 0);
		this.boxFx = new Fx.Tween(this.box, settings);
		this.navFx = new Fx.Tween(this.nav, settings);
		this.frameFx = new Fx.Morph(this.frame, {
			duration: this.options.resDuration,
			transition: this.options.resTransition,
			link: 'cancel'
		});
		this.reset();
	},
	
	reset: function () {
		var height = this.options.initHeight;
		var width = this.options.initWidth;
		
		this.boxFx.start('opacity', 0);
		this.navFx.start('height', 0);
		// set correct fx cancel
		var settings = {
			'height': height,
			'margin-top': -(height / 2) + window.getScroll().y,
			'width': width,
			'margin-left': -(width / 2)
		}
		this.frameFx.set(settings);
		this.frameFx.start(settings);
		
		// css reset
		this.frame.addClass('preload');
		this.frame.setStyle('display', 'none');
		this.box.setStyle('display', 'none');
		this.nav.setStyle('display', 'none');
	},
	
	dim: function (state) {
		// dim window
		if(state) {
			this.attachEvents();
			this.disable(true);
			this.adjust();
			
			this.frame.setStyle('display', 'block');
			this.canvas.setStyle('display', 'block');
			this.canvasFx.start('opacity', this.options.dimOpacity);
		
			// slideshow functionality?
			if(this.slideshow) this.autoplay();
		} else {
			this.detachEvents();
			
			this.canvasFx.start('opacity', 0).chain(function () {
				this.canvas.setStyle('display', 'none');
				this.disable(false);
			}.bind(this));
			
			// hide frame
			this.hide();
			
			// reset animations
			this.reset();
			
			// reset slideshow
			$clear(this.timer);
		}
	},
	
	disable: function (state) {
		// (c) slimbox, disable embedded videos/flash/ie6 selects
		["object", Browser.Engine.trident4 ? "select" : "embed"].forEach(function(tag) {
			Array.forEach(document.getElements(tag), function(el) {
				if (state) el.deactivate = el.style.visibility;
				el.style.visibility = state ? "hidden" : el.deactivate;
			});
		});
	},
	
	attachEvents: function () {
		window.addEvents({
			'scroll': this.adjust.bind(this),
			'resize': this.adjust.bind(this),
			'keydown': this.keyControl.bindWithEvent(this)
		});
	},
	
	detachEvents: function () {
		window.removeEvents({
			'scroll': this.adjust.bind(this),
			'resize': this.adjust.bind(this)
		});
	},
	
	keyControl: function (event) {
		var code = event.code;
		return this.options.closeKeys.contains(code) ? this.dim(false, this)
			: this.options.nextKeys.contains(code) ? this.next()
			: this.options.previousKeys.contains(code) ? this.prev()
			: false;
	},

	adjust: function () {
		// set dynamig dim height
		this.canvas.setStyle('height', (window.getSize().y + window.getScroll().y));
		
		// set dynamic frame position
		this.frame.setStyle('margin-top', (-(this.frame.getStyle('height').toInt()) / 2) + window.getScroll().y);
	},
	
	filter: function (href) {
		// check extenstion for filetype
		var extension = href.split('.').pop();
		
		// check extension for youtube
		if(href.match(/youtube\.com/i)) var extension = 'swf';
		
		switch(extension) {
			case 'jpg':
			case 'gif':
			case 'png':
			case 'tiff':
				this.image(href);
				break;
			case 'swf':
				this.video('swf', href);
				break;
			case 'wmv':
			case 'avi':
				this.video('wmv', href);
				break;
			case 'mov':
				this.video('mov', href);
				break;
			default:
				this.iframe(href);
				//alert('this service is not supported');
		}
	},
	
	image: function (href) {
		this.detection();
		
		// preload image
		var image = new Asset.image(href, {
			onload: function (image) {
				image.inject(this.box);
				this.resize(image.width, image.height);
			}.bind(this)
		});
	},
	
	video: function (type, href) {
		this.detection();
		
		var str = '';
		var width = 560;
		var height = 340;
		
		if(type == 'swf') {
			var video = new Element('div', { id: 'vlightbox' });
			
			new Swiff(href, {
				width: width,
				height: height,
				params: {
					wMode: 'window'
				},
				container: video
			});
		}
		
		if(type == 'wmv') {
			width = 480;
			height = 360;
			
			str += '<object type="application/x-oleobject" classid="CLSID:22D6f312-B0F6-11D0-94AB-0080C74C7E95" codebase="http://activex.microsoft.com/activex/controls/mplayer/en/nsmp2inf.cab" width="' + width + '" height="' + height + '">';
			str += '<param name="filename" value="' + href + '" />';
			str += '<param name="Showcontrols" value="true" />';
			str += '<param name="autoStart" value="false" />';
			str += '<embed type="application/x-mplayer2" src="' + href + '" Showcontrols="true" autoStart="false" width="' + width + '" height="' + height + '"></embed>';
			str += '<object/>';
			
			var video = new Element('div', { id: 'vlightbox', html: str });
		}

		if(type == 'mov') {
			width = 480;
			height = 220;

			str += '<object type="video/quicktime" classid="clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B" codebase="http://www.apple.com/qtactivex/qtplugin.cab width="' + width + '" height="' + height + '">';
			str += '<param name="src" value="' + href + '" />';
			str += '<param name="autoplay" value="false" />';
			str += '<param name="controller" value="true" />';
			str += '<param name="enablejavascript" value="true" />';
			str += '<embed src="' + href + '" autoplay="false" pluginspage="http://www.apple.com/quicktime/download/" width="' + width + '" height="' + height + '"></embed>';
			str += '<object/>';
			
			var video = new Element('div', { id: 'vlightbox', html: str });
		}

		// inject video
		video.inject(this.box);
		this.resize(width, height);
	},
	
	iframe: function (href) {
		this.detection();

		var width = 700;
		var height = 450;
		
		var str = '<iframe src="' + href + '" name="generated_iframe" width="' + width + '" height="' + height + '" marginheight="10" marginwidth="10" align="right"></iframe>';
		
		var iframe = new Element('div', { id: 'iframe', html: str });
		
		iframe.inject(this.box);
		this.resize(width, height);
		
		this.box.getElement('a.lightbox-box-prev').setStyle('visibility', 'hidden');
		this.box.getElement('a.lightbox-box-next').setStyle('visibility', 'hidden');
	},
	
	detection: function () {
		// detect images
		if(this.box.getElement('img')) this.box.getElement('img').dispose();
		// detect iframes
		if(this.box.getElement('flightbox')) this.box.getElement('flightbox').dispose();
		// detect video
		if(this.box.getElement('#vlightbox')) this.box.getElement('#vlightbox').dispose();
		// detect iframe
		if(this.box.getElement('#iframe')) {
			this.box.getElement('#iframe').dispose();
			this.box.getElement('a.lightbox-box-prev').setStyle('visibility', 'visible');
			this.box.getElement('a.lightbox-box-next').setStyle('visibility', 'visible');
		}
	},
	
	resize: function (width, height) {
		// remove preloader class
		this.frame.removeClass('preload');
		
		// mutate elements width and height
		var width = width + this.options.offset;
		var height = height + this.options.offset;
		
		// animation
		this.frameFx.start({
			// needs ie6 margin top fix (1px padding)
			'margin-top': -(height / 2) + window.getScroll().y,
			'height': height
		}).chain(function () {
		this.start({
			'width': width,
			'margin-left': -(width / 2)
			});
		}).chain(function () {
			this.show(height);	
		}.bind(this));
	},
	
	show: function (height) {
		// set title
		var html = this.title + this.desc;
		this.nav.getElement('.lightbox-caption').set('html', html);
		
		// set status
		if(this.length > 1) {
			// implement status
			var status = this.options.lang.status;
			status = status.replace('{1}', this.index + 1);
			status = status.replace('{2}', this.elements.length);
			this.nav.getElement('.lightbox-status').set('html', status);
		}
		if(this.length <= 1) this.nav.getElement('.lightbox-status').set('html', '');

		// show anchors & nav
		if(this.length > 0) {
			this.box.getElements('a').setStyles({
				'display': 'block',
				'height': height
			});
			this.nav.getElement('a.lightbox-next').setStyle('display', 'block');
			this.nav.getElement('a.lightbox-prev').setStyle('display', 'block');
		}
		
		// check slideshow control
		this.slidecontrol = this.frame.getElement('.lightbox-slideshow');
		this.slidecontrol.setStyle('display', 'block');
		if(this.options.slideshow == false || this.length <= 1) this.slidecontrol.setStyle('display', 'none');
		
		// animate element
		this.boxFx.set('display', 'block');
		this.boxFx.start('opacity', 1).chain(function () {
			this.nav.setStyle('display', 'block');
			this.navFx.start('height', this.options.navHeight);
		}.bind(this));
		
		// looping anchors?
		if(!this.loops) this.loop();
	},
	
	hide: function () {
		this.box.getElements('a').setStyle('display', 'none');
	},
	
	loop: function() {
		if(this.index == (this.length - 1)) this.box.getElement('a.lightbox-box-next').setStyle('display', 'none');
		if(this.index == 0) this.box.getElement('a.lightbox-box-prev').setStyle('display', 'none');

		if(this.index == (this.length - 1)) this.nav.getElement('a.lightbox-next').setStyle('display', 'none');
		if(this.index == 0) this.nav.getElement('a.lightbox-prev').setStyle('display', 'none');
	},
	
	autoplay: function () {
		// add events
		this.control = this.nav.getElement('a.lightbox-slideshow');
		this.control.addEvent('click', this.trigger.bind(this));
		
		// check autoplay
		this.state = (this.options.autoplay == true) ? true : false;
		
		this.trigger();
	},
	
	trigger: function (state) {
		(this.state) ? this.play() : this.pause();
	},
	
	play: function () {
		console.log('play');
		this.state = false;
		this.control.addClass('lbbtn');
		this.control.set('html', this.options.lang.stop);
		
		// start timer
		this.timer = (function () { this.next(false); }).bind(this).periodical(this.options.slide);
	},
	
	pause: function () {
		this.state = true;
		this.control.removeClass('lbbtn');
		this.control.set('html', this.options.lang.play);

		// clear timer
		$clear(this.timer);
	},
	
	next: function (abort) {
		this.change();
		if(abort) $clear(this.timer);
		if((this.index == (this.length - 2)) && !this.loops) $clear(this.timer);
		
		this.index = (this.index < (this.elements.length - 1)) ? this.index + 1 : 0;
		this.filter(this.elements[this.index].get('href'));
	},
	
	prev: function (abort) {
		this.change();
		if(abort) $clear(this.timer);
		
		this.index = (this.index == 0) ? this.elements.length - 1 : this.index - 1;
		this.filter(this.elements[this.index].get('href'));
	},
	
	change: function () {
		this.frame.addClass('preload');
		this.boxFx.start('opacity', 0);
		this.box.setStyle('display', 'none');
		this.navFx.start('height', 0);
		this.nav.setStyle('display', 'none');
	}
	
});
