function loaddata()
{
    var feedUrl = 'http://www.google.com/calendar/feeds/agsbv7labmnvc5fk5g9o1ltbso%40group.calendar.google.com/public/basic' +  //timessquarenyc - outgoing google calendar
			'?start-min=' + calconf['selected_year'] + '-' + two_digits(calconf['selected_month_number']) + '-' + '01' + 'T00:00:00-05:00' + 
			'&start-max=' + calconf['selected_year'] + '-' + two_digits(calconf['selected_month_number']) + '-' + two_digits(calconf['selected_month_last_day_number']) + 'T23:59:59-05:00' +
			'&singleevents=true' +
			'&orderby=starttime' +
			'&sortorder=ascending' +
			'&max-results=1488'
			     // max-results needs to be large enough for a very very very busy month...
			     // 2 events per hour x 24 hrs each day x 31 days = 1488 events per month

//setCalVal('bottomText', '<a href="' + feedUrl + '">' + feedUrl + '</a>');

	if (!myService)
	{
		myService = new google.gdata.calendar.CalendarService('tsacal');
	}
	
    myService.getEventsFeed(feedUrl, loaddata_handler, loaddata_error);
}

function loaddata_error(e)
{
    calend();
    alert("There was an error!" + "\n\n" + e.cause ? e.cause.statusText : e.message);
}

function loaddata_handler(myResultsFeedRoot)
{
    var h = '';
    var day = '';
    var skip = '';
    var skip_delimiter = ' ';
    var entries = myResultsFeedRoot.feed.entry;

    for (e = 0; e < entries.length; e++)
    {
        var entry = entries[e];

        var id = entry.getId().getValue();

        if (skip.match(id + skip_delimiter))
        {
            continue;
        }

        var event = loaddata_handler_create_event(entry);

        if (entry.getContent().getText().match('Replaces event'))
        {
            //print_array(entry.getContent().getText()); exit;
            // if this event is apart of an occurence and replaces it then the id will the be of the form <recurrenceid>_<replace_id>
            // so I take parse out the recurrence id and note it to be skipped

            skip = skip + event['id'].substr(0, id.indexOf('_')) + skip_delimiter;
        }

        ////////////////

        day = event['start']['day_number'];

        if (!calconf['events'][day])
        {
            calconf['events'][day] = new Array();
        }

        calconf['events'][day][  calconf['events'][day].length  ] = event;

    } // for each entry...

    loaddata_handler_display();
    
} //loaddata_handler() 

