/* Array indexOf method */
if (!Array.prototype.indexOf) {
	Array.prototype.indexOf = function(val) {
		for (var i = 0; i < this.length; i++) {
			if (val == this[i]) {
				return i;
			}
		}
		return -1;
	};
}

/* String Prototype */
String.prototype.ltrim = function() {
	return this.replace(/^\s\s*/, '');
}

String.prototype.rtrim = function() {
	var ws = /\s/,
		i = this.length;
	while (ws.test(this.charAt(--i)));
	return this.slice(0, i + 1);
}

String.prototype.trim = function() {
	return this.ltrim().rtrim();
}

/* Log */
window.alert = function(msg) {
	var req;
	var elog = getSiteRoot() + "ELog.aspx";
	var msg = "emsg=" + encodeURIComponent(msg);
	msg += "&surl=" + encodeURIComponent(window.location);
	if (window.XMLHttpRequest) {
		req = new XMLHttpRequest();
		if (req.overrideMimeType)
			req.overrideMimeType('txt/xml');
	} else if (window.ActiveXObject) {
		try {
			req = new ActiveXObject("Msxml2.XMLHTTP");
		}
		catch (e) {
			try {
				req = new ActiveXObject("Microsoft.XMLHTTP");
			}
			catch (e) {}		
		}
	}
	
	if (!req)
		return false;
	
	req.onreadystatechange = function() {};
	req.open('POST', elog, true);
	req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
	req.send(msg);
}

function getSiteRoot() {
	var url = window.location.protocol + '//' + window.location.host,
		path = '/Site';
	if (window.location.pathname.indexOf(path) == 0) {
		url += path
	}
	return url + '/';
}

/* Page Load Event Manager */
function addLoadEvent(func) {
  var oldonload = window.onload;
  if (typeof window.onload != 'function') {
    window.onload = func;
  } else {
    window.onload = function() {
      if (oldonload) {
        oldonload();
      }
      func();
    }
  }
}

/* DOM Loaded Event Manager */
function addDOMLoadEvent(func) {
   if (!window.__load_events) {
      var init = function () {
          // quit if this function has already been called
          if (arguments.callee.done) return;
      
          // flag this function so we don't do the same thing twice
          arguments.callee.done = true;
      
          // kill the timer
          if (window.__load_timer) {
              clearInterval(window.__load_timer);
              window.__load_timer = null;
          }
          
          // execute each function in the stack in the order they were added
          for (var i=0;i < window.__load_events.length;i++) {
              window.__load_events[i]();
          }
          window.__load_events = null;
      };
   
      // for Mozilla/Opera9
      if (document.addEventListener) {
          document.addEventListener("DOMContentLoaded", init, false);
      }
      
      // for Internet Explorer
      /*@cc_on @*/
      /*@if (@_win32)
          document.write("<scr"+"ipt id=__ie_onload defer src=//0><\/scr"+"ipt>");
          var script = document.getElementById("__ie_onload");
          script.onreadystatechange = function() {
              if (this.readyState == "complete") {
                  init(); // call the onload handler
              }
          };
      /*@end @*/
      
      // for Safari
      if (/WebKit/i.test(navigator.userAgent)) { // sniff
          window.__load_timer = setInterval(function() {
              if (/loaded|complete/.test(document.readyState)) {
                  init(); // call the onload handler
              }
          }, 10);
      }
      
      // for other browsers
      window.onload = init;
      
      // create event function stack
      window.__load_events = [];
   }
   
   // add function to event stack
   window.__load_events.push(func);
}


/* Form Submit Event Manager */
function addFormOnSubmit(form, func) {
	form = checkElement(form);
	var oldfsub = form.onsubmit;
	if (typeof form.onsubmit != 'function') {
	form.onsubmit = func;
	} else {
		form.onsubmit = function() {
		if (oldfsub) {
			oldfsub();
		}
		return func();
		}
	}
}

//Event Handler
function addEvent(element, type, handler) {
	//console.group('Function: addEvent');
	//console.info('Parameters:\nelement: ' + element + '\ntype: ' + type + '\nhandler: ' + handler);
	//console.log(element);
	element = checkElement(element);
	//console.log(element);
	if (typeof element == "undefined" || !element) {
		//console.log('No Element defined');
		//console.groupEnd();
		return false;
	}
	if (element.addEventListener) {
		element.addEventListener(type, handler, false);
	} else {
		// assign each event handler a unique ID
		if (!handler.$$guid) handler.$$guid = addEvent.guid++;
		// create a hash table of event types for the element
		if (!element.events) element.events = {};
		// create a hash table of event handlers for each element/event pair
		var handlers = element.events[type];
		if (!handlers) {
			handlers = element.events[type] = {};
			// store the existing event handler (if there is one)
			if (element["on" + type]) {
				handlers[0] = element["on" + type];
			}
		}
		// store the event handler in the hash table
		handlers[handler.$$guid] = handler;
		// assign a global event handler to do all the work
		element["on" + type] = handleEvent;
	}
	//console.groupEnd();
}
// a counter used to create unique IDs
addEvent.guid = 1;

function removeEvent(element, type, handler) {
	if (element.removeEventListener) {
		element.removeEventListener(type, handler, false);
	} else {
		// delete the event handler from the hash table
		if (element.events && element.events[type]) {
			delete element.events[type][handler.$$guid];
		}
	}
};

function handleEvent(event) {
	var returnValue = true;
	// grab the event object (IE uses a global event object)
	event = event || fixEvent(((this.ownerDocument || this.document || this).parentWindow || window).event);
	// get a reference to the hash table of event handlers
	var handlers = this.events[event.type];
	// execute each event handler
	for (var i in handlers) {
		this.$$handleEvent = handlers[i];
		if (this.$$handleEvent(event) === false) {
			returnValue = false;
		}
	}
	return returnValue;
};

function fixEvent(event) {
	// add W3C standard event methods
	event.preventDefault = fixEvent.preventDefault;
	event.stopPropagation = fixEvent.stopPropagation;
	return event;
};
fixEvent.preventDefault = function() {
	this.returnValue = false;
};
fixEvent.stopPropagation = function() {
	this.cancelBubble = true;
};

/*
	parseUri 1.2.1
	(c) 2007 Steven Levithan <stevenlevithan.com>
	MIT License
*/

function parseUri (str) {
	var	o   = parseUri.options,
		m   = o.parser[o.strictMode ? "strict" : "loose"].exec(str),
		uri = {},
		i   = 14;

	while (i--) uri[o.key[i]] = m[i] || "";

	uri[o.q.name] = {};
	uri[o.key[12]].replace(o.q.parser, function ($0, $1, $2) {
		if ($1) uri[o.q.name][$1] = $2;
	});

	return uri;
};

parseUri.options = {
	strictMode: false,
	key: ["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"],
	q:   {
		name:   "queryKey",
		parser: /(?:^|&)([^&=]*)=?([^&]*)/g
	},
	parser: {
		strict: /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/,
		loose:  /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/
	}
};

function getElementsByClassName(cssClass, tag, parentEl) {
	//Setup tag
	tag = tag || '*';
	//If no parent element is set, document as parent
	if (typeof parentEl == 'string')
		parentEl = checkElement(parentEl);
	parentEl = parentEl || document;
	//Get all Elements under parent element
	var els = parentEl.getElementsByTagName(tag);
	//Loop through elements and find elements with matching class names
	var matched = new Array(),
			currEl;
	var re = new RegExp('(^|\\s)' + cssClass + '($|\\s)');
	for (var x = 0; x < els.length; x++) {
		currEl = els[x];
		if (re.test(currEl.className))
			matched.push(currEl);
	}
	return matched;
}

function getStyle(oElm, strCssRule){
    var strValue = "";
    if(document.defaultView && document.defaultView.getComputedStyle){
        strValue = document.defaultView.getComputedStyle(oElm, "").getPropertyValue(strCssRule);
    }
    else if(oElm.currentStyle){
        strCssRule = strCssRule.replace(/\-(\w)/g, function (strMatch, p1){
            return p1.toUpperCase();
        });
        strValue = oElm.currentStyle[strCssRule];
    }
    return strValue;
}

function isset(obj, type) {
	//console.info('Function: %o \nobj: %o', arguments.callee, obj);
	if (typeof obj == 'undefined' || obj == null)
		return false;
	return true;
}

/* Checks if an object has a property
 * Parameters:
 * 	obj (Object)		: Object to evaluate
 * 	prop (String/Array)	: Name (or Array of Names) of property/properties to evaluate
 * 	
 * Return value: Boolean
 * 	TRUE	: If all requested properties exist in object
 * 	FALSE	: If at least one requested property does NOT exist in object      
 */
function hasProp(obj, prop, type, flag) {
	var ret = false,
		iProp;
	try {
		if (!isset(obj) || !isset(prop))
			return false;
		//Check if prop is an Array
		if (!(prop instanceof Array))
			prop = [prop];
		if (typeof obj == 'object') {
			for (var x = 0; x < prop.length; x++) {
				iProp = prop[x];
				if (iProp in obj) {
					ret = true;
					if (isset(type) && !(obj[iProp] instanceof type))
						ret = false;
				}
				if (!ret)
					break;
			}
		}
	}
	catch(e) {
		ret = false;
	}
	return ret;
}

//Checks if item is function
function isFunction(o) {
	return typeof o == 'function';
}

//Checks if item is a String
function isString(s) {
	return typeof s == 'string';
}

//Checks an object's property for the existence of a value
function objArrayIndexOf(arr, prop, searchValue) {
	//console.group('Function: %o', arguments.callee);
	var tempArr = [];
	//load property value into temporary array
	for (var x = 0; x < arr.length; x++) {
		if (prop in arr[x])
			tempArr.push(arr[x][prop]);
	}
	//console.warn('Array: %o', tempArr);
	//console.groupEnd();
	return tempArr.indexOf(searchValue);
}


