/*
<summary>
URL encodes the specified string so that it may be properly used in a URL.
</summary>
<param name="s">The string to encode</param>
*/
function WebUtility_UrlEncode( s ) {

	if( s == null ) {
		return null;
	}

	if( typeof(s) != "string" ) {
		s = s.toString();
	}

	var SafeChars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_.!~*'()";
	var HexChars = "0123456789ABCDEF";
	var encoded = "";

	for( var i = 0; i < s.length; i++ ) {
		var ch = s.charAt( i );

		if( SafeChars.indexOf(ch) != -1 ) {
			encoded += ch;
		}
		else if( ch == ' ' ) {
			encoded += '+';
		}
		else {
			var code = s.charCodeAt( i );

			if( code < 255 ) {
				encoded += '%';
				encoded += HexChars.charAt( (code >> 4) & 15 );
				encoded += HexChars.charAt( (code >> 0) & 15 );
			}
			else {
				encoded += '%u';
				encoded += HexChars.charAt( (code >> 12) & 15 );
				encoded += HexChars.charAt( (code >> 8) & 15 );
				encoded += HexChars.charAt( (code >> 4) & 15 );
				encoded += HexChars.charAt( (code >> 0) & 15 );
			}
		}
	}

	return encoded;
}

/*
<summary>
Decodes a URL encoded string.
</summary>
<param name="s">The string to decode</param>
*/
function WebUtility_UrlDecode( s ) {

	if( s == null ) {
		return null;
	}

	if( typeof(s) != "string" ) {
		s = s.toString();
	}

	var HexChars = "0123456789ABCDEF";
	var decoded = "";
	var i = 0;

	while( i < s.length ) {
		var ch = s.charAt( i );
		if( ch == '+' ) {
			decoded += ' ';
			i++;
		}
		else if( ch == '%' ) {
			// this is an escape sequence
			if( (i + 2) > s.length ) {
				throw "Invalid encoding";
			}

			if( s.charAt(i + 1) == 'u' ) {
				if( (i + 5) > s.length ) {
					throw "Invalid encoding";
				}

				var hex1 = s.charAt( i + 2 );
				var hex2 = s.charAt( i + 3 );
				var hex3 = s.charAt( i + 4 );
				var hex4 = s.charAt( i + 5 );
				var index1 = HexChars.indexOf( hex1 );
				var index2 = HexChars.indexOf( hex2 );
				var index3 = HexChars.indexOf( hex3 );
				var index4 = HexChars.indexOf( hex4 );
				if( index1 != -1 && index2 != -1 && index3 != -1 && index4 != -1 ) {
					decoded += String.fromCharCode( (index1 << 12) | (index2 << 8) | (index3 << 4) | index4 );
					i += 5;
				}
				else {
					throw "Invalid encoding";
				}
			}
			else {
				var hex1 = s.charAt( i + 1 );
				var hex2 = s.charAt( i + 2 );
				var index1 = HexChars.indexOf( hex1 );
				var index2 = HexChars.indexOf( hex2 );
				if( index1 != -1 && index2 != -1 ) {
					decoded += String.fromCharCode( (index1 << 4) | index2 );
					i += 3;
				}
				else {
					throw "Invalid encoding";
				}
			}
		}
		else {
			decoded += ch;
			i++;
		}
	}

	return decoded;	
}

/*
<summary>
Encodes the specified string so that it may be used in HTML content.
</summary>
<param name="s">The string to encode</param>
*/
function WebUtility_HtmlEncode( s ) {

	if( s == null ) {
		return null;
	}

	if( typeof(s) != "string" ) {
		s = s.toString();
	}

	var encoded = "";

	for( var i = 0; i < s.length; i++ ) {
		var ch = s.charAt( i );

		if( ch == '&' ) {
			encoded += "&amp;";
		}
		else if( ch == '<' ) {
			encoded += "&lt;";
		}
		else if( ch == '>' ) {
			encoded += "&gt;";
		}
		else if( ch == '"' ) {
			encoded += "&quot;";
		}
		else {
			encoded += ch;
		}
	}

	return encoded;
}

