var TextBox = Class.create();

TextBox.prototype = {
	
	/*
	 * Initialize Phase - initialze()
	 * 1.) activate() - Add click functionality to certain <a> tags on the page
	 *
	 * Open Phase - open()
	 * 1.) hideSelects() - select field will screw with LightText, so hide them
	 * 2.) hideFlash() - flash will screw with LightText, so hide it
	 * 3.) addMarkup() - write the textbox html
	 * 4.) loadContent() - load the content
	 * 5.) showContent() - show the content then display the close and print buttons
	 *
	 * Close Phase - close()
	 * 1.) removeMarkup() - remove all the textbox html
	*/
	 
	animSpeed: 0.4,
	overlayOpacity: 0.8,
	minOpacity: 0.0,
	maxOpacity: 1.0,
	
	linkToLoad: null,
	ignore: false, // if yes, ignore textbox and open in a popup
	popupName: 'textbox',
	
	contentID: 'tbContentOuter',
	group: 'textbox',
	style: 'grow', // options are: grow, appear, instant
	hasClose: true,
	hasPrint: true,
	hasBackground: false,
	/* if you change contentHeight or contentWidth you will need to change it in the css as well */
	contentWidth: 600,
	contentHeight: 450,
	
	anchors: null,
	
	overlay: null,
	contentOuter: null,
	contentInner: null,
	btnClose: null,
	btnPrint: null,
	body: null,
	
	scrollRef: null, // only used as a reference to a bound event listener
	resizeRef: null, // only used as a reference to a bound event listener
	
	
	
	// initializes links on the page to use textbox, this should always be run first!
	// group, link, id, style, close, print, width, height, ignore
	//initialize: function(g, l, id, s, c, p, w, h, i) {
	initialize: function() {
		this.group = typeof arguments[0] != 'undefined' ? arguments[0] : this.group;
		this.linkToLoad = typeof arguments[1] != 'undefined' ? arguments[1] : this.linkToLoad;
		this.contentID = typeof arguments[2] != 'undefined' ? arguments[2] : this.contentID;
		this.style = typeof arguments[3] != 'undefined' ? arguments[3] : this.style;
		this.hasClose = typeof arguments[4] != 'undefined' ? arguments[4] : this.hasClose;
		this.hasPrint = typeof arguments[5] != 'undefined' ? arguments[5] : this.hasPrint;
		this.contentWidth = typeof arguments[6] != 'undefined' ? arguments[6] : this.contentWidth;
		this.contentHeight = typeof arguments[7] != 'undefined' ? arguments[7] : this.contentHeight;
		this.ignore = typeof arguments[8] != 'undefined' ? arguments[8] : this.ignore;
		
		if(!this.linkToLoad) this.activate();
		else this.open();
	},
	
	
	
	// opens the textbox
	open: function() {
		if(!this.ignore) {
			
			this.hideSelects();
			this.hideFlash();
			
			this.addMarkup();	// add the html
			
			// position the content div
			this.centerContent();
			
			// size the overlay to the size of the viewport
			var dims = this.getViewportDimensions();
			this.overlay.setStyle({'height': dims.height + 'px', 'width': dims.width + 'px', 'top': dims.vOffset + 'px', 'left': dims.hOffset + 'px'});
			
			// listen for a viewport scroll
			this.scrollRef = this.scrollOverlay.bindAsEventListener(this);
			Event.observe(window, 'scroll', this.scrollRef, false);
			
			// listen for a viewport resize
			this.resizeRef = this.resizeOverlay.bindAsEventListener(this);
			Event.observe(window, 'resize', this.resizeRef, false);
			
			// fade in the overlay
			new Effect.Appear(this.overlay, { duration: this.animSpeed, from: this.minOpacity, to: this.overlayOpacity, queue: 'end' });
			
			// fade in the content box then load the content
			if(!this.linkToLoad) new Effect.Appear(this.contentOuter, { duration: this.animSpeed, from: this.minOpacity, to: this.maxOpacity, queue: 'end', afterFinish: this.loadContent.bind(this, arguments[1])});
			else new Effect.Appear(this.contentOuter, { duration: this.animSpeed, from: this.minOpacity, to: this.maxOpacity, queue: 'end', afterFinish: this.loadContent.bind(this, this.linkToLoad)});
		
		} else {
			
			var url;
			
			if(!this.linkToLoad) url = arguments[1];
			else url = this.linkToLoad;
			
			var newWindow = window.open(url + '?bypass=', this.popupName, 'height=' + this.contentHeight + ',width=' + this.contentWidth + ',resizable=yes');
			if(window.focus) newWindow.focus();
			
		}
	},
	
	
	
	// closes the textbox
	close: function() {
		// clean up the html
		this.removeMarkup();
		
		// stop and unbind the scroll listener
		Event.stopObserving(window, 'scroll', this.scrollRef, false);
		this.scrollRef = null;
		
		// stop and unbind the resize listener
		Event.stopObserving(window, 'resize', this.resizeRef, false);
		this.resizeRef = null;
		
		this.showSelects();
		this.showFlash();
	},
	
	
	
	// moves the overlay when the viewport is scrolled
	scrollOverlay: function() {
		var dims = this.getViewportDimensions();
		this.overlay.setStyle({'left': dims.hOffset + 'px', 'top': dims.vOffset + 'px'});
	},
	
	
	
	// resizes the overlay when the viewport is resized
	resizeOverlay: function() {
		var dims = this.getViewportDimensions();
		this.overlay.setStyle({'width': dims.width + 'px', 'height' : dims.height + 'px', 'left': dims.hOffset + 'px', 'top': dims.vOffset + 'px'});
	},
	
	
	
	// cleans up textbox's mess
	removeMarkup: function() {
		this.body.removeChild(this.overlay);
		this.body.removeChild(this.contentOuter);
		if(this.hasClose) {this.body.removeChild(this.btnClose);}
		if(this.hasPrint) {this.body.removeChild(this.btnPrint);}
	},
	
	
	
	// loads content into the hidden inner content div
	loadContent: function(href) {
		switch(this.style) {
			case 'grow': new Ajax.Updater(this.contentInner, href, {evalScripts: true, onComplete: this.growContent.bind(this)}); break;
			case 'appear': new Ajax.Updater(this.contentInner, href, {evalScripts: true, onComplete: this.appearContentBegin.bind(this)}); break;
			case 'instant': new Ajax.Updater(this.contentInner, href, {evalScripts: true, onComplete: this.instantContentBegin.bind(this)}); break;
		}
	},
	
	
	
	instantContentBegin: function() {
		// fade out the loading box
		new Effect.Appear(this.contentOuter, { duration: this.animSpeed, to: this.minOpacity, queue: 'end', afterFinish: this.instantContentEnd.bind(this) });
	},
	
	
	
	instantContentEnd: function() {
		// remove the outer content background styles
		this.contentOuter.setStyle({background: 'none'});
		
		// resize the outer content box
		this.contentOuter.setStyle({width: this.contentWidth + 'px', height: this.contentHeight + 'px'});
		
		// center the outer content box
		this.centerContent();
		
		// make sure the content will be visible
		this.showContent();
		
		//this.contentOuter.show();
		new Effect.Appear(this.contentOuter, { duration: 0, to: this.maxOpacity, queue: 'end' });
	},
	
	
	
	growContent: function() {
		var center = this.centerContent.bind(this);
		var finish = this.showContent.bind(this);
		
		var xScale = (this.contentWidth / this.contentOuter.getWidth()) * 100;
		var yScale = (this.contentHeight / this.contentOuter.getHeight()) * 100;
		
		this.contentOuter.setStyle({'background-image': 'none'});
		
		new Effect.Scale(this.contentOuter, xScale, {scaleY: false, scaleContent: false, scaleFromCenter: false, duration: this.animSpeed * 1.5, queue: 'end', afterUpdate: center});
		new Effect.Scale(this.contentOuter, yScale, {scaleX: false, scaleContent: false, scaleFromCenter: false, duration: this.animSpeed * 1.5, queue: 'end', afterUpdate: center, afterFinish: finish});
	},
	
	
	
	appearContentBegin: function() {
		// fade out the loading box
		new Effect.Appear(this.contentOuter, { duration: this.animSpeed, to: this.minOpacity, queue: 'end', afterFinish: this.appearContentEnd.bind(this) });
	},
	
	
	
	appearContentEnd: function() {
		// remove the outer content background styles
		if(!this.hasBackground) this.contentOuter.setStyle({background: 'none'});
		
		// resize the outer content box
		this.contentOuter.setStyle({width: this.contentWidth + 'px', height: this.contentHeight + 'px'});
		
		// center the outer content box
		this.centerContent();
		
		// make sure the content will be visible
		this.showContent();
		
		// fade in the content
		new Effect.Appear(this.contentOuter, { duration: this.animSpeed, from: this.minOpacity, to: this.maxOpacity, queue: 'end'});
	},
	
	
	
	// centers and positions the contentOuter div relative to the viewport
	centerContent: function() {
		var dims = this.getViewportDimensions();
		this.contentOuter.setStyle({'left': ((dims.width / 2) - (this.contentOuter.getWidth() / 2)) + 'px', 'top': ((dims.height / 2) - (this.contentOuter.getHeight() / 2) + dims.vOffset) + 'px'});
	},
	
	
	
	showContent: function() {
		this.contentInner.show();
		
		// position and move the close button
		if(this.hasClose) {
			var left = this.cleanStyle(this.contentOuter.getStyle('left')) + this.contentOuter.getWidth() - this.btnClose.getWidth();
			var top = this.cleanStyle(this.contentOuter.getStyle('top'));
			this.btnClose.setStyle({'left': left + 'px', 'top': top + 'px'});
			this.btnClose.show();
			new Effect.Move(this.btnClose, { duration: this.animSpeed, x: left, y: (top - this.btnClose.getHeight()), mode: 'absolute', queue: 'end' });
		}
		
		// position and move the print button
		if(this.hasPrint) {
			left -= this.btnPrint.getWidth() + 2;
			this.btnPrint.setStyle({'left': left + 'px', 'top': top + 'px'});
			this.btnPrint.show();
			new Effect.Move(this.btnPrint, { duration: this.animSpeed, x: left, y: (top - this.btnPrint.getHeight()), mode: 'absolute', queue: 'end' });
		}
	},
	
	
	
	// toggle functions for flash content
	hideFlash: function() {
		$A(document.getElementsByTagName("object")).each(function(s) {Element.extend(s).setStyle({visibility: 'hidden'})});
		$A(document.getElementsByTagName("embed")).each(function(s) {Element.extend(s).setStyle({visibility: 'hidden'})});
	},
	showFlash: function() {
		$A(document.getElementsByTagName("object")).each(function(s) {Element.extend(s).setStyle({visibility: 'visible'})});
		$A(document.getElementsByTagName("embed")).each(function(s) {sElement.extend(s).setStyle({visibility: 'visible'})});
	},
	
	
	
	// toggle functions for select form fields
	hideSelects: function() {$A(document.getElementsByTagName("select")).each(function(s) {Element.extend(s).setStyle({visibility: 'hidden'})});},
	showSelects: function() {$A(document.getElementsByTagName("select")).each(function(s) {Element.extend(s).setStyle({visibility: 'visible'})});},
	
	
	
	// activates the links on the page
	activate: function() {
		// activate the links on the page
		var func = this.activateAnchor.bind(this);
		this.anchors = $A(document.getElementsByTagName('a'));
		this.anchors.each(func);
	},
	
	
	
	activateAnchor: function(anchor) {
		var rel = String(Element.extend(anchor).readAttribute('rel'));
		if (anchor.readAttribute('href') && (rel.toLowerCase().match(String(this.group)))) {
			Event.observe(anchor, 'click', this.open.bindAsEventListener(this, anchor.readAttribute('href')), false);
			anchor.onclick = function(){return false;};
		}
	},
	
	
	
	// adds all necessary html to the page
	addMarkup: function() {
		this.body = document.getElementsByTagName('body')[0];
		
		// the overlay
		this.overlay = document.createElement('div');
		Element.extend(this.overlay);
		this.overlay.setAttribute('id', 'tbOverlay');
		this.overlay.hide();
		
		// the outer content box
		this.contentOuter = document.createElement('div');
		Element.extend(this.contentOuter);
		this.contentOuter.setAttribute('id', this.contentID);
		this.contentOuter.hide();
		
		// the inner content box
		this.contentInner = document.createElement('div');
		Element.extend(this.contentInner);
		this.contentInner.setAttribute('id', 'tbContentInner');
		this.contentInner.hide();
		
		// append the high level stuff to the body
		this.body.appendChild(this.overlay);
		this.body.appendChild(this.contentOuter);
		this.contentOuter.appendChild(this.contentInner);
		
		// activate the overlay
		Event.observe(this.overlay, 'click', this.close.bindAsEventListener(this), false);
		
		// add the close button
		if(this.hasClose) {
			// create it
			this.btnClose = document.createElement('div');
			Element.extend(this.btnClose);
			this.btnClose.setAttribute('id', 'tbClose');
			this.btnClose.hide();
			
			// attach it
			this.body.appendChild(this.btnClose);
			
			// activate it
			Event.observe(this.btnClose, 'click', this.close.bindAsEventListener(this), false);
		}
		
		// add the print button
		if(this.hasPrint) {
			// create it
			this.btnPrint = document.createElement('div');
			Element.extend(this.btnPrint);
			this.btnPrint.setAttribute('id', 'tbPrint');
			this.btnPrint.hide();
			
			// attach it
			this.body.appendChild(this.btnPrint);
			
			// activate it
			Event.observe(this.btnPrint, 'click', this.print.bindAsEventListener(this), false);
		}
	},
	
	
	
	print: function() {window.print();},
	
	
	
	// removes the trailing 2 characters from a string (i.e. 190px becomes 190)
	cleanStyle: function(str) {return str != null ? Number(str.substr(0, str.length - 2)) : 0 ;},

	
	
	// returns the height, width, and current vertical scroll position of the viewport
	getViewportDimensions: function() {
		var vpWidth, vpHeight, vpVOffset, vpHOffset;
		
		if(document.body.clientWidth) {vpWidth = document.body.clientWidth;}
		if(document.documentElement.clientWidth) {vpWidth = document.documentElement.clientWidth;}
		
		if(document.body.clientHeight) {vpHeight = document.body.clientHeight;}
		if(document.documentElement.clientHeight) {vpHeight = document.documentElement.clientHeight;}
		
		if(document.all) {
			if(!document.documentElement.scrollTop) {vpVOffset = document.body.scrollTop;}
			else {vpVOffset = document.documentElement.scrollTop;}
			if(!document.documentElement.scrollLeft) {vpHOffset = document.body.scrollLeft;}
			else {vpHOffset = document.documentElement.scrollLeft;}
		} else {
			vpVOffset = window.pageYOffset;
			vpHOffset = window.pageXOffset;
		}
		
		return {width: vpWidth, height: vpHeight, vOffset: vpVOffset, hOffset: vpHOffset};
	}
}
