function getXmlhttp() {
		
	try {
		tmp_xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
	}
	catch( e ) {
		try {
			tmp_xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
		}
		catch( E ) {
			tmp_xmlhttp = false;
		}
	}
	if( !tmp_xmlhttp && typeof XMLHttpRequest != 'undefined' ) {
		tmp_xmlhttp = new XMLHttpRequest;
	}
	return tmp_xmlhttp;
}
			
//setup AJAX object
var get_xmlhttp = getXmlhttp();
var get_req_q = Array();

function getRequest( get_str, param_str ) {
	var new_req = new Object();
	new_req.get_str = get_str;
	new_req.param_str = param_str;
	
	get_req_q.push( new_req );
	
	makeGetRequest();
	
}
		
function makeGetRequest() {
	if( get_xmlhttp ) {
		if( get_xmlhttp.readyState == 0 || get_xmlhttp.readyState == 4 ) {
			if( get_req_q.length > 0 ) {
				
				var cur_req = get_req_q.shift();
				
				get_xmlhttp.open( "GET", 'view.php?reqdata=' + cur_req.get_str + '&' + cur_req.param_str, true );
				get_xmlhttp.setRequestHeader( 'Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8' );

				get_xmlhttp.onreadystatechange = function() {
					if( get_xmlhttp.readyState == 4 && get_xmlhttp.status == 200 ) {
						var resp_text = get_xmlhttp.responseText;
						if( resp_text.indexOf( '{"' ) != 0 ) serverSideError_RH();
						else{
							makeGetRequest();

							//var response_datas = jsonEval( resp_text );
							var resp_datas_2  = jsonParse( resp_text );
							getResponseHandler( resp_datas_2 );
						}
					}
				}
				
				get_xmlhttp.send( null );
			}
		}	
	}
}
/*function jsonEval( json_text ) {
	return eval( '(' + json_text + ')' );
}*/
function getResponseHandler( resp_datas ) {
	if( typeof resp_datas['status'] == 'undefined' ) serverSideError_RH();
	if( resp_datas['status'] == 'error' && resp_datas['error'] == 'auth' ) authError_RH();							
	if( resp_datas['status'] == 'error' && resp_datas['error'] == 'blocked' ) blockedError_RH();							
	else {
		if( resp_datas['reqdata'] == 'getschedule' ) fetchSchedule_RH( resp_datas );
		if( resp_datas['reqdata'] == 'getdaysforstaff' ) getDaysForStaff_RH( resp_datas );

	}
}
function authError_RH() {
	alert( 'It appears you are no longer logged in. Press "OK" to login again.' );
	location.href = '../login.php';
}
function blockedError_RH() {
	alert( 'The account your are trying to view is temporarily unavailable. Please try again later.' );
}	
function serverSideError_RH() {
	alert( 'We are sorry but an error occured on the server. We recommend reloading the page.' );
}
///////////////////////////////////////////////////////////

var H2_AsynchronousRequests = function() {
	var _async_obj = this;
	this.requests = [];
	this.xmlhttp = getXmlhttp();
	
	this.newRequest = function( get_str, post_str, callback ) {
		var method = post_str ? 'POST' : 'GET';
		var new_req = { method: method, get_str: get_str, post_str: post_str, callback: callback };
		this.requests.push( new_req );
		this.makeRequests();
	}
	this.makeRequests = function() {
		if( this.xmlhttp ) {
			if( this.xmlhttp.readyState == 0 || this.xmlhttp.readyState == 4 ) {
				if( this.requests.length > 0 ) {
					
					var cur_req = this.requests.shift();
					
					this.xmlhttp.open( cur_req.method, cur_req.get_str, true );
					this.xmlhttp.setRequestHeader( 'Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8' );
	
					this.xmlhttp.onreadystatechange = function() {
						if(  _async_obj.xmlhttp.readyState == 4 &&  _async_obj.xmlhttp.status == 200 ) {
							var resp_text = _async_obj.xmlhttp.responseText;
							if( resp_text.indexOf( '{"' ) != 0 ) serverSideError_RH();
							else{
								_async_obj.makeRequests();
	
								var resp_datas  = jsonParse( resp_text );
								//getResponseHandler( resp_datas );
								cur_req.callback( resp_datas );
							}
						}
					}
					
					this.xmlhttp.send( cur_req.post_str );
				}
			}	
		}
	}
}