/*
<summary>
Decodes an HTML encoded string.
</summary>
<param name="s">The string to decode</param>
*/
function WebUtility_HtmlDecode( s ) {

	if( s == null ) {
		return null;
	}

	if( typeof(s) != "string" ) {
		s = s.toString();
	}

	var i = 0;
	var decoded = "";

	while( i < s.length ) {
		var amp = s.indexOf( '&', i );

		if( amp == -1 ) {
			decoded += s.substring( i, s.length );
			i = s.length;
			continue;
		}

		// copy everything between the current position and the '&' to the output.
		decoded += s.substring( i, amp );

		var semi = s.indexOf( ';', amp + 1 );

		if( semi == -1 ) {
			decoded += s.substring( amp, s.length );
			i = s.length;
			continue;
		}

		if( semi > amp + 16 ) {
			decoded += '&';
			i = amp + 1;
			continue;
		}

		var name = s.substring( amp + 1, semi );

		if( name == "amp" ) {
			decoded += "&";
		}
		else if( name == "lt" ) {
			decoded += "<";
		}
		else if( name == "gt" ) {
			decoded += ">";
		}
		else if( name == "quot" ) {
			decoded += "\"";
		}
		else if( name.length > 1 && name.charAt(0) == '#' ) {
			if( name.charAt(1) == 'x' || name.charAt(1) == 'X' ) {
				var code = parseInt( "0x" + name.substr(2, semi - amp - 3) );

				decoded += String.fromCharCode( code );
			}
			else {
				var code = parseInt( name.substr(1, semi - amp - 2) );

				decoded += String.fromCharCode( code );
			}
		}
		else {
			// just copy the '&' to the output and pick up immediately after
			decoded += '&';
			i = amp + 1;
			continue;
		}

		i = semi + 1;
	}

	return decoded;
}

/*
<summary>
Returns the element with the specified id.
</summary>
<param name="id">The id of the element to retrieve</param>
*/
function WebUtility_GetElement( id ) {

	return document.getElementById( id );
}

/*
<summary>
Returns the value of the specified string as a floating point number.  The string can be
of the form:
<VALUE><UNIT>
where VALUE is a numeric value and UNIT is any of the allowed HTML unit specifications such
as px, pt, in, cm, ...
</summary>
<param name="v">The value</param>
*/
function WebUtility_GetUnitValue( v ) {

	if( v == "" ) {
		return 0;
	}

	return parseFloat( v );
}

/*
<summary>
Returns the CSS style object that matches the specified CSS selector.
</summary>
<param name="selector">The CSS selector used to define the scope of the style object</selector>
*/
function WebUtility_GetStyleObject( selector ) {
	// Internet Explorer
	if( WebUtility.Browser.IsIE == true ) {
		for( var i = 0; i < document.styleSheets.length; i++ ) {
			var styleSheet = document.styleSheets[i];
			for( var j = 0; j < styleSheet.rules.length; j++ ) {
				if( styleSheet.rules[j].selectorText == selector ) {
					return styleSheet.rules[j].style;
				}
			}
		}
	}
	
	for( var i = 0; i < document.styleSheets.length; i++ ) {
		var styleSheet = document.styleSheets[i];

		for( var j = 0; j < styleSheet.cssRules.length; j++ ) {
			if( styleSheet.cssRules[j].selectorText == selector ) {
				return styleSheet.cssRules[j].style;
			}
		}
	}
	return null;
}

/*
<summary>
Returns the width of the client area of the browser window in pixels.
</summary>
*/
function WebUtility_GetClientWidth() {

	if( window.self != null && self.innerWidth != null ) {
		return self.innerWidth;
	}

	if( document.documentElement != null && document.documentElement.clientWidth != null ) {
		return document.documentElement.clientWidth;
	}

	return 0;
}

/*
<summary>
Returns the height of the client area of the browser window in pixels.
</summary>
*/
function WebUtility_GetClientHeight() {

	if( window.self != null && self.innerHeight != null ) {
		return self.innerHeight;
	}

	if( document.documentElement != null && document.documentElement.clientHeight != null ) {
		return document.documentElement.clientHeight;
	}

	return 0;
}

/*
<summary>
Returns the the left and top coordinates of an object
Got code from http://www.quirksmode.org/js/findpos.html
</summary>
*/
function WebUtility_FindPos( obj )
{	
	var origObj = obj;
	var curleft = 0;
	var curtop = 0;
	
	if( obj == null ) {
		return [0,0,0,0];
	}
	
	if ( obj.offsetParent ) {
	
		curleft = obj.offsetLeft
		curtop = obj.offsetTop
		while ( obj = obj.offsetParent ) {
			curleft += obj.offsetLeft
			curtop += obj.offsetTop
		}
	}
	return [curleft,curtop, origObj.offsetWidth, origObj.offsetHeight];
}

/*
<summary>
Pads a numeric value with zeros so that the length of the resulting string will be at least
2 characters.
</summary>
<param name="v">The numeric value to pad</param>
*/
function _ZeroPad( v ) {

	return ( (v < 10) ? "0" : "" ) + v;
}