/*Element Height Equalizer
 * Element IDs are listed as pairs
 * If an element is nested (and the height of the parent element should be considered),
 *	the parent element's ID should also be provided
 * Elements are provided as parameters to the function
 * Elements are separated by a ',' character
 * Parent elements are attached to the child element with a '|' character
 *
 * Example: eqH('elementOne,elementTwo|parentTwo');
 */
function eqH_ext() {
	//console.group('Function: eqH_ext');
	//console.info('Parameters:');
	//console.log(arguments);
	//Cancel processing if no arguments were passed
	if (arguments.length < 1)
		return false;
	//Process element groups
	//console.group('Processing Element Groups');
	var splitArr, elSplit, argIsString;
	var adjustHeightElements = new Array('padding-top', 'padding-bottom', 'border-top-width', 'border-bottom-width');
	for (i = 0; i < arguments.length; i++) {
		argIsString = (typeof arguments[i] == "string") ? true : false;
		//console.group('Argument: ' + (i + 1) + ' of ' + arguments.length);
		//console.info('Argument is a string: %s', argIsString);
		var nestArr = new Array();
		var elHeights = new Array();
		var adjustHeight;
		var mx = {val: -1, el: ""};
		//Remove all spaces from argument
		if (argIsString) {
			//console.log('Original Argument: %s', arguments[i]);
			arguments[i] = arguments[i].replace(/ /g, '');
			//console.log('Trimmed Argument: %s', arguments[i]);
		}
		//Split elements
		splitArr = (argIsString) ? arguments[i].split(',') : arguments[i];	
		//console.info('Split Argument %d: %o', i, arguments[i]);
		//console.info('Elements in Group: ' + splitArr.length);
		//Skip this iteration if there are not at least 2 elements
		if (splitArr.length < 2)
			continue;
		//Process Element Groups
		for (x = 0; x < splitArr.length; x++) {
			//console.group('Current Element: %o', splitArr[x]);
			splitArr[x] = {el: splitArr[x]};
			//console.log('Converted to object member: %o', splitArr[x]);
			//Get parents of elements
			if (argIsString) {
				if (splitArr[x].el.search("|") != -1) {
					elSplit = splitArr[x].el.split("|", 2);
					splitArr[x].el = elSplit[0];
					
					splitArr[x].parent = document.getElementById(elSplit[1]);
					if (null != splitArr[x].parent) {
						splitArr[x].parent.height = splitArr[x].parent.offsetHeight;
						//console.log(splitArr[x].el + ' Parent: ' + splitArr[x].parent.id + '\nHeight: ' + splitArr[x].parent.height);
						//Compare Parent Height to other elements
						if (splitArr[x].parent.height > mx.val) {
							mx.val = splitArr[x].parent.height;
							mx.el = splitArr[x].el;
						}
					}
				}
			}
			//Get height of each element
			splitArr[x].el = checkElement(splitArr[x].el)
			if (null != splitArr[x].el) {
				splitArr[x].height = splitArr[x].el.offsetHeight;
				//console.log(splitArr[x].el.id + ' Height: ' + splitArr[x].height);
			}
			//Compare Element Heights
			if (splitArr[x].height > mx.val) {
				mx.val = splitArr[x].height;
				mx.el = splitArr[x].el;
			}
			//console.log('Max Height: ' + mx.val + '\nElement: ' + mx.el.id);
			//alert('Tallest Element\n' + mx.el.id + '\nHeight: ' + mx.val + '\nCurrent Element\n' + splitArr[x].el.id + '\nHeight: ' + splitArr[x].height);
			//console.groupEnd();		
		}
		//Equalize Heights of Elements in Group
		//console.group('Compare Heights of Elements in Group');
		for (x = 0; x < splitArr.length; x++) {
			//console.group('splitArr Index: ' + x);
			////console.info('Current Element: ' + splitArr[x].el.id);
			if (splitArr[x].el != mx.el) {
				////console.log(splitArr[x].el.id + ' is smaller than ' + mx.el.id + '\nHeight: ' + splitArr[x].height + '\nMax Height: ' + mx.val);
				newH = (null != splitArr[x].parent) ? mx.val - splitArr[x].parent.height + splitArr[x].height : mx.val;
				//console.log('New height: ' + newH);			
				//Compensate for padding/borders
				adjustHeight = 0;
				for (aH = 0; aH < adjustHeightElements.length; aH++) {
					//alert(splitArr[x].el.id + '\n' + adjustHeightElements[aH] + '\n' + getStyle(splitArr[x].el, adjustHeightElements[aH]) + '\nInt: ' + parseInt(getStyle(splitArr[x].el, adjustHeightElements[aH])));
					valTemp = parseInt(getStyle(splitArr[x].el, adjustHeightElements[aH]))
					//console.log('Property: %s\nValue: %s', adjustHeightElements[aH], getStyle(splitArr[x].el, adjustHeightElements[aH]));
					adjustHeight += (valTemp > 0) ? valTemp : 0;
					//alert(adjustHeight);
				}
				//alert(splitArr[x].el.id + '\nNew Height: ' + newH + '\nAdjustment: ' + adjustHeight + '\nFinal: ' + (newH - adjustHeight).toString());
				newH -= adjustHeight;
				//alert(newH);
				//Set new height for Element
				splitArr[x].el.style.height = newH + 'px';
			}
			//console.groupEnd();
		}
		//console.groupEnd();
		//console.groupEnd(); //Argument Loop
	}
	//console.groupEnd();
	//console.groupEnd();
}

//DIV Height Equalizer
function eqH(one, two, nested) {
	//Get columns to be compared
	var c1 = document.getElementById(one);
	var c2 = document.getElementById(two);
	
	//Remove Height (if set)
	c1.style.height = "";
	c2.style.height = "";
	
	//alert('Equalizing: ' + one + '(' + c1.offsetHeight + ') and ' + two + '(' + c2.offsetHeight + ')');
	
	//alert(one + ': ' + c1.offsetHeight + '\n' + two + ': ' + c2.offsetHeight);
	
	//Determine which column is taller
	//Debug - alert(one + ": " + c1.offsetHeight + "\n" + two + ": " + c2.offsetHeight);
	if ( c1.offsetHeight == c2.offsetHeight ) {
		//Debug - alert('Column heights are equal');
		return false;
	}
	if ( c1.offsetHeight > c2.offsetHeight ) {
		mx = c1.offsetHeight;
		sm = c2;
	} else {
		mx = c2.offsetHeight;
		sm = c1;
	}
	
	//Get Border-top/bottom of smaller column
	brdTop = getStyle(sm, "border-top-width");
		//Trim Value
	brdTop = parseFloat(brdTop.substr(0, (brdTop.length - 2)));
	if ( isNaN(brdTop) ) brdTop = 0;
	brdBottom = getStyle(sm, "border-bottom-width");
		//Trim Value
	brdBottom = parseFloat(brdBottom.substr(0, (brdBottom.length - 2)));
	if ( isNaN(brdBottom) ) brdBottom = 0;
	brdWidth = brdTop + brdBottom;
	
	//Get Padding-top/bottom of smaller column
	pdTop = getStyle(sm, "padding-top");
		//Trim value
	pdTop = parseFloat(pdTop.substr(0, (pdTop.length - 2)));
	if ( isNaN(pdTop) ) pdTop = 0;
	pdBottom = getStyle(sm, "padding-bottom");
		//Trim Value
	pdBottom = parseFloat(pdBottom.substr(0, (pdBottom.length - 2)));
	if ( isNaN(pdBottom) ) pdBottom = 0;
	pdTotal = pdTop + pdBottom;
	//Debug - alert("Border size: " + brdWidth);
	mx -= (brdWidth + pdTotal);
	
	//Set shorter column to the same height as the taller column
	//alert("New height of taller column: " + mx);
	if ( typeof nested != "undefined" && (c2.offsetHeight > c1.offsetHeight) ) {
		//Debug - alert("Column 2 is taller than Column 1");
		sm = document.getElementById(nested);
		mx -= 57;
	}
		
	//Debug - alert("New Height: " + mx);
	sm.style.height = mx + 'px';
}

function resetFH() {
	//console.group('Function: resetFH()');
	//Quickly Get Height of Form
	set_height = document.getElementById('fhot_form').style.height;		
	document.getElementById('fhot_form').style.height = "";
	ff_height = document.getElementById('fhot_form').offsetHeight;
	//document.getElementById('fhot_form').style.height = set_height;
	eqH('FindHotel', 'NearbyHotels', 'fhot_form');
	//console.groupEnd(); //resetFH()
}

/* Tab Selection Handler
 * Parameters:
 * 
 * tabs (Element/String ID)			: Tabs Wrapper Element
 * container (Element/String ID)	: Parent Container Element 
 * [pre] (Object of Functions)		: (Optional) Function to execute BEFORE container's class is changed
 * 										- Member name aligns with Tab to execute function for
 * 											- Example: {tab_1: function() {alert('Tab 1 Selected');}, tab_2: function() {alert('Tab 2 Selected');}}
 * [post] (Object of Functions)		: (Optional) Function to execute AFTER container's class is changed
 * 										- Same object structure as [pre] parameter   
 *
 * Methodology:
 * - Determine which tab is selected
 * - Get ID of selected tab 
 * - Add class to container element
 * 	- Class relates to selected tab
 */
