/*
 * This is a script to provide DHTML functions to the avaialability page.
 */

// Global variables
var colr =Array(); // The colr Array holds the original colours of the highlighed week.
var bgnd = Array(); // Array to hold background images from calendar tables.
var priceFieldVal;  // This variable holds the original value of the priceField element in the page.
var calcFieldVal;  // This variable holds the original value of the priceField element in the page.

var year1; // Variables to hold the year values so they do not need to be hard coded.
var year2;

var priceArray1 = new Array(); // Array to hold the price data from the prices.xml file from the first year.
var priceArray2 = new Array(); // Array to hold the price data from the prices.xml file from the second year.

/**
 *	The function loadPopups() loads the XML file prices.xml, which contains
 * 	price data for each year.
 */
 function loadPopups() {
  var priceDoc;
  // Use the standard DOM level 2 technique, if it is supported.
  if (document.implementation && document.implementation.createDocument) {
      // Create a new Document object
      pPriceDoc = document.implementation.createDocument("", "", null);
      // Specify what should happen when it finishes loading
      pPriceDoc.onload = function(  ) { setPriceArray(pPriceDoc); }
  }
  // Otherwise, use Microsoft's proprietary API for Internet Explorer
  else if (window.ActiveXObject) {
      pPriceDoc = new ActiveXObject("Microsoft.XMLDOM");   // Create doc
      pPriceDoc.onreadystatechange = function(  ) {              // Specify onload
          if (pPriceDoc.readyState == 4) setPriceArray(pPriceDoc);
      }
  }
  pPriceDoc.load("scripts/prices.xml"); // Start loading!
}

/**
 * The function setPriceArray() sets up an array that contains the prices from the prices.xml file.
 */
function setPriceArray(xmlDoc){

    var dataTag = 0;
    // Get year1 and year2 (global variables) from the xml file
    var xmlPriceYear = xmlDoc.getElementsByTagName("priceyear");

    for (yearTag=0; yearTag<xmlPriceYear.length; yearTag++) {
        var yearNum = yearTag +1;
        var xmlDateRange = xmlPriceYear[yearTag].getElementsByTagName("daterange");

        // Get the price year from the XML document
        var prYearVal = xmlPriceYear[yearTag].getAttribute("id");

        this['year'+yearNum] = prYearVal;

        for (dataTag = 0; dataTag<xmlDateRange.length; dataTag++) {
            //Create an array to hold the data for one price range
            var xmlPriceRow = new Array(9);

            var startDate = xmlDateRange[dataTag].childNodes[1].childNodes[1].childNodes[0].nodeValue;
            var endDate = xmlDateRange[dataTag].childNodes[3].childNodes[1].childNodes[0].nodeValue;

            // Put the price range data into the array.
            xmlPriceRow[0] = startDate;
            xmlPriceRow[1] = xmlDateRange[dataTag].childNodes[1].childNodes[3].childNodes[0].nodeValue; // Start Date Week Number
            xmlPriceRow[2] = startDate.substring(0, startDate.indexOf(" ")); // The day
            xmlPriceRow[3] = parseMonth(startDate); // The numeric value of the month
            xmlPriceRow[4] = endDate;
            xmlPriceRow[5] = xmlDateRange[dataTag].childNodes[3].childNodes[3].childNodes[0].nodeValue; // End Date Week Number
            xmlPriceRow[6] = endDate.substring(0, endDate.indexOf(" ")); // The day
            xmlPriceRow[7] = parseMonth(endDate); // The numeric value of the month
            xmlPriceRow[8] = xmlDateRange[dataTag].childNodes[5].childNodes[0].nodeValue; // The price for this period

            // Add the array to the priceArray
            this['priceArray'+yearNum][dataTag] = xmlPriceRow;
        }
    }
}

