/* MarcGrabanski.com */
/* Pop-Up Calendar Built from Scratch by Marc Grabanski      */

/* Script edited by Stefan Langer -- August 2007. 
   changed script so only certain dates are 'clickable'. 
   modified the location of the previous/next buttons.
   added time-, play title-, season ticket- and 
   price-update functions as well. 
   in addition, created 'hours before performance' function. */

/* NOTE: event dates, blocked dates, ticket prices and the default phone 
   number are set as global variables outside of this file on the main page.  */


// specify the minimum number of hours a person is 
// permitted to make an online reservation before show. 
var minHours_BeforeShow = 48; 

// specify the maximum number of hours a person is 
// permitted to make an online reservation before show. 
var maxHours_BeforeShow = 1440; // note: 1440 hours equals 60 days. 

// convert a single hour into milliseconds. 
var oneHour = 1000 * 60 * 60; 

// define a global array to hold date values, 
// a global array to hold time values, 
// a global array to hold play titles,  
// a global array to hold season ticket information
// and a global array to hold blocked dates.
var datesArray        = new Array(32); 
var timesArray        = new Array(32); 
var titlesArray       = new Array(32); 
var seasonTicketArray = new Array(32); 
var blockedDatesArray = new Array(32); 
var waitListArray     = new Array(32); 
var eventDatesArray   = new Array(); 