function tabManager(tabs, container, pre, post) {
 	//console.warn(arguments.callee);

	tabs = checkElement(tabs);
	//Set Container element
	var cnr = checkElement((isset(container)) ? container : document.body),
		selTab = false,
		selTabText = 'selected',
		tabName = [],
		elID,
		tabStart,
		tabPrefix = 'tab_';
		
	//Exit if Elements not valid
	if (!tabs || !cnr)
		return false;
	if (!isset(pre))
		pre = {};
	if (!isset(post))
		post = {};
	//Determine selected tab
	//Get Tab links
	var tabLinks = tabs.getElementsByTagName('a');
	//Get Selected Link
	for (var i = 0; i < tabLinks.length; i++) {	
		if (hasClass(tabLinks[i], selTabText)) {
			selTab = i;
		}
		//Get current tab's ID
		elID = (hasProp(tabLinks[i], 'id')) ? tabLinks[i].id : '';
		//Extract tab name from ID
		tabStart = elID.lastIndexOf(tabPrefix);
		tabName[i] = (tabStart != -1) ? elID.substring(tabStart) : '';
	}
	if (selTab === false)
		return false;
	var modeClassPrefix = 'mode_';
	var modeClass = modeClassPrefix + tabName[selTab];
	
	var setContainerClass = function() {
		//Remove classes set by previous actions
		for (var i = 0; i < tabLinks.length; i++) {
			if (i != selTab)
				removeClass(cnr, modeClassPrefix + tabName[i]);
		}
		addClass(cnr, modeClass);
	};
	
	var doActions = function(actType) {
		var act = eval(actType);
		if (selTab < act.length && isFunction(act[selTab]))
			act[selTab]();	
	};
	
	doActions('pre');
		
	//Add CSS class to container
	setContainerClass();
	
	//Run post actions for tab
	doActions('post');
}

/* Tab Selection Handler
 * Control: FindAHotel 
 */
function FindAHotelTabs(tabs, container) {
	//Define additional Pre/Post actions for specific tabs
	var pre = [],
		post = [];
	pre[0] = pre[1] = function() {clearStyle(container, 'height');};
	pre[2] = function() {setHeight(container)};
	
	post[2] = function() {
		var map = findMap(container);
		if (!isMap(map))
			return false;
		//Reset View
		startMap(map);
		//Resize Map
		map.checkResize();	
	};
	
	tabManager(tabs, container, pre, post);
}

//Reloads Map
function reloadMap(map, container) {
	//console.warn('Reloading Map');
	if (!isset(map) || !isMap(map))
		map = findMap(container);
	if (!isMap(map))
		return false;
	//Reset View
	startMap(map);
	//Resize Map
	map.checkResize();	
}

//Adds style property to Element
function setStyle(el, prop, val) {
	el = checkElement(el);
	if (!el || !isset(prop) || !hasProp(el, 'style') || !hasProp(el.style, prop))
		return false;
	if (!isset(val))
		val = '';
	if (el.style[prop] != val)
		el.style[prop] = val; 
}

//Removes style property from Element
function clearStyle(el, prop) {
	setStyle(el, prop);
}

//Set height of Element
function setHeight(el, val, unit) {
	el = checkElement(el);
	if (!el)
		return false;
	if (!isset(unit))
		unit = 'px';
	//If value is not set, set container to current height
	if (!isset(val)) {
		if (el.style.height != '')
			return false;
		//Get height of container
		var eH = el.offsetHeight;
		setStyle(el, 'height', eH + unit);
	}
	
	//Check Height
	//console.info('Set Height: %o \nNew OffsetHeight: %o', eH, el.offsetHeight);
	if (eH != el.offsetHeight) {
		//console.warn('Adjusting Height');
		var diff = eH - el.offsetHeight;
		//console.log('Height Difference: %o \nAdjusted Height: %o', diff, el.offsetHeight + diff);
		setStyle(el, 'height', (eH + diff) + unit);
	}
}

 
 //Displays Element
 function showIt(el, disp) {
	setVisibility(el, 1, disp);
 }
 
 //Hides Element
 function hideIt(el, disp) {
	setVisibility(el,0,disp);
 }
 
 //Set Visibility
function setVisibility(el, viz, disp) {
	var element = checkElement(el);
	if (!element)
		return false;
	var visibility = (viz == 1) ? "visible" : "hidden";
	element.style.visibility = visibility;
	if (viz == 1 && element.style.display == 'none')
		element.style.display = '';
	if (disp != undefined)
		element.style.display = disp;
}

//General Form Validation Error Checker
//Checks to see if any form validation error messages were passed and displays them
function checkError(err) {
	err.msg = checkElement(err.msg);
	err.box = checkElement(err.box);
	//alert('Message: ' + err.msg.style.visibility + '\nBox: ' + err.msg.style.display);
	if (err.msg.style.visibitlity != 'hidden' && err.msg.style.display != 'none')
		showIt(err.box, err.displayType);
	else
		hideIt(err.box, '');
}

//Checks to see if any error messages were passed and displays them
function checkErrors() {
	//Check vCountry
	vc = document.getElementById('vcountry');
	cmsg = vc.getElementsByTagName('span')[0];
 	//Check Hotel Name
 	hn = document.getElementById('vhotel');
	hmsg = hn.getElementsByTagName('span')[0];
	
	//alert('Country: ' + cmsg.style.visibility + '\nHotel Name: ' + hmsg.style.visibility);
	vc.style.display = (cmsg.style.visibility == 'visible') ? 'block' : 'none';
	hn.style.display = (hmsg.style.visibility == 'visible') ? 'block' : 'none';

	retval = ( (cmsg.style.visibility != 'hidden') || (hmsg.style.visibility != 'hidden') ) ? false : true;
	
	return retval;
};

function referFormCheck() {
	//Set Error Order
	var hasError = -1;
	var errorOrder = new Array(2, 0, 1, 3);
	//Get Error Message Elements
	re = document.getElementById('refer_errors');
	reboxes = re.getElementsByTagName('div');
	respans = re.getElementsByTagName('span');
	//Check message visibility
	for (i in errorOrder) {
		if (respans[errorOrder[i]].style.display != 'none') {
			hasError = errorOrder[i];
			reboxes[errorOrder[i]].style.display = 'block';
			break;
		}	
	}
	//Hide all other boxes
	for (i = 0; i < reboxes.length; i++) {
		if (i != hasError)
			reboxes[i].style.display = 'none';
	}
	return (hasError == -1) ? true : false;
}

function registerClick(el) {
	if (typeof(el) == 'string')
		var el = document.getElementById(el);
	lastClicked = el;
	//alert('Last Clicked: ' + lastClicked.id);
}

function userFormCheck() {
	//alert(lastClicked);
	var error_signin = document.getElementById('error_signin');
	var error_join = document.getElementById('error_join');
	var eSel;
	var eHide;
	var retVal = true;
	var msgs = new Array();
	var jmsgs = new Array();
	var note;
	//Determine which form was submitted
	switch(lastClicked) {
		case btnJoin:
			eSel = error_join;
			eHide = error_signin;
			espans = document.getElementById('Join').getElementsByTagName('span');
			for(i = 0; i < espans.length; i++) {
				if (espans[i].className == 'error_val') {
					//alert('Adding: ' + espans[i].id);
					jmsgs.push(espans[i]);
				}
			}
			break;
		case btnSignIn:
			eSel = error_signin;
			eHide = error_join;
			break;
	}
	//Hide other errors
	hideIt(eHide, 'none');
	//Show selected errors
	var msgs = eSel.getElementsByTagName('span');
	if (msgs.length > 0) {
		for (i = 0; i < msgs.length; i++) {
			if (msgs[i].style.visibility != 'hidden' && msgs[i].style.display != 'none') {
				showIt(eSel, 'block');
				retVal = false;
				break;
			}
		}
	}
	if (jmsgs.length > 0) {
		for (i = 0; i < jmsgs.length; i++) {
			if (jmsgs[i].style.visibility != 'hidden' && jmsgs[i].style.display != 'none') {
				retVal = false;
				break;
			}
		}
	}
	//alert(errorBlock.id);
	eqH('Join', 'SignIn'); eqH('Join', 'jblend'); eqH('Join', 'sblend');
	return retVal;
}

//Expand/Collapse Form Groups
function formAccordion(activator, accordion) {
	var activator = checkElement(activator);
	var accordion = checkElement(accordion);
	if (activator.checked == true)
		showIt(accordion, '');
	else
		hideIt(accordion, 'none');
}

//Checks if element is defined or is string ID of element
function checkElement(el) {
	//console.group('Function: checkElement()');
	//console.info('Parameters\nel: %s', el);
	//console.log('Element Type: %s', (typeof el));
	if (typeof el == 'string') {
		//console.groupEnd();
		return document.getElementById(el);
	} else {
		//console.groupEnd();
		return el;
	}
}

//Return Position of Selected Element
function getPos(el) {
	el = checkElement(el);
	if (el == undefined)
		return false;
	var posX = posY = 0;
	if (el.offsetParent) {
		//Get Initial Values
		posX = el.offsetLeft;
		posY = el.offsetTop;
		//Iterate until coordiates are calculated at the page-level
		while (el = el.offsetParent) {
			posX += el.offsetLeft;
			posY += el.offsetTop;
		}
		//Return coordinates as Array
		return [posX,posY];
	} else
		return false;
}

//Sets the position of an element
function setPos(el, pos) {
	el = checkElement(el);
	el.style.left = pos[0].toString() + 'px';
	el.style.top = pos[1].toString() + 'px';
}

//Registers Text Field
function regTextField(el, val) {
	el = checkElement(el);
	if (!el)
		return false;
	if (!el.value) {
		//Set Text field value
		el.value = val
		//Set onClick Event
		addEvent(el, 'focus', function() {
			if (el.value == val)
				el.value = "";
		});
	}
}

//Limit Characters allowed in Textarea
function setTextareaLimit(el, limit, msg) {
	//console.group('Function: setTextareaLimit');
	//console.info('Parameters:\nel: ' + el + "\nlimit: " + limit);
	el = checkElement(el);
	if(!el)
		return false;
	//console.log("Register onKeyUp Event for " + el.id);
	el.onkeyup = function() {
		countCharacters(el, msg, limit);
		if (el.value.length > limit)
			el.value = el.value.substr(0, limit);
	};
	
	//console.groupEnd();
}