function loaddata_handler_create_event(entry)
{
	function parse_time_string(time_string, array_ptr)
	{
		var h = 0;
		var time = new Array();
		    time['hour_12'] = '';
		    time['hour_24'] = '';
		    time['min'] = '';
		    time['ampm'] = '';

		if (!time_string)
		{
			return time;
		}

		if (time_string.split(':').length > 1)  // if of the form 7:30pm, then...
		{
			h = time_string.split(':')[0];
			h = parseInt(h, 10);
			time['min'] = time_string.split(':')[1]
			time['min'] = (time['min'].length > 2) ? time['min'].substr(0,2) : time['min'];

			if (time_string.indexOf('am') > 1)
			{
				time['ampm'] = 'am';
			}
			else if (time_string.indexOf('pm') > 1)
			{
				time['ampm'] = 'pm';
			}
			else
			{
				time['ampm'] = (h > 11) ? 'pm' : 'am';
			}
		}
		else // else is of the form 7pm, then...
		{
			time['min'] = '00';
			if (time_string.split('pm').length > 1)
			{
				h = time_string.split('pm')[0];
				time['ampm'] = 'pm';
			}
			else
			{
				h = time_string.split('pm')[0];
				time['hour'] = time_string.split('am')[0];
				time['ampm'] = 'am';
			}
		}

		h = parseInt(h, 10);
		time['hour_12'] = (h < 13) ? h : h - 12;
		time['hour_12'] = (time['hour_12'] == 0) ? 12 : time['hour_12'];
		time['hour_24'] = (h > 12) ? h : h + 12;

		// not sure if these are useful as numbers
		// time['hour_integer'] = parseInt(time['hour'], 10);
		// time['min_integer'] = parseInt(time['min'], 10);

		if (array_ptr)
		{
		   array_ptr['hour_12'] = time['hour_12'];
		   array_ptr['hour_24'] = time['hour_24'];
		   array_ptr['min']     = time['min'];
		   array_ptr['ampm']    = time['ampm'];
		}

		return time;
	}

	function parse_tsacal_tag(tag_name, text)
	{
		var content = '';

		if (tag_name == 'tsaevtlink')
		{
			// replaces {tsaevtlink}http://domain.com|linkname{/tsaevtlink} the specified tag and surrounding space;
			// the original content with the replaced tag is returned.

			function make_link(bracket_content)
			{
				var link = '';
				if (bracket_content && typeof bracket_content == 'string' && bracket_content.length > 0)
				{
					var url = '';
					var name = '';
					if (bracket_content.split('|').length == 2)
					{
						url  = bracket_content.split('|')[0].trim();
						name = bracket_content.split('|')[1].trim();
					}
					else if (bracket_content.trim().match('http'))
					{
						url  = bracket_content.trim();
						name = url;
					}
					else
					{
						name  = bracket_content.trim();
						return name;
					}
					name = (name.length > 35) ? name.substr(0,35) + '...' : name;
					link = '<a href="' + url + '">' + name + '</a>';
				}
				return link;
			}

			content = text;
			content = content.replace(/\{tsaevtlink\}([^\{]+){\/tsaevtlink\}/g, function($1, $2) {  return make_link($2); });
		}
		else if (text.match('{' + tag_name + '}'))
		{
			// removes the specified tag and surrounding space;
			// the content of the tag is returned!!!

			content = text.split('{' + tag_name + '}')[1].split('{/' + tag_name + '}')[0]; 
		}

		return content;
	}


	function remove_tsacal_tag(tag_name, string_ptr)
	{
		if (string_ptr.match('{' + tag_name + '}'))
		{
			string_ptr = string_ptr.split('{' + tag_name + '}')[0] + string_ptr.split('{/' + tag_name + '}')[1];
			string_ptr = string_ptr.trim();
		}

		return string_ptr;
	}

	function get_event_time_key(time)
	{
		// key form: YYYYMMDDTHHMI

		var mm = '';
		if (typeof time['month'] == 'string' && time['month'].trim().match(new RegExp('[0-9][0-9]')))
		{
			mm = time['month'];
		}
		else
		{
			mm = (time['month'] == 'Jan') ? '01' : mm;
			mm = (time['month'] == 'Feb') ? '02' : mm;
			mm = (time['month'] == 'Mar') ? '03' : mm;
			mm = (time['month'] == 'Apr') ? '04' : mm;
			mm = (time['month'] == 'May') ? '05' : mm;
			mm = (time['month'] == 'Jun') ? '06' : mm;
			mm = (time['month'] == 'Jul') ? '07' : mm;
			mm = (time['month'] == 'Aug') ? '08' : mm;
			mm = (time['month'] == 'Sep') ? '09' : mm;
			mm = (time['month'] == 'Oct') ? '10' : mm;
			mm = (time['month'] == 'Nov') ? '11' : mm;
			mm = (time['month'] == 'Dec') ? '12' : mm;
		}

		var dd = (parseInt(time['day_number']) < 10) ? ('0' + parseInt(time['day_number'])) : time['day_number'];

		var ss = (time['sec']) ? time['sec'] : '00';

		var key = time['year'] + mm + dd; //+ 'T' + time['hour_24'] + time['min'] + ss

		return key
	}

    ////////////////

    var id = entry.getId().getValue();

    var description  = entry.getContent().getText();
        description  = description.replace('&nbsp;', ' ');
        description  = description.replace("\n", ' ');
        description  = description.replace("\r", ' ');
        description  = description.replace("\r\n", ' ' );
        description  = description.replace('  ',' ');  // replace multiple spaces between words with a single space

    // 05/02/08, monjay, Google decided to change their line delimiter in the description from <br> to <br /> and so now lets assume multiple delimiters might apply
    var lines;
    var possible_delimiters = new Array('<br>', '<br/>', '<br />');
    for (var p = 0; p < possible_delimiters.length; p++)
    {
        lines = description.split(possible_delimiters[p]);
        if (lines.length > 1)
        {
            p = possible_delimiters.length
        }
    }

    var event = new Array();   // for calconf['events'][  calconf['events'].length  ] = event;
        event['id'] = id;
        event['title'] = entry.getTitle().getText();
        event['start'] = new Array();
        event['end'] = new Array();
        event['icon'] = '';
        event['flg_display'] = true;
        event['flg_allday']  = false;
        event['flg_endsnextday'] = false;

    // parse google description...
    if (description && (typeof description == 'string') && description.match('When:')) // maybe this line doesn't make sense...
    {
        for (var line = 0; line < lines.length; line++)
        {
            lines[line] = lines[line].trim();
            if (lines[line].match('Where:'))
            {
                event['location'] = lines[line].split('Where:')[1].trim();
            }
            else if (lines[line].match('When:'))
            {
                // Note that when these are enabled... the times for all events will be the same!
                //
                // case 5: (seems to occur when a request hits the calendar miliseconds after an event has been added! and google's formatter hasn't run)
                // lines[line] = 'When: Tue Apr 1, 2008 5pm to Tue Apr 1, 2008 8pm EDT';  // test case 1
                // lines[line] = 'When: Tue Apr 1, 2008 17:00 to Tue Apr 1, 2008 20:00';  // test case 2
                // lines[line] = 'When: Sat Apr 5, 2008 to Sun Apr 6, 2008'  // test case 3
                // lines[line] = 'When: Tue Apr 1, 2008 11am to 2pm EDT' // test case 4
                // lines[line] = 'When: 2008-04-01 17:00 to 2008-04-01 20:00 EDT';  // test case 5 
                // lines[line] = 'When: 2008-04-02'; // test case 6
                // lines[line] = 'When: Wed Apr 30, 2008 23:00 to 00:00'; // test case 7
                // lines[line] = 'When: 2008-04-01 11:00 to 14:00'; // test case 8
                // lines[line] = 'When: 2008-04-17 to 2008-04-20'; // test case 9

                var is_time_range = (lines[line].split('to').length > 1) ? true : false;
                if (is_time_range)
                {
                    event['start']['words'] = lines[line].split('to')[0].replace('When: ', '').trim();
                    event['start_words'] = event['start']['words'];

                    if (event['start']['words'].match(new RegExp('[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9] +[0-9][0-9]:[0-9][0-9]')))
                    {
                        // 2008-04-01 17:00
                        event['start']['case']        = '1';
                        event['start']['day_name']    = '';
                        event['start']['month']       = event['start']['words'].substr(5,2);
                        event['start']['day_number']  = event['start']['words'].substr(8,2);
                        event['start']['year']        = event['start']['words'].substr(0,4);
                        event['start']['time']        = event['start']['words'].split(' ')[1];
                    }
                    else if (event['start']['words'].match(new RegExp('[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]')))
                    {
                        // 2008-04-01
                        event['start']['case']        = '2';
                        event['start']['day_name']    = '';
                        event['start']['month']       = event['start']['words'].substr(5,2);
                        event['start']['day_number']  = event['start']['words'].substr(8,2);
                        event['start']['year']        = event['start']['words'].substr(0,4);
                        event['start']['time']        = '';
                    }
                    else
                    {
                        // Wed Apr 2, 2008 7pm EDT
                        event['start']['case']        = '3';
                        event['start']['day_name']    = event['start']['words'].split(' ')[0];
                        event['start']['month']       = event['start']['words'].split(' ')[1];
                        event['start']['day_number']  = event['start']['words'].split(' ')[2].replace(',', '');
                        event['start']['year']        = event['start']['words'].split(' ')[3];
                        event['start']['time']        = event['start']['words'].split(' ')[4];
                    }

                    if (!event['start']['time'])
                    {
                        event['flg_allday'] = true;
                    }
                    else
                    {
                        parse_time_string(event['start']['time'], event['start']);
                    }

                    //////////////// end time

                    event['end']['words'] = lines[line].split('to')[1].trim();
                    event['end_words'] = event['end']['words'];
                    if (event['end']['words'].match(new RegExp('[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9] +[0-9][0-9]:[0-9][0-9]'))) // as in 2008-04-01 20:00 EDT
                    {
                        event['end']['case']        = '1';
                        event['end']['day_name']    = '';
                        event['end']['month']       = event['end']['words'].substr(5,2);
                        event['end']['day_number']  = event['end']['words'].substr(8,2);
                        event['end']['year']        = event['end']['words'].substr(0,4);
                        event['end']['time']        = event['end']['words'].split(' ')[1];
                        event['end']['std']         = event['end']['words'].split(' ')[2];
                    }
                    else if (event['end']['words'].match(new RegExp('[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]'))) // as in 2008-04-01
                    {
                        event['end']['case']        = '2';
                        event['end']['day_name']    = '';
                        event['end']['month']       = event['end']['words'].substr(5,2);
                        event['end']['day_number']  = event['end']['words'].substr(8,2);
                        event['end']['year']        = event['end']['words'].substr(0,4);
                        event['end']['time']        = '11:59pm';
                        event['end']['std']         = '';
                    }
                    else if (event['end']['words'].match(new RegExp('[0-9][0-9]:[0-9][0-9]'))) // as in 20:00 EDT
                    {
                        event['end']['case']        = '3';
                        event['end']['day_name']    = event['start']['day_name'];
                        event['end']['month']       = event['start']['month'];
                        event['end']['day_number']  = event['start']['day_number'];
                        event['end']['year']        = event['start']['year'];
                        event['end']['time']        = event['end']['words'];
                        event['end']['std']         = event['end']['words'].split(' ')[1];
                    }

                    if (event['end']['words'].split(' ').length == 2)   // as in '2pm EDT'
                    {
                        event['end']['case']        = '4';
                        event['end']['day_name']    = event['start']['day_name'];
                        event['end']['month']       = event['start']['month'];
                        event['end']['day_number']  = event['start']['day_number'];
                        event['end']['year']        = event['start']['year'];
                        event['end']['time']        = event['end']['words'].split(' ')[0];
                        event['end']['std']         = event['end']['words'].split(' ')[1];
                    }
                    else if (event['end']['words'].split(' ').length > 4) // as in 'Wed Apr 2, 2008 9:30pm EDT' or as in 'Wed Apr 2, 2008 17:30'
                    {
                        event['end']['case']        = '5';
                        event['end']['day_name']    = event['end']['words'].split(' ')[0];
                        event['end']['month']       = event['end']['words'].split(' ')[1];
                        event['end']['day_number']  = event['end']['words'].split(' ')[2].replace(',', '');
                        event['end']['year']        = event['end']['words'].split(' ')[3];
                        event['end']['time']        = event['end']['words'].split(' ')[4];
                        event['end']['std']         = event['end']['words'].split(' ')[5];
                    }

                    event['start']['std'] = event['end']['std'];
                    parse_time_string(event['end']['time'], event['end']);

                } // is time range
                else
                {
                    event['flg_allday'] = true;

                    event['start']['words']       = lines[line].split('to')[0].replace('When: ', '');
                    if (event['start']['words'].match(new RegExp('[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]')))
                    {
                        // 2008-04-01
                        event['start']['case']        = 'AD1';
                        event['start']['day_name']    = '';
                        event['start']['month']       = event['start']['words'].substr(5,2);
                        event['start']['day_number']  = event['start']['words'].substr(8,2);
                        event['start']['year']        = event['start']['words'].substr(0,4);
                        event['start']['time']        = '';
                    }
                    else
                    {
                        event['start']['case']        = 'AD2';
                        event['start']['day_name']    = event['start']['words'].split(' ')[0];
                        event['start']['month']       = event['start']['words'].split(' ')[1];
                        event['start']['day_number']  = event['start']['words'].split(' ')[2].replace(',', '');
                        event['start']['year']        = event['start']['words'].split(' ')[3];
                        event['start']['time']        = '';
                    }

                    parse_time_string(event['start']['time'], event['start']);
                }

            }
            else if (lines[line].match('Replaces event'))
            {
                // if this event is apart of an occurence and replaces it then the id will the be of the form <recurrenceid>_<replace_id>
                // so I take parse out the recurrence id and note it to be skipped
                var skip = skip + event['id'].substr(0, id.indexOf('_')) + skip_delimiter;
            }
            else if (lines[line].match('Description'))
            {
                event['desc'] = lines[line].substr(lines[line].indexOf(':') + 2, lines[line].length).trim();
            }

        } // When: for loop

    }
    else if (description && (typeof description == 'string') && description.match('Recurring Event'))
    {
/* 04/22/08, monjay, this seems to be no longer useful
        // test for a regular event, then with all day setting, etc...
        for (var line = 0; line < lines.length; line++)
        {
            // 01234567890123456789012345678901234567890
            // First start: 2008-04-01 19:00:00 EDT
            if (lines[line].match('First start'))
            {
                time['start']['hour'] = lines[line].substr(25,2);
                time['start']['ampm'] = (time['start']['hour'] > 12) ? 'pm' : 'am';
                time['start']['min']  = lines[line].substr(28,2);
                time['start']['sec']  = lines[line].substr(30,2);
                time['start']['std']  = lines[line].substr(33,3);   // EDT
            }
            else if (lines[line].match('Description'))
            {
                // 01234567890123456789012345678901234567890
                // Event Description: lipsum...
                description = lines[line].substr(19, lines[line].length);
            }
        }
*/
        event['flg_display'] = false;
    }

    // ugh! events on google calendar marked private
    // still appear in the feed with valid times but no title and description
    // so let's not display these
    
    if (!event['title'])
    {
        event['flg_display'] = false;
    }

    // only render events that occur on day
    // google's feeds day queries can return results not neccessaily valid
    // a bug I see: if a single/regular event and an All Day event occur a given day,
    // 	the single even appears in the feed for the next day even though it has ended and has nothing to do with the next day.

    event['start']['key'] = get_event_time_key(event['start']);
    event['end']['key']   = get_event_time_key(event['end']);

    // set next day flag (in case it's needed later)

    if (event['start']['key'].substr(6,2) != event['end']['key'].substr(6,2))
    {
        // if an event starts on the 21st and ends on the 22nd
        // or starts on the 30th and ends on the 1st
        // then the event start day and end day are 'different' and the event ends on the next day

        event['flg_endsnextday'] = true;
    }
    else if (event['start']['ampm'] == 'pm' && event['end']['ampm'] == 'am')
    {
        event['flg_endsnextday'] = true;
    }

//print_array(event); exit;

    ///////////////////////////////////////////////////////
    // parse out tsaevt codes...
    ///////////////////////////////////////////////////////

    if (event['desc'] && event['desc'].match('{tsaevticon}'))
    {
        event['icon'] = parse_tsacal_tag('tsaevticon', event['desc']);
        event['desc'] = remove_tsacal_tag('tsaevticon', event['desc']);
    }
    if (event['desc'] && event['desc'].match('{tsaevtcolor}'))
    {
        event['color'] = parse_tsacal_tag('tsaevtcolor', event['desc']);
        event['color'] = (event['color'] == 'tsapink') ? '#ed008c' : event['color'];  // should try to use site styles
        event['desc']  = remove_tsacal_tag('tsaevtcolor', event['desc']);
    }
    if (event['desc'] && event['desc'].match('{tsaevtlink}'))
    {
        event['desc'] = parse_tsacal_tag('tsaevtlink', event['desc']);
    }

    //
    // display code for the event
    //

    if (event['flg_display'])
    {
        event['html_summary'] = '';
        event['html_long'] = '';

        var time = '';
        if (event['flg_allday'])
        {
            time = 'All Day';
        }
        else
        {
            var s_time = '<span class="eventDetailsStartTime">' + 
                        event['start']['hour_12'] + 
                        ((event['start']['min']  != '00')                 ? ':' + event['start']['min']  : '') + 
                        ((event['start']['ampm'] != event['end']['ampm']) ?       event['start']['ampm'] : '') + 
                        '</span>';

            var sep = (event['end']['hour_12']) ? '&nbsp;-&nbsp;' : '';
            
            var e_time = '<span class="eventDetailsEndTime">' +
                        ((event['end']['hour_12'])     ?       event['end']['hour_12'] : '') +
                        ((event['end']['min'] != '00') ? ':' + event['end']['min']     : '') + 
                         event['end']['ampm'] +
                        '</span>';

            time = s_time + sep + e_time;
        }

        time = (event['color']) ? '<span style="color:' + event['color'] + '">' + time + '</span>' :  time;

        var title = ''
            title = (event['color']) ? '<span style="color:' + event['color'] + '">' + event['title'] + '</span>' :  event['title'];

        event['html_summary'] = '<b>' + time + '</b>' + '<br/>' + title;
    }

    return event;

} //loaddata_handler_create_event()

function loaddata_handler_display()
{
    // render events on the calendar... this should be a function unto itself because it drives off of calconf['events']
    // html_1 is for allday events, html_2 for regularly scheduled events with a start and end time
    for (var week = 1; week < 7; week++)
    {
        for (var d = 1; d < 8; d++)
        {
            var day = getCalVal('dataDayWeek' + week + 'Day' + d);
            if (day)
            {
                if (calconf['events'][day])
                {
                    var html   = '';
                    var html_1 = '';
                    var html_2 = '';
                    
                    var cnt = new Array();
                        cnt['allday']  = 0;
                        cnt['regular'] = 0;
                    
                    var separator = new Array();
                        separator['between'] = '<hr class="eventDetailsSeparator" />';
                        separator['end']     = '<br/><br/>';
                    

                    // tally allday and regular events...
                    for (var eventE = 0; eventE < calconf['events'][day].length; eventE++)
                    {
                        if (calconf['events'][day][eventE]['flg_display'])
                        {
                            if (calconf['events'][day][eventE]['flg_allday'])
                            {
                                cnt['allday']  = cnt['allday'] + 1;
                            }
                            else
                            {
                                cnt['regular'] = cnt['regular'] + 1;
                            }
                        }
                    }

                    cnt['total'] = cnt['allday'] + cnt['regular'];

                    var sep = '';
                    var cnt_allday  = 0;
                    var cnt_regular = 0;

                    for (var eventE = 0; eventE < calconf['events'][day].length; eventE++)
                    {
                        if (calconf['events'][day][eventE]['flg_display'])
                        {
                            if (calconf['events'][day][eventE]['flg_allday'])
                            {
                                if (cnt['regular'] > 0)
                                {
                                    sep = separator['between'];
                                }
                                else
                                {
                                    sep = (cnt_allday < (cnt['allday'] - 1)) ? separator['between'] : separator['end'];
                                }
                    
                                html_1 = html_1 + calconf['events'][day][eventE]['html_summary'] + sep;
                                cnt_allday = cnt_allday + 1;
                            }
                            else
                            {
                                sep = (cnt_regular < (cnt['regular'] - 1)) ? separator['between'] : separator['end'];
                                html_2 = html_2 + calconf['events'][day][eventE]['html_summary'] + sep;
                                cnt_regular = cnt_regular + 1;
                            }
                        }
                    }

                    html = '<span style="cursor:pointer;" onClick="javascript:event_details(\'' + day + '\',\'' + week + '\');return false;">' + html_1 + html_2 + '</span>';
                    setCalVal('dataEventWeek' + week + 'Day' + d, html);
    
                } // if the day has events
            } // if (day)
        } // for each day d
    } // for each week

    calend();

} //loaddata_handler_display()