/*
<summary>
Formats the specified date object.  This method uses the formatting conventions
of the .NET framework to specify the format string.
</summary>
<param name="date">The date to format</param>
<param name="format">The format string</param>
<remarks>
The following format specifiers may be used to define the format of the resulting date string:
yyyy:	Outputs the 4 digit year
yy:		Outputs the 2 digit year
BB:		Outputs the full month name
B:		Outputs the abbreviated month name
CC:		Outputs the 2 digit month, zero padded if necessary
C:		Outputs the 1 or 2 digit month with no zero padding
dd:		Outputs the 2 digit day, zero padded if necessary
d:		Outputs the 1 or 2 digit day with no zero padding
EE:		Outputs the full day of the week
E:		Outputs the abbreviated day of the week
HH:		Outputs the 2 digit hour in 24 hour format, zero padded if necessary
H:		Outputs the 1 or 2 digit hour in 24 hour format with no zero padding
hh:		Outputs the 2 digit hour in 12 hour format, zero padded if necessary
h:		Outputs the 1 or 2 digit hour in 12 hour format with no zero padding
mm:		Outputs the 2 digit minute, zero padded if necessary
m:		Outputs the 1 or 2 digit minute with no zero padding
ss:		Outputs the 2 digit second, zero padded if necessary
s:		Outputs the 1 or 2 digit second with no zero padding
tt:		Outputs AM or PM depending on the time of day
Note: for the brute force solution we have implemented, we should avoid using the following capital letters 
as they will be duplicates with some translations of days or months
(A, D, F, J, M, N, O, P, S, T, W)
</remarks>
*/

var WebUtility_Months		= new Array( "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" );
var WebUtility_ShortMonths	= new Array( "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" );
var WebUtility_Days			= new Array( "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" );
var WebUtility_ShortDays	= new Array( "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" );
var WebUtility_ShortDays2	= new Array( "Sun", "Mon", "Tues", "Wed", "Thur", "Fri", "Sat" );

function WebUtility_FormatDate( date, format ) {

	var year			= date.getFullYear();
	var month			= date.getMonth() + 1;
	var day				= date.getDate();
	var hour			= date.getHours();
	var minute			= date.getMinutes();
	var second			= date.getSeconds();
	var dayOfWeek		= date.getDay();
	var hourBase12		= hour > 12 ? ( hour - 12 ) : hour;
	if( hourBase12 == 0 ) {
		hourBase12 = 12;
	}

	var dateString		= format;

	dateString			= dateString.replace( "yyyy", year ).replace( "yy", year.toString().substring( 3, 4 ) );
	dateString			= dateString.replace( "dd", _ZeroPad( day ) ).replace( "d", day );
	dateString			= dateString.replace( "HH", _ZeroPad( hour ) ).replace( "H", hour );
	dateString			= dateString.replace( "hh", _ZeroPad( hourBase12 ) ).replace( "h", hourBase12 );
	dateString			= dateString.replace( "mm", _ZeroPad( minute ) ).replace( "m", minute );
	dateString			= dateString.replace( "ss", _ZeroPad( second ) ).replace( "s", second );
	dateString			= dateString.replace( "CC", _ZeroPad( month ) ).replace( "C", month );
	dateString			= dateString.replace( "BB", WebUtility_Months[month - 1] ).replace( "B", WebUtility_ShortMonths[month - 1] );
	dateString			= dateString.replace( "tt", hour >= 12 ? "PM" : "AM" );
	dateString			= dateString.replace( "EE", WebUtility_Days[dayOfWeek] ).replace( "E", WebUtility_ShortDays[dayOfWeek] );

	return dateString;
}

function WebUtility_FormatDataDate( date ) {

	var year	= date.getFullYear();
	var month	= date.getMonth() + 1;
	var day		= date.getDate();
	var hour	= date.getHours();
	var minute	= date.getMinutes();
	
	if( month < 10 ) {
		month = "0" + month;
	}
	if( day < 10 ) {
		day = "0" + day;
	}
	if( hour < 10 ) {
		hour = "0" + hour;
	}
	if( minute < 10 ) {
		minute = "0" + minute;
	}

	return "" + year + month + day + hour + minute;
}

function WebUtility_GetTime( date ) {
	var hour = date.getHours();
	var minute = date.getMinutes();
	if( minute < 10 ) {
		minute = "0" + minute;
	}
	var basehour = hour;
	if( basehour > 12 ) {
		basehour -= 12;
	}
	else if( basehour == 0 ) {
		basehour = 12;
	}
	
	return basehour + ":" + minute + " " + (hour >= 12 ? "PM" : "AM");
}

