//	Calendar Javascript - Copyright (C) 2007-2010 Charles A Upsdell, All Rights Reserved; www.upsdell.com
//
aModule.uses( 'cCalendar', 'cal_config' );


// CALENDAR DATA

kal.aMonthName = [ 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' ];
kal.aMonthNameSmall = [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ];
kal.aWeekDayName = [ 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday' ];
kal.aWeekDayNameSmall = [ 'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat' ];
kal.aWeekDayNameXSmall = [ 'Su', 'M', 'Tu', 'W', 'Th', 'F', 'Sa' ];
kal.aDaysInMonths = [ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ];


// LOCAL FUNCTIONS

function calEventPriority ( eType )
{
return( kal.eventData.indexOf( eType ) );
}


function calDays ( y1, m1, d1, y2, m2, d2 )
{
var $name = 'calDays';
y1 = ( y1 === undefined ) ? 2000 : y1;
m1 = ( m1 === undefined ) ? 0 : m1;
d1 = ( d1 === undefined ) ? 0 : d1;
if ( y1 instanceof String )
	y1 = Number(y1);
if ( m1 instanceof String )
	m1 = Number(m1);
if ( d1 instanceof String )
	d1 = Number(d1);
if ( y1 < 2000 )
	{ $name.alert( '', 'year < 2000 in "%0 %1 %2"', y1, m1, d1 ); return -1; }
var nDays = 0;
for ( var y = 2000; y <= y1; ++y )
  {
	var nLeapDays = ((y%4 == 0) && ((y%100 != 0) || (y%400 == 0))) ? 1 : 0;
	if ( y < y1 )
	  {
		nDays += 365 + nLeapDays;
	  }
	else if ( y == y1 )
	  {
		for ( var m = 0; m < m1; m++ )
		  {
			nDays += kal.aDaysInMonths[ m ];
			if ( m == 1 )
				nDays += nLeapDays;
		  }
		nDays += d1;
	  }
  }
if ( y2 === undefined )
	return nDays;
else
	return calDays(y2, m2, d2) - nDays;
}


function calMonth ( name )
{
var rv = -1;
if ( name !== undefined )
  {
	if ( typeof(name) != 'number' )
	  {
		if ( name.length == 3 )
			rv = kal.aMonthNameSmall.indexOf( name );
		else
			rv = kal.aMonthName.indexOf( name );
	  }
	else if ( isInRange(0,name,11) )
		rv = name;
  }
return rv;
}


function calInsertFilenamePrefix ( s )
{
if ( kal.filenamePrefix == '' )
	return s;
var i1 = s.indexOf( 'href=' );
if ( i1 == -1 )
	return s;
var i2 = s.indexOf( 'href="http://' );
if ( i2 != -1 )
	return s;
return s.substring(0,i1+6) + kal.filenamePrefix + s.substring(i1+6);
}


function calMakeUrl ( name, classes )
{
var $name = 'calMakeUrl';
var rv = '';
if ( (name != '') && !(typeof(name) != 'string') && !(typeof(name) != 'number') )
	{ $name.alert( '', '"%0" is %1, must be string or number', name, typeof(name) ); return rv; }
if ( arguments.length == 0 )
	return rv;
rv = name;
if ( rv instanceof Number )
	rv = rv.toString();
else if ( rv.length == 0 )
	return rv;
else if ( name instanceof Array )
  {
	rv = new Array();
	for ( var i = 0; i < name.length; ++i )
		rv[i] = calMakeUrl( name[i], classes );
  }
else if ( rv.charAt(0) == '@' )
  {
	var sAddress;
	var sName;
	classes = (arguments.length < 2) ? '' : ' class="' + classes + '"';
	var ix = rv.indexOf(' ');
	if ( ix > 0 )
	  {
		sAddress = rv.substring(1,ix);
		sName = rv.substring(ix+1);
		rv = '<a href="' + sAddress + '"' + classes + '>' + sName + '</a>';
	  }
  }
return rv;
}

function calScore ( s1, s2, s )
{
var $name = 'calScore';
var rv = '';
var argc = arguments.length;
if ( argc < 2 )
	{ $name.alert( '', 'needs 2 arguments, has %0', argc ); return rv; }
if ( argc < 3 )
	s = '-';
rv = '' + s1 + s + s2;
if ( (Number(s1) < Number(s2)) && (typeof(kal.isHighLowScores) != 'undefined') && (kal.isHighLowScores)  )
	rv = '' + s2 + s + s1;
return rv;
}

// CLASSES & METHODS

String.prototype.isCalDigit = function ( n, s )
{
var rv = false;
var sChar = ' ';
if ( arguments.length == 0 )
	n = 0;
if ( arguments.length < 2 )
	s = '';
if ( n >= 0 )
  {
	if ( n < this.length )
		sChar = this.charAt( n );
  }
else
  {
	n = -n;
	if ( (this.length - n) >= 0 )
		sChar = this.charAt( this.length - n );
  }
rv = (s+'0123456789').indexOf( sChar ) != -1;
return rv;
}

cType.prototype.$name = 'cType';

function cType ( type )
{
if ( arguments.length == 0 )
	type = '?';
else if ( !(type instanceof cType) )
  {
	for ( var i = 0; i < arguments.length; ++i )
		this['t'+i] = arguments[i];
  }
else
  {
	this.set( type );
  }
}

cType.prototype.isEqual = function ( arglist )
{
var rv = false;
if ( arguments.length == 0 )
	return rv;
for ( var i = 0; i < arguments.length; ++i )
  {
	if ( arguments[i] instanceof Array )
	  {	// Check initial tn properties
		for ( var j = 0; j < arguments[i].length; ++j )
		  {
			if ( arguments[i][j] === undefined )
				continue;
			if ( this['t'+j] !== arguments[i][j] )
				return rv;
		  }
		continue;
	  }
	else if ( !(arguments[i] instanceof cType) )
	  {
		return rv;
	  }
	else for ( var property in this )
	  {	// Check this. properties
		if ( typeof(this[property]) == 'function' )
			continue;
		if ( this[property] != arguments[i][property] )
			return rv;
	  }
  }
return true;
}

cType.prototype.set = function ( type )
{
if ( !(type instanceof cType) )
  {
	for ( var i = 0; i < arguments.length; ++i )
		this['t'+i] = arguments[i];
  }
else
  {
	for ( var property in this )
	  {
		if ( typeof(type[property]) == 'function' )
			continue;
		this[property] = undefined;
  	  }
	for ( var property in type )
	  {
		if ( typeof(type[property]) == 'function' )
			continue;
		this[property] = type[property];
  	  }
  }
}


cCalendar.prototype.$name = 'cCalendar';

function cCalendar ( y1, y2 )
{
if ( arguments.length < 1 )
	{ this.$name.alert( '', 'no arguments' ); return; }
if ( y2 === undefined )
	y2 = y1;
else if ( y1 > y2 )
	{ this.$name.alert( '', 'y1 > y2' ); return; }
this.aYear = new Array();
for ( var i = 0; i <= (y2-y1); ++i )
	this.aYear[i] = new cEventYear( y1 + i );
this.M( 0, y1 );
this.nSaveYear = this.nSaveDay = this.nSaveListIx = -1;
}

cCalendar.prototype.E = function ( nMonthDay, sType, sEvent, arg3, arg4, arg5, arg6 )
{
var $name = 'E';
if ( arguments[0] instanceof Array )
  {
	var nMonth = this.aYear[this.y].nMonth;
	var nYear = this.y;
	for ( var i = 0; i < arguments[0].length; ++ i )
	  {
		if ( typeof(arguments[0][i]) == 'number' )
		  {
			if ( arguments[0][i] >= 2000 )
				this.Y( arguments[0][i] );
			else
				this.E( arguments[0][i], sType, sEvent, arg3, arg4, arg5 );
		  }
		else
		  {
			if ( arguments[0][i] == '' )
				this.M( nMonth, nYear );
			else
				this.M( arguments[0][i] );
		  }
	  }
	this.M( nMonth, nYear );
	return;
  }
var hasTime = false;
var aDays, aDaysList;
var sTime = '';
var sLocation = '';
var sSeries = '';
var sTitle = '';
if ( (arguments.length < 3) || (arguments[2] === undefined) )
	{ this.$name.alert( $name, '< 3 arguments, ', this.y, this.aYear[this.y].nMonth, nMonthDay ); return; }
else if ( (arguments.length == 3) || (arguments[3] === undefined) )
	aDays = [ 1 ];
else if ( arg3 instanceof Array )
  {
	aDays = arg3;
	if ( arg4 instanceof Array )
	  {
		aDaysList = arg4;
		arg4 = undefined;
	  }
  }
else
  {
	hasTime = true;
	sTime = ( arg3 === undefined ) ? '' : arg3 ;
	sLocation = ( arg4 === undefined ) ? '' : arg4 ;
	aDays = ( arg5 === undefined ) ? [ 1 ] : arg5 ;
	if ( !(aDays instanceof Array) )
		{ this.$name.alert( $name, 'arg5 not array on %0/%1/%2', this.aYear[this.y].nYear, kal.aMonthName[this.aYear[this.y].nMonth], nMonthDay ); return; }
	if ( arg6 instanceof Array )
		aDaysList = arg6;
  }
var oType = new cType();
if ( sType == '' )
	sType = '-';
switch ( sType.charAt(0) )
  {
  case	'-':
		oType.set( '-', '-' );
		break;
  case	'E':
		if ( sType == 'E2' )
			oType.set ( 'E2', 'E', '2' );
		else
			oType.set ( 'E', 'E', ' ' );
		break;
  case	'C':
		oType.set( 'C', 'C' );
		break;
  case	'H':
		oType.set( 'H', 'H' );
		break;
  case	'N':
		{
		if ( sType == 'N!' )
			oType.set ( 'N!', 'N', '!' );
		else
			oType.set ( 'N', 'N', ' ' );
		if ( sEvent instanceof Array )
		  {
			var sExpires = (sEvent.length > 2) ? sEvent[2] : '';
			sTitle = (sEvent.length > 0) ? sEvent[0] : '';
			sEvent = (sEvent.length > 1) ? sEvent[1] : '';
			if ( sExpires != '' )
			  {
				var numExp = /^[0-9]+$/;
				var nExpYear = -1;
				var nExpMonth = -1;
				var nExpDay = -1;
				var aExpires = new Array();
				aExpires = sExpires.split( ' ' );
				if ( aExpires.length != 3 )
					{ this.$name.alert( $name, 'News expiry date %0 needs 3 fields', sExpires ); return; }
				for ( var i = 0; i < aExpires.length; ++i )
				  {
					if ( aExpires[i].match ( numExp ) )
					  {
						if ( aExpires[i] >= 2000 )
							nExpYear = aExpires[i];
						else
							nExpDay =  aExpires[i];
					  }
					else
					  {
						nExpMonth = calMonth( aExpires[i] );
					  }
				  }
				if ( (nExpYear == -1) || (nExpMonth == -1) || (nExpDay == -1) )
					{ this.$name.alert( $name, 'Invalid expiry date', sExpires ); return; }
				var today = new Date();
				if ( calDays( nExpYear, nExpMonth, nExpDay-1, today.getFullYear(), today.getMonth(), today.getDate() - 1 ) >= 0 )
				  {
					if ( !(String(window.location).indexOf('file:') == 0) )
						return;
					sTitle = '<del>' + sTitle + '</del>';
					sEvent = '<del>' + sEvent + '</del>';
				  }
			  }
		  }
		}
		break;
  case	'P':
		if ( sType == 'P!' )
			oType.set ( 'P!', 'P', '!' );
		else
			oType.set ( 'P', 'P', ' ' );
		break;
  case	'S':
		if ( sType.length > 2 )
			sSeries = sType.substring(2);
		if ( (sType.length > 1) && (sType.charAt(1) == '!') )
			oType.set( 'S', 'S', ' ', '!' );
		else
			oType.set( 'S', 'S', ' ', ' ' );
		break;
  case	'T':
		if ( sType.length > 2 )
			sSeries = sType.substring(2);
		if ( (sType.length > 1) && (sType.charAt(1) == '!') )
			oType.set( 'S', 'S', 'T', '!' );
		else
			oType.set( 'S', 'S', 'T', ' ' );
		break;
  default:
		break;
  }
sEvent = calMakeUrl( sEvent );
if ( kal.eventData.indexOf( oType.t0 ) < 0 )
	{ this.$name.alert( $name, 'invalid event type', oType.t0 ); return; }
var isAddEvent = ( nMonthDay > 0 );
var nInterval = 7;
var oMultiDayEvent = new cMultiDayEvent();
if ( oType.t0 == 'S' )
	oMultiDayEvent.nInterval = nInterval = 1;
for ( var i = 0; i < aDays.length; ++i )
	oMultiDayEvent.addRepeat( aDays[i] );
var nDay = this.aYear[this.y].aYearDays[this.aYear[this.y].nMonth] + Math.abs(nMonthDay) - 1;
for ( var i = 0; i < aDays.length; ++i )
  {
	if ( aDays[i] < 0 )
		nInterval = -aDays[i];
	else if ( aDays[i] == 0 )
		nDay += nInterval;
	else for ( var j = 0; j < aDays[i]; ++j )
	  {
		if ( nInterval > 1 )
			oMultiDayEvent.nRepeats = 0;
		if ( nDay < this.aYear[this.y].daysInYear )
		  {
			var ix = -1;
			oMultiDayEvent.addDay();
			var oEvent = new cEvent( oType.t0, oType, sEvent, oMultiDayEvent, sTime, sLocation );
			oEvent.sSeries = sSeries;
			if ( sTitle !== '' )
				oEvent.sNewsTitle = sTitle;
			if ( isAddEvent )
				ix = this.aYear[this.y].aDay[nDay].addEvent( oEvent );
			else
				ix = this.aYear[this.y].aDay[nDay].removeEvent( oEvent );
			if ( ix >= 0 )
				this.setLastListPosition ( this.y, nDay, ix );
		  }
		nDay += nInterval;
	  }
  }
if ( aDaysList instanceof Array )
	this.E( aDaysList, oType.t0, sEvent, arg3, arg4 );
}


cCalendar.prototype.G = function ( nMonthDay, sType, sEvent, sTime, sT1, sT2, sLocn, nS1, nS2 )
{
var $name = 'G';
if ( arguments.length < 6 )
	{ this.$name.alert( $name, '< 6 arguments' ); return; }
var sHome = sT1.charAt(0);
if ( (sT1.length > 1) && ((sHome == '+') || (sHome == '-')) )
  {
	nS2 = nS1;
	nS1 = sLocn;
	sLocn = sT2;
	sT1 = sT1.substring(1);
	sT2 = '-';
	if ( sHome == '-' )
	  {
		sT2 = sT1;
		sT1 = '-';
	  }
  }
else if ( sT1 == sT2 )
  	{ this.$name.alert( $name, 'both teams %0', sT1 ); return; }
sEvent = calMakeUrl( sEvent );
var sSeries = '';
var sType0 = sType.charAt(0);
var isHG = (sT1 == '-');
var oType = new cType( 'G', 'G', sType0, (isHG ? 'H' : 'A'), ' ' );
if ( (sType0 != 'R') && (sType0 != 'T') && (sType0 != 'X') )
	{ this.$name.alert( $name, '"%0" not game sType', sType ); return; }
if ( sType.length > 1 )
  {
	if ( sType.charAt(1) == '!' )
		oType.t4 = '!';
	if ( sType.length > 2 )
	  {
		sSeries = sType.substring(2);
		sType = sType0;
	  }
  }
nS1 = (nS1 === undefined) ? '' : nS1;
nS2 = (nS2 === undefined) ? '' : nS2;
if ( !isHG )
  {
	sT2 = sT1;
	sT1 = '-';
	if ( !kal.isUsThemScores )
	  {
		var temp = nS1;
		nS1 = nS2;
		nS2 = temp;
	  }
  }
oType.t0 = oType.t1 + oType.t2 + oType.t3;
if ( sLocn.charAt(0) == '-' )
  {
	if ( isHG )
		sLocn = teamhome.getTeamHome( kal.ourTeam, sLocn );
	else if ( (sT2 != '') && (sT2.indexOf('TBA') == -1) )
		sLocn = teamhome.getTeamHome( sT2, sLocn );
	else
		sLocn = 'TBA';
  }
var nDay = this.aYear[this.y].aYearDays[this.aYear[this.y].nMonth];
nDay += (Math.abs(nMonthDay) - 1);
var oMultiDayEvent = new cMultiDayEvent();
var oEvent = new cEvent( oType.t0, oType, sEvent, oMultiDayEvent, sTime, sLocn, sT1, sT2, true, isHG, (sType0 == 'X'), (sType0 == 'T'), nS1, nS2 );
var ix = -1;
oEvent.sSeries = sSeries;
if ( nMonthDay > 0 )
	ix = this.aYear[this.y].aDay[nDay].addEvent( oEvent );
else
	ix = this.aYear[this.y].aDay[nDay].removeEvent( oEvent );
if ( ix >= 0 )
	this.setLastListPosition ( this.y, nDay, ix );
}


cCalendar.prototype.D = function ( name, val )
{
var $name = 'D';
if ( arguments.length%2 == 1 )
	this.$name.alert( $name, 'not all pairs' );
else for ( var i = 0; i < arguments.length; i += 2 )
  {
	var y = this.nSaveYear;
	var d = this.nSaveDay;
	var property = arguments[i];
	var value = arguments[i+1];
	if ( typeof(this.aYear[y].aDay[d][property]) != 'undefined' )
 		this.$name.alert( $name, 'property %0 already defined, is "%1"', property, this.aYear[y].aDay[d][property] );
	else
		this.aYear[y].aDay[d][property] = value;
  }
}


cCalendar.prototype.P = function ( name, val )
{
var $name = 'P';
if ( arguments.length%2 == 1 )
	this.$name.alert( $name, 'not all pairs' );
else for ( var i = 0; i < arguments.length; i += 2 )
  {
	var y = this.nSaveYear;
	var d = this.nSaveDay;
	var ix = this.nSaveListIx;
	var property = arguments[i];
	var value = arguments[i+1];
	if ( property instanceof Array )
	  {
		for ( var j = 0; j < property.length; ++j )
			this.P( property[j], value );
	  }
	else
	  {
		if ( typeof(this.aYear[y].aDay[d].aEvent[ix].oType[property]) != 'undefined' )
 			this.$name.alert( $name, 'property %0 already defined, is "%1"', property, this.aYear[y].aDay[d].aEvent[ix].oType[property] );
		else
			this.aYear[y].aDay[d].aEvent[ix].oType[property] = value;
	  }
  }
}


cCalendar.prototype.getDate = function ( d, m, y, format, isTitleWeekday )
{
d = d || 0;
m = m || 0;
y = y || this.y;
format = format || [ 'Y', 'M', 'd' ];
isTitleWeekday = isTitleWeekday || false;
var nWeekDay = undefined;
if ( m < 0 )
  {
	var iY;
	for ( iY = 0; iY < this.aYear.length; ++iY )
	  {
		if ( this.aYear[iY].nYear == y )
			break;
	  }
	if ( iY == this.aYear.length )
		iY = this.y;
	if ( isTitleWeekday )
		nWeekDay = this.aYear[iY].aDay[d].nWeekDay;
	for ( m = 0; m < this.aYear[iY].aMonthDays.length; ++m )
	  {
		if ( d < this.aYear[iY].aMonthDays[m] )
			break;
		else
			d -= this.aYear[iY].aMonthDays[m];
	  }
  }
var rv = '';
var separator = '-';
for ( var i = 0; i < format.length; ++ i )
  {
	if ( rv.length > 0 )
		rv += separator;
	var c = format[i];
	if ( c == 'Y' )
		rv += y.toString();
	else if ( c == 'M' )
		rv += kal.aMonthName[ m ];
	else if ( c == 'm' )
		rv += kal.aMonthNameSmall[ m ];
	else if ( c == 'd' )
		rv += (d+1).toString();
	else
		separator = c;
  }
if ( nWeekDay !== undefined )
	rv = '<span class="weekday" title="%0, %1 %2, %3">%4</span>'.blend( kal.aWeekDayName[nWeekDay], kal.aMonthName[ m ], (d+1).toString(), y.toString(), rv );
return rv;
}


cCalendar.prototype.setLastListPosition = function ( y, nDay, ix )
{
this.nSaveYear = y;
this.nSaveDay = nDay;
this.nSaveListIx = ix;
}


cCalendar.prototype.M = function ( sMonth, sYear )
{
var $name = 'M';
if ( arguments.length < 1 )
	{ this.$name.alert( $name, 'no arguments' ); return; }
var m = calMonth( sMonth );
if ( m == -1 )
	{ this.$name.alert( $name, 'invalid month', sMonth ); return; }
if ( sYear !== undefined )
	this.Y( sYear );
this.aYear[this.y].nMonth = m;
}


cCalendar.prototype.Y = function ( year, bErrorOkay )
{
var $name = 'Y';
if ( arguments.length < 1 )
	{ this.$name.alert( $name, 'no arguments' ); return -1; }
if ( bErrorOkay === undefined )
	bErrorOkay = false;
var y = year;
if ( year >= 2000 ) for ( y = 0; (y < this.aYear.length) && (this.aYear[y].nYear != year); ++y )
	;
if ( y >= this.aYear.length )
  {
	if ( bErrorOkay == false )
		this.$name.alert( $name, 'year not set ', year );
	return -1;
  }
return( this.y = y );
}


cCalendar.prototype.toHTML = function ( type, aPeriod, sOption, sOption2, sOption3, sOption4 )
{
var $name = 'toHTML';
if ( type === undefined )
	type = 'grid';
if ( (arguments.length < 2) || (aPeriod.length == 0) )
	aPeriod = [this.aYear[0].nYear, 'Jan', this.aYear[this.aYear.length-1].nYear, 'Dec' ];
if ( sOption === undefined )
	sOption = '';

var y1, sm1, y2, sm2;
y1 = aPeriod[0];
if ( aPeriod.length < 2 )
  {	// year only: default is year
	sm1 = 0;
	y2 = aPeriod[0];
	sm2 = 11;
  }
else if ( aPeriod.length < 3 )
  {	// year and month only: default is that month
	sm1 = aPeriod[1];
	y2 = aPeriod[0];
	sm2 = aPeriod[1];
  }
else if ( aPeriod.length < 4 )
  {	// first year, first month, last year: default is to end of last year
	sm1 = aPeriod[1];
	y2 = aPeriod[2];
	sm2 = 11;
  }
else
  {	// first year, first month, last year, last month
	sm1 = aPeriod[1];
	y2 = aPeriod[2];
	sm2 = aPeriod[3];
  }
if ( y2 < y1 )
	{ this.$name.alert( $name, 'last year < first year' ); return ''; }
var m1 = calMonth( sm1 );
if ( m1 < 0 )
	{ this.$name.alert( $name, 'first month name invalid' ); return ''; }
var m2 = calMonth( sm2 );
if ( m2 < 0 )
	{ this.$name.alert( $name, 'last month name invalid' ); return ''; }

var sd = new Object();
sd.type = type;
var today = new Date();
sd.this_year = today.getFullYear();
sd.this_month = today.getMonth();
sd.this_day = today.getDate() - 1;
sd.this_minute = (60 * today.getHours()) + today.getMinutes();
sd.isMarkDate = kal.games.isSplitList;
var sHTML = '';
var sPrefixHTML = '';
switch ( type )
  {
  case	'check':
		sHTML += calCheckSchedulesInit( sd );
		break;
  case	'list':
  case	'grid':
		sHTML += calGridAndListInit( sd );
		break;
  case	'games':
		var r = new cEventGames( 'Reg Games' );
		var x = new cEventGames( 'Exhibition Games' );
		var t = new cEventGames( 'Tournament Games' );
		if ( arguments.length < 3 )
			sOption = 'RTX';
		sOption = sOption.toUpperCase();
		sd.tournament = sOption2;
		sd.isMobileDevice = isMobileDevice();
		var sGamesHeader = calGamesInit( sd, sOption, sOption3 );
		break;
  case	'news':
		this.Y( sd.this_year, true );
		var nStartYear = sd.this_year;
		var nStartMonth = sd.this_month;
		var nStartDay = sd.this_day;
		sd.nDaysToToday = 1 + calDays( y1, m1, 0, nStartYear, nStartMonth, nStartDay );
		nStartDay -= kal.news.period[0];
		if ( nStartDay < 0 )
		  {
			if ( nStartMonth == 0 )
			  {
				nStartYear--;
				nStartMonth = 12;
			  }
			nStartMonth--;
			nStartDay += this.aYear[this.y].aMonthDays[nStartMonth];
		  }
		sd.this_year = nStartYear;
		sd.this_month = nStartMonth;
		sd.this_day = nStartDay;
		sHTML += calNewsInit( sd );
		break;
  case	'stats':
		sHTML += calStatsInit( sd );
		break;
  case	'upcoming':
		sPrefixHTML += calUpcomingInit( sd );
		break;
  default:
		alert( 'cCalendar.toHTML() error: invalid type, ' + type );
		this.$name.alert( $name, 'invalid type', type );
		break;
  }

for ( var y = y1; y <= y2; ++y )
  {
	if ( this.Y( y ) < 0 )
		return '';
	var start = (y == y1) ? m1 : 0;
	var end = (y == y2) ? m2 : 11;
	for ( var m = start; m <= end; ++m )
	  {
		switch ( type )
		  {
		  case	'check':
				sHTML += this.aYear[this.y].toCheckHTML( y, m, sd );
				break;
		  case	'list':
				sHTML += this.aYear[this.y].toListHTML( y1, m1, y, m, y2, m2, sd );
				break;
		  case	'games':
				sHTML += this.aYear[this.y].toGamesHTML( y, m, r, x, t, sd );
				break;
		  case	'grid':
				sHTML += this.aYear[this.y].toGridHTML( y1, m1, y, m, y2, m2, sd );
				break;
		  case	'news':
				var sMonthNews = this.aYear[this.y].toNewsHTML( y, m, sd );
				sHTML = sMonthNews + sHTML;
				break;
 		  case	'stats':
				this.aYear[this.y].toStatsHTML( y, m, sd );
				break;
 		  case	'upcoming':
				sHTML += this.aYear[this.y].toUpcomingHTML( y, m, sd );
				break;
		  default:
				return '';
				break;
		  }
	  }
  }

switch ( type )
  {
  case	'check':
		sHTML = calCheckSchedulesTerm ( sd, sHTML );
		break;
  case	'list':
  case	'grid':
		break;
  case	'games':
		if ( sHTML.length == 0 )
		  {
			if ( typeof(kal.games.noGamesHTML) != 'undefined' )
				sHTML = kal.games.noGamesHTML;
		  }
		else
		  {
			sHTML = sGamesHeader + sHTML;
			sHTML += (typeof(sOption4) == 'undefined') ? kal.games.bottomHTML : sOption4;
		  }
		r.nEstimated = kal.games.estimatedGames[0];
		var o = getElement( kal.games.seasonRecord[0] );
		if ( o )
			o.innerHTML = r.toHTML( kal.games.isBarCharts, kal.games.estimatedGames[0] );
		var total = new cEventGames( 'All Games', r.nGames+x.nGames+t.nGames, r.nWin+x.nWin+t.nWin, r.nLose+x.nLose+t.nLose, r.nTie+x.nTie+t.nTie, r.nEstimated+x.nEstimated+t.nEstimated+kal.games.estimatedGames[1], r.nNoScoreYet+x.nNoScoreYet+t.nNoScoreYet );
		o = getElement ( kal.games.seasonRecord[1] );
		if ( o )
			o.innerHTML = total.toHTML( kal.games.isBarCharts, kal.games.estimatedGames[1] );
		break;
  case	'news':
		sHTML = this.aYear[this.y].toTournamentNewsHTML( sd ) + sHTML;
		if ( typeof(kal.news.trailerHTML) != 'undefined' )
			sHTML += kal.news.trailerHTML;
		break;
  case	'stats':
		sHTML += calStatsReport( sd );
		break;
  case	'upcoming':
		if ( (sHTML.length == 0) && (typeof(kal.coming.noComingHTML) != 'undefined') )
			sHTML = kal.coming.noComingHTML;
		else
			sHTML = sPrefixHTML + sHTML;
		if ( typeof(kal.coming.trailerHTML) != 'undefined' )
			sHTML += kal.coming.trailerHTML;
		break;
  default:
		break;
  }
return sHTML;
}


cEvent.prototype.$name = 'cEvent';


function cEvent ( sType, oType, sEvent, oMultiDayEvent, sTime, sLocn, sT1, sT2, isGame, isHG, isXG, isTG, sS1, sS2 )
{
if ( arguments.length < 3 )
	{ this.$name.alert( '', '< 3 arguments' ); return; }
if ( sLocn === undefined )
	sLocn = '';
else if ( (typeof(place) != 'undefined') && (typeof(place.getLocation) != 'undefined') )
	sLocn = place.getLocation( sLocn );
if ( isGame === undefined )
	isGame = false;
this.oType = new cType( oType );
if ( sEvent instanceof Array )
  {
	var aEvent = sEvent;
	sEvent = '';
	for ( var i = 0; i < aEvent.length; ++i )
	  {
		var ix = aEvent[i].indexOf( ' ' );
		if ( ix >= 0 )
		  {
			if ( aEvent[i].substr(0,ix) == 'sEvent' )
				sEvent = aEvent[i].substr(ix+1);
			else
				this.oType[aEvent[i].substr(0,ix)] = aEvent[i].substr(ix+1);
		  }
		else
		  {
			this.oType[aEvent[i]] = '';
		  }
	  }
  }
sEvent = ( sEvent instanceof Number ) ? sEvent.toString() : sEvent;
if ( (sEvent == '') && ((oType.t1 == 'P')) )
	sEvent = 'practice';
if ( kal.filenamePrefix != '' )
	sEvent = calInsertFilenamePrefix( sEvent );
if ( (!isGame) && ((this.oType.t0 == 'S') || (this.oType.t0 == 'T')) )
	this.isSeries = true;
else
	this.isSeries = false;
this.isCancelled = false;
this.sWhyCancelled = '';
if ( (sEvent.length > 0) && (sEvent.charAt(0) == '-') )
  {
	this.isCancelled = true;
	var i = sEvent.indexOf('-',1);
	if ( i < 0 )
	  {
		this.sWhyCancelled = 'Cancelled';
		sEvent = sEvent.substring(1);
	  }
	else
	  {
		this.sWhyCancelled = sEvent.substring(1,i);
		sEvent = sEvent.substring(i+1);
	  }
  }
this.sEvent = sEvent;
this.oMultiDayEvent = new cMultiDayEvent( oMultiDayEvent );
this.sTime = (sTime === undefined) ? '' : sTime;
this.oTime = new cTime( this.sTime );
this.sLocation = sLocn;
this.sSeries = '';
if ( isGame && (sT2 != '') && (typeof(teamname) != 'undefined') )
	sT2 = teamname.valueOf( sT2, 2, 0, undefined, true );
this.sTeam2 = ( sT2 === undefined ) ? '' : sT2;
this.isGame = isGame;
this.isHomeGame = ( isHG === undefined ) ? false : isHG;
this.isExhibitionGame = ( isXG === undefined ) ? false : isXG;
this.isTournamentGame = ( isTG === undefined ) ? false : isTG;
this.isRegularGame = isGame && !this.isExhibitionGame && !this.isTournamentGame;
this.sScore1 = ( sS1 === undefined ) ? '' : sS1;
this.sScore2 = ( sS2 === undefined ) ? '' : sS2;
if ( (this.sScore1 instanceof Number) && (this.sScore1 < 0) )
  {
	this.isCancelled = true;
	if ( this.sWhyCancelled == 'Cancelled' )
		this.sWhyCancelled = this.sScore2;
  }
this.sConflict = '';
}


cEvent.prototype.isConflict = function ( e )
{
var $name = 'isConflict';
var rv = '';
if ( arguments.length < 1 )
	return rv;
else if ( ! (e instanceof cEvent) )
	return rv;
else if ( (this.oTime.t1 == 0) || (e.oTime.t1 == 0) ) 
	return rv;
else if ( (this.oTime.t1 >= e.oTime.t1) && (e.oTime.t2 > 0)  )
  {
	if ( e.oTime.t2 > this.oTime.t1 )
		rv = 'conflict';
  }
else if ( (this.oTime.t1 < e.oTime.t1) && (this.oTime.t2 > 0)  )
  {
	if ( e.oTime.t2 < this.oTime.t1 )
		rv = 'conflict';
  }
return rv;
}

cEvent.prototype.isEqual = function ( e )
{
var $name = 'isEqual';
var rv = true;
if ( arguments.length < 1 )
	return false;
else if ( ! (e instanceof cEvent) )
	return false;
for ( var property in this )
  {
	if ( (property == 'oMultiDayEvent') || (property == 'sConflict') )
		continue;
	if ( typeof(this[property]) == 'function' )
		continue;
	else if ( (this[property] instanceof cTime) || ((this[property] instanceof cType)) )
	  {
		if ( (typeof(this[property]) == typeof(e[property])) && (this[property].isEqual(e[property])) )
			continue;
		rv = false;
		break;
	  }
	else if ( (typeof(this[property]) == typeof(e[property]) ) && (this[property] == e[property]) )
		continue;
	rv = false;
	break;
  }
return rv;
}


cEvent.prototype.toHTML = function ( type, option1 )
{
var $name = 'toHTML';
type = type || '_';
var sAddendum = type + '_addendum';
var sHTML = '';
if ( this.isGame && (type.charAt(0) == 'N') && (this.sScore1 !== '') && (this.sScore1 >= 0) )
  {
	var sOpponent;
	if ( this.isTournamentGame || (typeof(teamname)=='undefined') )
		sOpponent = getTheTeamName( this.sTeam2 );
	else
		sOpponent = teamname.getTeamName( this.sTeam2 );
	if ( typeof(this.game_opponent) != 'undefined' )
		sOpponent += this.game_opponent;
	if ( typeof(this.oType.game_descriptor) != 'undefined' )
		sHTML += this.oType.game_descriptor;
	var sOpponentDescriptor = (typeof(this.oType.opponent_descriptor) == 'undefined') ? '' : this.oType.opponent_descriptor;
	var sScore = (this.sScore2 == 99) ? '' : ' ' + calScore( this.sScore1, this.sScore2 );
	if ( this.sScore1 > this.sScore2 )
	  {
		var sWon = '';
		if ( this.sTeam2 == option1 )
			sWon = (typeof(this.getWinPhrase) != 'undefined') ? (this.getWinPhrase(sOpponent,true)) : ('won') ;
		else
			sWon = (typeof(this.getWinPhrase) != 'undefined') ? (this.getWinPhrase(sOpponent)) : ('beat ' + sOpponent) ;
		if ( this.sScore1 != 99 )
		  {
			if ( sWon.indexOf('$1') != -1 )
				sWon = sWon.replace( '$1', '' + sOpponentDescriptor + ', winning ' + calScore( this.sScore1, this.sScore2 ) );
			else
			  {
				if ( '' == sOpponentDescriptor )
					sWon += (sWon.isCalDigit(-1) ? ', ': ' ') + sScore;
				else
					sWon += '' + sOpponentDescriptor + ', ' + sScore;
			  }
		  }
		sWon = sWon.replace( '$1', '' );
		sHTML += sWon;
	  }
	else if ( this.sScore1 < this.sScore2 )
	  {
		var sOtherTeam = (this.sTeam2 == option1) ? 'them' : sOpponent;
		sHTML += 'lost ' + sScore + ' to ' + sOtherTeam + sOpponentDescriptor;
	  }
	else
	  {
		var sOtherTeam = (this.sTeam2 == option1) ? 'them' : sOpponent;
		if ( '' == sOpponentDescriptor )
			sHTML += 'tied ' + sOtherTeam + ((sOtherTeam.isCalDigit(-1,')')) ? ', ' : ' ') + sScore;
		else
			sHTML += 'tied ' + sOtherTeam + sOpponentDescriptor + ', ' + sScore;
	  }
  }
else if ( this.isGame && (type.charAt(0) == 'N') && (this.sScore1 === '') && !this.isCancelled )
  {
	sHTML += 'don&rsquo;t have the %0 %1 game score'.blend( this.sTime, this.sTeam2 );
  }
else
  {
	if ( (this.sTime != '') && (this.sTime != 'TBA') )
		sHTML += this.oTime.toHTML( '', '-', true, undefined, 'span class=\"ampm\"', true );
	if ( this.sEvent != '' )
	  {
		if ( (type == 'upcoming') && (this.oType.t0 == 'T') )
			sHTML += (' <em class="title">' + this.sEvent + '</em>' );
		else
			sHTML += (' ' + this.sEvent);
	  }
	if ( this.isGame )
	  {
		if ( this.isTournamentGame )
			sHTML += ' tournament';
		else
		  {
			if ( this.isExhibitionGame )
				sHTML += ' exhibition';
			if ( (type.indexOf('list') != -1) || (this.sLocation == '') || (this.sLocation == 'TBA') )
			  {
				if ( this.isHomeGame )
					sHTML += ' home';
				else
					sHTML += ' away';
			  }
		  }
		sHTML += ' game';
	  }
	if ( (this.sTeam2 != '') && (this.sTeam2 != 'TBA') )
	  {
		var sWith = ' with the ';
		if ( this.sTeam2.charAt(0) == ' ' )
			sWith = ' with ';
		sHTML += sWith + this.sTeam2;
	  }
	if ( (this.sTime != '') && (this.sTime == 'TBA') )
		sHTML += ', time TBA';
	if ( this.sLocation != '' )
	  {
		if ( this.sLocation == 'TBA' )
			sHTML += ', location TBA';
		else if ( (this.sLocation.charAt(0) == ' ') && (type != 'calendar') )
			sHTML += ' at the' + this.sLocation;
		else
			sHTML += ' at ' + this.sLocation;
	  }
  }
if ( typeof(this.oType.addendum) != 'undefined' )
	sHTML += '. ' + this.oType.addendum;
if ( (typeof(this.oType[sAddendum]) != 'undefined') && (type != '_') && (sAddendum.indexOf(type) != -1) )
  {
	var s = this.oType[sAddendum];
	if ( s.charAt(0) == ' ' )
		s = s.substring(1);
	sHTML += ((',.:;?!'.indexOf(s.charAt(0))!=-1)? '' : ' ') + s;
  }
if ( this.isGame )
	sHTML = '<span class="game">' + sHTML + '</span>';
else if ( this.oType.t0 == 'P' )
	sHTML = '<span class="practice">' + sHTML + '</span>';
if ( this.isCancelled )
	sHTML = '<del>' + sHTML + '</del> ' + this.sWhyCancelled;
if ( typeof(this.oType.game_comment) != 'undefined' )
	sHTML += this.oType.game_comment;
return sHTML;
}


cEventList.prototype.$name = 'cEventList';


function cEventList ( nMonth, nWeekDay, nMonthDay )
{
if ( arguments.length < 3 )
	{ this.$name.alert( '', 'too few arguments' ); return; }
this.nMonth = nMonth;
this.nWeekDay = nWeekDay;
this.nMonthDay = nMonthDay;
this.isSeriesDay = false;
this.aEvent = new Array();
this.sTournament = '';
}


cEventList.prototype.addEvent = function ( e )
{
var $name = 'addEvent';
this.isError = false;
this.errmsg = '';
var ix = -1;
if ( arguments.length < 1 )
	{ this.$name.alert( $name, 'no argument' ); return ix; }
else if ( ! (e instanceof cEvent) )
	{ this.$name.alert( $name, 'arg1 is not cEvent object' ); return ix; }
else
  {
	var nEvents = this.aEvent.length;
	if ( e.oType.t1 == 'S' )
	  {
		for ( var j = nEvents; j > 0; --j )
			this.aEvent[j] = this.aEvent[j-1];
		this.aEvent[0] = e;
	  }
	else if ( e.oTime.t1 == 0 )
	  {
		for ( ix = 0; ix < nEvents; ++ix )
		  {
			if ( this.aEvent[ix].oTime.t1 > 0 )
				continue;
			if ( calEventPriority(this.aEvent[ix].oType.t0) >= calEventPriority(e.oType.t0) )
				continue;
			for ( var j = nEvents; ix < j; --j )
				this.aEvent[j] = this.aEvent[j-1];
			break;
		  }
		this.aEvent[ix] = e;
	  }
	else
	  {
		ix = 0;
		if ( (nEvents > 0) && (this.aEvent[0].oType.t1 == 'S') )
			ix++;
		for ( ; ix < nEvents; ++ix )
		  {
			if ( (this.aEvent[ix].oTime.t1 > 0) && (this.aEvent[ix].oTime.t1 <= e.oTime.t1) )
				continue;
			var sConflict = this.aEvent[ix].isConflict( e );
			if ( sConflict != '' )
				e.sConflict = sConflict;
			for ( var j = nEvents; ix < j; --j )
				this.aEvent[j] = this.aEvent[j-1];
			break;
		  }
		this.aEvent[ix] = e;
	  }
  }
if ( e.isSeries )
	this.isSeriesDay = true;
if ( (e.isSeries) && !(e.isGame) )
	this.sTournament = e.sEvent;
return ix;
}


cEventList.prototype.removeEvent = function ( e )
{
var $name = 'removeEvent';
this.isError = false;
this.errmsg = '';
var ix = -1;
if ( arguments.length < 1 )
	{ this.$name.alert( $name, 'no argument' ); return ix; }
else if ( ! (e instanceof cEvent) )
	{ this.$name.alert( $name, 'arg1 is not cEvent object' ); return ix; }
else
  {
	for ( ix = 0; ix < this.aEvent.length; ++ ix )
	  {
		if ( e.isEqual( this.aEvent[ix] ) )
			break;
	  }
	if ( ix == this.aEvent.length )
		{ this.$name.alert( $name, 'no matching %0 %1 event to remove on %2 %3', e.sTime, e.oType.t1, kal.aMonthNameSmall[this.nMonth], this.nMonthDay+1 ); return ix; }
	for ( ; ix < this.aEvent.length; ++ ix )
	  {
		if ( (ix+1) == this.aEvent.length )
			this.aEvent.length -= 1;
		else
			this.aEvent[ix] = this.aEvent[ix+1];
	  }
  }
return ix;
}


cEventGames.prototype.$name = 'cEventGames';

function cEventGames ( sTitle, nGames, nWin, nLose, nTie, nEstimated, nNoScoreYet )
{
this.sTitle = (sTitle === undefined) ? 0 : sTitle;
this.nGames = (nGames === undefined) ? 0 : nGames;
this.nWin = (nWin === undefined) ? 0 : nWin;
this.nLose = (nLose === undefined) ? 0 : nLose;
this.nTie = (nTie === undefined) ? 0 : nTie;
this.nEstimated = (nEstimated === undefined) ? 0 : nEstimated;
this.nNoScoreYet = (nNoScoreYet === undefined) ? 0 : nNoScoreYet;
}

cEventGames.prototype.getPoints = function ()
{
return 2*this.nWin + 1*this.nTie;
}

cEventGames.prototype.getWinLoseTie = function ()
{
return this.nWin.toString() + '&#8211;' + this.nLose.toString() + '&#8211;' + this.nTie.toString();
}


cEventYear.prototype.$name = 'cEventYear';

function cEventYear ( nYear )
{
if ( arguments.length < 1 )
	{ this.$name.alert( '', 'no argument' ); return; }
if ( nYear < 2000 )
	{ this.$name.alert( '', 'year < 2000' ); return; }
this.nYear = nYear;
this.nMonth = 0;
this.nFirstWeekDay = 6;
for ( var y = 2000; y <= this.nYear; ++y )
  {
	this.isLeapYear = (y%4 == 0) && ((y%100 != 0) || (y%400 == 0));
	if ( y < this.nYear )
		this.nFirstWeekDay = ( this.nFirstWeekDay + 365 + (this.isLeapYear ? 1 : 0) ) % 7;
  }
this.aMonthDays = [ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ];
this.aMonthDays[1] += ( this.isLeapYear ? 1 : 0 );
this.aYearDays = new Array( 12 );
this.daysInYear = 365 + ( this.isLeapYear ? 1 : 0 );
this.aDay = new Array( this.daysInYear );
var nYearDay = 0;
var nWeekDay = this.nFirstWeekDay;
for ( var nMonth = 0; nMonth < this.aMonthDays.length; ++nMonth )
  {
	this.aYearDays[nMonth] = nYearDay;
	var nDaysInMonth = this.aMonthDays[nMonth];
	for ( var nMonthDay = 0; nMonthDay < nDaysInMonth; ++nMonthDay )
	  {
		this.aDay[nYearDay++] = new cEventList( nMonth, nWeekDay, nMonthDay );
		nWeekDay = ( 1+nWeekDay ) % 7;
	  }
  }
}


cMultiDayEvent.prototype.$name = 'cMultiDayEvent';

function cMultiDayEvent ( nDay, nRepeats, nDays )
{
if ( nDay === undefined )
	nDay = 0;
if ( typeof(nDay) == 'number' )
  { // Normal constructor
	if ( nRepeats === undefined )
		nRepeats = 0;
	if ( nDays === undefined )
		nDays = nRepeats;
	this.nDay = nDay;
	this.nRepeats = nRepeats;
	this.nDays = nDays;
	this.isDaySkipped = false;
	this.nInterval = 7;
  }
else
  { // Copy constructor
	this.nDay = arguments[0].nDay;
	this.nRepeats = arguments[0].nRepeats;
	this.nDays = arguments[0].nDays;
	this.isDaySkipped = arguments[0].isDaySkipped;
	this.nInterval = arguments[0].nInterval;
  }
}

cMultiDayEvent.prototype.addDay = function ()
{
var $name = 'addDay';
if ( this.nDays > 1 )
	this.nDay += 1;
}

cMultiDayEvent.prototype.addRepeat = function ( n )
{
var $name = 'addRepeat';
if ( arguments.length != 1 )
	{ this.$name.alert( $name, '1 argument expected' ); return; }
if ( n < 0 )
	this.nInterval = Math.abs( n );
else if ( n > 0 )
	this.nDays = (this.nRepeats += n);
if ( (n==0) || ((n>1) && (this.nInterval>1)) )
	this.isDaySkipped = true;
}

cMultiDayEvent.prototype.daysLeft = function ()
{
var $name = 'daysLeft';
if ( (this.nDays > 1) && (this.nDays == this.nRepeats) )
	return this.nDays - this.nDay + 1;
else
	return 0;
}

cMultiDayEvent.prototype.toString = function ()
{
var $name = 'toString';
return this.nDay + ' ' + this.nRepeats + ' ' + this.nDays;
}


// INSTANTIATE CALENDAR

var cal = new cCalendar( kal.period[0], kal.period[2] );