var popUpCal = {
    selectedMonth: new Date().getMonth(), // 0-11
    selectedYear: new Date().getFullYear(), // 4-digit year
    selectedDay: new Date().getDate(),
    calendarId: 'calendarDiv',
    inputClass: 'calendarSelectDate',
    
	init: function () {
        var x = getElementsByClass(popUpCal.inputClass, document, 'input');
        var y = document.getElementById(popUpCal.calendarId);
        // set the calendar position based on the input position
        for (var i=0; i<x.length; i++) {
            x[i].onfocus = function () {
				// popUpCal.selectedMonth = new Date().getMonth();
                setPos(this, y); // setPos(targetObj,moveObj)
                y.style.display = 'block';
                popUpCal.drawCalendar(this); 
                popUpCal.setupLinks(this);
            }
        }
    },

    // update the day, time and title arrays with any 
    // event info matching the current month and year. 
    populateArrays: function (inputObj) {

       // set local variables. 
       var playTitleString    = ""; 
       var seasonTicketString = ""; 
       var blockedStatusArray = ""; 
       var analyzeDateFlag    = "true"; 
       var eventDates_YearMonthArray; 
       var eventDates_ArrayStatus; 

       // reset the global arrays, which 
       // hold dates, times, play titles 
       // and season ticket information. 
       datesArray        = new Array(32); 
       timesArray        = new Array(32); 
       titlesArray       = new Array(32); 
       seasonTicketArray = new Array(32); 
       blockedDatesArray = new Array(32); 
       waitListArray     = new Array(32); 

       // set the name of the events array that corresponds to the 
       // current calendar view (should one exist) as a variable. 
       eventDates_YearMonthArray = "eventDates" + popUpCal.selectedYear + eval(popUpCal.selectedMonth + 1) + "Array"; 

       // test whether an array exists: one that corresponds to 
       // the current calendar view. set the result as a variable.  
       eventDates_ArrayStatus = eval("typeof(" + eventDates_YearMonthArray + ")");

       // determine if no array-of-events 
       // corresponds to the current calendar view. 
       if (eventDates_ArrayStatus == "undefined") { 

          // reset the events array so no dates 
          // are highlighted for the current month. 
          eventDatesArray = new Array(); 

       // otherwise, there is a valid array-of-events 
       // corresponding to the current calendar view. 
       } else { 

          // retrieve the appropriate date array and set it 
          // as a variable; one that will be easier to refer to. 
          eval("eventDatesArray = " + eventDates_YearMonthArray); 

       } // end-if statement 

       // loop through the event dates array. 
       for (var arrayIndex = 0; arrayIndex < eventDatesArray.length; arrayIndex++) { 

          // reset the flag. 
          analyzeDateFlag = "true"; 

          // ensure the string is more than 12 characters long before continuing. 
          if (eventDatesArray[arrayIndex].length > 12) { 

             // determine if the current index in the array holds the 
             // title of the play, which will apply to the dates that follow. 
             if (eventDatesArray[arrayIndex].substring(0, 12) == "Play Title: ") { 
                // extract the play title from the string, setting it as a variable. 
                playTitleString = eventDatesArray[arrayIndex].substring(12, eventDatesArray[arrayIndex].length); 
                // make sure this index in the array is not analyzed as a date. 
                analyzeDateFlag = "false"; 
             } // end-if statement 

          } // end-if statement 

          // ensure the string is more than 16 characters long before continuing. 
          if (eventDatesArray[arrayIndex].length > 16) { 

             // determine if the current index specifies 
             // whether this show is part of the season 
             // ticket, which applies to the dates that follow. 
             if (eventDatesArray[arrayIndex].substring(0, 16) == "Season Ticket?: ") { 
                // extract the season ticket info from the string, setting it as a variable. 
                seasonTicketString = eventDatesArray[arrayIndex].substring(16, eventDatesArray[arrayIndex].length); 
                // make sure this index in the array is not analyzed as a date. 
                analyzeDateFlag = "false"; 
             } // end-if statement 

          } // end-if statement 

          // continue only if the current string is a valid date and time. 
          if (analyzeDateFlag == "true") { 

             // split the date from the time info, using the space as a delimiter. 
             dateTimeArray = eventDatesArray[arrayIndex].split(" "); 

             // split the date info into separate 
             // components, using the '/' as a delimiter. 
             dateComponentsArray = dateTimeArray[0].split("/"); 

             // determine if the event's month and day match 
             // the one currently displayed on the page. 
             if ((dateComponentsArray[0] == eval(popUpCal.selectedMonth + 1)) && 
                 (dateComponentsArray[2] == popUpCal.selectedYear)) { 

                // determine if the current show date and time has been blocked. the values 
                // returned by the function are: [0] whether patrons can be waitlisted for this 
                // performance; and [1] an explanation of why the performance was blocked. 
                blockedStatusArray = blockedDateCheck(eventDatesArray[arrayIndex]); 

                // update the arrays, using the event's day as the index number. 
                datesArray[dateComponentsArray[1]]        = "true"; 
                timesArray[dateComponentsArray[1]]        = dateTimeArray[1]; 
                titlesArray[dateComponentsArray[1]]       = playTitleString; 
                seasonTicketArray[dateComponentsArray[1]] = seasonTicketString; 
                waitListArray[dateComponentsArray[1]]     = blockedStatusArray[0]; 
                blockedDatesArray[dateComponentsArray[1]] = blockedStatusArray[1]; 

             } // end-if statement 

          } // end-if statement 

       } // end-for loop 

    }, // end populateArrays function


    drawCalendar: function (inputObj) {

            // repopulate arrays with event data 
            // pertinent to the current month and year. 
            popUpCal.populateArrays(inputObj); 
		
		var html = '';
		html = '<a id="closeCalender">Close Calendar</a>';
		html += '<table cellpadding="0" cellspacing="0" id="linksTable"><tr>';
		html += '	<th><a id="prevMonth">&lt;&lt;</a></th>';
		html += '   <th colspan="5" class="calendarHeader">'+getMonthName(popUpCal.selectedMonth)+' '+popUpCal.selectedYear+'</th>';
		html += '	<th><a id="nextMonth">&gt;&gt;</a></th>';
		html += '</tr></table>';
		html += '<table id="calendar" cellpadding="0" cellspacing="0">';
		html += '<tr class="weekDaysTitleRow">';
        var weekDays = new Array('S','M','T','W','T','F','S');
        for (var j=0; j<weekDays.length; j++) {
		html += '<td>'+weekDays[j]+'</td>';
        }

        var validLinkFlag = false; 
        var currentDateString; 
        var eventComponentsArray; 
        var daysInMonth = getDaysInMonth(popUpCal.selectedYear, popUpCal.selectedMonth);
        var startDay = getFirstDayofMonth(popUpCal.selectedYear, popUpCal.selectedMonth);
        var numRows = 0;
        var printDate = 1;
        var cssSuffix = ""; 
        if (startDay != 7) {
            numRows = Math.ceil(((startDay+1)+(daysInMonth))/7); // calculate the number of rows to generate
        }
		
        // calculate number of days before calendar starts
        if (startDay != 7) {
            var noPrintDays = startDay + 1; 
        } else {
            var noPrintDays = 0; // if sunday print right away	
        }
		var today = new Date().getDate();
		var thisMonth = new Date().getMonth();
		var thisYear = new Date().getFullYear();
        // create calendar rows
        for (var e=0; e<numRows; e++) {
			html += '<tr class="weekDaysRow">';

            // create calendar days
            for (var f=0; f<7; f++) {

                        // reset variables.
                        validLinkFlag = false; 
                        cssSuffix     = ""; 

                        // loop through the array of valid event dates. 
                        for (var arrayIndex = 0; arrayIndex < eventDatesArray.length; arrayIndex++) { 

                           // set the current date as a string. 
                           currentDateString = eval(popUpCal.selectedMonth + 1) + '/' + 
                                               printDate                        + '/' + 
                                               popUpCal.selectedYear; 

                           // split the date info, using the space as a delimiter. 
                           eventComponentsArray = eventDatesArray[arrayIndex].split(" ");

                           // determine if the current date matches one 
                           // of the valid event dates in the array. 
                           if (datesArray[printDate] == "true") { 

                              // set a flag ensuring that the current date is 'clickable'. 
                              validLinkFlag = true; 

                              // set the status of the current link as a variable (i.e. either 'blocked' or blank). this value
                              //  will be used to ensure that the appropriate css is displayed based on the link's status. 
                              cssSuffix = linkStatus(printDate); 

                           } // end-if statement 

                        } // end-loop 


				if ( (printDate == today) 
					 && (validLinkFlag != true) 
					 && (popUpCal.selectedYear == thisYear) 
					 && (popUpCal.selectedMonth == thisMonth) 
					 && (noPrintDays == 0)) {
					html += '<td id="today" class="todaysCell">';

                        // otherwise, determine if this is a clickable date. 
				} else if ((validLinkFlag == true) && (noPrintDays == 0)) {
					html += '<td class="weekDaysCell' + cssSuffix + '">'; 

				} else {
					html += '<td class="weekDaysCellOff">';
				}

                if (noPrintDays == 0) {

					if (printDate <= daysInMonth) {

                                 // determine if the current date 
                                 // should be made into a link. 
                                 if (validLinkFlag == true) { 
						html += '<a>'+printDate+'</a>';
                                 // otherwise, the current date should not be a link. 
                                 } else { 
						html += printDate; 
                                 } 

					}
                    printDate++;
                }

                html += '</td>';
                if(noPrintDays > 0) noPrintDays--;
            }
            html += '</tr>';
        }
		html += '</table>';
        
        // add calendar element to calendar Div
        var calendarDiv = document.getElementById(popUpCal.calendarId);
        calendarDiv.innerHTML = html;
        
        // close button link
        document.getElementById('closeCalender').onclick = function () {
            calendarDiv.style.display = 'none';
        }
		// setup next and previous links
        document.getElementById('prevMonth').onclick = function () {
            popUpCal.selectedMonth--;
            if (popUpCal.selectedMonth < 0) {
                popUpCal.selectedMonth = 11;
                popUpCal.selectedYear--;
            }
            popUpCal.drawCalendar(inputObj); 
            popUpCal.setupLinks(inputObj);
        }
        document.getElementById('nextMonth').onclick = function () {
            popUpCal.selectedMonth++;
            if (popUpCal.selectedMonth > 11) {
                popUpCal.selectedMonth = 0;
                popUpCal.selectedYear++;
            }
            popUpCal.drawCalendar(inputObj); 
            popUpCal.setupLinks(inputObj);
        }
        
    }, // end drawCalendar function


    setupLinks: function (inputObj) {
        // set up link events on calendar table
        var y = document.getElementById('calendar');
        var x = y.getElementsByTagName('a');
        var cssSuffix = ""; 

        for (var i=0; i<x.length; i++) { 

            x[i].onmouseover = function () { 

                // set the status of the current link as a variable (i.e. either 'blocked' or blank). this value
                //  will be used to ensure that the appropriate css is displayed based on the link's status. 
                cssSuffix = linkStatus(this.innerHTML); 

                this.parentNode.className = 'weekDaysCell' + cssSuffix + 'Over';
            }
            x[i].onmouseout = function () { 

                // set the status of the current link as a variable (i.e. either 'blocked' or blank). this value
                //  will be used to ensure that the appropriate css is displayed based on the link's status. 
                cssSuffix = linkStatus(this.innerHTML); 

                this.parentNode.className = 'weekDaysCell' + cssSuffix;
            }
            x[i].onclick = function () {
                document.getElementById(popUpCal.calendarId).style.display = 'none';
                popUpCal.selectedDay = this.innerHTML;
                inputObj.value = formatDate(popUpCal.selectedDay, popUpCal.selectedMonth, popUpCal.selectedYear);	
                updateTimeField(popUpCal.selectedDay, popUpCal.selectedMonth, popUpCal.selectedYear); 
                updateTitleField(popUpCal.selectedDay); 
                changeFieldAccessibility(popUpCal.selectedDay); 
                updatePrices(popUpCal.selectedYear, popUpCal.selectedMonth, popUpCal.selectedDay);
                reportErrors(popUpCal.selectedYear, popUpCal.selectedMonth, 
                             popUpCal.selectedDay,  timesArray[popUpCal.selectedDay]); 
            }
        }
    }    
}