function WebUtility_GetTimeOffset( date, offsetHours, offsetMinutes ) {
	
	var hour = date.getHours() + offsetHours;
	var minute = date.getMinutes() + offsetMinutes;
	if( minute < 0 ) {
		hour--;
		minute = 60 + minute;
	}
	if( minute > 60 ) {
		hour++;
		minute = minute - 60;
	}
	if( hour > 24 ) {
		hour = hour - 24;
	}
	if( hour < 0 ) {
		hour = 24 + hour;
	}
		
	if( minute < 10 ) {
		minute = "0" + minute;
	}
	var basehour = hour;
	if( basehour > 12 ) {
		basehour -= 12;
	}
	else if( basehour == 0 ) {
		basehour = 12;
	}
	
	return basehour + ":" + minute + " " + (hour >= 12 ? "PM" : "AM");
}

function WebUtility_GetDate( date ) {
	var month = date.getMonth() + 1;
	var day = date.getDate();
	var year = date.getFullYear();
	
	return month + "/" + day + "/" + year;
}

function WebUtility_GetShortDate( date ) {
	var month = date.getMonth() + 1;
	var day = date.getDate();
	
	return month + "/" + day;
}

function WebUtility_GetDay( date ) {
	
	return WebUtility_Days[date.getDay()];
}

function WebUtility_GetShortDay( date ) {
	
	return WebUtility_ShortDays2[date.getDay()];
}

function WebUtility_GetMonth( date ) {
	
	return WebUtility_Months[date.getMonth()];
}
/*
<summary>
Given a datetime string, generates a datetime string
</summary>
<param name="date">Input datetime string</param>
<returns>Datetime string</returns>
*/
function WebUtility_FormatDateFromString( dateTime ) {
	
	var returnTime		= new Date();
	var dateTimeString	= dateTime.toString();
	var month			= dateTimeString.substr(4, 2);
	
	// Month is represented as 0-11 in javascript, so adjust month from Tribune Data
	month = month - 1;
	returnTime.setFullYear( dateTimeString.substr(0, 4), month , dateTimeString.substr(6, 2) );
	returnTime.setHours( dateTimeString.substr(8, 2), dateTimeString.substr(10, 2) );
	return returnTime;	
}

/*
<summary>
Formats an output string according to the specified format string and a list of objects to be
included in the formatted string.  This method uses the formatting conventions of the .NET
framework to specify the format string.
</summary>
<remarks>
Substitution is performed by specifying an object to be substituted via its positional index.
For example:
FormatString( "Hello {0}.  You are looking {1} today.", "SnapStream", "totally awesome" );

Would produce the following output:
Hello SnapStream.  You are looking totally awesome today.
</remarks>
*/
function WebUtility_FormatString( format ) {

	var result = "";
	var openBrace = -1;
	var closeBrace = -1;

	while( true ) {
		openBrace = format.indexOf( '{', closeBrace + 1 );
		if( openBrace == -1 ) {
			// append the rest of the string.
			result += format.substring( closeBrace + 1, format.length );
			break;
		}

		// append the portion of the format string that contains no substitutions
		result += format.substring( closeBrace + 1, openBrace );

		// check to see if the client actually wanted to output a single '{'
		if( (openBrace + 1 < format.length) && (format.charAt(openBrace + 1) == '{') ) {
			closeBrace = openBrace + 1;
			result += "{";
			continue;
		}

		closeBrace = format.indexOf( '}', openBrace + 1 );
		if( closeBrace == -1 ) {
			result += format.substring( openBrace, format.length );
			break;
		}

		var index = parseInt( format.substring(openBrace + 1, closeBrace) );

		result += arguments[index + 1];
	}

	return result;
}

/*
<summary>
Converts the specified date object into a UTC date object.
</summary>
<param name="date">The date to convert</param>
*/
function WebUtility_ToUtcDate( date ) {

	return new Date( date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours(), 
		date.getUTCMinutes(), date.getUTCSeconds(), date.getUTCMilliseconds() );
}

/*
<summary>
Converts the specified UTC date object into a local date object.
</summary>
<param name="date">The date to convert</param>
*/
function WebUtility_FromUtcDate( date ) {

	return new Date( Date.UTC(date.getFullYear(), date.getMonth(), date.getDate(), date.getHours(), date.getMinutes(),
		date.getSeconds(), date.getMilliseconds()) );
}

function WebUtility_GetMilli( date ) {

	return Date.UTC( date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours(), 
		date.getUTCMinutes(), date.getUTCSeconds(), date.getUTCMilliseconds() );
}