function parseMonth(dateStr){
    var monthStr = dateStr.substring(dateStr.indexOf(" ")+1)
    var monthNum = 0;

    switch (monthStr) {
        case "Jan":
            monthNum = 1;
            break;
        case 'Feb':
            monthNum = 2;
            break;
        case 'Mar':
            monthNum = 3;
            break;
        case 'Apr':
            monthNum = 4;
            break;
        case 'May':
            monthNum = 5;
            break;
        case 'Jun':
            monthNum = 6;
            break;
        case 'Jul':
            monthNum = 7;
            break;
        case 'Aug':
            monthNum = 8;
            break;
        case 'Sep':
            monthNum = 9;
            break;
        case 'Oct':
            monthNum = 10;
            break;
        case 'Nov':
            monthNum = 11;
            break;
        case 'Dec':
            monthNum = 12;
            break;
        default:
            alert("A date is missing from the prices XML file");
    }
    return monthNum;
}

 /**
  * The function dateHover() highlights a week in the calendar
  * and shows the price of that week in a poppup and in a text field.
  */
 function dateHover(id) {

    var week = document.getElementById(id); // Represents the week to highlight
    var day = week.getElementsByTagName("td"); // Represents an Array of days in the highlighted week.
    var indxStr = id.slice(-3); // Get the number of the week under the cursor.
    var indx = parseInt(indxStr, 10); // Get the number of the week under the cursor.
    var altWeek; // The alternative week represents the same week on a different month
    var altDay = new Array();   // Variable for the array of days in the alterntative week.
    var arrayLength = day.length;

    if (id == "week" +indxStr) {
       altWeek = document.getElementById("week_" + indxStr);
    }else{
       altWeek = document.getElementById("week" + indxStr);
    }

    if (altWeek != null) {
        altDay = altWeek.getElementsByTagName("td"); // The days of the alternative week.
        arrayLength = day.length + altDay.length;
    }

    colr.length = bgnd.length = arrayLength; // Set the length of the colr Array to the combined lengths of the day Array and altDay Array.
    var i = 0; // Simple counter for the for loops (declaring var in the function keeps it as a local variable within the function scope)

    // Highlight all active cells by changing the background to yellow.
    for (i=0; i<day.length; i++) { // The selected week's info is held in the first part of the colr and bgnd arrays.
      // Save the original backgrond colours.
      colr[i] = day[i].style.backgroundColor;
      bgnd[i] = day[i].style.backgroundImage;

      // Select only week days (not greyed out days)
      if (day[i].className == "A" ||
          day[i].className == "AB" ||
          day[i].className == "AC" ||
          day[i].className == "B" ||
          day[i].className == "BA" ||
          day[i].className == "BC" ||
          day[i].className == "C" ||
          day[i].className == "CA" ||
          day[i].className == "CB") {

          // Highlight the week and turn off images.
          day[i].style.backgroundColor = "yellow";
          day[i].style.backgroundImage = "none";
      }
    }

    if (altWeek != null) {
      for (i=day.length; i<arrayLength; i++) { // The alternative week's info is held in the second part of the colr and bgnd arrays.
        var j = i-7;

        // Save the original backgrond colours.
        colr[i] = altDay[j].style.backgroundColor;
        bgnd[i] = altDay[j].style.backgroundImage;

        // Select only week days (not greyed out days)
        if (altDay[j].className == "A" ||
            altDay[j].className == "AB" ||
            altDay[j].className == "AC" ||
            altDay[j].className == "B" ||
            altDay[j].className == "BA" ||
            altDay[j].className == "BC" ||
            altDay[j].className == "C" ||
            altDay[j].className == "CA" ||
            altDay[j].className == "CB") {

            // Highlight the week and turn off images.
            altDay[j].style.backgroundColor = "yellow";
            altDay[j].style.backgroundImage = "none";
        }
      }
    }

    var price = getWeekRate(indx); // Get the price associated with the highlighted week.
    var priceString = new String(price + " p/w");
    week.setAttribute("title", priceString); // Set the title attribute on the week row (creates poppup).

    // Save the original text in priceField and change priceField to present the price message.
    var priceField = document.getElementById("priceField");
    var priceField2 = document.getElementById("priceField2");
    priceFieldVal = priceField.firstChild.nodeValue;
    priceField.firstChild.nodeValue = priceField2.firstChild.nodeValue = "The price for the highlighted week is " + price;
 }

 /**
  * The function dateOut() puts everything back to normal
  * when the mouse is moved off the calendar tables.
  */
 function dateOut(id) {
    var week = document.getElementById(id); // Represents the week to highlight
    var day = week.getElementsByTagName("td"); // Represents an Array of days in the highlighted week.
    var indxStr = id.slice(-3); // Get the number of the week undert the cursor.
    var indx = parseInt(indxStr, 10); // Get the number of the week undert the cursor.
    var altWeek;  // The alternative week represents the same week on a different month
    var altDay = new Array();   // Variable for the array of days in the alterntative week.
    var arrayLength = day.length;

    if (id == "week" +indxStr) {
      altWeek = document.getElementById("week_" + indxStr);
    }else{
      altWeek = document.getElementById("week" + indxStr);
    }

     if (altWeek != null) {
        altDay = altWeek.getElementsByTagName("td"); // The days of the alternative week.
        var arrayLength = day.length + altDay.length;
    }

    // Set the background colour back to the original colours
    // that were saved in the function dateHover().
    for (var i=0; i<day.length; i++) { // The selected week's info is retrieved from the first part of the colr and bgnd arrays.
        day[i].style.backgroundColor = colr[i];
        day[i].style.backgroundImage = bgnd[i];
    }

    if (altWeek != null) {
      for (i=day.length; i<arrayLength; i++) { // The alternative week's info is retrieved from the second part of the colr and bgnd arrays.
        var j = i-7;
        altDay[j].style.backgroundColor = colr[i];
        altDay[j].style.backgroundImage = bgnd[i];
      }
    }

    // Change the priceField element value back to what it was originally.
    document.getElementById("priceField").firstChild.nodeValue =
    document.getElementById("priceField2").firstChild.nodeValue = priceFieldVal;
 }


 /**
  * The function getWeekRate() returns the price associated
  * wth the highlighted week.
  */
 function getWeekRate(weekNum) {
    var startDate = 0;
    var startWeekNum = 1;
    var endDate = 4;
    var endWeekNum = 5;
    var price = 8;

    var rate; // Variable to hold the price to be returned.

    // Get the week number from the appropriate array and
    // Calculate the price from the week number.
    if (weekNum >= priceArray1[0][startWeekNum] && weekNum <= priceArray1[0][endWeekNum]) {
        rate = priceArray1[0][price];
    }else if (weekNum >=priceArray1[1][startWeekNum] && weekNum <=priceArray1[1][endWeekNum]) {
        rate = priceArray1[1][price];
    }else if (weekNum >=priceArray1[2][startWeekNum] && weekNum <=priceArray1[2][endWeekNum]) {
        rate = priceArray1[2][price];
    }else if (weekNum >=priceArray1[3][startWeekNum] && weekNum <=priceArray1[3][endWeekNum]) {
        rate = priceArray1[3][price];
    }else if (weekNum >=priceArray1[4][startWeekNum] && weekNum <=priceArray1[4][endWeekNum]) {
        rate = priceArray1[4][price];
    }else if (weekNum >=priceArray1[5][startWeekNum] && weekNum <=priceArray1[5][endWeekNum]) {
        rate = priceArray1[5][price];
    }else if (weekNum >=priceArray1[6][startWeekNum] && weekNum <=priceArray1[6][endWeekNum]) {
        rate = priceArray1[6][price];
    }else if (weekNum >=priceArray1[7][startWeekNum] && weekNum <=priceArray1[7][endWeekNum]) {
        rate = priceArray1[7][price];
    }else if (weekNum >=priceArray1[8][startWeekNum] && weekNum <=priceArray1[8][endWeekNum]) {
        rate = priceArray1[8][price];
    }else if (weekNum >=priceArray1[9][startWeekNum] && weekNum <=priceArray1[9][endWeekNum]) {
        rate = priceArray1[9][price];
    }else if (weekNum >=priceArray2[0][startWeekNum] && weekNum <= priceArray2[0][endWeekNum]) {
        rate = priceArray2[0][price];
    }else if (weekNum >=priceArray2[1][startWeekNum] && weekNum <=priceArray2[1][endWeekNum]) {
        rate = priceArray2[1][price];
    }else if (weekNum >=priceArray2[2][startWeekNum] && weekNum <=priceArray2[2][endWeekNum]) {
        rate = priceArray2[2][price];
    }else if (weekNum >=priceArray2[3][startWeekNum] && weekNum <=priceArray2[3][endWeekNum]) {
        rate = priceArray2[3][price];
    }else if (weekNum >=priceArray2[4][startWeekNum] && weekNum <=priceArray2[4][endWeekNum]) {
        rate = priceArray2[4][price];
    }else if (weekNum >=priceArray2[5][startWeekNum] && weekNum <=priceArray2[5][endWeekNum]) {
        rate = priceArray2[5][price];
    }else if (weekNum >=priceArray2[6][startWeekNum] && weekNum <=priceArray2[6][endWeekNum]) {
        rate = priceArray2[6][price];
    }else if (weekNum >=priceArray2[7][startWeekNum] && weekNum <=priceArray2[7][endWeekNum]) {
        rate = priceArray2[7][price];
    }else if (weekNum >=priceArray2[8][startWeekNum] && weekNum <=priceArray2[8][endWeekNum]) {
        rate = priceArray2[8][price];
    }else if (weekNum >=priceArray2[9][startWeekNum] && weekNum <=priceArray2[9][endWeekNum]) {
        rate = priceArray2[9][price];
    }
    return rate;

 }

 /**
  * The function calcPrice() calculates the price of the requested period.
  */
 function calcPrice() {
    // Get the requested start date
    var startDay = document.getElementById("sDay")
    var startMonth = document.getElementById("sMonth")
    var startYear = document.getElementById("sYear")
    var sDay = startDay.value;
    var sMonth = startMonth.value;
    var sYear = startYear.value;

    // Get the requested end date
    var endDay = document.getElementById("eDay")
    var endMonth = document.getElementById("eMonth")
    var endYear = document.getElementById("eYear")
    var eDay = endDay.value;
    var eMonth = endMonth.value;
    var eYear = endYear.value;

    var i = 0;              // local variable for loop counters
    var price = 0;        // variable to hold the calculated price
    var sYearDay = 0;  // The day of the year of the start date
    var eYearDay = 0;  // The day of the year of the end date
    var sCalcDay = 0;  // The start day for the rate calculation.
    var eCalcDay = 0;  // The end day for the rate calculation.

    // Validate the dates
    var sDate = validateDate(sDay, sMonth, sYear);  //Validates the dates and returns the
    var eDate = validateDate(eDay, eMonth, eYear); // millisecond representation of each.
    var eDateGTsDate = eDate>sDate;
    if (!eDateGTsDate) { // If dates are wrong way around, switch them.
        var tDay = sDay;
        var tMonth = sMonth;
        var tYear = sYear;
        sDay = eDay;
        sMonth = eMonth;
        sYear = eYear;
        eDay = tDay;
        eMonth = tMonth;
        eYear = tYear;
    }

    // Calculate the number of days from the begining of the year to the selected dates.
    sYearDay = calcYearDay(sDay, sMonth, sYear);
    eYearDay = calcYearDay(eDay, eMonth, eYear);

    /* The following if statement calculates the price between the requested dates by
      * adding up the per diem price from the start date up to (but not including) the end date.
      */
    // If time is requested across the New Year, calculate for each year.
    if (sYear < eYear) {
      sCalcDay = sYearDay;  // Set to the requested start date.
      eCalcDay = calcYearDay(31, 12, sYear)  // Calculate the year day for Dec 31
      cYear = sYear;
      for (i = sCalcDay; i<=eCalcDay; i++) {
        price += getDayRate(i, cYear);
      }
      sCalcDay = 1;  // The year day for Jan 01
      eCalcDay = eYearDay;  // Set to the requested end date.
      cYear = eYear;
      price += getDayRate(1, cYear);  // Add day rate for overnight stay from New Years Eve to New Years Day
      for (i = sCalcDay; i<eCalcDay; i++) {
        price += getDayRate(i, cYear);
      }
    }else {  // Otherwise
      for (i = sYearDay; i<eYearDay; i++) {
        price += getDayRate(i, sYear);  // Calculation is straight forward.
      }
    }
    price = Math.round(price);

    //alert("The price calculated is " + price);
    var calcField = document.getElementById("calcField");
    if (price == 0) {
        calcField.firstChild.nodeValue = "The price of the requested dates cannot be calculated at the moment";
        calcField.childNodes[2].nodeValue = "Please contact us for details";
    }else{
        // Write the information back to the page.
        calcField.firstChild.nodeValue = "The cost from "+sDay+"/"+sMonth+"/"+sYear+" to "+eDay+"/"+eMonth+"/"+eYear+" is "+price+" GB Pounds";
        calcField.childNodes[2].nodeValue = "plus a refundable security deposit of 100 GB Pounds per week or part week";
    }
 }

 /**
  * validateDate ensures entered dates are valid.
  */