// Add calendar event that has wide browser support
if ( typeof window.addEventListener != "undefined" )
    window.addEventListener( "load", popUpCal.init, false );
else if ( typeof window.attachEvent != "undefined" )
    window.attachEvent( "onload", popUpCal.init );
else {
    if ( window.onload != null ) {
        var oldOnload = window.onload;
        window.onload = function ( e ) {
            oldOnload( e );
            popUpCal.init();
        };
    }
    else
        window.onload = popUpCal.init;
}

/* Functions Dealing with Dates */

function formatDate(Day, Month, Year) {
    Month++; // adjust javascript month
    if (Month <10) Month = '0'+Month; // add a zero if less than 10
    if (Day < 10) Day = '0'+Day; // add a zero if less than 10
    var dateString = Month+'/'+Day+'/'+Year;
    return dateString;
}

// once a date is selected, automatically update the time field.
function updateTimeField(day, month, year) {

   // by default, hide the multiple showtime div.
   document.getElementById('multiple_showtimes').style.display = 'none';

   // assume that all properties referenced 
   // below are prefaced with this object. 
   with (window.document.forms[0]) { 

      // using the day as an index, set the 
      // appropriate time as a local variable.
      var time_string = timesArray[day];

      // determine if there is a comma in the time string. that 
      // means there is more than one performance on the same day.
      if (time_string.indexOf(",") != -1) {
         // update the reservations page and retrieve 
         // the default time for this performance.
         time_string = multiple_showtimes_selector(time_string, day, month, year);
      } // end-if statement 

      // update the time field with the 
      // appropriate value, using the day as an index. 
      show_time.value = time_string; 

   } // end-with statement
} // end-updateTimeField function 