//Gets Multi-Error Boxes
function getErrorsMulti(el, e_class) {
	//console.group('Function: getErrorsMulti()');
	//console.info('Parameters\nel: ' + el + '\ne_class: ' + e_class);
	el = checkElement(el);
	//console.log('el: ' + el);
	//Setup default parent element
	if (!el || typeof el == 'undefined') {
		//console.log('No element defined, using document object as parent');
		el = document;
	}
	//Setup class to search for
	if (typeof e_class == 'undefined') {
		//console.log('No class specified, using default class');
		e_class = 'error_multi';
		//console.log('e_class: ' + e_class);
	}
	//Setup global variables
	if (!('m_children' in window))
		m_children = new Array();
	if (!('e_boxes' in window))
		e_boxes = new Array();
	var all_boxes = el.getElementsByTagName('div');
	var watched_inputs = new Object();
	for (i = 0; i < all_boxes.length; i++) {
		//If element is a multi-box, add it to array
		if (all_boxes[i].className.indexOf(e_class) != -1) {
			e_boxes.push(all_boxes[i]);
			//Attach Array of error messages in element to element (used when checking if errors should be displayed)
			all_boxes[i].e_msgs = new Array();
			//Get error messages contained in multi-box
			//console.log('Get error messages contained in multi-box');
			m_children = all_boxes[i].getElementsByTagName('*');
			//console.dir(m_children);
			//Check if error message is attached to an input field
			//console.group('Iterate through children');
			for (x = 0; x < m_children.length; x++) {
				//console.group('Child: ' + x);
				//console.log(m_children[x].id);
				////console.log(eval(m_children[x].id));
				if("validationGroup" in m_children[x]) {
					//console.log('Validation Group: %s', m_children[x].validationGroup);
					if ("controltovalidate" in m_children[x]) {
						//console.log('Control to Validate: %s', m_children[x].controltovalidate);
						if (!(m_children[x].controltovalidate in watched_inputs)) {
							//Add input to list of watched inputs
							watched_inputs[m_children[x].controltovalidate] = "";
							//console.log('Added ' + m_children[x].controltovalidate + ' to watched list');
							//Attach event listener to input field attached to error message
							iField = checkElement(m_children[x].controltovalidate);
							if(iField) {
								//console.log('Attach Event listener to ' + m_children[x].controltovalidate);
								addEvent(iField, 'change', function() {
									//console.log('Blurred: ' + this.id);
									checkErrorsMulti();
								});
							}
						}
					}
					all_boxes[i].e_msgs.push(m_children[x]);	
				}
				//console.groupEnd(); //Child x
			}
			//console.groupEnd();
		}
	}
	//console.log('There are ' + e_boxes.length + ' multi error boxes in form');
	//console.dir(e_boxes);
	//console.groupEnd(); //getErrorsMulti()
}

//Checks if multi-error boxes should be displayed
function checkErrorsMulti() {
	//console.group('Function: checkErrorsMulti');
	var showError;
	var e_children;
	//Display Error boxes
	//console.group('Display Error Boxes');
	if (e_boxes.length > 0) {
		//console.log(e_boxes.length + ' error boxes to display');
		for (i = 0; i < e_boxes.length; i++) {
			//Reset showError (error indicator)
			showError = 0;
			//console.group('Box: ' + i + '\n Check if errors are displayed in box');
			e_children = e_boxes[i].e_msgs;
			//console.log('Box contains ' + e_children.length + ' messages');
			//console.log('Loop through messages to see if any are visible');
			for (x = 0; x < e_children.length; x++) {
				//Check if error is visible
				if (e_children[x].style.display == 'inline')
					showError = 1;
			}
			if (showError == 1) {
				e_boxes[i].style.display = 'block';
				//console.log('There are errors in this box');
			} else {
				e_boxes[i].style.display = 'none';
				//console.log('There are no errors in this box');
			}
			//console.groupEnd() //Box i
		}
	}
	//console.groupEnd(); //Display Error Boxes
	//console.groupEnd(); //checkErrorsMulti()
}

function setStatus(val, clean) {
	var sep = ' > ';
	if (isset(clean) && !!clean) {
		window.status = '';
	}
	
	if (window.status.length > 0)
		window.status += sep;
	window.status += val;
}

//Registers CC form on Page
function registerCC(ccNum, ccType, ccExpMonth, ccExpYear, fBtn, eBox) {
	//Setup CC Types
	setupCCTypes();
	//Get DOM elements from arguments
	for (var x = 0; x < arguments.length; x++)
		arguments[x] = checkElement(arguments[x]);
	//Build object of initial CC values
	var cc = {
				num: 	ccNum.value,
				type:	ccType.value
			 };
	//Add to CC/Type objects
	ccNum['init'] = cc;
	ccType['init'] = ccNum['init'];
	//Add Events to form fields

	//CC Num
	addEvent(ccNum, 'blur', function() {
		//console.info('Num blurred');
		//setStatus('Num blurred', true);
		checkCC(ccNum, ccType);
	});
	//CC Type
	addEvent(ccType, 'change', function() {
		//console.info('Type Changed');
		//setStatus('Type Changed', true);
		checkCC(ccNum, ccType);
		/*
		if (!checkCCInit(ccNum, ccType))
			checkCCType(ccNum, ccType);
		
		if (ccNum.value.length > 0) {
			if (!checkCC(ccNum, ccType))
				//console.log('Card is invalid');
			else
				//console.log('Card is valid');
		}
		*/
	});

	//Expiration Date Fields
	addEvent(ccExpMonth, 'change', function() {
		//console.log('Month Changed');
		checkCCDate(ccExpMonth, ccExpYear);
	});
	
	addEvent(ccExpYear, 'change', function() {
		//console.log('Year Changed');
		checkCCDate(ccExpMonth, ccExpYear);
	});
	/*
	//Save Button
	addEvent(fBtn, 'click', function() {
		//console.log('Button Clicked');
		if (ccNum.value.length > 0 && ccType.selectedIndex != 0) {
			if (!checkCC(ccNum, ccType)) {
				//console.log('Card is invalid');
			} else
				//console.log('Card is valid');
		}
		return false;
	});
	*/
	//Form Submission
	var theform = checkElement('form1');
	theform.onsubmit =  function() {
		//setStatus('Form Submitted', true);
		var ret = true;
		//console.log('Form submitted');
		if (ccNum.value.length > 0 && ccType.selectedIndex != 0) {
			if (!checkCC(ccNum, ccType)) {
				//console.log('Card is invalid');
				ret = false;
			} 
			if (!checkCCDate(ccExpMonth, ccExpYear)) {
				ret = false;
			}
		}
		return ret;
	};
} //END registerCC

//CC Types Setup
function setupCCTypes() {
	ccTypes = {
				AX: {length: 15, prefix: "1-3,34,37"},
				VI: {length: "13,16", prefix: "4"},
				MC: {length: 16, prefix: "51-55"},
				DC: {length: 14, prefix: "300-305,36,38"},
				DS: {length: 16, prefix: "6011"}
				}
} //END setupCCTypes

//Master function to set validator status
function setErrorStatus(el, eType, eStatus) {
	//conFunc(arguments);
	var disp = 'none';
	if (isset(eStatus) && !eStatus) {
		disp = '';
	}
	//Define validator types
	var eTypes = {
				 required:	'valr',
				 pattern:	'valx'
				 }
	if (isString(eType) && hasProp(el, 'Validators') && hasProp(eTypes, eType)) {
		//Iterate through validators until requested type is found
		var x = 0;
		for (x; x < el.Validators.length; x++) {
			//Check ID of validator
			//console.log('%o : %o', x, el.Validators[x].id);
			if (el.Validators[x].id.indexOf('_' + eTypes[eType]) != -1) {
				//console.log('Validator Found\n', el.Validators[x]);
				//console.log('Setting Values:\nisValid: %o \nstyle.display: %o', eStatus, disp);
				//Display Validator
				setTimeout(function() {
				el.Validators[x].isvalid = eStatus;
				el.Validators[x].enabled = true;
				ValidatorUpdateDisplay(el.Validators[x]);
				//el.Validators[x].style.display = disp;
				}, 1);
				break;
			}
		}
	}
	//conFuncEnd();
}

//Displays selected error message for element
function showError(el, eType) {
	//conFunc(arguments);
	setErrorStatus(el, eType, false);
	//conFuncEnd();
}

//Hides error message
function hideError(el, eType) {
	setErrorStatus(el, eType, true);
}

//Checks CC Length (based on selected CC Type)
function checkCCLength(ccNum, ccType) {
	//conFunc(arguments);
	var ccLen = 0,
		ccNumVal = ccNum.value;
	//Length
	//console.log('Length\nNum: %s\nType: %s', ccNumVal.toString().length, ccType.length);
	//Check if multiple lengths are possible
	ccType.length = ccType.length.toString().split(',');
	for (var x = 0; x < ccType.length.length; x++) {
		if (ccNumVal.length == ccType.length[x]) {
			ccLen = 1;
			break;
		}
	}
	//conFuncEnd();
	return ccLen;	
}

//Checks CC Prefix (based on selected CC Type)
function checkCCPrefix(ccNum, ccType) {
	//conFunc(arguments);
	var prefix,
		preMatch = false,
		rStart,
		rEnd;
	//Prefix
	//Check for multiple prefixes
	//console.log('Prefix: %s', ccType.prefix);
	ccType.prefix = ccType.prefix.toString().split(',');
	//console.log('New Prefix: %o', ccType.prefix);
	//Iterate through prefixes
	//console.info('Iterating through prefixes');
	for (var i = 0; i < ccType.prefix.length; i++) {
		//console.group('Index: %s\nPrefix: %s\nLength: %s', i, ccType.prefix[i], ccType.prefix.length);
		prefix = ccType.prefix[i];
		//Check for ranges
		if (prefix.toString().indexOf('-') != -1) {
			//console.log('Range of Prefixes found - Splitting');
			preRange = prefix.split('-');
			//console.log(prefix);
			//Skip current iteration if there are not exactly 2 numbers in range (low - high)
			if ( preRange.length != 2 || isNaN(parseInt(preRange[0])) || isNaN(parseInt(preRange[1])) )
				continue;
			//Set range start/end
			for(var rx = 0; rx < preRange.length; rx++)
				preRange[rx] = parseInt(preRange[rx]);
			if (preRange[0] < preRange[1]) {
				rStart = preRange[0];
				rEnd = preRange[1];
			} else {
				rStart = preRange[1];
				rEnd = preRange[0];
			}
			for (var rI = rStart; rI <= rEnd; rI++) {
				//Add to main prefix array
				ccType.prefix.push(rI);
				//console.log('Adding %s to Prefix Array', rI);
			}
			//Exit current iteration
			//console.groupEnd();
			continue;
		}
		//Check Prefix
		//console.log('Checking Prefix');
		prefix = parseInt(prefix);
		if (isNaN(prefix))
			continue;
		if (prefix == ccNum.value.substr(0, prefix.toString().length)) {
			//console.log('Matching Prefix has been found!');
			preMatch = true;
			//console.groupEnd();
			break;
		}
		//console.groupEnd();
	}
	//conFuncEnd();
	return preMatch;
}