function validateDate(vDay, vMonth, vYear) {
    /* Create an array of days per month. The zero in the first array location is a place holder
      * to allow the month to be used as an array index reference. The other 12 indices
      * in the array corresponds to one month of the year.
      * The array values are the number of days in the corresponding month. */
    var monthDays = new Array(0,31,28,31,30,31,30,31,31,30,31,30,31);
    var vDate = new Date();

    // Check if this is a leap year
    var leapYear = (vYear % 4 == 0);
    if (leapYear) {
        monthDays[2] = 29;
    }

    if (parseInt(vDay) > monthDays[vMonth]) {
        alert("You have entered an invalid date!");
        vDate = null;
    }else{
        vDate.setFullYear(vYear, vMonth-1, vDay); // The months are on a zero based ordinal sequence i.e. Jan = 0.
    }
    return vDate;
}

 /**
  * The calcYearDay() function calculates the number of days from
  * the beginning of the year to the date passed in to this function
  */
 function calcYearDay(cDay, cMonth, cYear) {
    var days = 0; // variable to hold the number of days calculated
    var dayNum = parseInt(cDay); // Variable to hold the integer number in cDay

    /* Create an array of days per month. The zero in the first array location is a place holder
      * to allow the month to be used as an array index reference. The other 12 indices
      * in the array corresponds to one month of the year.
      * The array values are the number of days in the corresponding month.*/
    var monthDays = new Array(0,31,28,31,30,31,30,31,31,30,31,30,31);

    // Check if this is a leap year
    var leapYear = (cYear % 4 == 0);
    if (leapYear) {
        monthDays[2] = 29;
    }

    // Add up the days to the current date.
    for (i=1; i<cMonth; i++) {
        days += monthDays[i];
    }
    days += dayNum;

    return days;
 }