// whenever a date has multiple showtimes, generate html 
// that will allow the user to select which showtime s/he 
// wants to see. this function also return the default showtime.
function multiple_showtimes_selector(time_string, day, month, year) {

   // set default values.
   var default_showtime     = '';
   var checked_string       = ''; 
   var show_time            = ''; 
   var show_type            = ''; 
   var show_label           = ''; 
   var show_price           = '0'; 
   var show_type_tag        = "Type: ";  
   var show_label_tag       = "Label: ";  
   var show_price_tag       = "Price: "; 
   var total_price          = "0.00";
   var all_showtimes_string = '';
   var all_showtimes_label  = 'Both';
   var html_string          = '<span class="showtimes_intro">' + 
                              'Which performance would you like to see?' + 
                              '</span><br /> ';

   // combine the current date and time into a string.
   var date_string = (month + 1) + '/' + day + '/' + year; 

   // separate the multiple times by splitting 
   // them into an array, using the ',' as a delimiter. 
   var showtimes_array = time_string.split(",");

   // determine if there are more than two showtimes.
   if (showtimes_array.length > 2) {
      all_showtimes_label  = 'All';
   } // end-if statement

   // loop through the array of times. 
   for (var array_index = 0; array_index < showtimes_array.length; array_index++) {

      // reset variables.
      checked_string = '';
      show_time      = ''; 
      show_type      = ''; 
      show_label     = ''; 
      show_price     = ''; 

      // find the position of an asterisk 
      // in the string (if applicable).
      var asterisk_position = showtimes_array[array_index].indexOf("*");

      // determine if an asterisk can be found at the 
      // end of the time. this makes it the default time.
      if (asterisk_position != -1) {
         // designate this as the default show 
         // time, removing the asterisk at the end.
         default_showtime = showtimes_array[array_index].substring(0, asterisk_position);
         // update the array.
         showtimes_array[array_index] = default_showtime;
         // make sure this radio button is checked.
         checked_string = 'checked="checked" ';
      } // end-if statement 

      // loop through the 'additional info' 
      // array, jumping to every fourth index.
      for (var i = 0; i < multiple_showtimes_info_array.length; i=(i+5)) {

         // determine if the date and time in the 'additional 
         // info' array matches the current date and time.
         if ((multiple_showtimes_info_array[i] == date_string) && 
             (showtimes_array[array_index]     == multiple_showtimes_info_array[(i + 1)])) {

            // update variables with the appropriate values.
            show_time   = multiple_showtimes_info_array[(i + 1)]; 
            show_type   = multiple_showtimes_info_array[(i + 2)]; 
            show_label  = multiple_showtimes_info_array[(i + 3)]; 
            show_price  = multiple_showtimes_info_array[(i + 4)]; 

            // remove any labeling text from the beginning of the string.
            show_type   = show_type.substring(show_type_tag.length,   show_type.length);
            show_label  = show_label.substring(show_label_tag.length, show_label.length);
            show_price  = show_price.substring(show_price_tag.length, show_price.length);

            break; // break the current loop.

         } // end-if statement 

      } // end-for loop

      // ensure that this isn't the first loop.
      if (array_index != 0) {
         // append an ampersand to the string.
         all_showtimes_string = all_showtimes_string + ' & ';
      } // end-if statement 

      // append the current showtime to the string.
      all_showtimes_string = all_showtimes_string + showtimes_array[array_index];

      // append the form elements for the 
      // current time to the html string.
      html_string = html_string + '' + 
                    '<input type="radio" name="showtimes" value="' + 
                     showtimes_array[array_index] + '" ' + checked_string  + 
                    'onClick="multiple_showtimes_recalculate(\'' + 
                     show_type  + '\', \'' + show_price + '\', \'' + 
                     showtimes_array[array_index] + '\');" /> '    + 
                    '<span class="fieldlabel_left">' + 
                     show_label + ' (' + showtimes_array[array_index] + ')</span><br /> ';

      // add the current ticket price to the total.
      total_price = (parseFloat(total_price) + parseFloat(show_price));

   } // end-for loop

   // append the 'all performances' form elements to the html string.
   html_string = html_string + '' + 
                 '<input type="radio" name="showtimes" value="' + all_showtimes_string + '" ' + 
                 'onClick="multiple_showtimes_recalculate(\''     + 
                  all_showtimes_label.toLowerCase()  + '\', \'' + 
                  total_price.toFixed(2) + '\', \'' + all_showtimes_string + '\');" /> ' + 
                 '<span class="fieldlabel_left"><i>' + all_showtimes_label     + '</i> (' + 
                  all_showtimes_string + ')</span><br /> ';

   // update the appropriate div layer with 
   // the multiple showtime form elements.  
   document.getElementById('multiple_showtimes').innerHTML = html_string;

   // display the multiple showtime div.
   document.getElementById('multiple_showtimes').style.display = 'block';

   // return the default showtime.
   return default_showtime;

} // end-function multiple_showtimes_selector


// when a user selects the performance time s/he wants to see, update 
// the ticket prices, total cost, and show time field accordingly.
function multiple_showtimes_recalculate(performance_type, new_price, start_time) {

   // assume that all properties referenced 
   // below are prefaced with this object. 
   with (window.document.forms[0]) {

      // update the performance time field.
      show_time.value = start_time;

      // update the appropriate span layer with the price.  
      document.getElementById('adultPriceDiv').innerHTML   = new_price;
      document.getElementById('studentPriceDiv').innerHTML = new_price;
      document.getElementById('seniorPriceDiv').innerHTML  = new_price;

      // update hidden fields that are used 
      // in calculating the total ticket price.
      tickets_adult_price.value   = new_price;
      tickets_student_price.value = new_price;
      tickets_senior_price.value  = new_price;

   } // end-with statement

   // recalculate the total ticket price.
   calculateTickets(); 

} // end-function multiple_showtimes_recalculate