var H2_XYScrollObj = function( id_prefix ) {
	var _xy_scroll = this;

	this.head_container_elem = document.getElementById( id_prefix + '-head-container' );
	this.shade_container_elem = document.getElementById( id_prefix + '-shade-container' );
	this.slide_shade_elem = document.getElementById( id_prefix + '-slide-shade' );  
	this.left_container_elem = document.getElementById( id_prefix + '-left-container' );
	this.main_container_elem = document.getElementById( id_prefix + '-main-container' );
	this.yardstick_elem = document.getElementById( id_prefix + '-yardstick' );
	
	var pos = getElemPos( this.head_container_elem );
	this.target_y_scroll = pos[1] - 30;
	//this.cur_y_scroll = false;
	this.last_y_scroll = this.main_container_elem.scrollTop;
	
	this.main_container_elem.onscroll = mkScroll();
	function mkScroll() { return function() { _xy_scroll.scrolled(); }; }
	
	window.onresize = function() {	//pretty dangerous!
		_xy_scroll.resized();
	} 
	
	//get width, and set elem widths accordingly.
	//head_container.
	// shade container full width
	//main container
	
	//heights
	// slide shade
	//left container
	//main container
	
	this.setWidths = function() {
		var w = this.yardstick_elem.offsetWidth;
		
		this.shade_container_elem.style.width = w+'px';
		
		var left_w = this.left_container_elem.offsetWidth;
		w = w - left_w - 5;
		
		this.head_container_elem.style.width = (w-16)+'px';
		this.main_container_elem.style.width = w+'px';
	}
	this.setHeights = function() {
		
		var win_height = (window.innerHeight)? window.innerHeight : document.documentElement.clientHeight;
		var h = win_height - 100;
		var head_height = this.head_container_elem.offsetHeight;
		
		var left_height = this.left_container_elem.firstChild.offsetHeight + 20;
		h = Math.min(h,left_height);

		this.shade_container_elem.style.height = h+'px';
		this.left_container_elem.style.height = (h-16)+'px';
		this.slide_shade_elem.style.top = '-'+head_height+'px';
		this.slide_shade_elem.style.height = (h-16+head_height)+'px';
		this.main_container_elem.style.height = h+'px';
	}
	
	this.resized = function() {
		this.setWidths();
		this.setHeights();		
	}
	this.scrolled = function() {
		var x_scroll = this.main_container_elem.scrollLeft;
		this.head_container_elem.scrollLeft = x_scroll;
		
		var y_scroll = this.main_container_elem.scrollTop;
		this.left_container_elem.scrollTop = y_scroll;
		
		x_scroll = x_scroll /2;
		x_scroll = Math.min( 22, x_scroll);
		x_scroll = x_scroll-22;
		this.slide_shade_elem.firstChild.style.left = x_scroll+'px'; 

		var delta_y = y_scroll - this.last_y_scroll;
		//delta_y = delta_y < 0 ? -delta_y: delta_y;
		
		var cur_win_y_scroll = (window.scrollY || window.scrollY === 0)? window.scrollY : document.documentElement.scrollTop;
		var diff = this.target_y_scroll - cur_win_y_scroll;
		
		if( diff > 2 && delta_y > 0 ) {
			if( delta_y > diff ) {
				window.scrollBy( 0, diff );
			}
			else {
				window.scrollBy( 0, delta_y );
			}
		}
		else if( diff < -2 && delta_y < 0 ) {
			if( delta_y < diff ) {
				window.scrollBy( 0, diff );
			}
			else {
				window.scrollBy( 0, delta_y );
			}
		}
		
		this.last_y_scroll = y_scroll;
	}
	
	this.setWidths();
	this.setHeights();
}		

////////////////////////////////////////////////////////////

function validateInteger( a_int ) {
	var error = false;
	if( typeof a_int != 'undefined' ) {
		a_int = a_int.toString();
		var int_len = a_int.length;
		for( var i=0; i<int_len; i++ ) {
			a_char = a_int.charAt(i).charCodeAt(0);
			if( a_char < 48 || a_char > 57 ) error = true;
		}
	}
	return !error;
}

