
var ContentFetcher = new Class({
	Implements: [Options, Events],
	overlay: null,
	outer: null,
	inner: null,
	loading: null,
	elements: [],
	animating: false,
	req: null,
	visible: false,
	imageload: {
		images: [],
		loaded: 0
	},
	fx: {
		overlay: null,
		outer: null,
		inner: null,
		loading: null
	},
	options: {
		append: '', //append this to the url to be fetched
		update: null, //update this element instead of displaying a lightbox
		opacity: 0.7,
		duration: 250,
		fixFlash: false, //hide flash when displaying the lightbox
		adoptOnly: '', //adopt only this element from the fetched contents
		onlyAdoptChildren: false, //only adopt children from options.adoptOnly
		classPrefix: 'jplb-',
		addCloseButton: true,
		closeButtonOptions: {
			'class': 'close',
			'href': 'Javascript:;',
			'text': 'close'
		},
		onReady: $empty,
		onClose: null
	},
	initialize: function (elements, options) {
		var onReady = (typeof options.onReady != 'undefined') ? options.onReady : null;
		var onClose = (typeof options.onClose != 'undefined') ? options.onClose : null;
		this.setOptions(options);
		this.options.onReady = onReady; //mootools gets rid of that, but we may still need it in this case
		this.options.onClose = onClose; //mootools gets rid of that, but we may still need it in this case
		this.elements = elements;

		this.setup();

		this.elements.each(function (el) {
			el.addEvent('click', this.clicked.bindWithEvent(this, el));
		}, this);
	},
	setup: function () {
		this.options.update = $(this.options.update);

		if (!this.isAnimated()) {
			this.inner = this.options.update;

			this.content = new Element('div', {
				id: this.options.classPrefix + 'contentNoAnim'
			}).injectInside(this.inner);

			this.loading = new Element('div', {
				id: this.options.classPrefix + 'loadingNoAnim',
				styles: {
					opacity: 1,
					display: 'none'
				}
			}).injectInside(this.inner);
		}
		else {
			var size = $(window).getScrollSize();
			this.overlay = new Element('div', {
				id: this.options.classPrefix + 'overlay',
				styles: {
					height: size.y,
//					width: size.x,
					opacity: this.options.opacity,
					visibility: 'hidden'
				}
			}).injectInside(document.body);
			this.overlay.addEvent('click', function (evt) {
				evt.stop();
				this.hide();
			}.bind(this));

			this.outer = new Element('div', {
				id: this.options.classPrefix + 'outer',
				styles: {
					opacity: 1,
					visibility: 'hidden'
				}
			}).injectInside(document.body);
			this.outer.addEvent('click', function (evt) {
				evt.stop();
				this.hide();
			}.bind(this));

			this.inner = new Element('div', {
				id: this.options.classPrefix + 'inner'
			}).injectInside(this.outer);
			this.inner.addEvent('click', function (evt) {
				evt.stopPropagation();
			}.bind(this));

			this.content = new Element('div', {
				id: this.options.classPrefix + 'content'
			}).injectInside(this.inner);

			this.loading = new Element('div', {
				id: this.options.classPrefix + 'loading',
				styles: {
					opacity: 1,
					visibility: 'hidden'
				}
			}).injectInside(this.inner);

			this.fx.overlay = new Fx.Tween(this.overlay, {
				duration: this.options.duration
			})
			this.fx.overlay.addEvent('start', this.start.bind(this));
			this.fx.overlay.addEvent('complete', this.completed.bind(this));

			this.fx.outer = new Fx.Tween(this.outer, {
				duration: this.options.duration
			})
			this.fx.outer.addEvent('start', this.start.bind(this));
			this.fx.outer.addEvent('complete', this.completed.bind(this));
		}
		this.fx.loading = new Fx.Tween(this.loading, {
			duration: this.options.duration
		})
		this.fx.loading.addEvent('complete', this.completed.bind(this));
		this.fx.loading.addEvent('start', this.start.bind(this));

//		window.addEvent('scroll', this.position.bind(this));
		window.addEvent('resize', this.resize.bind(this));
	},
	start: function (el) {
		switch (el) {
			case this.overlay:
				if (this.visible) {
					el.setStyle('display', 'block');
					this.fixFlash(true);
				}
				break;
			case this.outer:
				if (this.visible) {
					el.setStyle('display', 'block');
				}
				break;
		}
	},
	completed: function (el) {
		var visible = el.getStyle('visibility') == 'hidden' ? false : true;
		switch (el) {
			case this.overlay:
				if (!this.visible) {
					el.setStyle('display', 'none');
					this.fixFlash();
				}
				break;
			case this.outer:
				if (!this.visible) {
					el.setStyle('display', 'none');
				}
				if (visible && this.req) {
					this.req.send();
				}
				break;
		}
	},
	imageLoaded: function () {
		this.imageload.loaded++;
		if (this.imageload.loaded == this.imageload.images.length) {
			this.show();
		}
	},
	loaded: function (tree, elements, html) {
		this.content.setStyles({
			visibility: 'hidden'
		});

		if (this.options.adoptOnly) {
			var numberOfFetchedElements = elements.length, i = 0;
			do {
				if (elements[i].get('id') == this.options.adoptOnly) {
					if (!this.options.onlyAdoptChildren) {
						this.content.adopt(elements[i]);
					}
					else {
						this.content.innerHTML = elements[i].innerHTML;
					}
					break;
				}
			}
			while (i++ < numberOfFetchedElements);
		}
		else {
			this.content.adopt(tree);
		}

//		if (!this.isAnimated()) {
//			this.inner.empty();
//		}
		this.content.injectInside(this.inner);

		var images = [];
		images.extend(this.content.getElements('img'));
		//get background images as well
		images.extend(this.getBackgroundImages());

		// load images
		this.imageload = {
			images: images,
			loaded: 0
		};
		images.each(function (el) {
			if (el.complete) {
				this.imageload.loaded++;
			}
			else {
				el.addEvent('load', this.imageLoaded.bind(this));
			}
		}, this);

		if (this.imageload.images.length >= this.imageload.loaded) {
			this.show();
		}
	},
	show: function () {
//		this.fx.loading.start('opacity', 1, 0);
		this.fx.loading.set('opacity', 0);
		this.loading.setStyles('display', 'none');

		if (this.options.addCloseButton) {
			this.addCloseButton();
		}

		this.position();
		this.fireEvent('ready', this.content.getChildren()); //ready to show

		this.handleFetchedLinks();

//		this.content.setStyle('visibility', 'visible');
		new Fx.Tween(this.content, {duration: this.options.duration}).start('opacity', 0, 1);
		this.fireEvent('complete');
	},
	hide: function () {
		this.visible = false;
		if (this.isAnimated()) {
			this.fx.overlay.start('opacity', 0)
			this.fx.outer.start('opacity', 0)
		}
		if (this.options.onClose) this.options.onClose();
	},
	load: function (url) {
		if (Browser.Engine.trident && Browser.Engine.version <= 4) { // IE6 may crash
			window.location = url;
			return;
		}
		this.req = new Request.HTML({
			url: url,
			evalScripts: false,
			onSuccess: this.loaded.bind(this),
			onFailure: function () {
				alert('The page request failed, please refresh the page and try again.');
				this.hide();
			}.bind(this),
			method: 'get'
		});

		this.inner.empty();
		// show loading
		var alreadyVisible = this.visible;
		this.visible = true;
		this.loading.setStyle('display', 'block');
		this.fx.loading.set('opacity', 1);
		this.loading.injectInside(this.inner);
		if (this.isAnimated() && !alreadyVisible) {
			// fade in
			this.fx.overlay.start('opacity', 0, this.options.opacity)
			this.fx.outer.start('opacity', 0, 1)
		}
		else {
			this.req.send();
		}
		this.position();
	},
	fixFlash: function (disable) {
		var elementsToHide = [];
		if (this.options.fixFlash) {
			elementsToHide.push('object');
			elementsToHide.push('embed');
		}
		if (Browser.Engine.trident && /MSIE\s6/.test(navigator.userAgent)) {
			elementsToHide.push('select');
		}

		elementsToHide.each(function(tag) {
			$$(tag).each(function(e) {
//				e.setStyle('visibility', disable ? 'hidden' : 'visible');
				e.style.visibility = disable ? 'hidden' : 'visible'; //meh
			});
		});
	},
	toggleTriggersClass: function(hide) {
		this.elements.each(function (el) {
			if (hide) {
				el.removeClass(this.options.triggerActiveClass);
			}
			else {
				el.addClass(this.options.triggerActiveClass);
			}
		}, this);
	},
	isAnimated: function() {
		//if the element to update is specified, then we won't have any
		//animation. Otherwise, animate with fading background.
		return !this.options.update;
	},
	//get the background images for all
	getBackgroundImages: function(e) {
		e = $(e);
		if (!e) e = this.content;
		var images = [];

		//has the element any background image?
		var bg = e.getStyle('background-image');
		if (bg && bg != 'none') {
			bg = bg.replace(/url\("?([^"\)]+)"?\)/i, '$1');
			var img = $(new Image());
			img.src = bg;
			images.push(img);
		}

		//recurse down to check the children
		e.getChildren().each(function(c) {
			images.extend(this.getBackgroundImages(c));
		}, this);

		return images;
	},
	addCloseButton: function() {
		new Element('a', this.options.closeButtonOptions).injectInside(this.content);
	},
	handleFetchedLinks: function() {
		//close buttons
		var closes = this.content.getElements('.close');
		closes.each(function (el) {
			el.addEvent('click', function (evt) {
				this.hide();
			}.bind(this));
		}, this);

//		var links = this.content.getElements('a.jpLightbox').each(function (el) {
//			el.addEvent('click', this.clicked.bindWithEvent(this, el));
//		}, this);
	},
	resize: function () {
		this.overlay.setStyles({
			display: 'none'
		});
		var size = $(window).getScrollSize();
		this.overlay.setStyles({
			height: size.y,
			width: size.x,
			display: ''
		});
		this.position();
	},
	position: function () {
		if (!this.visible) {
			return;
		}
		var size = this.inner.getSize();

		var windowSize = {
			x: window.getWidth() - 56,
			y: window.getHeight() - 20
		}
		var position = {
			left: window.getScrollLeft() + ((windowSize.x - size.x) / 2),
			top: window.getScrollTop() + ((windowSize.y - size.y) / 2)
		}
		this.inner.setStyles(position);
	}
});