function WebUtility_GetUtcMilli( date ) {

	return Date.UTC( date.getFullYear(), date.getMonth(), date.getDate(), date.getHours(), 
		date.getMinutes(), date.getSeconds(), date.getMilliseconds() );
}

function _Browser() {

	var agent = navigator.userAgent.toLowerCase();
	var major = parseInt( navigator.appVersion );
	var minor = parseFloat( navigator.appVersion );	

	this.IsIE = ( (agent.indexOf("msie") != -1) && (agent.indexOf("opera") == -1) );
	this.IsIE5 = ( this.IsIE && (major == 4) && (agent.indexOf("msie 5.0") != -1) );
	this.IsIE5_5 = ( this.IsIE && (major == 4) && (agent.indexOf("msie 5.5") != -1) );
	this.IsIE6 = ( this.IsIE && (major == 4) && (agent.indexOf("msie 6.") != -1) );
	this.IsIE7 = ( this.IsIE && (agent.indexOf("msie 7.") != -1) );
	this.IsOpera = ( agent.indexOf("opera") != -1 );
	this.IsGecko = ( agent.indexOf("gecko") != -1 );
	this.IsFirefox = ( agent.indexOf("firefox") != -1 );
	this.IsFirefox1 = ( agent.indexOf("firefox/1.") != -1 );
	this.IsFirefox1_5 = ( agent.indexOf("firefox/1.5") != -1 );
	this.IsFirefox2 = ( agent.indexOf("firefox/2.") != -1 );

	return;
}

/*
<summary>
Ensures that every charater in the string is numeric
</summary>
<param name="ch">The character to test</param>
<param name="allowEnter">Boolean to tell whether we should allow the neter key press or not</param>
<returns>True if all the characters are numeric (0-9), otherwise false</returns>
*/
function WebUtility_IsCharNumeric( ch, allowEnter ) {

	if( ch == 13 && allowEnter == true ) {
		return true;
	}

	if( ch < 48 || ch > 57 ) {
		return false;
	}

	return true;
}

/*
<summary>
Gets the event event correctly for IE or Firefox
</summary>
<param name="possibleEvent">The event object that was passed into an event handler for non-IE browsers</param>
<param name="possibleEvent2">The event object for IE browsers</param>
<returns>The correct event object</returns>
*/
function WebUtility_GetEvent( possibleEvent, possibleEvent2 ) {

	var	outputEvent;

	outputEvent = possibleEvent;
	if( outputEvent == null ) {
		outputEvent = possibleEvent2;
	}

	return outputEvent;
}

/*
<summary>
Gets the key code from an event correctly for IE or Firefox
</summary>
<param name="ch">The event that contains the key code</param>
<returns>The key code or 0 if the code doesn't exist</returns>
*/
function WebUtility_GetKeyCode( keyEvent ) {

	var	keyCode;

	keyCode = 0;
	if( WebUtility.Browser.IsIE == true ) {
		keyCode = keyEvent.keyCode;
	}
	else if( WebUtility.Browser.IsFirefox == true ) {
		keyCode = keyEvent.which;
	}

	return keyCode;
}

// Attach this function to prevent the enter from submitting the form if anything other than a text box or a submit
// button has focus.
// Note: This function only works for IE
// Note: This function should be tied to an event handler and return "true" to do nothing and "false" to stop the event
function WebUtility_EnterOnTextOrButton_IE() {

	// If this is not IE, we are not going to do anything
	if( WebUtility.Browser.IsIE == false ) {
		return true;
	}

	// Prevent the form submission for anything other than a text box or submit button
	if( event.keyCode == 13 && event.srcElement.type != 'text' && event.srcElement.type != 'submit' ) {
		return false;
	}

	// We are either a non-enter press, a text box, or a submit button so do nothing
	return true;
}

function WebUtility_DecodeQueryString( sSearch ) {
	var Parameters = new Object();
	var sNameValuePairs = sSearch.split('&');
	
	Parameters["station"] = "";
	Parameters["startTime"] = "";
	Parameters["endTime"] = "";
	
	for (var i = 0; i < sNameValuePairs.length; i++) {
		var sNameValuePair = sNameValuePairs[i].split('=');
		Parameters[sNameValuePair[0]] = sNameValuePair[1];
	}
	return Parameters;
}

function WebUtility_GetMinuteDifference( date1, date2 ) {
	return ( date2.getTime() - date1.getTime() ) / ( 60 * 1000 );
}

