/*
 * Internet Time
 *
 * Swatch Internet Time Utilities
 * Copyright (C) 2009
 * Packetizer, Inc.
 * All Rights Reserved.
 *
 */

/*
 * GetSwatchInternetTime
 *
 * This function will calculate the Internet time and return a properly
 * formatted string.
 *
 * Parameters:
 *     [in] time - A Date object representing the date for which
 *                 the Internet Time shall be calculated (optional;
 *                 the current time is used of no Date object is passed in)
 * 
 * Returns:
 *     A string representing the Internet time.
 *
 */
function GetSwatchInternetTime(time)
{
    var beats;
    var year;
    var month;
    var day;
    var itime;
    var pad = function(to_pad,length)
    {
        to_pad = to_pad.toString();
        while(to_pad.length < length)
        {
            to_pad = "0" + to_pad;
        }
        return to_pad;
    }

    // Create a date object
    itime = new Date();

    // Use the time passed into the function (if an object is passed in)
    if (typeof time == "object")
    {
        itime.setTime(time.getTime());
    }

    // Update the time to be Biel Mean Time (i.e., UTC+1)
    itime.setTime(itime.getTime() + 3600000);

    // Calculate the number of .beats
    beats = pad(parseInt((itime.getTime() % 86400000) / 86400), 3);

    // Get the year, month, and day
    year = itime.getUTCFullYear();
    month = pad(itime.getUTCMonth() + 1, 2);
    day = pad(itime.getUTCDate(), 2);

    return "@" + beats + " d" + day + "." + month + "." + year;
}

/*
 * UpdateInternetTime
 *
 * This function will update a web page to contain the current Internet Time.
 *
 * Parameters:
 *     [in] element - A string that represents the DOM element ID that will be
 *                    updated to contain the Internet Time. (optional; if
 *                    absent, the function will look for an element with
 *                    the name 'internet_time')
 *
 * Returns:
 *     Nothing.
 *
 */
function UpdateInternetTime(element)
{
    var to_update;
    var request = null;
    var time_milliseconds;
    var i;
    var timer = null;

    if (typeof element != "string")
    {
        element = "internet_time";
    }

    // We will assume that we will use remote time
    if (typeof UpdateInternetTime.useRemoteTime == "undefined")
    {
        UpdateInternetTime.useRemoteTime = 1;
        UpdateInternetTime.time = new Date();
        UpdateInternetTime.elements = new Array();
        UpdateInternetTime.elements.push(element);
    }
    else
    {
        // If this function is invoked with the name of an element to
        // update that is different than the first one, then just
        // store it on the array of elements.  It will get updated once
        // the interval expires (<1s).
        if (UpdateInternetTime.elements[0] != element)
        {
            UpdateInternetTime.elements.push(element);
            return;
        }
    }

    // So long as we are using the time from the remote server,
    // we will keep a counter for each second that passes
    if (UpdateInternetTime.useRemoteTime)
    {
        if (typeof UpdateInternetTime.counter == "undefined")
        {
            UpdateInternetTime.counter = 0;
        }
        else
        {
            UpdateInternetTime.counter++;
        }
    }

    // Each hour, we will clear the interval and refresh the time
    // if we are using time provided by the remote server
    if ((UpdateInternetTime.useRemoteTime) && 
        !(UpdateInternetTime.counter % 3600))
    {
        // Reset the counter
        UpdateInternetTime.counter = 0;

        if (typeof UpdateInternetTime.interval != "undefined")
        {
            clearInterval(UpdateInternetTime.interval);
            UpdateInternetTime.interval = undefined;
        }

        // Try to create an XML HTTP Request object
        if (window.XMLHttpRequest)
        {
            request = new XMLHttpRequest();
        }
        else if (window.ActiveXObject)
        {
            request = new ActiveXObject("Microsoft.XMLHTTP");
        }
        else
        {
            request = null;
        }

        if (request != null)
        {
            // This routine will handle state changes as the async request
            // to get the time from the server is executes.
            request.onreadystatechange = function()
            {
                var time_seconds;
                var xml_doc;

                if (request.readyState == 4)
                {
                    // Cancel the timer if it is still running
                    if (timer)
                    {
                        clearTimeout(timer);
                        timer = null;
                    }

                    if ((request.status == 200) &&
                        (UpdateInternetTime.useRemoteTime))
                    {
                        if ((request.getResponseHeader(
                            "Content-Type").indexOf("application/xml") >= 0) &&
                            request.responseXML &&
                            request.responseXML.firstChild)
                        {
                            xml_doc = request.responseXML.documentElement;
                            time_seconds = xml_doc.getElementsByTagName("TimeInSeconds")[0].firstChild.nodeValue;
                            if (time_seconds != null)
                            {
                                UpdateInternetTime.time.setTime(time_seconds * 1000);
                            }
                        }
                        else
                        {
                            UpdateInternetTime.useRemoteTime = 0;
                            UpdateInternetTime.time = undefined;
                        }
                    }
                    else
                    {
                        UpdateInternetTime.useRemoteTime = 0;
                        UpdateInternetTime.time = undefined;
                    }
                    UpdateInternetTime(UpdateInternetTime.elements[0]);
                }
            }

            // Cancel request is called if the XHR request takes more than
            // three seconds.  In that case, we will just use local time.
            cancelRequest = function()
            {
                request.abort();
                timer = null;
                UpdateInternetTime.useRemoteTime = 0;
                UpdateInternetTime.time = undefined;
                UpdateInternetTime(UpdateInternetTime.elements[0]);
            }

            request.open("GET",
                         "http://www.packetizer.com/fcgi-bin/pwsp?service=time",
                         true);
            request.setRequestHeader("Accept", "application/xml");
            request.send(null);
            timer = setTimeout("cancelRequest();", 3000);
            return;
        }
        else
        {
            // We could not allocate an object to fetch the time
            // from the remote server, so we will use local system time
            UpdateInternetTime.useRemoteTime = 0;
        }
    }

    // If we are using remote time and the counter is > 1, then
    // we should increment the time we are storing
    if (UpdateInternetTime.useRemoteTime)
    {
        // We will increment the time each second if the counter
        // is greater than 1 (this is the first time the routine
        // would be called by the timer)
        if (UpdateInternetTime.counter > 1)
        {
            time_milliseconds = UpdateInternetTime.time.getTime();
            time_milliseconds += 1000;
            UpdateInternetTime.time.setTime(time_milliseconds);
        }
    }

    // Locate the element(s) to update and set the innerHTML property to be
    // the Internet Time string.
    for (i=0; i<UpdateInternetTime.elements.length; i++)
    {
        to_update = document.getElementById(UpdateInternetTime.elements[i]);

        // If the element ID exists, then we shall set the time and a timer
        if (to_update != null)
        {
            if (UpdateInternetTime.useRemoteTime)
            {
                to_update.innerHTML = GetSwatchInternetTime(UpdateInternetTime.time);
            }
            else
            {
                to_update.innerHTML = GetSwatchInternetTime();
            }
        }
    }

    // Set a timer to update the time; 86400ms (1 beat) would be useful,
    // but we do not want to be a beat behind all the time, so we will
    // update more frequently (every 1000ms).
    if (typeof UpdateInternetTime.interval == "undefined")
    {
        UpdateInternetTime.interval =
            setInterval("UpdateInternetTime('" + element + "')", 1000);
    }
}

