if (typeof Panagora != 'object' || typeof Panagora == 'undefined')
	var Panagora = {};
	
if (typeof console != 'object')
	var console = { log: function() {}, info: function() {} }

var $j = jQuery.noConflict();

/**
	@param {DOMElement/string} content Id or element
	@param {DOMElement/string} toggleLink Id or element
	@param {Object} [options] Options for ModalWindow
*/
Panagora.CreateModalFromElement = function(content, toggleLink, options) {
	function toggleWindow(e) {
		e.stopPropagation();
		e.cancelBubble = true;
		if (isVisible) modalWindow.Hide();
		else modalWindow.Show();
		return false;
	}
	
	function windowUp() {
		isVisible = true;
	}
	
	function windowDown() {
		isVisible = false;
	}
	
	var modalWindow;
	var isVisible = false;

	options = options || {};
	options.callbacks = options.callbacks || {};
	options.callbacks.hide = windowDown;
	options.callbacks.show = windowUp;

	content = content.tagName ? $j(content) : $j('#' + content);
	toggleLink = toggleLink.tagName ? $j(toggleLink) : $j('#' + toggleLink);
	
	$j(document).ready(function () {
		modalWindow = new Panagora.ModalWindow(options);

		modalWindow.SetContent(content);
		toggleLink.click(toggleWindow);
	});
}

/**
	@param {DOMElement/string} toggleElement Clickable element (or id) with href containing the image link
	@param {Object} [options] See ModalWindow options (width, height and callbacks.hide will be overridden)
*/
Panagora.AddImageZoom = function(toggleElement, options) {
	function shutdown() {
		modalWindow.ShutDown();
	}
	
	function open(e) {
		e.stopPropagation();
		e.cancelBubble = true;
		
		// set options
		options.width = 0;
		options.height = 0;
		options.callbacks = options.callbacks || {};
		options.callbacks.hide = shutdown;


		// create window
		toggleElement.modalWindow = modalWindow = new Panagora.ModalWindow(options);
		
		// create image element
		var image = $j('<img src="/images/wait.gif"/>').get(0);

		// load progress animation
		modalWindow.SetContent(image);
		
		// load big image (with some insane IE workarounds)
		var imgObj = new Image();
		imgObj.onload = function () {
			img = $j('<img/>')
				.load(function () {
					var dims = {
						height: imgObj.height,
						width: imgObj.width
					};
					
					if (dims.width && dims.height) {
						modalWindow.SetOptions(dims);
					}
					
					$j(img).click(shutdown); // click to close
			
					// add image
					modalWindow.SetContent(img);
			
					// show window
					modalWindow.Show();
				});
			
			img.attr('src', imgObj.src);
		}
		imgObj.src = toggleElement.attr('href');

		return false;
	}
	
	var modalWindow;
	var toggleElement;
	
	options = options || {};

	// get link element
	toggleElement = toggleElement.tagName ? $j(toggleElement) : $j('#' + toggleElement);
	
	// declare img variable for later use
	var img;
	
	$j(document).ready(function () {
		toggleElement.click(open);
	});
}