function WebUtility_GetHourDifference( date1, date2 ) {
	return ( date2.getTime() - date1.getTime() ) / ( 60 * 60 * 1000 );
}

function WebUtility_GetMilliMinuteDifference( date1, date2 ) {
	return ( date2 - date1 ) / ( 60 * 1000 );
}

function WebUtility_GetMilliHourDifference( date1, date2 ) {
	return ( date2 - date1 ) / ( 60 * 60 * 1000 );
}

///<summary>
///Checks to see if input is the min Javascript DateTime value, 00:00:00, January 1, 1901.
///</summary>
///<param name="inputDateTime">The inputDateTime to test</param>
///<returns>Returns true if input is min value</returns>
function WebUtility_IsMinDateTime( inputDateTime ) {
	
	// Represents minimum Javascript Date 00:00:00, January 1, 1901.
	var minDate = new Date( 1, 0, 1, 0, 0, 0 );

	if( inputDateTime.valueOf() == minDate.valueOf() ) {
		return true;
	}
	return false;
}

function DaysInMonth( iMonth, iYear ) {
	return 32 - new Date( iYear, iMonth, 32 ).getDate();
}

/*
private static DateTime GetRelativeDate(int year, int month, int targetDayOfWeek, int numberOfSundays) {
    DateTime time;

    if (numberOfSundays <= 4) {
        //
        // Get the (numberOfSundays)th Sunday.
        //
        time = new DateTime(year, month, 1);

        int dayOfWeek = (int)time.DayOfWeek;
        int delta = targetDayOfWeek - dayOfWeek;
        if (delta < 0) {
            delta += 7;
        }
        delta += 7 * (numberOfSundays - 1);

        if (delta > 0) {
            time = time.AddDays(delta);
        }
    }
    else {
        //
        // If numberOfSunday is greater than 4, we will get the last sunday.
        //
        Int32 daysInMonth = DateTime.DaysInMonth(year, month);
        time = new DateTime(year, month, daysInMonth);
        // This is the day of week for the last day of the month.
        int dayOfWeek = (int)time.DayOfWeek;
        int delta = dayOfWeek - targetDayOfWeek;
        if (delta < 0) {
            delta += 7;
        }

        if (delta > 0) {
            time = time.AddDays(-delta);
        }
    }
    return time;
}
*/


function GetRelativeDate( year, month, targetDayOfWeek, numberOfSundays ) {
    var time;

    if( numberOfSundays <= 4 ) {
        //
        // Get the (numberOfSundays)th Sunday.
        //
        time = new Date( year, month - 1, 1 );

        var dayOfWeek = time.getDay();
        var delta = targetDayOfWeek - dayOfWeek;
        if( delta < 0 ) {
            delta += 7;
        }
        delta += 7 * (numberOfSundays - 1);

        if( delta > 0 ) {
            time.setDate( time.getDate() + delta );
        }
    }
    else {
        //
        // If numberOfSunday is greater than 4, we will get the last sunday.
        //
        var daysInMonth = DaysInMonth( year, month );
        time = new Date( year, month - 1, daysInMonth );
        // This is the day of week for the last day of the month.
        var dayOfWeek = time.getDay();
        var delta = dayOfWeek - targetDayOfWeek;
        if( delta < 0 ) {
            delta += 7;
        }

        if (delta > 0) {
            time.setDate( time.getDate() - delta );
        }
    }
    return time;
}

/*
private static DaylightTime GetDaylightTime(Int32 year, zoneInfo zone) {
    TimeSpan delta = zone.DaylightBias;
    DateTime startTime = GetRelativeDate(year, zone.DaylightTransitionMonth, zone.DaylightTransitionDayOfWeek, zone.DaylightTransitionWeek);
    startTime = startTime.AddTicks(zone.DaylightTransitionTimeOfDay.Ticks);
    DateTime endTime = GetRelativeDate(year, zone.StandardTransitionMonth, zone.StandardTransitionDayOfWeek, zone.StandardTransitionWeek);
    endTime = endTime.AddTicks(zone.StandardTransitionTimeOfDay.Ticks);
    return new DaylightTime(startTime, endTime, delta);
}
 */
function GetDaylightTimeStart( time, zone ) {
	var startTime = GetRelativeDate( time.getFullYear(), zone.DTM, zone.DTDOW, zone.DTW );
	return WebUtility.GetUtcMilli(startTime) + zone.DTTOD;
}