/**
 * The getDayRate() function calculates the price of a stay based on
 * the dates requiested in the page form.
 * NOTE: Price changes and dates are set up in this function.
 */
 function getDayRate(rDay, rYear) {
    var startDay = 2;
    var startMth = 3;
    var endDay = 6;
    var endMth = 7;
    var priceVal = 8;
//alert(priceArray1[0][priceVal].substring(1));
    var price = 0; // variable to hold the returned per diem rate.

    /************************
      * NOTE:  for calculations across two years, this function
      * requires the addition of a year check and a separate block of dates
      * and rates for the second year.
      ***********************/

    switch (rYear) {
      case year1:
        // set up day rates and change dates
        // Dates and prices are taken from the price arrays in the global scope
        // NOTE: The currency symbol is stripped from the price using substring() leaving just the number for purposes of calculation.
        if (rDay >= calcYearDay(priceArray1[0][startDay], priceArray1[0][startMth]) && rDay <= calcYearDay(priceArray1[0][endDay], priceArray1[0][endMth])) {
          price = priceArray1[0][priceVal].substring(1)/7;
        }else if (rDay >= calcYearDay(priceArray1[1][startDay], priceArray1[1][startMth]) && rDay <= calcYearDay(priceArray1[1][endDay], priceArray1[1][endMth])) {
          price = priceArray1[1][priceVal].substring(1)/7;
        }else if (rDay >= calcYearDay(priceArray1[2][startDay], priceArray1[2][startMth]) && rDay <= calcYearDay(priceArray1[2][endDay], priceArray1[2][endMth])) {
          price = priceArray1[2][priceVal].substring(1)/7;
        }else if (rDay >= calcYearDay(priceArray1[3][startDay], priceArray1[3][startMth]) && rDay <= calcYearDay(priceArray1[3][endDay], priceArray1[3][endMth])) {
          price = priceArray1[3][priceVal].substring(1)/7;
        }else if (rDay >= calcYearDay(priceArray1[4][startDay], priceArray1[4][startMth]) && rDay <= calcYearDay(priceArray1[4][endDay], priceArray1[4][endMth])) {
          price = priceArray1[4][priceVal].substring(1)/7;
        }else if (rDay >= calcYearDay(priceArray1[5][startDay], priceArray1[5][startMth]) && rDay <= calcYearDay(priceArray1[5][endDay], priceArray1[5][endMth])) {
          price = priceArray1[5][priceVal].substring(1)/7;
        }else if (rDay >= calcYearDay(priceArray1[6][startDay], priceArray1[6][startMth]) && rDay <= calcYearDay(priceArray1[6][endDay], priceArray1[6][endMth])) {
          price = priceArray1[6][priceVal].substring(1)/7;
        }else if (rDay >= calcYearDay(priceArray1[7][startDay], priceArray1[7][startMth]) && rDay <= calcYearDay(priceArray1[7][endDay], priceArray1[7][endMth])) {
          price = priceArray1[7][priceVal].substring(1)/7;
        }else if (rDay >= calcYearDay(priceArray1[8][startDay], priceArray1[8][startMth]) && rDay <= calcYearDay(priceArray1[8][endDay], priceArray1[8][endMth])) {
          price = priceArray1[8][priceVal].substring(1)/7;
        }else if (rDay >= calcYearDay(priceArray1[9][startDay], priceArray1[9][startMth]) && rDay <= calcYearDay(priceArray1[9][endDay], priceArray1[9][endMth])) {
          price = priceArray1[9][priceVal].substring(1)/7;
        }
        break;
      case year2:
        // set up day rates and change dates
        // Dates and prices are taken from the price arrays in the global scope
        // NOTE: The currency symbol is stripped from the price using substring() leaving just the number for purposes of calculation.
        if (rDay >= calcYearDay(priceArray2[0][startDay], priceArray2[0][startMth]) && rDay <= calcYearDay(priceArray2[0][endDay], priceArray2[0][endMth])) {
          price = priceArray2[0][priceVal].substring(1)/7;
        }else if (rDay >= calcYearDay(priceArray2[1][startDay], priceArray2[1][startMth]) && rDay <= calcYearDay(priceArray2[1][endDay], priceArray2[1][endMth])) {
          price = priceArray2[1][priceVal].substring(1)/7;
        }else if (rDay >= calcYearDay(priceArray2[2][startDay], priceArray2[2][startMth]) && rDay <= calcYearDay(priceArray2[2][endDay], priceArray2[2][endMth])) {
          price = priceArray2[2][priceVal].substring(1)/7;
        }else if (rDay >= calcYearDay(priceArray2[3][startDay], priceArray2[3][startMth]) && rDay <= calcYearDay(priceArray2[3][endDay], priceArray2[3][endMth])) {
          price = priceArray2[3][priceVal].substring(1)/7;
        }else if (rDay >= calcYearDay(priceArray2[4][startDay], priceArray2[4][startMth]) && rDay <= calcYearDay(priceArray2[4][endDay], priceArray2[4][endMth])) {
          price = priceArray2[4][priceVal].substring(1)/7;
        }else if (rDay >= calcYearDay(priceArray2[5][startDay], priceArray2[5][startMth]) && rDay <= calcYearDay(priceArray2[5][endDay], priceArray2[5][endMth])) {
          price = priceArray2[5][priceVal].substring(1)/7;
        }else if (rDay >= calcYearDay(priceArray2[6][startDay], priceArray2[6][startMth]) && rDay <= calcYearDay(priceArray2[6][endDay], priceArray2[6][endMth])) {
          price = priceArray2[6][priceVal].substring(1)/7;
        }else if (rDay >= calcYearDay(priceArray2[7][startDay], priceArray2[7][startMth]) && rDay <= calcYearDay(priceArray2[7][endDay], priceArray2[7][endMth])) {
          price = priceArray2[7][priceVal].substring(1)/7;
        }else if (rDay >= calcYearDay(priceArray2[8][startDay], priceArray2[8][startMth]) && rDay <= calcYearDay(priceArray2[8][endDay], priceArray2[8][endMth])) {
          price = priceArray2[8][priceVal].substring(1)/7;
        }else if (rDay >= calcYearDay(priceArray2[9][startDay], priceArray2[9][startMth]) && rDay <= calcYearDay(priceArray2[9][endDay], priceArray2[9][endMth])) {
          price = priceArray2[9][priceVal].substring(1)/7;
        }
        break;
      default:
        price = 0;
    } // End switch statement

    return price;
 }

  /**
 * This debug function displays plain-text debugging messages in a
 * special box at the end of a document. It is a useful alternative
 * to using alert(  ) to display debugging messages.
 **/