function H2_Date( str ) {
	
	this.error=false;
	
	var date_parts = str.split( '-' );
	if( date_parts.length != 3 ) this.error = true;
	
	var year = parseInt(date_parts[0], 10);
	if( !validateInteger(year) ) this.error = true;

	
	var month = parseInt(date_parts[1], 10);
	if( !validateInteger(month) ) this.error = true;

	
	var day = parseInt(date_parts[2], 10);
	if(!validateInteger(day) ) this.error = true;

	if( !this.error ) {
		var test_date = new Date( year, month - 1, day );
		if( test_date.getDate() != day ) this.error = true;
		if( test_date.getMonth() != month - 1 ) this.error = true;
		if( test_date.getFullYear() != year ) this.error = true;
	}
	
	this.year = year;
	this.month = month;
	this.day = day;
	
	this.asMysql = function() {
		var m_str = this.month;
		if( this.month < 10 ) {
			m_str = '0'+m_str;
		}
		var d_str = this.day;
		if( this.day < 10 ) {
			d_str = '0'+d_str;
		}
		var str = this.year + '-' + m_str + '-' + d_str;
		return str;
	}
	this.asReadable = function () {
		//blah
		return this.monthAsShort() + ' ' + this.day + ' ' + this.year;
	}
	this.monthAsShort = function() {
		var month_str = '';
		switch(parseInt(this.month,10)) {
			case 1: month_str = 'Jan'; break;
			case 2: month_str = 'Feb'; break;
			case 3: month_str = 'Mar'; break;
			case 4: month_str = 'Apr'; break;
			case 5: month_str = 'May'; break;
			case 6: month_str = 'Jun'; break;
			case 7: month_str = 'Jul'; break;
			case 8: month_str = 'Aug'; break;
			case 9: month_str = 'Sep'; break;
			case 10: month_str = 'Oct'; break;
			case 11: month_str = 'Nov'; break;
			case 12: month_str = 'Dec'; break;
		}
		return month_str;
	}
	this.yearAsShort = function() {
		yr_str = this.year.toString();
		return yr_str.substring(2);
	}
	this.weekdayAsLong = function() {
		var wd = parseInt(this.weekdayAsNum(), 10);
		var wd_str = '';
		switch(wd) {
			case 0: wd_str = 'Sunday'; break;
			case 1: wd_str = 'Monday'; break;
			case 2: wd_str = 'Tuesday'; break;
			case 3: wd_str = 'Wednesday'; break;
			case 4: wd_str = 'Thursday'; break;
			case 5: wd_str = 'Friday'; break;
			case 6: wd_str = 'Saturday'; break;
		}
		return wd_str;
	}
	this.weekdayAsShort = function() {
		var wd = parseInt(this.weekdayAsNum(), 10);
		var wd_str = '';
		switch(wd) {
			case 0: wd_str = 'Sun'; break;
			case 1: wd_str = 'Mon'; break;
			case 2: wd_str = 'Tue'; break;
			case 3: wd_str = 'Wed'; break;
			case 4: wd_str = 'Thu'; break;
			case 5: wd_str = 'Fri'; break;
			case 6: wd_str = 'Sat'; break;
		}
		return wd_str;
	}	
	this.addDays = function( num ) {

		var new_day = parseInt(this.day, 10) + parseInt(num, 10);
		if( new_day > 0 && new_day < 28 ) {
			this.day = new_day;
		}
		else {
			var tmp_date = new Date( this.year, this.month-1, this.day );
			tmp_date.setDate( new_day );
			this.year = tmp_date.getFullYear();
			this.month = tmp_date.getMonth()+1;
			this.day = tmp_date.getDate();
		}
	}
	this.addOneDay = function() {
		this.addDays(1);
	}
	this.subtractDays = function( num ) {
		this.addDays( -num );
	}

	this.equalTo = function( date ) {
		if( this.year == date.year && this.month == date.month && this.day == date.day ) return true;
		else return false;
	}
	this.greaterThan = function( date ) {
		var ret;
		
		if( this.year > date.year ) { ret = true; }
		else if( this.year == date.year && this.month > date.month ) { ret = true; }
		else if( this.year == date.year && this.month == date.month && this.day > date.day ) { ret = true; }	
		else { ret = false; }

		return ret;
	}
	this.greaterEqualThan = function( date ) {
		var ret;
	
		if( this.greaterThan(date) || this.equalTo(date) ) ret = true;

		return ret;
	}
	this.lessThan = function( date ) {
		var ret;
		
		if( this.year < date.year ) { ret = true; }
		else if( this.year == date.year && this.month < date.month ) { ret = true; }
		else if( this.year == date.year && this.month == date.month && this.day < date.day ) { ret = true; }	
		else { ret = false; }

		return ret;
	}
	this.lessEqualThan = function( date ) {
		var ret;
	
		if( this.lessThan(date) || this.equalTo(date) ) ret = true;

		return ret;
	}
	
	this.weekdayAsNum = function() {
		var tmp_date = new Date( this.year, this.month-1, this.day );		
		return tmp_date.getDay();
	}
	this.prevSunday = function() {	//later expand to prev -any weekday, and next-- any weekday
		var wd = this.weekdayAsNum();
		this.subtractDays( wd );
	}
}

function H2_mkDateToday() {
	var d = new Date();
	var m = d.getMonth()+1;
	return new H2_Date( d.getFullYear() + '-' + m + '-' + d.getDate() );
}