function checkCCType(ccNum, ccType) {
	//conFunc(arguments);
	var retVal = false;
	//Check number against card type
	var ccTypeSel = getCCType(ccType);
	//console.log('Validating Number for Card Type: %o', ccTypeSel);
	if (!ccTypeSel) {
		retval = false;
		hideError(ccType, 'pattern');
	} else if (checkCCLength(ccNum, ccTypeSel) && checkCCPrefix(ccNum, ccTypeSel)) {
			retVal = true;
			hideError(ccType, 'pattern');
	} else 
		showError(ccType, 'pattern');
	//conFuncEnd();
	//setStatus('Type: ' + retVal);
	return retVal;
}

function getCCType(ccType) {
	var ccTypeSel;
	//Check if selected card type is supported
	//console.log('Checking Card Type');
	if (!(ccType.value in ccTypes)) {
		//console.warn('Unsupported Card Type - Exiting');
		return false;
	}
	//console.log('Card Type is Valid\nCard Type: %o', ccTypes[ccType.value]);
	ccTypeSel = ccTypes[ccType.value];
	return ccTypeSel;
}

function checkCCNumber(ccNum, ccType) {
	//conFunc(arguments);
	var retVal = false,
		ccNumVal = ccNum.value,
		ccVal,
		ccSum = 0,
		ccTypeSel = getCCType(ccType),
		auth;
	
	if (!isInteger(ccNumVal)) {
		//console.warn('Number is invalid (Not an integer)');
		retVal = false;
	} else {
		//console.log('Card Number is an integer');
		//Check Number
		
		//Set Authorization Algorithm
		auth = (!ccTypeSel && hasProp(ccTypeSel, 'auth') && !isNaN(ccTypeSel.auth)) ? ccTypeSel.auth : 10;
		
		//console.info('Checking Number: %s', ccNumVal);
		//console.info('Num type: %s', (typeof ccNumVal));
		for (var x = (ccNumVal.length - 1); x >= 0; x--) {
			//console.group('Index: %s\nValue: %d', x, ccNumVal.charAt(x));
			//Add current value to sum
			ccSum += parseInt(ccNumVal.charAt(x));
			//console.log('Sum: %d', ccSum);
			if ((x - 1) < 0) {
				//console.groupEnd();
				break;
			}
			x--;
			//console.log('New Index: %s\nNew Value: %s', x, ccNumVal.charAt(x));
			ccVal = parseInt(ccNumVal.charAt(x));
			//Double value
			ccVal = ccVal * 2;
			//console.log('Doubled Value: %d', ccVal);
			//Convert to string and add each digit to sum
			ccVal = ccVal.toString();
			for (var i = 0; i < ccVal.length; i++) {
				//console.log('Value: %s', ccVal.charAt(i));
				ccSum += parseInt(ccVal.charAt(i));
				//console.log('New Sum: %d', ccSum);
			}
			//console.groupEnd();
		}
		//Validate Number against algorithm
		if (ccSum != 0 && (ccSum % auth) == 0) {
			//console.log('Card Number is Valid - Exiting');
			retVal = true;
		}
	}
	
	if (!retVal)
		showError(ccNum, 'pattern');
	//conFuncEnd();
	//setStatus('Num: ' + retVal);
	return retVal;
}

function setCCStatus(obj, valid) {
	if (hasProp(obj, 'init')) {
		obj.init['match'] = valid;
	}
	setErrorStatus(obj, 'pattern', valid);
}

function getCCStatus(obj) {
	//conFunc(arguments);
	var retVal = false;
	if (hasProp(obj, 'init') && hasProp(obj.init, 'match') && obj.init.match)
		retVal = true;
	//console.log('Return Value: %o', retVal);
	//conFuncEnd();
	var objst = ' = init value: ';
	if (obj.id.toLowerCase().indexOf('cardnumber') != -1)
		objst = 'Number' + objst;
	else
		objst = 'Type' + objst;
	
	//setStatus(objst + retVal);
	return retVal; 
}

function checkCCInit(ccNum, ccType) {
	//Pass validation to server-side if cc number is masked
	var retVal = false;
	if (ccNum.value.toString().indexOf('*') == 0) {
		//console.log('* Found in number');
		//Check if number and type are set to their initial values
		if (ccNum.value == ccNum.init.num && ccType.value == ccType.init.type) {
			//console.log('Initial values unchanged, passing validation to server');
			retVal = true;
			setCCStatus(ccNum, true);
			setCCStatus(ccType, true);
		} else {
			//setStatus('Vals != init')
			if (ccType.value != ccType.init.type && !!getCCType(ccType)) {
				setCCStatus(ccType, false);
			} else {
				setCCStatus(ccType, true);
			}
			if (ccNum.value != ccNum.init.num) {
				//setStatus('Num != init value');
				//console.log('Current Value: %o \nInit Value: %o', ccNum.value, ccNum.init.num);
				setCCStatus(ccNum, false);
			} else {
				//setStatus('Num = init value');
				setCCStatus(ccNum, true);
			}
			retVal = false;
		}
	}
	
	//setStatus('Init: ' + retVal);
	return retVal;
}

//CC Validation
function checkCC(ccNum, ccType) {
	//conFunc(arguments);
	//setStatus('Checking CC');
	var retVal = false;
	
	if (checkCCInit(ccNum, ccType)) {
		retVal = true;
	} else {
		//Check for null num
		if (ccNum.value.trim().length > 0) {
			//setStatus('Checking Num/Type');
			console.log('Initial values are not used');
			if (ccNum.init.num == ccNum.value) {
				console.log('Num is init');
				//Number is init, set: num valid / type invalid (set by checkCCInit)
				retVal = false;
			} else {
				console.log('Num is not init');
				//Number is different from init value
				//check num
				if (checkCCNumber(ccNum, ccType)) {
					console.log('Num is valid');
					//if num is valid, check type
					if (checkCCType(ccNum, ccType)) {
						//if type also valid, set retVal = true
						retVal = true;
					} else {
						retVal = false;
					}
				} else {
					console.log('Num is invalid');
					//num is invalid, set: num invalid / clear type errors (check type for null) / retVal = false
					retVal = false;
					//Set num as invalid
					setErrorStatus(ccNum, 'pattern', retVal);
					//Clear type errors (check for null)
					if (!getCCType(ccType))
						setErrorStatus(ccType, 'required', retVal);
					setErrorStatus(ccType, 'pattern', !retVal);
				}
			}
		} else {
			//Num is null, set: num required / clear type errors (check for null) / retVal = false
			retVal = false;
			setErrorStatus(ccNum, 'required', retVal);
			setErrorStatus(ccType, 'pattern', !retVal);
			if (!getCCType(ccType))
				setErrorStatus(ccType, 'required', retVal);
		}
	}
	//conFuncEnd();
	//setStatus('CC Valid: ' + retVal);
	return retVal;
} //END checkCC

function isInteger(val) {
	if (!isNaN(val) && Math.floor(val) == val)
		return true;
	return false;
}

function checkCCDate(month, year) {
	//conFunc(arguments);
	var diff = -1, ccDate, today, monthVal, yearVal;
	if (hasProp(month, 'value') && hasProp(year, 'value')) {
		monthVal = month.value;
		yearVal = year.value;
	}
	//console.log('Comparing Dates');
	if (isInteger(monthVal) && isInteger(yearVal)) {
		ccDate = new Date(yearVal, monthVal-1, 1);
		today = new Date();
		today = new Date(today.getFullYear(), today.getMonth(), 1);
		diff = ccDate - today;
	} else {
		//console.log('Invalid parameters');
		return false;
	}
	if (diff >= 0) {
		//console.log('Date is valid');
		hideError(month, 'pattern');
		return true;
	}
	//console.log('Date is invalid');
	showError(month, 'pattern');
	//conFuncEnd();
	return false;
}

/* Build single error message
 * Parameters:
 * opts (object) - Options
 * 	> msg (string)			- Error Message
 * 	> img (string)			- Error Image
 * 	> output (string)		- Output type (obj [Default], string)
 *  > parent (DOM Pointer)	- Parent object to insert error message into
 *  > cssBox (string)		- Error Object's CSS Class
 *  > cssMsg (string)		- Message CSS Class 
 */
