/**
 * Util
 *
 * A collection of common functions to aid in rapid, custom JavaScript development.
 */

var Util;
if (typeof Util == "undefined") 
	Util = {};

/**
 * DOM
 */

Util.addClass = function(el, cname) {
	el.className = el.className + " " + cname;
}

Util.removeClass = function(el, cname) {
	el.className = el.className.replace(new RegExp(" ?" + cname), "");
}

/**
 * Event
 */

Util.addEventListener = function(eventType, el, func) {
	if (el.addEventListener)
		el.addEventListener(eventType, func, false);
	else if (el.attachEvent)
		el.attachEvent('on' + eventType, func);
}

Util.removeEventListener = function(eventType, el, func) {
	if (el.removeEventListener)
		el.removeEventListener(eventType, func, false);
	else if (el.detachEvent)
		el.detachEvent('on' + eventType, func);
}

/**
 * Other
 */

Util.getScrollPosition = function() {
	var pos = {x:0,y:0};
	pos.x = window.pageXOffset ? window.pageXOffset : document.documentElement.scrollLeft;
	pos.y = window.pageYOffset ? window.pageYOffset : document.documentElement.scrollTop;
	return pos;
}

Util.getElementDimensions = function(el) {
	var dim = {width:0, height:0};
	dim.width = el.offsetWidth;
	dim.height = el.offsetHeight;
	return dim;
}

Util.getElementPosition = function(el) {
	var pos = {x:0, y:0};
	pos.x = el.offsetLeft;
	pos.y = el.offsetTop;
	return pos;
}

Util.getMouseCoordinates = function(e) {
	var pos = { x:0, y:0 };
	if (!e) var e = window.event;
	if (e.pageX || e.pageY) 	{
		pos.x = e.pageX;
		pos.y = e.pageY;
	}
	else if (e.clientX || e.clientY) 	{
		pos.x = e.clientX + document.body.scrollLeft
			+ document.documentElement.scrollLeft;
		pos.y = e.clientY + document.body.scrollTop
			+ document.documentElement.scrollTop;
	}
	return pos;
}

Util.getViewport = function() {
	var v = {width:0, height:0};
	if (window.innerHeight) {
		v.height = window.innerHeight;
		v.width = window.innerWidth;
	} else if (document.documentElement.clientHeight) {
		v.height = document.documentElement.clientHeight;
		v.width = document.documentElement.clientWidth;
	} else {
		v.height = document.body.clientHeight;
		v.width = document.body.clientWidth;
	}
	return v;
}

/**
 * Overlay
 *
 * Places a div over the entire screen and places a div with some content over
 * it. Intended to display pictures and other content in a modal fashion.
 */