// once a date is selected, automatically update 
// the title on the page and in a hidden field.
function updateTitleField(day) { 

   // set local variable. 
   var crString = ' '; 

   // assume that all properties referenced 
   // below are prefaced with this object. 
   with (window.document.forms[0]) { 

      // update the hidden field with the appropriate 
      // play title, using the day as an index. 
      play_title.value = titlesArray[day]; 

      // determine if there are more than 25 characters in this title. 
      if (titlesArray[day].length > 25) { 
         // make sure a carriage return is 
         // inserted into the appropriate spot. 
         crString = '&nbsp;<br />'; 
      } // end-if statement 

      // update the appropriate div layer with the play title.  
      document.getElementById('playTitle').innerHTML = 'Tickets for' + crString + 
                                                       '<i>' + titlesArray[day]  + '</i>:&nbsp;'; 

   } // end-with statement

} // end-updateTimeField function 


// the following function changes 
// the css-class of an html element. 
function changeCSSClass(cssClassName,cell_id1) { 

   // declare local variable. 
   var cellObject1;  

   // continue if the browser is ie4. 
   if (document.all) { 
      // create objects to reference the table cells. 
      cellObject1 = eval('document.all.'+ cell_id1); 
   } // end-if statement 

   // continue if the browser is ie5 or ns6.  
   if (document.getElementById) { 
      // create objects to reference the table cells. 
      cellObject1 = document.getElementById(cell_id1); 
   } // end-if statement 

   // continue if an appropriate browser is being used. 
   if (document.all || document.getElementById) { 
      // update the table cells with the new background color. 
      cellObject1.className = eval("'" + cssClassName + "'"); 
   } // end-if statement 

} // end-function changeCSSClass 


// enable/disable the 'season ticket holder' field. 
function changeFieldAccessibility(day) { 

   // using the day as an index, set the season ticket 
   // information for the current show as a variable. 
   var season_ticket_flag = seasonTicketArray[day]; 

   // assume that all properties referenced 
   // below are prefaced with this object. 
   with (window.document.forms[0]) { 

      // determine if the current show 
      // is part of the season ticket. 
      if ((season_ticket_flag == "Yes") || 
          (season_ticket_flag == "Flex")) { 

         // determine if the 'season ticket 
         // holder' field is currently disabled. 
         if (tickets_prepaid.disabled == true) { 

            // enable the 'season ticket holder' field.
            tickets_prepaid.disabled = false; 

            // apply the default css-style properties to the descriptive text. 
            changeCSSClass('fieldlabel_left','seasonTicketLabel'); 

            // apply the default css-style properties to the form field. 
            changeCSSClass('field_enabled','prepaidPriceField'); 

         } // end-if statement 

      // otherwise, the current show is not part of the season ticket. 
      } else { 

         // reset the season ticket holder field. 
         tickets_prepaid.value = "0"; 

         // disable the 'season ticket holder' field.
         tickets_prepaid.disabled = true; 

         // apply the 'disabled' css-style properties to the descriptive text. 
         changeCSSClass('fieldlabel_left_disabled','seasonTicketLabel'); 

         // apply the 'disabled' css-style properties to the form field. 
         changeCSSClass('field_disabled','prepaidPriceField'); 

      } // end-if statement 

   } // end-with statement

} // end-function changeFieldAccessibility


// depending on the date the user 
// selected, update the pricing information. 
function updatePrices(year, month, day) { 

   // note: ticket prices are set as global variables 
   // outside of this file on the main page. 

   // set default ticket prices as variables. 
   var adult_price   = default_adult_price; 
   var student_price = default_student_price; 
   var senior_price  = default_senior_price; 
   var prepaid_price = default_prepaid_price; 

   // determine if the show takes place in january, before the 
   // year 2008; in july, after 2008; or august 2009. if so, then 
   // this is the playwrights festival and there is special pricing. 
   if (((year <= '2008') && (month == 0)) || 
       ((year >  '2008') && (month == 6)) || 
       ((year == '2009') && (month == 7))) { 

      // set the playwright festival prices as variables. 
      adult_price   = alt_adult_price1; 
      student_price = alt_student_price1; 
      senior_price  = alt_senior_price1; 
      prepaid_price = alt_prepaid_price1; 

      // determine if this is the july 2010 playwrights festival. 
      if ((year  == '2010') && (month == 6)) { 

         // the tickets are cheaper than usual. 
         // subtract the correct amount from each price. 
         adult_price   = eval(adult_price   - 2).toFixed(2); 
         student_price = eval(student_price - 2).toFixed(2); 
         senior_price  = eval(senior_price  - 2).toFixed(2); 

      // determine if this is a free event. 
      } else if ((year  == '2009') && 
                 (month == 7)      && 
                 (day   == 2)) { 

         // set the alternate prices as variables. 
         adult_price   = alt_adult_price3; 
         student_price = alt_student_price3; 
         senior_price  = alt_senior_price3; 
         prepaid_price = alt_prepaid_price3; 

      } // end-if statement 

   } // end-if statement 

   // determine if the show takes place in may or 
   // june of 2009. if so, then this is the end 
   // of year musical and there is special pricing. 
   if (((month == 4) || (month == 5)) && 
       (year == '2009')) { 

      // set the playwright festival prices as variables. 
      adult_price   = alt_adult_price2; 
      student_price = alt_student_price2; 
      senior_price  = alt_senior_price2; 
      prepaid_price = alt_prepaid_price2; 

   } // end-if statement 

   // determine if the current month / year combination happened 
   // before august 2008, when the ticket prices were raised. 
   if  (((year == '2008') && (month < 7)) || 
         (year  < '2008')) { 

       // subtract the correct amount from each price. 
       adult_price   = eval(adult_price   - 2).toFixed(2); 
       student_price = eval(student_price - 2).toFixed(2); 
       senior_price  = eval(senior_price  - 2).toFixed(2); 

   } // end-if statement 

   // assume that all properties referenced 
   // below are prefaced with this object. 
   with (window.document.forms[0]) { 

      // update the hidden fields with the appropriate values. 
      tickets_adult_price.value   = adult_price; 
      tickets_student_price.value = student_price; 
      tickets_senior_price.value  = senior_price; 
      tickets_prepaid_price.value = prepaid_price; 

   } // end-with statement

   // determine if the pre-paid ticket holders 
   // won't be changed for the selected show.
   if (prepaid_price < 1) { 
      // update the variable to something more descriptive. 
      prepaid_price = 'Pre-Paid'; 
   // otherwise, the ticket costs something. 
   } else { 
      // prepend the ticket price with a dollar sign. 
      prepaid_price = '$' + prepaid_price; 
   } // end-if statement 

   // update the appropriate span layer with the price.  
   document.getElementById('adultPriceDiv').innerHTML   = adult_price;
   document.getElementById('studentPriceDiv').innerHTML = student_price;
   document.getElementById('seniorPriceDiv').innerHTML  = senior_price;
   document.getElementById('prepaidPriceDiv').innerHTML = prepaid_price;

   // recalculate the price totals for any tickets the 
   // user may have already input. note: the following 
   // function is in the 'calculate_tickets.js' file. 
   startCalc();

} // end-function updatePrices 


