
/*
 Support functions to get the date formated into the user's preferred strftime()-compatible format
 Based on code by Ross Presser posted to comp.lang.javascript
 and Clock 2.1.2, by Andrew Shearer http://www.shearersoftware.com/software/web-tools/clock/
 */

var dayNames=new Array("Sunday","Monday","Tuesday","Wednesday", "Thursday","Friday","Saturday");
var dayShortNames=new Array("Sun","Mon","Tue","Wed","Thu","Fri","Sat");
var monthNames=new Array("January","February","March","April","May", "June","July","August","September","October","November","December");
var monthShortNames=new Array("Jan","Feb","Mar","Apr","May","Jun", "Jul","Aug","Sep","Oct","Nov","Dec"); 

function getDayOfYear(dt) {
    var d1 = Date.UTC(dt.getYear(),dt.getMonth(),dt.getDate());
    var d2 = Date.UTC(dt.getYear(),0,1);
    return 1+((d1-d2)/86400000);
}

// definition of a % specification
function Spec(ch,defLen,defChar,func) {
    this.ch = ch;
    this.defPadLen = defLen;
    this.defPadChar = defChar;
    this.PadLen = null;
    this.PadChar = null;
    this.PadDir = null;
    this.str = null;
    this.func = func;
}

// create all the specifications we support
var Specs = new Object();
makespecs();

function makespecs() {
    Specs['%'] = new Spec('%',0,' ', function()   {return "%"                                                 });
    Specs['a'] = new Spec('a',0,' ', function(dt) {return dayShortNames[dt.getDay()]                          });        
    Specs['A'] = new Spec('A',0,' ', function(dt) {return dayNames[dt.getDay()]                               });        
    Specs['b'] = new Spec('b',0,' ', function(dt) {return monthShortNames[dt.getMonth()]                      });        
    Specs['h'] = new Spec('h',0,' ', Specs['b'].func);
    Specs['B'] = new Spec('B',0,' ', function(dt) {return monthNames[dt.getMonth()]                           });
    Specs['c'] = new Spec('c',0,' ', function(dt) {return dt.toString()                                       });
    Specs['d'] = new Spec('d',2,'0', function(dt) {return dt.getDate()                                        });
    Specs['D'] = new Spec('D',0,' ', function(dt) {return strftime(dt,"%2m/%2d/%2y")                          });
    Specs['e'] = new Spec('e',2,' ', Specs['d'].func);
    Specs['H'] = new Spec('H',2,'0', function(dt) {return dt.getHours()                                       });
    Specs['I'] = new Spec('I',2,'0', function(dt) { var x=dt.getHours()%12; return (x==0 ? 12 : x)            });
    Specs['j'] = new Spec('j',3,'0', function(dt) {return getDayOfYear(dt)                                    });
    Specs['k'] = new Spec('k',2,' ', Specs['H'].func);
    Specs['l'] = new Spec('l',2,' ', Specs['I'].func);
    Specs['m'] = new Spec('m',2,'0', function(dt) {return 1+dt.getMonth()                                     });
    Specs['M'] = new Spec('M',2,'0', function(dt) {return dt.getMinutes()                                     });
    Specs['n'] = new Spec('n',0,' ', function()   {return "\n"                                                });
    Specs['p'] = new Spec('p',0,' ', function(dt) {return (dt.getHours() < 12) ? "AM" : "PM"                  });
    Specs['r'] = new Spec('r',0,' ', function(dt) {return strftime(dt,"%I:%M:%S %p")                          });
    Specs['s'] = new Spec('s',0,' ', function(dt) {return Math.floor(dt.valueOf()/1000)                       });
    Specs['S'] = new Spec('S',2,'0', function(dt) {return dt.getSeconds()                                     });
    Specs['t'] = new Spec('t',0,' ', function()   {return "\t"                                                });
    Specs['T'] = new Spec('T',0,' ', function(dt) {return strftime(dt,"%H:%M:%S")                             });
    Specs['w'] = new Spec('w',0,' ', function(dt) {return dt.getDay()                                         });
    Specs['x'] = new Spec('x',0,' ', function(dt) {return strftime(dt,"%m/%d/%y")                             });
    Specs['X'] = new Spec('X',0,' ', function(dt) {return strftime(dt,"%H:%M:%S")                             });
    Specs['y'] = new Spec('y',2,'0', function(dt) {return (dt.getFullYear() % 100)                            });
    Specs['Y'] = new Spec('Y',4,'0', function(dt) {return dt.getFullYear()                                    });
    Specs['z'] = new Spec('z',4,'0', function(dt) {x=dt.getTimezoneOffset(); y=Math.abs(x);
                                                   return (Math.floor(y/60)*100 +(y%60))*(x<0 ? 1 : -1)       });
    Specs['Z'] = new Spec('Z',0,' ', function(dt) {return dt.toString().split(' ')[4]                         });
}

