/**
 * g3.tools.js
 * @author G3 Systems, Inc.
 * @copyright G3 Systems, Inc.
 * @version 20110202
 * @package g3
 */

var SCRIPT_PATH = getScriptPath('g3.tools.js');

/**
 * Include a JavaScript file by appending a <script> element to the <head> element.
 * @param string fileName Name of the JavaScript file to include
 */
function include_js(fileName) {
	
	var script = document.createElement('script');
	script.setAttribute('src', SCRIPT_PATH + fileName);
	script.setAttribute('type', 'text/javascript');
	
	var head = document.getElementsByTagName('head')[0];
	head.appendChild(script);
}

/**
 * Get the base URL of a script file by searching <script> elements for a match.
 * @param string scriptName Name of script file
 */
function getScriptPath(scriptName) {
	var scripts = document.getElementsByTagName('script');
	var src = null;
	for(var i=0; i<scripts.length; i++) {
		if(src = scripts[i].getAttribute('src')) {
			var idx = src.lastIndexOf(scriptName);
			if(idx > 0) {
				return src.substring(0, idx);
			}
		}
	}
	return '';
}

/**
 * Cross-browser wrapper for getElementsByClassName()
 * @param string className Class name
 * @param Object node Element in which to search
 * @return Array Array of elements with matching class name
 */
function getElementsByClassName(className, node) {
	
	node = node || document;
	
	if(node.getElementsByClassName) {
		
		return node.getElementsByClassName(className);
	
	}else {
		var matches = new Array();
		
		for(var i=0; i<node.childNodes.length; i++) {
			
			if(node.childNodes[i].className) {
				
				var classes = node.childNodes[i].className.split(' ');
				
				for(var j=0; j<classes.length; j++) {
					
					if(classes[j] == className) {
						
						matches[matches.length] = node.childNodes[i];
					}
				}
			}
			
			if(node.childNodes[i].childNodes.length > 0) {
				
				matches = matches.concat(getElementsByClassName(className, node.childNodes[i]));
			}
		}
		
		return matches;
	}
}

/**
 * Create a tree view of an array.
 * @param Array Array to view
 * @param Integer level Used internally to calculate tabs
 * @return String Tree view of array
 */
function sprint_r(array, level) {
	
	level = level || 1;
	
	var tabs = '';
	for(var i=0; i<level; i++) {
		tabs += '\t';
	}
	
	var string = 'array(';
	
	for(var i=0; i<array.length; i++) {
		
		string += '\n' + tabs + '[' + i + ']' + ' = ';
		
		if(array[i].length > 0) {
			 string += sprint_r(array[i], level + 1);
		}else {
			string += '"' + String(array[i]) + '"';
		}
	}
	
	string += '\n' + tabs + ')';
	
	return string;
}

/**
 * @link http://simonwillison.net/2006/Jan/20/escape/
 */
function regex_escape(text) {
	
	if (!arguments.callee.sRE) {
		
		var specials = ['/', '.', '*', '+', '?', '|','(', ')', '[', ']', '{', '}', '\\'];
		arguments.callee.sRE = new RegExp('(\\' + specials.join('|\\') + ')', 'g');
	}
	
	return text.replace(arguments.callee.sRE, '\\$1');
}

/**
 * Adapted from script by Carnix
 * @link http://www.ozzu.com/programming-forum/javascript-sleep-function-t66049.html
 */
function sleep(seconds) {
	
	var duration = seconds * 1000;
	var asleep = true;
	var now = new Date();
	var start = now.getTime();
	var current = 0;
	
	while(asleep) {
		
		now = new Date();
		current = now.getTime();
		asleep = ((current - start) > duration) ? false : true;
	}
}

/**
 * Open select page content in a new window and print.
 * @param string className class name of printable elements (defaults to 'printable')
 * @param string cssFile path to optional CSS file relative to SCRIPT_PATH (defaults to '../css/printable.css')
 */
function printerFriendly(className, cssFile) {

	className = className ? className : 'printable';
	cssFile = cssFile ? cssFile : '../css/printable.css';
	cssFile = SCRIPT_PATH + cssFile;
	
	printableWindow = window.open("","Print","scrollbars,left=30px,top=40px,width=670px,height=520px");
	printableWindow.document.write(
		'<?xml version="1.0" standalone="yes"?>'
		+ '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">'
		+ '<html xmlns="http://www.w3.org/1999/xhtml">'
		+ '  <head>'
		+ '    <title>' + document.title + '</title>'
		+ '    <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />'
		+ '    <meta http-equiv="Content-Style-Type" content="text/css" />'
		+ '    <link href="' + cssFile + '" rel="stylesheet" type="text/css" media="all" />'
		+ '  </head>'
		+ '  <body></body>'
		+ '</html>'
	);
	
	var content = printableWindow.document.createElement('div');
	var elems = getElementsByClassName(className);
	
	if(elems) {
		for(var i=0; i<elems.length; i++) {
			content.appendChild(printableWindow.document.importNode(elems[i], true));
		}
	}
	
	printableWindow.document.getElementsByTagName('body')[0].appendChild(content);
	printableWindow.print();
}

/**
 * Get the source element, event type, and button/key pressed in a
 * cross-browser-friendly manner and pass them to the callback function.
 * @param Event e DOM Event object
 * @param pointer callback function(Element source, string type, int key)
 */
function handleEvent(e, callback) {
	
	if(callback) {
		
		e = e ? e : window.event;
		var key = e.button ? e.button : (e.keyCode ? e.keyCode : (e.which ? e.which : null));
		var source = e.target ? e.target : (e.srcElement ? e.srcElement : null);
		source = (source.nodeType == 3) ? source.parentNode : source;
		
		if(callback(source, e.type, key)) {
			e.cancelBubble = true;
			if(e.stopPropagation) e.stopPropagation();
		}
	}
	
	return true;
}

/**
 * Submit a form when either the return or enter key is pressed.
 * Use as a callback with handleEvent().
 * @param Element source event trigger
 * @param string type event type
 * @param int key keycode
 */
function onEnterSubmit(source, type, key) {
	
	if(source) {
		
		switch(key) {
			case 13: // return
			case 14: // enter
				if(source.form) {
					source.form.submit();
					return true;
				}
				break;
			default:
				break;
		}
	}
	
	return false;
}
