/**
 * LightBox - Builds and manages a set of elements that makeup a lightbox
 * options:
 * box					mixed		Element id or object that holds the content
 * overlay				mixed		Element id or object that acts as the overlay
 * closeButton			mixed		Element id or object that acts as a close button
 * boxClass				string		CSS class that can be added to the box
 * overlayClass			string		CSS class that can be added to the overlay
 * closeClass			string		CSS class that can be added to the close button
 * imgClass				string		CSS class used to identify images to preload
 * contentClass			string		CSS class used for content wrapper (default: lbContentWrapper)
 * frameClass			string		CSS class used for iframe wrapper (default: lbContentFrame)
 * autoRegisterEvents	boolean		Determines if click events for displaying images should be automatically created
 * makeCloseButton		boolean		Determines if a close button is created if one is not specified
 * onshow				function	Function to execute when the lightbox is shown
 * onhide				function	Function to execute when the lightbox is hidden
 *
 * @param	options		object		optional;Object specifying options
 * @return				LightBox	New LightBox instance
 */
function LightBox(options) {
	//internals
	this.isShowing = false;
	this.initialized = false;
	this.isIE = false;
	this.regexFilename = /^.*\/([^\/]*)$/i;
	this.regexFullpath = /^(?:https?:\/\/|(\/))?(.*)$/i;
	this.images = {};
	
	//options and objects
	this.box = null;
	this.overlay = null;
	this.closeButton = null;
	this.options = {
		boxClass: '',
		overlayClass: '',
		closeClass: 'lbClose',
		imgClass: '',
		contentClass: 'lbContentWrapper',
		frameClass: 'lbContentFrame',
		makeCloseButton: true,
		autoRegisterEvents: true
	};
	this.events = {
		onshow: null,
		onhide: null
	};
	
	options = options || {};
	
	domLoader.register(function initialize(){
		this.isIE = window.ActiveXObject ? (window.XMLHttpRequest ? 7 : 6) : false;
		
		for(var k in options) {
			if(options.hasOwnProperty(k) && k in this.options) {
				this.options[k] = options[k];
			}
		}
		
		var docbody = dbt('body')[0];
		
		function isString(str) {
			return str && (typeof str == 'string' || (typeof str == 'object' && typeof str.valueOf() == 'string'));
		}
		
		var box_id = 'lightbox';
		if(options['box'] && isString(options['box'])) {
			this.box = did(options['box']);
			box_id = options['box'];
		} else if(options['box'] && typeof options['box'] == 'object') {
			this.box = options['box'];
		}
		
		if(!this.box) {
			this.box = createElement('div');
			this.box.id = box_id;
			docbody.insertBefore(this.box, first(docbody));
		}
		addClass(this.box, this.options.boxClass);
		this.box.style.display = 'none';
		
		if(options['closeButton'] && isString(options['closeButton'])) {
			this.closeButton = did(options['closeButton']);
		} else {
			this.closeButton = options['closeButton'];
		}
		
		if(!this.closeButton && this.options.makeCloseButton) {
			this.closeButton = createElement('a');
			this.options.closeClass = this.options.closeClass.trim();
			this.closeButton.innerHTML = 'Close X';
			if(this.options.closeClass) {
				addClass(this.closeButton, this.options.closeClass);
			}
			this.box.appendChild(this.closeButton);
		}
		
		var overlay_id = 'overlay';
		if(options['overlay'] && isString(options['overlay'])) {
			this.overlay = did(options['overlay']);
			overlay_id = options['overlay'];
		} else if(options['overlay'] && typeof options['overlay'] == 'object') {
			this.overlay = options['overlay'];
		}
		
		if(!this.overlay) {
			this.overlay = createElement('div');
			this.overlay.id = overlay_id;
			docbody.insertBefore(this.overlay, this.box);
		}
		addClass(this.overlay, this.options.overlayClass);
		this.overlay.style.display = 'none';
				
		if(this.isIE) {
			this.shim = createElement('iframe');
			this.shim.style.cssText = 'display: none;position: absolute;top: 0px;left: 0px;filter:progid:DXImageTransform.Microsoft.alpha(opacity=0);z-index:'+(getStyle(this.overlay,'zIndex')-1);
			this.shim.frameBorder = 0;
			this.shim.scrolling = 'no';
			this.shim.src = dbt('base')[0].href + 'blankpage';
			docbody.insertBefore(this.shim, first(docbody));
		}
		
		registerEvent(window, 'resize', this.createCaller(this,this.resize));
		registerEvent(window, 'scroll', this.createCaller(this,this.resize));
		registerEvent(this.overlay, 'click', this.createCaller(this,this.hide));
		if(this.closeButton) {
			registerEvent(this.closeButton, 'click', this.createCaller(this, this.hide));
		}
		
		for(var eName in this.events) {
			if(typeof options[eName] == 'function') {
				this.events[eName] = options[eName];
				this.listen(eName, this.events[eName]);
			}
		}
		
		this.preloadImages();
		this.initialized = true;
	},this);
}
LightBox.prototype = {
	preloadImages: function preloadImages(className) {
		className = (className ? String(className) : this.options.imgClass).trim();
		if(className == '') {
			return false;
		}
		var nodes = slice(dbc(className)), tagname='', imgsrc='';
		nodes.forEach(this.preloadImage,this);
	},
	preloadImage: function preloadImage(src, fn) {
		var node;
		if(typeof src == 'object' && src.nodeType == 1) {
			node = src;
			var tag = node.tagName.toLowerCase();
			if(tag == 'a' && node.href != '') {
				src = node.href;
			} else if(tagname == 'img' && node.src != '') {
				src = node.src;
			}
		}
		
		src = (src ? String(src) : '').trim();
		var fname = src.replace(this.regexFullpath, '$1$2');
		if(!src || !fname) {
			return null;
		}
		
		if(!this.images[fname]) {
			this.images[fname] = new Image();
			if(fn && typeof fn == 'function') {
				var self = this;
				registerEvent(this.images[fname], 'load', function imgLoad(){
					e.target = self.images[fname];
					unregisterEvent(e.target, 'load', arguments.callee);
					fn.call(self, e);
				});
			}
			this.images[fname].src = src;
		} else if(typeof fn == 'function') {
			fn.call(this,{target: this.images[fname]});
		}
		if(this.options.autoRegisterEvents && node) {
			registerEvent(node, 'click', this.createCaller(this, this.showIMG, true, fname,'','',''));
		}
		return (fname in this.images) ? this.images[fname] : null;
	},
	createWrapper: function createWrapper(html) {
		if(!this.initialized){
			return false;
		}
		if(this.frame){ this.frame.style.display = 'none'; }
		if(!this.content) {
			this.options.contentClass = this.options.contentClass.trim() || 'lbContentWrapper';
			this.content = createElement('div');
			this.content.className = this.options.contentClass;
			this.box.appendChild(this.content);
		}
		html = html || '';
		if(html != '') {
			this.content.innerHTML = String(html);
		}
		this.content.style.display = '';
	},
	showHTML: function showHTML(html) {
		if(!this.initialized){
			return false;
		}
		this.createWrapper(html);
		this.show();
		return this;
	},
	showDOM: function showDOM(node, clone) {
		if(!this.initialized){
			return false;
		}
		this.createWrapper();
		clone = clone == null ? true : clone;
		if(node && node.nodeType == 1 && !contains(this.content,node)) {
			if(clone){
				var nodeClone = node.cloneNode(true);
				this.content.appendChild(nodeClone);
			} else {
				this.content.appendChild(node);
			}
		}
		this.show();
		this.resize();
		return this;
	},
	showIMG: function showIMG(src, width, height, alt) {
		if(!this.initialized){
			return false;
		}
		this.createWrapper('<div>Loading Image...</div>');
		
		this.preloadImage(src, function displayImage(e) {
			var img = e.target;
			var attributes = {'width':(width || img.width), 'height':(height || img.height), 'alt': (alt || '')};
			for(var atr in attributes) {
				if(attributes.hasOwnProperty(atr)) {
					img.setAttribute(atr, attributes[atr]);
				}
			}
			this.content.innerHTML = '';
			this.showDOM(img,false);
		});
		return this;
	},
	showURL: function showURL(url) {
		if(!this.initialized){
			return false;
		}
		if(this.content){
			this.content.style.display = 'none';
		}
		if(!this.frame) {
			this.options.frameClass = this.options.frameClass.trim() || 'lbContentFrame';
			this.frame = createElement('iframe');
			this.frame.className = this.options.frameClass;
			this.frame.frameBorder = 0;
			this.box.appendChild(this.frame);
		}
		
		this.frame.src = url;
		this.frame.style.display = '';
		this.show();
		return this;
	},
	clear: function clear() {
		this.box.innerHTML = '';
		this.content = null;
		this.frame = null;
		return this;
	},
	show: function show() {
		this.resize();
		this.box.style.display = '';
		this.overlay.style.display = '';
		if(this.shim) {
			this.shim.style.display = '';
		}
		if(!this.isShowing) {
			triggerEvent(this.box, 'focus', false, false);
		}
		this.isShowing = true;
		return this;
	},
	hide: function hide() {
		this.box.style.display = 'none';
		this.overlay.style.display = 'none';
		if(this.shim) {
			this.shim.style.display = 'none';
		}
		if(this.isShowing) {
			triggerEvent(this.box, 'blur', false, false);
		}
		this.isShowing = false;
		return this;
	},
	toggle: function toggle() {
		var fn = this.isShowing ? 'hide':'show';
		this[fn]();
	},
	resize: function resize() {
		var max = getMaxDocSize();
		['overlay','shim'].forEach(function(item){
			if(this[item]) {
				this[item].style.width = max['width']+'px';
				this[item].style.height = max['height']+'px';
			}
		},this);
		
		var docsize = getDocSize(), scroll = getScrollXY();
		if(!this.isShowing) {
			this.box.style.visibility = 'hidden';
			this.box.style.display = '';
		}
		var boxWidth = this.isIE ? this.box.offsetWidth : getStyle(this.box,'width')
		var boxHeight = this.isIE ? this.box.offsetHeight : getStyle(this.box,'height');
		if(!this.isShowing) {
			this.box.style.display = 'none';
			this.box.style.visibility = 'visible';
		}
		boxWidth = isNaN(boxWidth) ? 0 : boxWidth;
		boxHeight = isNaN(boxHeight) ? 0 : boxHeight;
		var topleft = {
			'x':Math.round((docsize['width']-boxWidth)/2)+scroll['x'],
			'y':Math.round((docsize['height']-boxHeight)/2)+scroll['y']
		};
		this.setPosition(topleft.x,topleft.y);
		return this;		 
	},
	setPosition: function setPosition(x, y) {
		if(x && x != 'auto') {
			this.box.style.left = parseInt(x)+'px';
		}
		if(y && y != 'auto') {
			this.box.style.top = parseInt(y)+'px';
		}
	},
	listen: function listen(event, fn) {
		if(typeof fn != 'function') {
			return false;
		}
		var self = this;
		function eventWrapper(func, stopDefault, stopBubble) {
			return function wrapping(e) {
				e = fixEvent(e);
				if(stopDefault) {
					e.preventDefault();
				}
				if(stopBubble) {
					e.stopPropagation();
				}
				func.call(self, e);
			}
		}
		switch(event) {
			case 'onshow':
				registerEvent(this.box, 'focus', eventWrapper(fn,true,true));
				break;
			case 'onhide':
				registerEvent(this.box, 'blur', eventWrapper(fn,true,true));
				break;
			default:
				break;
		}
	},
	createCaller: function createCaller(obj, fn, stopDefault){
		var args = slice(arguments,3);
		return function callMethod(e) {
			e = fixEvent(e);
			if(stopDefault) {
				e.preventDefault();
			}
			fn.apply(obj, args.concat([e]));
		}
	},
	constructor: LightBox
};