function buildErrorMessage(opts) {
	//console.log('Options');
	//console.dir(opts);
	if (!isset(opts) || typeof(opts) != 'object')
		var opts = {};
	//Setup default options
	var dOpts = {
				msg:		'Error',
				img:		'images/error_icon.gif',
				output:		'obj',
				parent:		false,
				cssBox:		'error_box',
				cssMsg:	'error_msg'
				};
	for (opt in dOpts) {
		if (!hasProp(opts, opt))
			opts[opt] = dOpts[opt];
	}
	//Check Parent property
	if (!!opts.parent) {
		opts.parent = checkElement(opts.parent);
		if (!opts.parent)
			opts.parent = false;
	}
	var eBox,
		eMsg,
		eImg,
		eSpan,
		eChildren;
	//Container
	eBox = document.createElement('div');
	eBox.className = opts.cssBox;
	if (opts.parent)
		opts.parent.appendChild(eBox);
	//console.log('Insert error icon into error box');
	eImg = document.createElement('img');
	eImg.setAttribute('src', opts.img);
	eBox.appendChild(eImg);
	//console.log('Insert message container into error box');
	eSpan = document.createElement('span');
	eSpan.className = opts.cssMsg;
	eBox.appendChild(document.createTextNode('\n'));
	eBox.appendChild(eSpan);
	//console.group('Move error messages into message container');
	if (!!opts.parent) {
		eChildren = opts.parent.childNodes;
		for (var i = 0; i < eChildren.length; i) {
			//console.log('i: %d\nChildren: %d\nCurrent Element: %o', i, eChildren.length, eChildren[i]);
			if (eChildren[i] == eBox) {
				i++;
				continue;
			}
			eSpan.appendChild(eChildren[i]);
		}
		//console.groupEnd(); //Moving messages
	} else {
		eSpan.innerHTML = opts.msg
	}
	//console.groupEnd(); //Current element
	return eBox;
}

/* Enhances Error Messages
 * Takes an object of options
 * Options
 * -------
 * ImgSrc (string)	-	Path to error image
 */ 
function buildErrorMessages(opts) {
	var eMsg,
		eMulti = false,
		eContent,
		eChildren,
		eImgSrc = hasProp(opts, 'ImgSrc') ? opts.ImgSrc : 'images/error_icon.gif',
		eImg,
		eBox,
		eBoxClass = 'error_box',
		eSpan,
		eSpanClass = 'error_msg';
	//console.group('Function: Error Message Enhancement');
	//console.log('Get all SPAN elements');
	var e_msgs = getElementsByClassName('error_wrap');
	//console.info('Error Messages on page: %d', e_msgs.length);
	//console.group('Add wrapper to error_msgs');
	for (var x = 0; x < e_msgs.length; x++) {
		/* DOM Method */
		//console.group('Element: %d - %o', x, e_msgs[x]);
		eMsg = e_msgs[x];
		//Check to make sure element has not already been converted
		if (getElementsByClassName(eBoxClass, 'div', eMsg).length > 0)
			continue;
		//console.log('Get all elements inside current element');
		eChildren = eMsg.childNodes;
		//console.log(eChildren);
		//console.log('Add Nodes to box');
		//console.log('Insert Error Box');
		eBox = document.createElement('div');
		eBox.className = eBoxClass;
		eMsg.appendChild(eBox);
		//console.log('Insert error icon into error box');
		eImg = document.createElement('img');
		eImg.setAttribute('src', eImgSrc);
		eBox.appendChild(eImg);
		//console.log('Insert message container into error box');
		eSpan = document.createElement('span');
		eSpan.className = eSpanClass;
		eBox.appendChild(document.createTextNode('\n'));
		eBox.appendChild(eSpan);
		//console.group('Move error messages into message container');
		for (var i = 0; i < eChildren.length; i) {
			//console.log('i: %d\nChildren: %d\nCurrent Element: %o', i, eChildren.length, eChildren[i]);
			if (eChildren[i] == eBox) {
				i++;
				continue;
			}
			eSpan.appendChild(eChildren[i]);
		}
		//console.groupEnd(); //Moving messages
		//console.log('Check for multi-error');
		if (eMsg.className.indexOf('error_multi') != -1) {
			eMulti = true;
			//console.log('Box is a multi-error');
			//Move multi class to box
			//console.log('Removing error_multi from wrapper\nClass: %s', eMsg.className);
			eMsg.className = eMsg.className.replace(/\berror_multi\b/, '');
			//console.log('New Class: %s', eMsg.className);
			//console.log('Set Box as multi-error\nClass: ', eBox.className);
			eBox.className += ' error_multi';
			//console.log('New Class: %s', eBox.className);
			//console.log('Register Multi-box');
			getErrorsMulti(eMsg);
		}
		//console.groupEnd(); //Current element
	}
	//console.groupEnd(); //Add Wrapper to error msgs
	
	//If there are multi-errors on page, register submit buttons to activate them as well
	if (eMulti) {
		//console.group('Binding all inputs for multi-errors');
		//Get all submit buttons
		var fInputs = document.getElementsByTagName('input');
		//console.log('Number of input elements: %d\nAdding Bindings to submit inputs', fInputs.length);
		for (x = 0; x < fInputs.length; x++) {
			if (fInputs[x].getAttribute('type') != 'submit')
				continue;
			//console.group('Index: %d\nInput: %o', x, fInputs[x]);
			//console.log('Adding Binding to click event');
			addEvent(fInputs[x], 'click', function() {
				//console.log('Submit button clicked\nChecking for multi-errors');
				checkErrorsMulti();
			});
			//console.groupEnd();
		}
		//console.groupEnd(); //Bind inputs
	}
	
	////console.warn(test);
	//test.style.visibility = 'visible';
	//console.groupEnd(); //Function end
} //END buildErrorMessages

function addCommas(nStr) {
	nStr += '';
	x = nStr.split('.');
	x1 = x[0];
	x2 = x.length > 1 ? '.' + x[1] : '';
	var rgx = /(\d+)(\d{3})/;
	while (rgx.test(x1)) {
		x1 = x1.replace(rgx, '$1' + ',' + '$2');
	}
	return x1 + x2;
}

//Equalize the heights of Country Lists in Featured Destinations
function eqHFDest() {
	var country_names = getElementsByClassName('country_name');
	var country_links = getElementsByClassName('country_link');
	
	
	//Equalize heights of link containers
	eqH_ext(country_names);
	//Align all links to bottom of containers
	//console.log('Links: %o', country_links);
	for (var x = 0; x < country_links.length; x++) {
		//console.info('X: %s', x);
		//console.log('Parent: %o', country_links[x].parentNode);
		if (country_links[x].parentNode.style.height.toString().length > 0)
			country_links[x].style.position = "absolute";
	}
}

//Form field character counter
function countCharacters(el, msg, limit) {
	el = checkElement(el);
	msg = checkElement(msg);
	limit = parseInt(limit);
	//Cancel function if element is not valid
	if (!el || typeof el == 'undefined')
		return false;
	
	//Count Characters
	var count = el.value.length;
	//Report length
	if (msg && typeof msg != 'undefined') {
		var msgText = count;
		if (!isNaN(limit))
			msgText += ' / ' + limit
		msg.innerHTML = msgText;
	}
	
} //END countCharacters


//Validates alternate phone number form fields
function CheckAltPhoneValid(ctrl) {
	var ddlAltconutry = document.getElementById(varddlAltConutry);
	var txtAltPhoneNumber = document.getElementById(vartxtAltPhone);
	var FlagNew;
	
	if (ctrl.type == "select-one") {
		if (ctrl.options[ctrl.selectedIndex].value == "--" & txtAltPhoneNumber.value == "") {
			FlagNew = false;
			ActiveAltPhoneValidation(false);
		}
		else if(ctrl.options[ctrl.selectedIndex].value != "--" & txtAltPhoneNumber.value != "") {
			FlagNew = false;
			ActiveAltPhoneValidation(false);
		}
		else {
			FlagNew= true;
			ActiveAltPhoneValidation(true);
		}

	}
	else if (ctrl.type == "text") {
		if (ctrl.value == "" & ddlAltconutry.options[ddlAltconutry.selectedIndex].value == "--") {
			FlagNew= false;   
			ActiveAltPhoneValidation(false);
		}
		else if (ctrl.value != "" & ddlAltconutry.options[ddlAltconutry.selectedIndex].value != "--") {
			FlagNew= false; 
			ActiveAltPhoneValidation(false);
		}
		else {
			FlagNew = true;
			ActiveAltPhoneValidation(true);
		}
	}
} //END CheckAltPhoneValid



//Validates Mobile phone number form fields
function CheckMobilePhoneValid(ctrl) {
	var ddlMobileCountry = document.getElementById(varddlMobileCountry);
	var txtMobile = document.getElementById(vartxtMobile);
	var FlagNew;
	
	if (ctrl.type == "select-one") {
		if (ctrl.options[ctrl.selectedIndex].value == "--" & txtMobile.value == "") {
			FlagNew = false;
			ActiveMobilePhoneValidation(false);
		}
		else if(ctrl.options[ctrl.selectedIndex].value != "--" & txtMobile.value != "") {
			FlagNew = false;
			ActiveMobilePhoneValidation(false);
		}
		else {
			FlagNew= true;
			ActiveMobilePhoneValidation(true);
		}

	}
	else if (ctrl.type == "text") {
		if (ctrl.value == "" & ddlMobileCountry.options[ddlMobileCountry.selectedIndex].value == "--") {
			FlagNew= false;   
			ActiveMobilePhoneValidation(false);
		}
		else if (ctrl.value != "" & ddlMobileCountry.options[ddlMobileCountry.selectedIndex].value != "--") {
			FlagNew= false; 
			ActiveMobilePhoneValidation(false);
		}
		else {
			FlagNew = true;
			ActiveMobilePhoneValidation(true);
		}
	}
} //END CheckMobilePhoneValid



function CheckEditAltPhoneValid(ctrl) {

	var ddlEditPhoneSec = document.getElementById(varddlEditPhoneSec);
	var txtEditPhone3Sec = document.getElementById(vartxtEditPhone3Sec);

	if (ctrl.type == "select-one") {
		if (ctrl.options[ctrl.selectedIndex].value == "--" & txtEditPhone3Sec.value == "") {
			FlagNew = false;
			ActiveEditAltPhoneValidation(false);
		}
		else if (ctrl.options[ctrl.selectedIndex].value != "--" & txtEditPhone3Sec.value != "") {
			FlagNew = false;
			ActiveEditAltPhoneValidation(false);
		}
		else {
			FlagNew = true;
			ActiveEditAltPhoneValidation(true);
		}

	}
	
	else if (ctrl.type == "text") {
		if (ctrl.value == "" & ddlEditPhoneSec.options[ddlEditPhoneSec.selectedIndex].value == "--") {
			FlagNew= false;   
			ActiveEditAltPhoneValidation(false);
		}
		else if (ctrl.value != "" & ddlEditPhoneSec.options[ddlEditPhoneSec.selectedIndex].value != "--") {
			FlagNew = false;
			ActiveEditAltPhoneValidation(false);
		}
		else {
			FlagNew= true;
			ActiveEditAltPhoneValidation(true);
		}
	}
} //END CheckEditAltPhoneValid