function debug(msg) {
    // If we haven't already created a box within which to display
    // our debugging messages, then do so now. Note that to avoid
    // using another global variable, we store the box node as
    // a proprty of this function.
    if (!debug.box) {
        // Create a new <div> element
        debug.box = document.createElement("div");
        // Specify what it looks like using CSS style attributes
        debug.box.setAttribute("style",
                               "background-color: white; " +
                               "font-family: monospace; " +
                               "border: solid black 3px; " +
                               "padding: 10px;");

        // Append our new <div> element to the end of the document
        document.body.appendChild(debug.box);

        // Now add a title to our <div>. Note that the innerHTML property is
        // used to parse a fragment of HTML and insert it into the document.
        // innerHTML is not part of the W3C DOM standard, but it is supported
        // by Netscape 6 and Internet Explorer 4 and later. We can avoid
        // the use of innerHTML by explicitly creating the <h1> element,
        // setting its style attribute, adding a Text node to it, and
        // inserting it into the document, but this is a nice shortcut.
        debug.box.innerHTML = "<h1 style='text-align:center'>Debugging Output</h2>";
    }

    // When we get here, debug.box refers to a <div> element into which
    // we can insert our debugging message.
    // First create a <p> node to hold the message.
    var p = document.createElement("p");
    // Now create a text node containing the message, and add it to the <p>
    p.appendChild(document.createTextNode(msg));
    // And append the <p> node to the <div> that holds the debugging output
    debug.box.appendChild(p);
}