/**
 * LightboxAlert creates a wrapper for the lightbox and uses it as a growl style alert.
 * Note: Does not fade in IE due to transparency issues with the PNG shadow.
 * 
 * Available options:
 * duration		int		The length of time (in miliseconds) the alert should show for.
 * 
 * Other options include everything available to the lightbox and fade effect.  Wrap these options inside of either 'lightbox' or 'fade' objects 
 * 
 * @param elm
 * @param options
 * @return
 */
var LightboxAlert = function( elm, options ){
	if(!options){
		var options = {};
	}
	
	this.options = {
		time_out: true,
		duration: 3000,
		onComplete: function(){}
	}
	
	for(var option in options){//set the options specified and keep the defaults
		this.options[option] = options[option];
	}
	
	var self = this;
	this.lb = new LightBox({
		box:elm,
		overlay:'overlay',
		hideOverlay:true,
		closeClass:'close',
		onhide:function(){
			clearTimeout(self.timer);
			self.opened = false;
		},
		makeCloseButton: this.options.time_out != true? false : true
	});
	this.opened = false;
	this.fade = new Fade(this.lb.box,(options.fade || {}));
};

LightboxAlert.prototype={
	isIE:(typeof window.ActiveXObject != 'undefined'),
	open:function(callback){
		var self = this;
		
		if(typeof callback == 'function'){
			callback();
		}
		
		if(this.opened){ 
			this.startTimer();
			return false; 
		}
		
		this.opened = true;
		
		this.lb.show();
		
		if(this.isIE){//no fading for IE
			this.startTimer();
			return;
		}
		
		this.fade.hide();
		
		this.fade.effect.options.onComplete=function(){
			self.startTimer.apply(self);
		};
		
		this.fade.fadeIn();
	},
	close:function(){
		this.opened = false;
		clearTimeout(this.timer);
		
		var self = this;
		if(this.isIE){
			self.options.onComplete();
			this.lb.hide();
			return;
		}
		
		this.fade.effect.options.onComplete=function(){
			self.lb.hide();
			self.options.onComplete();
		};
		
		this.fade.fadeOut();
		
	},
	startTimer:function(){
		clearTimeout(this.timer);
		if ( this.options.time_out ) {
			var self = this;
			this.timer = setTimeout(function(){self.close.apply(self);},this.options.duration);
		}
	}
};