//Scans page for phone input groups
function buildInputPhone() {
	//console.group('Function: buildInputPhone');
	//Setup default values
	var groupClass = "input_phone",
			prefix = "phone_prefix",
			area = "phone_area",
			number = "phone_number",
			currGroup,
			currInput,
			inputs,
			selEls,
			inputTypes = ['input', 'select'];
	
	//Get all phone input groups on page
	var groups = getElementsByClassName(groupClass);
	//console.log('Groups found: %s', groups.length);
	//console.group('Iterate through groups');
	for (var x = 0; x < groups.length; x++) {
		//console.group('Group: %s', x);
		//Search current group for inputs
		currGroup = groups[x];
		inputs = [];
		//console.group('Getting Inputs');
		for (var t = 0; t < inputTypes.length; t++) {
			//console.info('Index: %s \nType: %s', t, inputTypes[t]);
			//Add new inputs to current input array
			//Simple method, doesn't work in IE
			//inputs = inputs.concat(Array.prototype.slice.call(currGroup.getElementsByTagName(inputTypes[t])));
			
			//Long method
			selEls = currGroup.getElementsByTagName(inputTypes[t]); 
			for (var n = 0; n < selEls.length; n++) {
				inputs.push(selEls[n]);
			}
			//console.log('Number of Inputs: %d', inputs.length);
		}
		//console.groupEnd() //Getting inputs
		
		////console.dir(inputs);
		//Iterate through inputs in group
		//console.group('Iterate through inputs');
		for (var i = 0; i < inputs.length; i++) {
			//console.log('Input: %d', i);
			//Add input array to input element
			currInput = inputs[i];
			currInput["inputGroup"] = inputs;
			//console.log('Add group to input\nInput\n %o \nGroup\n %o \n', currInput, inputs);
			//Attach onChange event handlers
			addEvent(currInput, 'change', function() {
				validateInputPhone(this);
			});
		}
		//console.groupEnd(); //Iterate through inputs
		
		//console.groupEnd(); //Current group
	}
	//console.groupEnd(); //Group Iteration
	//console.groupEnd();
} //END buildInputPhone

//Validates phone input groups
function validateInputPhone(el) {
	//console.group('Function: validateInputPhone');
	//Build array of validators
	var validators = [],
			iEl,
			dir = false;
	for (var x = 0; x < el.inputGroup.length; x++) {
		iEl = el.inputGroup[x];
		validators = validators.concat(iEl.Validators);
		//console.log('Validators: %d', validators.length);
		//Check if current element has user input
		if (iEl.value.length > 0 && iEl.value != "--") {
			dir = true;
		}
	}
	//If element needs to be validated, enable validators for all elements in group
	validatorsSwitch(validators, dir);
	//console.groupEnd() //Function group
} //END validateInputPhone

//Enables/Disables groups of validators
function validatorsSwitch(obj, dir) {
	//console.group('Function: validatorsSwitch');
	//console.info('Validators: %d', obj.length);
	for (var x = 0; x < obj.length; x++)
		ValidatorEnable(obj[x], dir);
	//console.groupEnd();
} //END validatorsSwitch

//Enables/Disables Validators belonging to a validation group
function validationGroupSwitch(group, dir) {
	//console.group('Function: validationGroupSwitch');
	//console.info('group: %s \ndir: %s', group, dir);
	if (typeof Page_Validators != 'undefined' && group.length > 0) {
		for (var i = 0; i < Page_Validators.length; i++) {
		if (Page_Validators[i].validationGroup == group) {
			ValidatorEnable(Page_Validators[i],dir);
			}
		}
	}
	//console.groupEnd();
} //END validationGroupSwitch

//Checks for errors in the Join Processes
function checkJoinErrors() {
	//console.group('Function: checkJoinErrors');
	if (valSummary.style.visibility != 'hidden' && valSummary.style.display != 'none') {
		showIt('error_summary');
	} else {
		hideIt('error_summary');
	}
} //END checkJoinErrors

//Checks whether element has a specific css class
function hasClass(el, className) {
	if (typeof el == 'undefined' || typeof className == 'undefined')
		return false;
	var reClass = ((typeof className == 'object' || typeof className == 'function') && 'exec' in className) ? className : buildAttributeRegEx(className);
	if (el.className.search(reClass) != -1)
		return true;
	return false;
} //END hasClass

//Adds class to element
function addClass(el, className) {
	el = checkElement(el);
	if (!el || !className)
		return false;
	//Make sure element doesn't already have class
	if (!hasClass(el, className))
		el.className = el.className + " " + className;
} //END addClass

//Removes class from element
function removeClass(el, className) {
	if (!el || !className)
		return false;
	var els = new Array();
	//Check if element is an array
	if ('length' in el)
		els = el;
	else
		els[0]= el;
	var reClass = buildAttributeRegEx(className);
	for (var x = 0; x < els.length; x++) { 
		els[x].className = els[x].className.replace(reClass, "");
	}
} //END removeClass

/* Retrieves class names of an Element as Array
 * Parameters
 * 	el (Element/String ID)		: Element to get class
 * 	@filter (String/RegExp)		: Filter (Future Development)
 * 	
 * Methodology
 * 	- Get full className text of element
 * 	- Split class names into array
 * 	
 * Return Value: Array
 * Structure
 *  - 0 	: Full className string
 *  - 1-n	: Individual classNames
 */

function fetchClass(el, filter) {
	el = checkElement(el);
	if (!el || !hasProp(el, 'className'))
		return false;
	//Get Element's class value & split into individual class names 
	var elClass = el.className,
		namesArr = elClass.split(' ');
	//Add full class string to front of names array
	namesArr.unshift(elClass);
	return namesArr;
}

function buildAttributeRegEx(searchString, flags) {
	if (typeof flags == 'undefined')
		flags = "";
	var re = new RegExp('(?:^|\\b)' + searchString + '(?:$|\\b)', flags);
	//var re = new RegExp('(?:^|\\s)' + searchString + '(?:$|\\s)', 'g');
	return re;
}

function sortObjArray(arr, prop) {
	var currO,
		nextO,
		temp;
	arr = arr.sort(function(a, b) {
		a = a[prop];
		b = b[prop];
		return (a > b) ? 1 : ((a < b) ? -1 : 0); 
	});
	return arr;
}

function getRows(obj) {
	var tables,
		rows = [];
		
	if (hasProp(obj, 'rows'))
		return obj.rows;
		
	//Get Table(s)
	if (hasProp(obj, 'id'))
		tables = checkElement(obj.id);
	else if (hasProp(obj, 'className'))
		tables = getElementsByClassName(obj.className);
	else
		tables = document.getElementsByTagName('table');
	
	if (hasProp(tables, 'nodeName'))
		tables = [tables];
	//Iterate over table(s) rows and add event handlers
	for (var x = 0; x < tables.length; x++) {
		tblRows = tables[x].getElementsByTagName('tr');
		for (var y = 0; y < tblRows.length; y++)
			rows.push(tblRows[y]);
	}
	return rows;
}

function rowSelect(obj){
	//Get Rows in Table(s)
	var rows = getRows(obj);
	for (var y = 0; y < rows.length; y++) {
		rows[y].onmouseover = function() {
			addClass(this, 'selected');
		}
		rows[y].onmouseout = function() {
			removeClass(this, 'selected');
		}
	}
}

function rowLinkify(obj) {
	var rows = getRows(obj),
		link,
		els,
		single = false;
	if (!hasProp(obj, 'link'))
		return false;
	var obj = obj.link;
	
	//Get link to linkify row with
	if (hasProp(obj, 'id')) {
		single = true;
		link = checkElement(obj.id);
	}
	
	for (var x = 0; x < rows.length; x++) {
		//Get link
		if (!single) {
			link = [];
			if (hasProp(obj, 'className')) {
				els = getElementsByClassName(obj.className, '*', rows[x]);
				if (els.length < 1)
					continue;
				//console.log('Elements: %o', els);
				var e = 0;
				while(link.length < 1) {
					//console.log('Checking Element (%o): %o', e, els[e]);
					if (els[e].nodeName.toLowerCase() == 'a') {
						//console.warn('Element is a link - Exiting');
						link.push(els[e]);
						//console.dir(link);
						break;
					}
					else
						link.push(els[e].getElementsByTagName('a')[0]);
					e++;
					if (link.length == e)
						break;
				}
			}
			else
				link = row[x].getElementsByTagName('a');
			
			//console.log('Raw Link: %o', link);
			if (link.length < 1)
				continue;
			link = link[0];
		}
		//console.log('Link: %o', link);
		//Get links HREF
		/*
		rows[x]['href'] = link.href;
		
		rows[x].onclick = function() {
			if (typeof clickLink == 'undefined')
				clickLink = false;
			if (!(clickLink)) {
				window.location = this.href;
			}
			clickLink = false;
		}
		*/
	}
	/*
	var dl = getElementsByClassName('button_delete');
	
	for (var z = 0; z < dl.length; z++) {
		dl[z].onclick = function() {
			clickLink = true;
		};
	}
	*/
}