// determine how many hours are between now and 
// the performance date/time the user selected. 
function hoursBeforePerformance(performanceYear, performanceMonth, performanceDay, performanceTime) { 

   // set local variables. 
   var errorMessage = ""; 
   var hourString   = "hour"; 

   // assume that the reservation is being 
   // made within a permitted time period. 
   var timeTestFlag = "passed"; 

   // calculate how many hours are between now and 
   // the performance date/time the user selected. 
   var hoursDifference = calculateHoursDifference(performanceYear, 
                                                  performanceMonth, 
                                                  performanceDay, 
                                                  performanceTime); 

   // determine if the user is attempting to 
   // make an online reservation with too few 
   // hours to go before a performance date/time. 
   if (hoursDifference < minHours_BeforeShow) { 
      // update a flag, acknowledging that 
      // the user failed the timespan test. 
      timeTestFlag = "failed"; 
   // determine if the user is attempting to make an online 
   // reservation way too far in advance of a performance date. 
   // } else if (hoursDifference > maxHours_BeforeShow) { 
      // update a flag, acknowledging that 
      // the user failed the timespan test. 
      // timeTestFlag = "failed"; 
   } // end-if statement 

   // determine if the user is no longer 
   // permitted to make an online reservation. 
   if (timeTestFlag == "failed") { 

      // ensure the performance is 
      // happening in more than an hour. 
      if (hoursDifference != 1) { 
         // append an 's' to the string. 
         hourString = hourString + "s"; 
      } // end-if statement 

      // determine if the date the user 
      // selected happened in the past. 
      if (hoursDifference < 0) { 

         // set the error message as a variable. 
         errorMessage = "The performance date you selected happened in the past. \n" + 
                        "Please choose one that has not already transpired."; 

      // otherwise, determine if the date the user 
      // selected is happening way too far in the future. 
      // } else if (hoursDifference > maxHours_BeforeShow) { 

         // set the error message as a variable. 
         // errorMessage = "Online reservations cannot be made more \n" + 
         //                "than " + eval(maxHours_BeforeShow/24) + " days in advance of a performance. \n" + 
         //                "The performance you selected happens in " + Math.ceil(hoursDifference/24) + " days. \n" + 
         //                "If you have any questions about this, please call the theater."; 

      // otherwise, the performance is happening too soon. 
      } else { 

         // set the error message as a variable. 
         errorMessage = "Online reservations must be made more \n" + 
                        "than " + minHours_BeforeShow + " hours in advance of a performance. \n" + 
                        "The performance you selected happens in " + hoursDifference + " " + hourString + ". \n" + 
                        "Please make this reservation over the phone instead."; 

      } // end-if statement 

   } // end-if statement 

   // return the error message (if one was 
   // found) to the function that requested it. 
   return errorMessage; 

} // end-hoursBeforePerformance function 