////////////////////////////////////////////
function UrlCreator( nav_params, config_params ) {
	this.nav_params = nav_params;
	this.config_params = config_params;
	
	this.series = function( series_id ) {
		var s_key = series[series_id].series_key;
		var nav = new Object();
		nav.s = s_key;
		return this.createUrl( nav, false );		
	}
	this.ruleset = function( series_id, rs_id ) {	//should be able to leav blank and have it use the current req obj data.??
		var s_key = series[series_id].series_key;
		var nav = new Object();
		nav.s = s_key;
		nav.rs_id = rs_id;
		return this.createUrl( nav, false );
	}
	this.findYourself = function( staff_id ) {
		var alt_nav_params = new Object();
		alt_nav_params.a = this.nav_params.a;
		alt_nav_params.page = 'findyourself';
		alt_nav_params.staff_id = staff_id;
		
		return this.createUrl( alt_nav_params, false );
	}
	this.ajaxRequest = function () {
		var alt_config = clone( this.config_params );
		alt_config.async = 'yes';
		alt_config.reqdata = 'actionresponse';
		return this.createUrl( this.nav_params, alt_config );
	}
	this.exportToPDF = function( view_mode, staff_id ) {
		var alt_nav_params = clone( this.nav_params );
		alt_nav_params.view_mode = view_mode;
		if( view_mode === false ) {
			delete alt_nav_params.view_mode;
		}
		alt_nav_params.staff_id = staff_id;
		if( staff_id === false ) {
			delete alt_nav_params.staff_id;
		}

		var alt_config_params = clone( this.config_params );
		alt_config_params.theme = 'pdf';
		alt_config_params.salt = Math.random();
		
		return this.createUrl( alt_nav_params, alt_config_params );		
	}
	this.createUrl = function ( nav_params, config_params ) {
		if( nav_params === false ) {
			nav_params = this.nav_params;
		}
		if( config_params === false ) {
			config_params = this.config_params;
		}
		
		var url = '';
		var p;
		for( p in nav_params ) {
			if( url != '' ) url += '&';
			url += p + '=' + nav_params[p];
		}
		for( p in config_params ) {
			if( url != '' ) url += '&';
			url += p + '=' + config_params[p];
		}
		
		url = 'view.php?' + url;
		return url;
	}
	this.ajaxLoadSchedule = function( ranges, cur_staff_only ) {
		var url = '';
		for( p in nav_params ) {
			if( url != '' ) url += '&';
			url += p + '=' + nav_params[p];
		}
		for( p in config_params ) {
			if( url != '' ) url += '&';
			url += p + '=' + config_params[p];
		}
		
		for( var i in ranges ) {
			if( url != '' ) url += '&';
			url += 'from_' + i + '=' + ranges[i].from.asMysql() + '&to_' + i + '=' + ranges[i].to.asMysql();
		}
		
		url += '&num_range=' + ranges.length + '&async=yes&curstaffonly=';
		url += cur_staff_only ? 'yes' : 'no';
		
		return url;
	}
	this.ajaxLoadDaysForStaff = function( staff_id ) {
		var url = '';
		for( p in nav_params ) {
			if( url != '' ) url += '&';
			url += p + '=' + nav_params[p];
		}
		for( p in config_params ) {
			if( url != '' ) url += '&';
			url += p + '=' + config_params[p];
		}
		
		url += '&staff_id=' + staff_id + '&async=yes';
		
		return url;		
	}
}
	
function clone(myObj)
{
	if(typeof(myObj) != 'object') return myObj;
	if(myObj == null) return myObj;

	var myNewObj = new Object();

	for(var i in myObj)
		myNewObj[i] = clone(myObj[i]);

	return myNewObj;
}

function htmlEncode( s )
{
	return s.replace(/&(?!\w+([;\s]|$))/g, "&amp;")
	.replace(/</g, "&lt;").replace(/>/g, "&gt;");
}

function getElemPos(obj) {
	var curleft = curtop = 0;
	if (obj.offsetParent) {
		do {
			curleft += obj.offsetLeft;
			curtop += obj.offsetTop;
		} while (obj = obj.offsetParent);
	}
	return [curleft,curtop];
}
function getMouseXY( evt ) {
	var posx = 0, posy = 0;
	if( evt.pageX ) {
		posx = evt.pageX;
		posy = evt.pageY;
	}
	else if( evt.clientX ) {
		posx = evt.clientX + document.body.scrollLeft
			+ document.documentElement.scrollLeft;
		posy = evt.clientY + document.body.scrollTop
			+ document.documentElement.scrollTop;
	}
	
	return [posx,posy];
}