function highlightTableHeaders(obj) {
	var tables,
		links,
		headers;
	//Get tables on page
	if (typeof obj == 'undefined')
		obj = {};
	if (hasProp(obj, 'id')) {
		tables = checkElement(obj.id);
	}
	else if (hasProp(obj, 'className')) {
		tables = getElementsByClassName(obj.className);
	}
	else
		tables = document.getElementsByTagName('table');
	//Iterate through tables
	for (var x = 0; x < tables.length; x++) {
		//Get all headers in table
		headers = tables[x].getElementsByTagName('th');
		//Iterate through headers
		for (var y = 0; y < headers.length; y++) {
			//Get links in header
			links = headers[y].getElementsByTagName('a');
			//Add event handlers to links
			for (var z = 0; z < links.length; z++) {
				links[z]['th'] = headers[y];
				links[z].onmouseover = function() {
					addClass(this.th, 'selected');
				}
				links[z].onmouseout = function() {
					removeClass(this.th, 'selected');
				}
			}
		}
	}
}

function previewTemplate(source, preview) {
	source = checkElement(source);
	preview = checkElement(preview);
	sVal = source.value;
	
	if (!source || !preview)
		return false;
	
	//Set Dynamic Values (for images, etc.)
	var uri = parseUri(window.location.href),
		baseUrl = uri.protocol + '://' + uri.host + ':' + uri.port,
		bQv = 'BId';
		brand = (hasProp(uri.queryKey, bQv)) ? uri.queryKey[bQv] : 1;
	if (uri.host.indexOf('localhost') == 0) {
		baseUrl += '/site';
	}
	
	//Replace dynamic variables in source with dynamic values
	//URL
	sVal = sVal.replace(/\$bodyDataSource\.brand\.baseUrl/g, baseUrl);
	sVal = sVal.replace(/\$bodyDataSource\.brand\.id/g, brand);
	
	preview.innerHTML = sVal;
}

/* Displays loading indicator (i.e. when submit button is clicked)
 * Parameters:
 * 	el (Element/String ID)					: Loading Element
 * 	[validators] (Element/String ID/Array)  : Validator(s) (or Validator(s) Container) Element
 * 	
 *	If validators are passed to the function, all validators must be valid for the loading element to be displayed  
 */
function showLoader(el, validators) {
	//console.group(arguments.callee);
	//console.info('Parameters:\nel: %o \nvalidators: %o', el, validators);
	el = checkElement(el);
	if (!el)
		return false;
	if (isset(validators)) {
		//Get validation element(s)
		//console.warn('Getting Validators');
		if (!(validators instanceof Array)) {
			validators = getValidators(validators);
		}
		if (!validators)
			return false;
		//console.warn('Validators Found: %o', validators);
	}
	if (checkValidators(validators))
		showIt(el, '');
	//console.groupEnd();
}

/* Checks whether element is a validator or not 
 * Return Type: Boolean
 * 
 * Parameters:
 * 	el (Element/String ID)	: Element to check   
 */
function isValidator(el) {
	el = checkElement(el);
	if (!el || !isset(el))
		return false;
	if (hasProp(el, 'isvalid'))
		return true;
	return false;
}

/* Check whether validator is valid */
function isValidatorValid(v) {
	v = checkElement(v);
	if (!v)
		return false;
	if (isValidator(v)) 
		if (v.isvalid === true) {
			//console.warn('Validator %o is Valid', v);
			return true;
		}
	return false;
}

/* Returns Array of ASP form validators
 * Parameters:
 * 	el (Element/String ID)		: Element to check for validators in (Default: Document)
 * 	
 * Methodology:
 * 	- Checks if element is a validator
 * 		- If element IS a validator, it adds validator to an array and returns the array (as a validator can have no children)
 * 		- If element IS NOT a validator, it looks at child nodes (recursive) for an validators
 * 			- When validators are found, they are added to the array
 * 	- Returns array of validators
 * 	- Returns FALSE (Bool) if no validators are found 
 */
function getValidators(el) {
	//console.group(arguments.callee);
	//console.info('Element: %o', el);
	el = (checkElement(el)) ? checkElement(el) : document;
	var v = false,
		vals;
	//Check if element is validator
	if (isValidator(el)) {
		//console.warn('Element is a validator');
		v = [];
		v.push(el);
	} else if (el.hasChildNodes && el.childNodes.length > 0) {
		//Search element's children for validators (recursive)
		for (var x = 0; x < el.childNodes.length; x++) {
			vals = [];
			vals = getValidators(el.childNodes[x]);
			if (vals) {
				if (!(v instanceof Array))
					v = [];
				v = v.concat(vals);
			}
		}
	}
	//console.info('Return value: %o', v);
	//console.groupEnd();
	return v;
}

/* Checks Validators
 * Parameters:
 * 	validators (Array)	: Array of Validators to Evaluate
 * 	
 * Methodology:
 * 	- Iterates through array of validators
 * 	- Checks if each validator is valid
 * 		- If a validator is NOT valid, return FALSE immediately
 * 	- If all validators are valid, return TRUE      
 */
function checkValidators(vArr) {
	//console.group(arguments.callee);
	//console.info('Parameters:\nvArr: %o', vArr);
	if (!isset(vArr))
		return false;
	for (var x = 0; x < vArr.length; x++) {
		if (!isValidatorValid(vArr[x]))
			return false;
	}
	return true;
	//console.groupEnd();
}

/* Creates console.group for Function
 * Parameters
 * 	args (Function arguments)	: Arguments passed from calling function
 * 	showParams (Boolean)		: Whether or not function parameters should be displayed or not   
 */
function conFunc(args, showParams) {
	console.group(args.callee);
	if (!isset(showParams))
		showParams = true;
	if (!!showParams)
		conParams(args);
}

// Closes console.group for a function call (wrapper to console.groupEnd for consistency)
function conFuncEnd() {
	console.groupEnd();
}

/* Creates console.info to list parameter values of a function call
 * Parameters
 * 	args (Function arguments)	: Arguments passed from calling function
 */
function conParams(args) {
	var disp = 'Parameters\\n',
		argList = '',
		arg,
		cInfo,
		params,
		argName;
	//Get argument names
	params = getFuncParams(args);
	
	//Build Console.info Call String
	if (args.length > 0) {
		for (var arg = 0; arg < args.length; arg++) {
			argName = (arg < params.length) ? params[arg] : arg;
			disp += argName + ': %o \\n';
			if (argList.length > 0)
				argList += ', ';
			argList += "args[" + arg + "]"
		}
	} else {
		argList = "'No Paramters'";
	}
	cInfo = "console.info(\"" + disp + "\", " + argList + ")";
	//Call console.info
	eval(cInfo);
}

/* Gets Parameter names for a function call
 * Parameters
 * 	args (Function arguments)	: Arguments passed from calling function
 * 	
 * Return Value: Parameter Names (Array)   
 */
function getFuncParams(args) {
	var p = [];
	if (!isset(args))
		return p;
	//Get string of function
	var f = ((isFunction(args)) ? args : args.callee).toString(),
		pS = f.indexOf('(');
		pE = f.indexOf(')');
	//Get Params from string
	if (pS == -1 || pE == -1)
		return p;
	//Extract Param list from string and Split Params into Array
	p = (f.substring(pS + 1, pE)).replace(' ', '').split(',');
	return p;
}
 
//Checks function call to make sure all parameters have a value
function checkFuncParams(args) {
	//Compare number of required params to number of passed params
	if (args.length < getFuncParams(args).length)
		return false;
	else {
		//Make sure all parameters have valid values
		for (var x = 0; x < args.length; x++) {
			if (!isset(args[x]))
				return false;
		}
	}
}

function getRates(opts) {
	var def = {
				"loading":		"Loading Price and Availability",
				"no_avail":		"There are no rooms available at this hotel during the selected date range",
				"error":		"Rates for this hotel during the selected date range are temporarily unavailable"
				};
	//Check if opts is an object
	if (isset(opts) && typeof(opts) == 'object') {
		//Check opts for required properties
		var prop;
		for (prop in def) {
			if (!hasProp(opts, prop))
				opts[prop] = def[prop];
			else if (opts[prop] == "")
				opts[prop] = def[prop];
		}
	} else {
		opts = def;
	}
	if (!hasProp(opts, 'start') || !hasProp(opts, 'end') || !hasProp(opts, 'g_t') || !hasProp(opts, 'gc') || !hasProp(opts, 'g_a') || !hasProp(opts, 'ref')) {
		return false;
	}
	//Get rate containers
	var rboxes = $('.hotel_rates');
	var showLoading = function(el) {
		//Display Loading indicator
		$(el).html('<span class="loading">' + opts.loading + '</span>');
	};
	rboxes.each(function(i) {
		//Show loader
		showLoading(this);
		var el = this;
		var pVars = {
					id:		el.id,
					start:	opts.start,
					end:	opts.end,
					g_t:	opts.g_t,
					gc:		opts.gc,
					g_a:	opts.g_a,
					ref:	opts.ref,
					ajax:	true
					};
		//Get Rates
		$.post(
			"hotel_availability.aspx",
			pVars,
			function(data) {
				//console.log('Data Returned:\n %o', data);
				//Trim Data
				if (data.indexOf('hotel_room_rates') == -1) {
					//Error
					if (data.indexOf('rate_error') != -1)
						data = buildRateError(opts.error);
					else
						data = buildRateError(opts.no_avail);
				} else {
					//Remove Form Tag
					var reForm = new RegExp("\\</*form.*?\\>", "gim");
					data = data.replace(reForm, '');
					reForm = new RegExp("\\<input[^\\>]+?type=\"hidden\".+?\\>", "gim");
					data = data.replace(reForm, '');
					reForm = /<script(.|\s)+?<\/script>/im;
					//console.log('Script Tag Matching:\n %o \n %o', reForm.toString(), reForm.exec(data));
					data = data.replace(reForm, '');
					//console.log('Data to display:\n %o', data);
				}
				$(el).hide().html(data).slideDown("slow");
				theForm = $('#form1')[0];
			}
		);
	});
}
	
function buildRateError(msg) {
	if (!isset(msg))
		msg = "Rates for this hotel during the selected date range are temporarily unavailable";
	cssClass = "alert";
	//return '<span class="' + cssClass + '">' + msg + '</span>';
	return buildErrorMessage({'msg': msg});
}