// determine if the current date has been blocked and 
// should be prevented from accepting a reservation. 
function blockedDateCheck(performanceDateTime) { 

   // define local variables. 
   var explanationString = ""; 
   var waitListString    = ""; 
   var nextIndex  = 0; 
   var thirdIndex = 0; 

   // loop through the blocked performance dates array. 
   for (var arrayIndex = 0; arrayIndex < eventBlockedDatesArray.length; arrayIndex++) { 

      // determine if the date passed to this function 
      // matches one of the blocked dates in the array. 
      if (eventBlockedDatesArray[arrayIndex] == performanceDateTime) { 

         // set the next array index as a variable. 
         nextIndex = eval(arrayIndex + 1); 

         // set the array index that is two steps forward as a variable. 
         thirdIndex = eval(arrayIndex + 2); 

         // ensure an index exists after this one. 
         if (nextIndex <= eventBlockedDatesArray.length) { 

            // ensure the string found at the next array index 
            // is more than 11 characters long before continuing. 
            if (eventBlockedDatesArray[nextIndex].length > 11) { 

               // determine if the next array index explains whether 
               // a patron can be waitlisted for this performance. 
               if (eventBlockedDatesArray[nextIndex].substring(0, 11) == "Waitlist?: ") { 
                  // extract the waitlist status from the string, setting it as a variable. 
                  waitListString = eventBlockedDatesArray[nextIndex].substring(11, eventBlockedDatesArray[nextIndex].length); 
               } // end-if statement 

            } // end-if statement 

         } // end-if statement 

         // ensure an index two steps forward exists. 
         if (thirdIndex <= eventBlockedDatesArray.length) { 

            // ensure the string found at the appropriate array 
            // index is more than 8 characters long before continuing. 
            if (eventBlockedDatesArray[thirdIndex].length > 8) { 

               // determine if the array index holds an explanation 
               // as to why this performance date has been blocked. 
               if (eventBlockedDatesArray[thirdIndex].substring(0, 8) == "Reason: ") { 
                  // extract the explanation from the string, setting it as a variable. 
                  explanationString = eventBlockedDatesArray[thirdIndex].substring(8, eventBlockedDatesArray[thirdIndex].length); 
               } // end-if statement 

            } // end-if statement 

         } // end-if statement 

         break; // break the for-loop. 

      } // end-if statement 

   } // end-for loop 

   // return the two values back to the function that called for it. 
   return [waitListString, explanationString]; 

} // end-blockedDateCheck function 


// if the current day is a blocked date, display an error message. 
function blockedDateMessage(performanceYear, performanceMonth, performanceDay, performanceTime) { 

   // set local variables. 
   var segmentLength; 
   var breakPosition1; 
   var breakPosition2; 
   var errorMessage      = ""; 
   var verbTenseString   = "is"; 
   var concludingMessage = ""; 

   // calculate how many hours are between now and 
   // the performance date/time the user selected. 
   var hoursDifference = calculateHoursDifference(performanceYear, 
                                                  performanceMonth, 
                                                  performanceDay, 
                                                  performanceTime); 
 
    // determine if patrons can be waitlisted for this performance. 
   if ((waitListArray[performanceDay] == "Yes") || 
       (waitListArray[performanceDay] == "yes") || 
       (waitListArray[performanceDay] == "Y")   || 
       (waitListArray[performanceDay] == "y")) { 
      // ensure that waitlisting is mentioned at the end of the error message. 
      concludingMessage = "To be placed on the waitlist for this performance, " + 
                          "please call " + phone_number_default + ". Thank you."; 
   } // end-if statement 
 
   // determine if the date the user 
   // selected happened in the past. 
   if (hoursDifference < 0) { 
      // make sure the appropriate verb is used. 
      verbTenseString   = "was"; 
      // don't tack on any concluding message 
      // since this date occurred in the past. 
      concludingMessage = ""; 
   } // end-if statement 

   // determine if the current day has a blocked date message associated with it. 
   if (blockedDatesArray[performanceDay].length > 0) {  
      // set the error message as a variable. 
      errorMessage = "Online reservations can no longer be accepted for this date. " + 
                     "The performance " + verbTenseString + " "  + 
                      blockedDatesArray[performanceDay]   + ". " + concludingMessage; 
   } // end-if statement 

   // determine if there are more than 130 characters in the error message.  
   if (errorMessage.length > 130) { 

      // divide the total number of characters in 
      // the string by three and set it as a variable. 
      var segmentLength = Math.ceil(errorMessage.length/3); 

      // starting roughly a third of the way into the string (less 3), 
      // find the nearest space and set the position as a variable. add 
      // one to the number to get the position right after the space. 
      var breakPosition1 = eval(errorMessage.indexOf(" ", eval(segmentLength - 3)) + 1); 

      // starting roughly two-thirds of the way into the string (less 3), 
      // find the nearest space and set the position as a variable. add 
      // one to the number to get the position right after the space. 
      var breakPosition2 = eval(errorMessage.indexOf(" ", eval(eval(segmentLength * 2) - 3)) + 1); 

      // insert line breaks at the appropriate positions throughout the string. 
      errorMessage = errorMessage.substring(0, breakPosition1)              + "\n" + 
                     errorMessage.substring(breakPosition1, breakPosition2) + "\n" + 
                     errorMessage.substring(breakPosition2, errorMessage.length); 

   // otherwise, determine if there are more 
   // than 65 characters in the error message. 
   } else if (errorMessage.length > 65) { 

      // divide the total number of characters in 
      // the string by two and set it as a variable. 
      var segmentLength = Math.ceil(errorMessage.length/2); 

      // starting roughly halfway into the string (less 3), find 
      // the nearest space and set the position as a variable. add 
      // one to the number to get the position right after the space. 
      var breakPosition1 = eval(errorMessage.indexOf(" ", eval(segmentLength - 3)) + 1); 

      // insert line breaks at the appropriate positions throughout the string. 
      errorMessage = errorMessage.substring(0, breakPosition1) + "\n" + 
                     errorMessage.substring(breakPosition1, errorMessage.length); 

   } // end-if statement 

   // return the error message (if one was 
   // found) to the function that requested it. 
   return errorMessage; 

} // end-blockedDateMessage function 