/**
	@constructor
	
	@param {Object} [options] Options for the modal window
	@param {Object} [options.callbacks] Callback functions
	@param {Function} [options.callbacks.shutDown] Called when window has shut down, no parameters sent
	@param {Function} [options.callbacks.hide] Called when window is hidden, sends reference to ModalWindow object
	@param {Function} [options.callbacks.show] Called when window is shown, sends reference to ModalWindow object
	@param {int/string} [options.width=0] Width in pixels (as int) or in percent of window size (as string). Will use content size if zero.
	@param {int/string} [options.height=0] Height in pixels (as int) or in percent of window size (as string). Will use content size if zero.
	@param {int} [hMargin=0] Horizontal margin (if options.width=0)
	@param {int} [vMargin=0] Vertical margin (if options.height=0)
	@param {string} [idBase=empty string] Adds ids to elements if supplied
*/
Panagora.ModalWindow = function(options) {
	var self = this;
	
	if (!options || typeof options != 'object')
		options = {};
	
	// default
	options.callbacks = options.callbacks || {};
	options.width = options.width || 0;
	options.height = options.height || 0;
	options.vMargin = options.vMargin || 0;
	options.hMargin = options.hMargin || 0;
	options.idBase = options.idBase || '';
			
	var gui = {
		overlay: $j('<div class="modal-overlay"></div>'),
		positioner: $j('<div class="modal-positioner"></div>'),
		padder: $j('<div class="modal-padder"></div>'),
		sizer: $j('<div class="modal-sizer"></div>'),
		content: $j('<div></div>'),
		closer: $j('<div class="modal-closer">X</div>')
	}

	// decorate with ids if we have to	
	if (options.idBase.length) {
		for (var key in gui) {
			var item = gui[key];
			if (item.attr('class').length)
				item.attr('id', options.idBase + '-' + item.attr('class'));
		}
	}
	
	function init() {

		// inject elements
		gui.overlay.appendTo(document.body);
		gui.positioner.appendTo(document.body);
		gui.padder.appendTo(gui.positioner);
		gui.sizer.appendTo(gui.padder);
		gui.closer.appendTo(gui.padder);
		gui.content.appendTo(gui.sizer);
		
		// hook up events
		gui.overlay.click(self.Hide);
		gui.closer.click(self.Hide);
	}

	// resize according to options
	function resizeContainer() {
		var wDims = Panagora.GetWindowSize();

		var width = wDims.width;
		if (options.width && !isNaN(options.width)) { // fixed width
			width = options.width;
		} else if (new String(options.width).match(/%$/)) { // relative width
			width = wDims.width * (parseInt(options.width, 10) / 100);
		} else if (options.hMargin && !isNaN(options.hMargin)) { // fixed margin
			width = wDims.width - options.hMargin * 2;
		} else { // size from content
			width = gui.content.width();
		}
		
		var height = wDims.height;
		if (options.height && !isNaN(options.height)) { // fixed
			gui.content.height('100%');
			height = options.height;
		} else if (new String(options.height).match(/%$/)) { // relative
			gui.content.height('100%');
			height = wDims.height * (parseInt(options.height, 10) / 100);
		} else if (options.vMargin && !isNaN(options.vMargin)) { // fixed margin
			gui.content.height('100%');
			height = wDims.height - options.vMargin * 2;
		} else { // size from content
			height = gui.content.height();
		}

//		console.log(width, height);

		// set width
		gui.sizer
			.width(width)
			.height(height);

//		gui.padder
//			.width(width)
//			.height(height);

		// set modal overlay size
		gui.overlay
			.width(wDims.width)
			.height(wDims.height);
	}
	
	// center
	function positionContainer() {
		var wDims = Panagora.GetWindowSize();
		var so = Panagora.GetScrollingOffset();
		
//		console.log(gui.positioner.width(), gui.positioner.height(), wDims);
		
		// set left pos
		var left = 0;
		if (gui.positioner.width() < wDims.width) {
			var left = Math.floor(wDims.width / 2 - gui.positioner.width() / 2) + so.left;
		}
		gui.positioner.css('left', left + 'px');
		
		// set top pos
		var top = 0;
		if (gui.positioner.height() < wDims.height) {
			top = Math.floor(wDims.height / 2 - gui.positioner.height() / 2) + so.top;
		}
		gui.positioner.css('top', top + 'px');
	}
	
	function positionOverlay() {
		var so = Panagora.GetScrollingOffset();
		
		gui.overlay
			.css('top', so.top + 'px')
			.css('left', so.left + 'px');
	}
	
	var resizeTimeout;
	
	// puts something in the sizer
	this.SetContent = function(content) {
		gui.content.html('');
		$j(content)
			.appendTo(gui.content)
			.css('display', 'block');

		positionOverlay();

		if (resizeTimeout)
			clearTimeout(resizeTimeout);

		resizeTimeout = setTimeout(function () {
			resizeContainer();
			positionContainer();
		}, 70);
	}
	
	// set options
	this.SetOptions = function (newOptions) {
		options.callbacks.hide = newOptions.callbacks ? newOptions.callbacks.hide : options.callbacks.hide;
		options.callbacks.show = newOptions.callbacks ? newOptions.callbacks.show : options.callbacks.show;
		options.callbacks.shutDown = newOptions.callbacks ? newOptions.callbacks.shutDown : options.callbacks.shutDown;
		options.width = newOptions.width != undefined ? newOptions.width : options.width;
		options.height = newOptions.height != undefined ? newOptions.height : options.height;
		options.vMargin = newOptions.vMargin != undefined ? newOptions.vMargin : options.vMargin;
		options.hMargin = newOptions.hMargin != undefined ? newOptions.hMargin : options.hMargin;
		options.idBase = newOptions.idBase != undefined ? newOptions.idBase : options.idBase;
	}
	
	function handleKey(e) {
		if (e.which == 27)
			self.Hide();
	}
	
	function handleResize() {
		positionOverlay();

		resizeContainer();
		positionContainer();
	}
	
	function handleScroll() {
		positionOverlay();

		positionContainer();
	}

	// reveals the modal window
	this.Show = function() {
		$j(document).keyup(handleKey);
		$j(window).bind('resize', handleResize);
		$j(window).bind('scroll', handleScroll);
		
		/*@cc_on
			if (document.all && (navigator.userAgent.toLowerCase().indexOf("msie 6.") != -1)) { // ie 6
				$j('select').css('visibility', 'hidden');
			}
		@*/
		
		gui.overlay.css('visibility', 'visible');
		gui.positioner.css('visibility', 'visible');

		positionOverlay();
		
		resizeContainer();
		positionContainer();

		if (options.callbacks.show)
			options.callbacks.show(this);
	}

	// hides the modal window
	this.Hide = function() {
		$j(document).unbind('keyup', handleKey);
		$j(window).unbind('resize', handleResize);
		$j(window).unbind('scroll', handleScroll);

		/*@cc_on
			if (document.all && (navigator.userAgent.toLowerCase().indexOf("msie 6.") != -1)) { // ie 6
				$j('select').css('visibility', '');
			}
		@*/

		gui.overlay.css('visibility', 'hidden');
		gui.positioner.css('visibility', 'hidden');

		if (options.callbacks.hide)
			options.callbacks.hide(this);
	}
	
	// removes events and kills the modal window
	this.ShutDown = function() {
		$j(document).unbind('keyup', handleKey);
		$j(window).unbind('resize', handleResize);
		$j(window).unbind('scroll', handleScroll);

		/*@cc_on
			if (document.all && (navigator.userAgent.toLowerCase().indexOf("msie 6.") != -1)) { // ie 6
				$j('select').css('visibility', '');
			}
		@*/

		gui.overlay.unbind('click', this.Hide);
		gui.closer.unbind('click', this.Hide);
		
		gui.closer.remove();
		gui.sizer.remove();
		gui.padder.remove();
		gui.positioner.remove();
		gui.overlay.remove();
		
		if (options.callbacks.shutDown)
			options.callbacks.shutDown();

		delete(gui);
		delete(options);
		delete(self);
	}
	
	// returns the width of the inner container
	this.GetContentWidth = function() {
		return gui.content.width();
	}

	// returns the height of the inner container
	this.GetContentHeight = function() {
		return gui.content.height();
	}
	
	init();
}

Panagora.GetWindowSize = function() {
	return {
		height: $j(window).height(),
		width: $j(window).width()
	};
}

Panagora.GetBodySize = function() {
	return {
		height: $j(document).height(),
		width: $j(document).width()
	}
}

Panagora.GetScrollingOffset = function() {
	var x,y;
	if (self.pageYOffset) // all except Explorer
	{
		x = self.pageXOffset;
		y = self.pageYOffset;
	}
	else if (document.documentElement && document.documentElement.scrollTop)
		// Explorer 6 Strict
	{
		x = document.documentElement.scrollLeft;
		y = document.documentElement.scrollTop;
	}
	else if (document.body) // all other Explorers
	{
		x = document.body.scrollLeft;
		y = document.body.scrollTop;
	}
	return { left: x, top: y };
}