function GetDaylightTimeEnd( time, zone ) {
	var startTime = GetRelativeDate( time.getFullYear(), zone.STM, zone.STDOW, zone.STW );
	return WebUtility.GetUtcMilli(startTime) + zone.DTTOD;
}

 /*       
public static Boolean GetIsDaylightSavingsFromUtc(DateTime time, zoneInfo zone) {
    if (!zone.SupportsDaylightSavings) {
        return false;
    }

    // Get the daylight changes for the year of the specified time.
    TimeSpan offset = -zone.Bias;
    DaylightTime daylightTime = GetDaylightTime(time.Year, zone);

    // The start and end times represent the range of universal times that are in DST for that year.                
    // Within that there is an ambiguous hour, usually right at the end, but at the beginning in
    // the unusual case of a negative daylight savings delta.
    DateTime startTime = daylightTime.Start - offset;
    DateTime endTime = daylightTime.End - offset + zone.DaylightBias;

    Boolean isDst = false;
    if (startTime > endTime) {
        // In southern hemisphere, the daylight saving time starts later in the year, and ends in the beginning of next year.
        // Note, the summer in the southern hemisphere begins late in the year.
        isDst = (time < endTime || time >= startTime);
    }
    else {
        // In northern hemisphere, the daylight saving time starts in the middle of the year.
        isDst = (time >= startTime && time < endTime);
    }
    return isDst;
}
*/
function WebUtility_GetIsDaylightSavingsFromUtc( time, zone ) {
	if( zone.SDS == false ) {
		return false;
	}
	var offset = -zone.B;
	var startTime = GetDaylightTimeStart( time, zone ) - offset;
	var endTime = GetDaylightTimeEnd( time, zone ) - offset + zone.DB;
	var utcMilli = WebUtility.GetUtcMilli( time );
    var isDst = false;
    if( startTime > endTime ) {
        isDst = (utcMilli < endTime || utcMilli >= startTime);
    }
    else {
        isDst = (utcMilli >= startTime && utcMilli < endTime);
    }
    return isDst;
}

/*
public static TimeSpan GetUtcOffsetFromUtc(DateTime time, zoneInfo zone) {
    TimeSpan baseOffset = -zone.Bias;
    Boolean isDaylightSavings = GetIsDaylightSavingsFromUtc(time, zone);
    TimeSpan finalOffset = baseOffset -= (isDaylightSavings ? zone.DaylightBias : TimeSpan.Zero);
    return baseOffset;
}
*/
function WebUtility_GetUtcOffsetFromUtc( time, zone ) {
	var baseOffset = -zone.B;
	var isDaylightSavings = WebUtility.GetIsDaylightSavingsFromUtc( time, zone );
	var finalOffset = baseOffset -= (isDaylightSavings ? zone.DB : 0);
	return baseOffset;
}

function WebUtility_GetTimeConversion( zone, startMilli, endMilli ) {
	var ret = new Object();

	var time = new Date( startMilli );
	var timeUtc = WebUtility.ToUtcDate( time );
	
	//then get all the offset vars
	//var offset = GetUtcOffsetFromUtc( timeTempUtc );
	var isDST = WebUtility.GetIsDaylightSavingsFromUtc( timeUtc, zone );
	
	var baseOffsetHours = -zone.BH;
	var baseOffsetMinutes = -zone.BM;
	var baseOffset = -zone.B;
	
	var offsetHours = baseOffsetHours - (isDST ? zone.DBH : 0);
	var offsetMinutes = baseOffsetMinutes - (isDST ? zone.DBM : 0);	
	var offset = baseOffset - (isDST ? zone.DB : 0);
	
	var timeCorrectDate = new Date( startMilli + offset + time.getTimezoneOffset() * 60000 );
	
	ret.startDay = WebUtility.GetDay( timeCorrectDate );
	ret.startTime = WebUtility.GetTimeOffset( timeUtc, offsetHours, offsetMinutes );
	ret.startDate = WebUtility.GetDate( timeCorrectDate );
	
	if( typeof(endMilli) != "undefined" ) {
	
		time = new Date( endMilli );
		timeUtc = WebUtility.ToUtcDate( time );
		
		isDST = WebUtility.GetIsDaylightSavingsFromUtc( time, zone );
		
		offsetHours = baseOffsetHours - (isDST ? zone.DBH : 0);
		offsetMinutes = baseOffsetMinutes - (isDST ? zone.DBM : 0);	
		
		ret.endTime = WebUtility.GetTimeOffset( timeUtc, offsetHours, offsetMinutes );
	}
	
	return ret;
}