// determine whether the date passed to this function is erroneous in some way 
// (i.e. occurs in the past, has been blocked, etc. if so, pop up an error message. 
function reportErrors(performanceYear, performanceMonth, performanceDay, performanceTime) { 

   // declare local variable. 
   var errorMessage; 

   // check whether the current date is supposed to be blocked. 
   // if so, an appropriate error message will be returned. 
   errorMessage = blockedDateMessage(performanceYear, performanceMonth, 
                                     performanceDay,  performanceTime); 

   // ensure that an error message hasn't 
   // been returned yet before continuing. 
   if (errorMessage.length == 0) { 
      // check whether the selected date has any time-related 
      // issues, such as occurring in the past or else existing 
      // less than 48 hours before the performance begins. if 
      // so, an appropriate error message will be returned. 
      errorMessage = hoursBeforePerformance(performanceYear, performanceMonth, 
                                            performanceDay,  performanceTime); 
   } // end-if statement 

   // ensure that an error message 
   // was returned before continuing. 
   if (errorMessage.length > 0) { 
 
      // pop-up the appropriate error message. 
      alert(errorMessage); 

      // assume that all properties referenced 
      // below are prefaced with this object. 
      with (window.document.forms[0]) { 
         // clear the date and time fields so the 
         // user cannot make an erroneous reservation. 
         show_date.value = ""; 
         show_time.value = ""; 
      } // end-with statement

   } // end-if statement 

} // end-reportErrors function 


// determine if the selected link has been blocked. 
function linkStatus(performanceDay) { 

   // reset variable. 
   var linkStatus = ""; 
 
   // determine if the current date has been blocked for some reason. 
   if (blockedDatesArray[performanceDay].length > 0) { 
      // update the variable, acknowledging 
      // that the current link has been blocked. 
      linkStatus = "Blocked"; 
   } // end-if statement 
 
    // return the link status back to 
    // the function that called for it. 
    return linkStatus; 

} // end-blockedLink function 


// create an object out of the date and 
// time components sent to this function. 
function createDateTimeObject(performanceYear, performanceMonth, performanceDay, performanceTime) { 

   // extract the individual parts of the performance time (hour, 
   // minute, time marker (am or pm)) and set them as variables. 
   var performanceHour       = performanceTime.substring(0, eval(performanceTime.length - 5)); 
   var performanceMinute     = performanceTime.substring(eval(performanceTime.length - 4), 
                                                         eval(performanceTime.length - 2)); 
   var performanceTimeMarker = performanceTime.substring(eval(performanceTime.length - 2), 
                                                         performanceTime.length); 

   // make sure the variable is treated as a number rather than a string. 
   performanceHour   = eval(performanceHour   * 1); 
   performanceMinute = eval(performanceMinute * 1); 

   // determine if the performance 
   // time is set in the afternoon/evening. 
   if ((performanceTimeMarker == "pm") || 
       (performanceTimeMarker == "PM")) { 
      // add 12 to the hour to convert it to military time. 
      performanceHour = eval(performanceHour + 12); 
   } // end-if statement 

   // create an object out of the performance's date/time. 
   var performanceDateObj = new Date(performanceYear, 
                                     performanceMonth, 
                                     performanceDay, 
                                     performanceHour, 
                                     performanceMinute, 0); 

   // return the date/time object to 
   // the function that called for it. 
   return performanceDateObj; 

} // end-createDateTimeObject function 


// calculate the number of hours between a date/time object 
// passed to this function and the current date and time. 
function calculateHoursDifference(performanceYear, performanceMonth, performanceDay, performanceTime) { 

   // set today's date/time as an object. 
   var todayObj = new Date(); 

    // create an object out of the performance's date/time. 
   var performanceDateObj = createDateTimeObject(performanceYear, 
                                                 performanceMonth, 
                                                 performanceDay, 
                                                 performanceTime); 

   // calculate how many hours are between now and 
   // the performance date/time the user selected. 
   var hoursDifference = Math.ceil(((performanceDateObj.getTime() - todayObj.getTime()) / oneHour)); 

   // return the difference in hours 
   // to the function that called for it.
   return hoursDifference; 

} // end-calculateHoursDifference function 


function getMonthName(month) {
    var monthNames = new Array('January','February','March','April','May','June','July','August','September','October','November','December');
    return monthNames[month];
}

function getDayName(day) {
    var dayNames = new Array('Monday','Tuesday','Wednesday','Thursday','Friday','Saturday','Sunday')
    return dayNames[day];
}

function getDaysInMonth(year, month) {
    return 32 - new Date(year, month, 32).getDate();
}

function getFirstDayofMonth(year, month) {
    var day;
    day = new Date(year, month, 0).getDay();
    return day;
}

/* Common Scripts */

function getElementsByClass(searchClass,node,tag) {
    var classElements = new Array();
    if ( node == null ) node = document;
    if ( tag == null ) tag = '*';
    var els = node.getElementsByTagName(tag);
    var elsLen = els.length;
    var pattern = new RegExp("(^|\\s)"+searchClass+"(\\s|$)");
    for (i = 0, j = 0; i < elsLen; i++) {
        if ( pattern.test(els[i].className) ) {
            classElements[j] = els[i];
            j++;
        }
    }
    return classElements;
}

/* Position Functions */

function setPos(targetObj,moveObj) {
    var coors = findPos(targetObj);
    moveObj.style.position = 'absolute';
    moveObj.style.top = coors[1]+20 + 'px';
    moveObj.style.left = coors[0] + 'px';
}

function findPos(obj) {
    var curleft = curtop = 0;
    if (obj.offsetParent) {
        curleft = obj.offsetLeft
        curtop = obj.offsetTop
        while (obj = obj.offsetParent) {
            curleft += obj.offsetLeft
            curtop += obj.offsetTop
        }
    }
    return [curleft,curtop];
}