// pad a number 'num' to length 'len' using chacter 'ch' in direction 'dir' (0=at left, 1=at right)
function numpad(num,len,ch,dir) {
    var n = parseInt(num);
    return ((n<0) ? "-" : "") + padstr(Math.abs(n),len,ch,dir);
}

// pad an arbitrary string 'str' to length 'len' using chacter 'ch' in direction 'dir' (0=at left, 1=at right)
function padstr(str,len,ch,dir) {
    var s = str.toString();
    while (s.length < len)
        s = ( dir ? (s+ch) : (ch+s) );
    return s;
}

function strftime(dt,fmt) {
    // regexp that tokenizes the fmt string into tokens of % specs and plain text
    var re1 = /(%[_-]?[0-9]*[%A-Za-z])|([^%]+)/g;
    // regexp that splits a % spec into leading _ or -, numeric specifier, and letter
    var re2 = /%([_-])?([0-9]+)?([%A-Za-z])/;
    var tokens;         // array of all tokens making up the fmt string
    var t;              // current token index
    var specstr;   // temporary for current spec string
    var c               // temporary for current spec character
    var curspec;   // current spec object

    // parse all the tokens and iterate
    tokens = fmt.match(re1);
    for (t=0; t<tokens.length;++t) {
        // if token starts with % then it's a % spec; split that up
        if (tokens[t].charAt(0)=='%') {
            specstr = tokens[t];
            specstr.match(re2);

                  // $3 is the spec character; check that we support it.
            c = RegExp.$3;
            if (c in Specs) {
                // set up the spec object.  Note that we modify the original object
                // instead of cloning it; hence we reapply the defaults at the beginning.
                curspec = Specs[c];
                curspec.str = specstr;
                curspec.PadLen=curspec.defPadLen;
                curspec.PadChar=curspec.defPadChar;
                curspec.PadDir=0;
                if (RegExp.$2.length > 0) {
                    curspec.PadLen=parseInt(RegExp.$2);
                    if (RegExp.$2.charAt(0)=='0') curspec.PadChar='0';
                } else if (RegExp.$1.length > 0) {
                    if (RegExp.$1=='_') curspec.PadChar=' ';    // GNU extension: %_d is space-padded
                    if (RegExp.$1=='-') curspec.PadLen=0;       // GNU extension: %-d is unpadded
                }
                          // execute the appropriate function.
                curspec.str = curspec.func(dt);
                          // pad the result if necessary.  Replace original token.
                if (curspec.PadLen!=0) {
                    tokens[t]=numpad(curspec.str,curspec.PadLen,curspec.PadChar,curspec.PadDir);
                } else {
                    tokens[t]=curspec.str;
                }
            }
        }
    }
    // join together all tokens for final result
    return tokens.join("");
} 



/*** simpleFindObj, by Andrew Shearer */

function simpleFindObj(name, inLayer) {
    return document[name] || (document.all && document.all[name])
        || (document.getElementById && document.getElementById(name))
        || (document.layers && inLayer && document.layers[inLayer].document[name]);
}

/*** Beginning of Clock 2.1.2, by Andrew Shearer
See: http://www.shearersoftware.com/software/web-tools/clock/
Redistribution is permitted with the above notice intact.
*/

var clockIncrementMillis = 60000;
var localTime;
var clockOffset;
var clockExpirationLocal;
var clockTimerID = null;