function Overlay(params, opts) {
	var ref = this;
	
// dependencies
	if (typeof Util == "undefined")
		alert("Error: this script requires Util.js.");
	
// instance options
	this.backgroundColor = '#000';
	this.backgroundImage = null;
	this.maxOpacity = 0.4;
	
	this.closeButtonImage = null;
	this.closeButtonImageHover = null;
	this.closeButtonImageActive = null;
	this.closeButtonHoverClass = 'hover';
	this.closeButtonActiveClass = 'active';
	
	this.enableFade = true;
	this.framerate = 30;
	this.duration = 500;
	
	this.enableDrag = false;
	
	this.overlayContentClass = 'overlayContent';
	this.closeButtonClass = 'overlayClose';

	if (typeof opts != "undefined")
		loadOptions(this);

// instance vars
	var closeElement = createCloseElement();
	var backgroundElement = createBackgroundElement();
	var contentContainer = createContentContainer();
	var contentElement = null;
	

// internal state vars	
	var isContentVisible = false;
	var cursorOffset = {x:0, y:0}; // for drag support

// initialization
	registerTriggerEvents();
	resizeOverlay();
	Util.addEventListener('resize', window, resizeAndRepositionAll);

// Load content and place it in the contentContainer, signal when done
	function loadContent(resourceObj) {
		if (resourceObj.resourceType == 'image') {
			contentElement = new Image();
			contentElement.onload = onContentReady;
			contentElement.src = resourceObj.resource;
		} else
			alert('Notice: only resources of type "image" are currently supported.');
	}

// Creates onclick listeners for all trigger elements
	function registerTriggerEvents() {
		var anchors = document.getElementsByTagName('A');
		for (var i = 0; i < anchors.length; i++)
			if (typeof params[anchors[i].id] != 'undefined')
				anchors[i].onclick = onTriggerClick;
	}
	
// Determines the appropriate content from the params array to display based on
// the id attribute of the trigger element.
	function onTriggerClick() {
		if (typeof params[this.id] != 'undefined')
			loadContent(params[this.id]);
		return false;
	}
	
	function showOverlay() {
		resizeOverlay();
		backgroundElement.style.display = 'block';
		contentContainer.style.display = 'block';
		contentElement.style.display = 'block';
		repositionContent();
	}
	
	function hideOverlay() {
		backgroundElement.style.display = 'none';
		contentContainer.style.display = 'none';
		contentElement.style.display = 'none';
	}
	
	function onContentReady() {
		contentContainer.appendChild(closeElement);
		closeElement.onclick = onContentClose;
		
		contentContainer.appendChild(contentElement);
		
		if (ref.enableFade)
			fadeIn();
		else
			showOverlay();
		
//		if (ref.enableDrag) {
//		} else {
//		}
	}
	
	function onContentClose() {
		if (ref.enableFade)
			fadeOut();
		else
			hideOverlay();
	}
	
	function fadeIn() {
		animateOpacity(backgroundElement, 0, ref.maxOpacity, null, null);
		// animateOpacity(containerElement, 0, 100, null, null);
		contentContainer.style.display = 'block';
		repositionContent();
	}
	
	function fadeOut() {
		animateOpacity(backgroundElement, ref.maxOpacity, 0-0, hideOverlay, null);
	}
	
	function createBackgroundElement() {
		var el = document.createElement('DIV');
		
		el.style.background = ref.backgroundColor;
		el.style.backgroundImage = 'url(' + ref.backgroundImage + ')';
		el.style.opacity = ref.maxOpacity;
		el.style.filter = 'alpha(opacity=' + (ref.maxOpacity * 100) + ')';
		el.style.position = 'absolute';
		el.style.top = '0px';
		el.style.left = '0px';
		el.style.display = 'none';
		document.body.appendChild(el);
		return el;
	}

// Build the document element that holds the content for this overlay
	function createContentContainer() {
		var el = document.createElement('DIV');
		el.style.position = 'absolute';
		el.style.top = '0px';
		el.style.left = '0px';
		el.style.display = 'none';
		Util.addClass(el, ref.overlayContentClass);
		document.body.appendChild(el);
		return el;
	}
	
// Creates the element that closes the overlay and registers the listeners
	function createCloseElement() {
		var el = document.createElement('DIV');
		var img = new Image();

		if (ref.closeButtonImage !== null) {
			img.src = ref.closeButtonImage;
			el.appendChild(img);
		} else {
			var elText = document.createTextNode('Close Window');
			el.appendChild(elText);
		}
		
		Util.addClass(el, ref.closeButtonClass);
		
		el.onclick = function() {
			Util.removeClass(el, 'hover');
			Util.removeClass(el, 'active');
			if (ref.closeButtonImage !== null) {
				img.src = ref.closeButtonImage;
			}
			onContentClose();
		}
		
		el.onmouseover = function() {
			Util.addClass(el, 'hover');
			if (ref.closeButtonImageHover !== null) {
				img.src = ref.closeButtonImageHover;
			}
		}
		
		el.onmousedown = function() {
			Util.removeClass(el, 'hover');
			Util.addClass(el, 'active');
			if (ref.closeButtonImageActive !== null) {
				img.src = ref.closeButtonImageActive;
			}
		}
		
		el.onmouseout = function() {
			Util.removeClass(el, 'hover');
			Util.removeClass(el, 'active');
			if (ref.closeButtonImage !== null) {
				img.src = ref.closeButtonImage;
			}
		}
		
		el.onmouseup = function() {
			Util.removeClass(el, 'active');
			Util.addClass(el, 'hover');
			if (ref.closeButtonImageHover !== null) {
				img.src = ref.closeButtonImageHover;
			}
		}
		
		closeElement = el;
		return el;
	}	

// Override default options with user preferences
	function loadOptions(obj) {
		for (var i in opts)
			if (typeof obj[i] != "undefined")
				obj[i] = opts[i];
	}

// adjust overlay size to fill document	
	function resizeOverlay() {
		var vp = Util.getViewport();
		var dm = Util.getElementDimensions(document.body);
		if (vp.height > dm.height)
			backgroundElement.style.height = vp.height + 'px';
		else
			backgroundElement.style.height = dm.height + 'px';
		backgroundElement.style.width = '100%';
	}

// position content in center of screen
	function repositionContent() {	
		var vp = Util.getViewport();
		var dm = Util.getElementDimensions(contentElement);	
		var sp = Util.getScrollPosition();
		contentContainer.style.top = (sp.y + ((vp.height - dm.height)/3)) +'px';
		contentContainer.style.left = (sp.x + ((vp.width - dm.width)/2)) + 'px';
	}

// resize and position everything important
	function resizeAndRepositionAll() {
		resizeOverlay();
		repositionContent();
	}

// TODO: position element based on mouse coordinates
	function updateContentPosition(e) {
		if (!e) e = window.event;
		var mc = Util.getMouseCoordinates(e);
		contentContainer.style.top = (mc.y - cursorOffset.y) + 'px';
		contentContainer.style.left = (mc.x - cursorOffset.x) + 'px';
	}

// animate opacity on the given element
// TODO: why is FF so fast?
// TODO: better handling of opacity and filter decisions
	function animateOpacity(el, start, end, callbackFunc, posFunc) {
		var fps = Math.floor(1000/ref.framerate);
		var currentValue = start;
		var finalValue = end;
		var increment = Math.abs(end - start)/(ref.duration/fps);
		var t;
	
		el.style.filter = 'alpha(opacity = '+(currentValue*100)+')';
		el.style.opacity = currentValue;

		// if (posFunc) posFunc();
		el.style.display = 'block';
		if (posFunc) posFunc();
		
		if (end >= start)
			t = setInterval(step, fps);
		else
			t = setInterval(reverseStep, fps);
		
		function step(off) {
			currentValue += increment;
			el.style.filter = 'alpha(opacity = '+(currentValue*100)+')';
			el.style.opacity = currentValue;
			if (currentValue >= finalValue) {
				clearTimeout(t);
				el.style.filter = 'alpha(opacity = '+(finalValue*100)+')';
				el.style.opacity = finalValue;
				if (callbackFunc) callbackFunc();
			}
		}
		
		function reverseStep() {
			currentValue -= increment;
			el.style.filter = 'alpha(opacity = '+(currentValue*100)+')';
			el.style.opacity = currentValue;
			if (currentValue <= finalValue) {
				clearTimeout(t);
				el.style.filter = 'alpha(opacity = '+(finalValue*100)+')';
				el.style.opacity = finalValue;;
				if (callbackFunc) callbackFunc();
			}
		}
	}
}

// This is the necessary code to get the overlay effect running
Util.addEventListener('load', window, function() {
	var myOverlay = new Overlay(overlayContent, overlayOptions);
});