function WebUtility_GetShortTimeConversion( zone, startMilli, endMilli ) {
	var ret = new Object();

	var time = new Date( startMilli );
	var timeUtc = WebUtility.ToUtcDate( time );
	
	//then get all the offset vars
	//var offset = GetUtcOffsetFromUtc( timeTempUtc );
	var isDST = WebUtility.GetIsDaylightSavingsFromUtc( timeUtc, zone );
	
	var baseOffsetHours = -zone.BH;
	var baseOffsetMinutes = -zone.BM;
	var baseOffset = -zone.B;
	
	var offsetHours = baseOffsetHours - (isDST ? zone.DBH : 0);
	var offsetMinutes = baseOffsetMinutes - (isDST ? zone.DBM : 0);	
	var offset = baseOffset - (isDST ? zone.DB : 0);
	
	var timeCorrectDate = new Date( startMilli + offset + time.getTimezoneOffset() * 60000 );
	
	ret.startDay = WebUtility.GetShortDay( timeCorrectDate );
	ret.startDate = WebUtility.GetShortDate( timeCorrectDate );
	ret.startTime = WebUtility.GetTimeOffset( timeUtc, offsetHours, offsetMinutes );
	
	if( typeof(endMilli) != "undefined" ) {
	
		time = new Date( endMilli );
		timeUtc = WebUtility.ToUtcDate( time );
		
		isDST = WebUtility.GetIsDaylightSavingsFromUtc( time, zone );
		
		offsetHours = baseOffsetHours - (isDST ? zone.DBH : 0);
		offsetMinutes = baseOffsetMinutes - (isDST ? zone.DBM : 0);	
		
		ret.endTime = WebUtility.GetTimeOffset( timeUtc, offsetHours, offsetMinutes );
	}
	return ret;
}

// setup a global object with nothing but functions hanging off it
var WebUtility = new Object();
WebUtility.DecodeQueryString = WebUtility_DecodeQueryString;
WebUtility.UrlEncode = WebUtility_UrlEncode;
WebUtility.UrlDecode = WebUtility_UrlDecode;
WebUtility.HtmlEncode = WebUtility_HtmlEncode;
WebUtility.HtmlDecode = WebUtility_HtmlDecode;
WebUtility.GetElement = WebUtility_GetElement;
WebUtility.GetUnitValue = WebUtility_GetUnitValue;
WebUtility.GetStyleObject = WebUtility_GetStyleObject;
WebUtility.FormatDate = WebUtility_FormatDate;
WebUtility.GetDate = WebUtility_GetDate;
WebUtility.GetShortDate = WebUtility_GetShortDate;
WebUtility.FormatDataDate = WebUtility_FormatDataDate;
WebUtility.GetTime = WebUtility_GetTime;
WebUtility.GetTimeOffset = WebUtility_GetTimeOffset;
WebUtility.GetDay = WebUtility_GetDay;
WebUtility.GetShortDay = WebUtility_GetShortDay;
WebUtility.GetMonth = WebUtility_GetMonth;
WebUtility.FormatString = WebUtility_FormatString;
WebUtility.ToUtcDate = WebUtility_ToUtcDate;
WebUtility.FromUtcDate = WebUtility_FromUtcDate;
WebUtility.GetTimeConversion = WebUtility_GetTimeConversion;
WebUtility.GetShortTimeConversion = WebUtility_GetShortTimeConversion;
WebUtility.GetIsDaylightSavingsFromUtc = WebUtility_GetIsDaylightSavingsFromUtc;
WebUtility.GetUtcOffsetFromUtc = WebUtility_GetUtcOffsetFromUtc;
WebUtility.GetMilli = WebUtility_GetMilli;
WebUtility.GetUtcMilli = WebUtility_GetUtcMilli;
WebUtility.GetClientWidth = WebUtility_GetClientWidth;
WebUtility.GetClientHeight = WebUtility_GetClientHeight;
WebUtility.IsCharNumeric = WebUtility_IsCharNumeric;
WebUtility.GetEvent = WebUtility_GetEvent;
WebUtility.GetKeyCode = WebUtility_GetKeyCode;
WebUtility.EnterOnTextOrButton_IE = WebUtility_EnterOnTextOrButton_IE;
WebUtility.Browser = new _Browser();
WebUtility.FormatDateFromString = WebUtility_FormatDateFromString;
WebUtility.GetMinuteDifference = WebUtility_GetMinuteDifference;
WebUtility.GetHourDifference = WebUtility_GetHourDifference;
WebUtility.GetMilliMinuteDifference = WebUtility_GetMilliMinuteDifference;
WebUtility.GetMilliHourDifference = WebUtility_GetMilliHourDifference;
WebUtility.IsMinDateTime = WebUtility_IsMinDateTime;
WebUtility.FindPos = WebUtility_FindPos;