function clockInit()
{
    localDateObject = clockLocalStartTime;
    serverDateObject = clockServerStartTime;

    var origRemoteClock = parseInt(clockGetCookieData("remoteClock"));
    var origLocalClock = parseInt(clockGetCookieData("localClock"));
    var newRemoteClock = serverDateObject.getTime();
    // May be stale (WinIE); will check against cookie later
    // Can't use the millisec. ctor here because of client inconsistencies.
    var newLocalClock = localDateObject.getTime();
    var maxClockAge = 60 * 60 * 1000;   // get new time from server every 1hr

    if (newRemoteClock != origRemoteClock) {
        // new clocks are up-to-date (newer than any cookies)
        document.cookie = "remoteClock=" + newRemoteClock;
        document.cookie = "localClock=" + newLocalClock;
        clockOffset = newRemoteClock - newLocalClock;
        clockExpirationLocal = newLocalClock + maxClockAge;
        localTime = newLocalClock;  // to keep clockUpdate() happy
    }
    else if (origLocalClock != origLocalClock) {
        // error; localClock cookie is invalid (parsed as NaN)
        clockOffset = null;
        clockExpirationLocal = null;
    }
    else {
        // fall back to clocks in cookies
        clockOffset = origRemoteClock - origLocalClock;
        clockExpirationLocal = origLocalClock + maxClockAge;
        localTime = origLocalClock;
        // so clockUpdate() will reload if newLocalClock
        // is earlier (clock was reset)
    }
    /* Reload page at server midnight to display the new date,
       by expiring the clock then */
    var nextDayLocal = (new Date(serverDateObject.getFullYear(),
            serverDateObject.getMonth(),
            serverDateObject.getDate() + 1)).getTime() - clockOffset;
    if (nextDayLocal < clockExpirationLocal) {
        clockExpirationLocal = nextDayLocal;
    }
}

function clockOnLoad()
{
    clockUpdate();
}

function clockOnUnload() {
    clockClearTimeout();
}

function clockClearTimeout() {
    if (clockTimerID) {
        clearTimeout(clockTimerID);
        clockTimerID = null;
    }
}

function clockDisplayTime2(serverTime) {
    var divObject = simpleFindObj('clockObject');
    if(divObject)
        divObject.value = serverTimeStr + ": " + strftime(serverTime,clockFormat);
}

function clockGetCookieData(label) {
    /* find the value of the specified cookie in the document's
    semicolon-delimited collection. For IE Win98 compatibility, search
    from the end of the string (to find most specific host/path) and
    don't require "=" between cookie name & empty cookie values. Returns
    null if cookie not found. One remaining problem: Under IE 5 [Win98],
    setting a cookie with no equals sign creates a cookie with no name,
    just data, which is indistinguishable from a cookie with that name
    but no data but can't be overwritten by any cookie with an equals
    sign. */
    var c = document.cookie;
    if (c) {
        var labelLen = label.length, cEnd = c.length;
        while (cEnd > 0) {
            var cStart = c.lastIndexOf(';',cEnd-1) + 1;
            /* bug fix to Danny Goodman's code: calculate cEnd, to
            prevent walking the string char-by-char & finding cookie
            labels that contained the desired label as suffixes */
            // skip leading spaces
            while (cStart < cEnd && c.charAt(cStart)==" ") cStart++;
            if (cStart + labelLen <= cEnd && c.substr(cStart,labelLen) == label) {
                if (cStart + labelLen == cEnd) {                
                    return ""; // empty cookie value, no "="
                }
                else if (c.charAt(cStart+labelLen) == "=") {
                    // has "=" after label
                    return unescape(c.substring(cStart + labelLen + 1,cEnd));
                }
            }
            cEnd = cStart - 1;  // skip semicolon
        }
    }
    return null;
}

/* Called regularly to update the clock display as well as onLoad (user
   may have clicked the Back button to arrive here, so the clock would need
   an immediate update) */
function clockUpdate()
{
    var lastLocalTime = localTime;
    localTime = (new Date()).getTime();
    
    /* Sanity-check the diff. in local time between successive calls;
       reload if user has reset system clock */
    if (clockOffset == null) {
        
    }
    else if (localTime < lastLocalTime || clockExpirationLocal < localTime) {
        /* Clock expired, or time appeared to go backward (user reset
           the clock). Reset cookies to prevent infinite reload loop if
           server doesn't give a new time. */
        document.cookie = 'remoteClock=-';
        document.cookie = 'localClock=-';
        location.reload();      // will refresh time values in cookies
    }
    else {
        // Compute what time would be on server 
        var serverTime = new Date(localTime + clockOffset);
        clockDisplayTime2(serverTime);
        // Reschedule this func to run on next even clockIncrementMillis boundary
        clockTimerID = setTimeout("clockUpdate()",
            clockIncrementMillis - (serverTime.getTime() % clockIncrementMillis));
    }
}

SafeAddOnload(clockInit);
SafeAddOnload(clockOnLoad);
SafeAddOnunload(clockOnUnload);

/*** End of Clock ***/
