/** HtmlCalendarRederer */

function HtmlCalendarRenderer() {}

HtmlCalendarRenderer.prototype = new DefaultClientRenderer();
HtmlCalendarRenderer.prototype.getConvertedValue =
                           function (context, component, submittedValue)
{
    var input = component.getField();
    if (input && input.date) { return input.date; }
    else { return null; }
}

function JSCalBase(domElem)
{
    this.domElem = domElem;
    this.hideElementsId = 0;
}

JSCalBase.prototype.toHideCallback = function ()
{
    var _jscalbase = this;
    return function ()
    {
        _jscalbase.hide();
    };
};

JSCalBase.prototype.clearTO = function ()
{
    clearTimeout(this.hideElementsId);
};

JSCalBase.prototype.resetTO = function (evt)
{
    this.clearTO();
    this.hideElementsId = setTimeout(this.toHideCallback(), 100);
    evt.cancelBubble = true;
};

function JSCalMonth(domElem)
{
    JSCalBase.call(this, domElem);
}

JSCalMonth.prototype = new JSCalBase();

JSCalMonth.prototype.hide = function ()
{
    this.domElem.style.visibility = "hidden";
    this.clearTO();
};

JSCalMonth.prototype.show = function (domCal, month, months, useVisible)
{
    this.buildList(month, months);
    var leftOffset = parseInt(domCal.style.left, 10) + 6 +
                  JSCal.prototype.getElement("jscal_Month").offsetLeft;
    var oStyle = this.domElem.style;
    oStyle.left = leftOffset + "px";
    oStyle.top  = parseInt(domCal.style.top, 10)  + 23 + "px";
    oStyle.visibility = useVisible ? "visible" : "show";

    JSCal.hideElements("SELECT", this.domElem);
    JSCal.hideElements("APPLET", this.domElem);
};

JSCalMonth.prototype.onclick = function (evt, month)
{
    this.hide();
    JSCal.curr.selectedM = month;
    JSCal.curr.buildCal();
    evt.cancelBubble = true;
};

JSCalMonth.prototype.buildList = function (month, months)
{
    var sName;
    var sHTML = new StringBuffer();
    this.hide();

    sHTML.add("<table width='35' class='calendar_dropdown_style'").
          add(" onmouseover='JSCal.jsMnth.clearTO()'").
          add(" cellspacing='0'").
          add(" onmouseout='JSCal.jsMnth.resetTO(event)'>");

    // roll through the list of month names and them to the table
    var i;
    for (i = 0; i < months.length; i++) {
        sName = months[i];
        // for most locales, the 13th (unidecember) is not used...
        if (sName.length > 0) {
            sHTML.add("<tr><td onmouseover='this.className=\"").
                  add("calendar_dropdown_select_style").
                  add("\"' onmouseout='this.className=\"").
                  add("calendar_dropdown_normal_style").
                  add("\"' onclick='JSCal.jsMnth.onclick(event,").
                  add(i).add(")'>&nbsp;");
            if (i === month) {
                sHTML.add("<b>").add(sName).add("</b>");
            } else {
                sHTML.add(sName);
            }
            sHTML.add("&nbsp;</td></tr>");
        }
    } // for()
    sHTML.add("</table>");
    this.domElem.innerHTML = sHTML.toString();

};

function JSCalYear(domElem)
{
    JSCalBase.call(this, domElem);

    this.scrollIntID = 0;
    this.scrollTOID = 0;
}

JSCalYear.prototype = new JSCalBase();

JSCalYear.prototype.clearInt = function ()
{
    clearInterval(this.scrollIntID);
};

JSCalYear.prototype.clearScroll = function ()
{
    this.clearInt();
    clearTimeout(this.scrollTOID);
};

JSCalYear.prototype.intCallback = function (decr)
{
    var _jscalyear = this;
    return function ()
    {
        if (decr) {
            _jscalyear.autoDecYear();
        } else {
            _jscalyear.autoIncYear();
        }
    };
};

JSCalYear.prototype.setupScroll = function (decr)
{
    this.clearScroll();
    this.intCnt = 0;
    this.interval = 10;
    this.scrollTOID = setTimeout(this.intCallback(decr), 250);
};

JSCalYear.prototype.newSpeed = function ()
{
    var bFlag = false;
    if (!this.intCnt) {
        this.interval = 500;
    }
    if (((this.intCnt++ % 10) === 0) && (this.interval > 50)) {
        this.interval = (this.interval / 2) | 0;  //Math.floor()
        this.clearInt();
        bFlag = true;
    }
    return bFlag;
};

JSCalYear.prototype.autoDecYear = function ()
{
    if (this.newSpeed()) {
        this.scrollIntID =
            setInterval(this.intCallback(true), this.interval);
    }
    this.decYear();
};

JSCalYear.prototype.autoIncYear = function ()
{
    if (this.newSpeed()) {
        this.scrollIntID =
            setInterval(this.intCallback(false), this.interval);
    }
    this.incYear();
};

JSCalYear.prototype.incYear = function ()
{
    this.buildList(this.startYear + 5, false);
    JSCal.bShow = true;
};

JSCalYear.prototype.decYear = function ()
{
    this.buildList(this.startYear + 3, false);
    JSCal.bShow = true;
};

JSCalYear.prototype.hide = function ()
{
    this.domElem.style.visibility = "hidden";
    this.clearTO();
    this.clearScroll();
};

JSCalYear.prototype.show = function (domCal, year, useVisible)
{
    this.currYear = year;
    this.buildList(year,true);
    var leftOffset = parseInt(domCal.style.left, 10) + 6 +
                   JSCal.prototype.getElement("jscal_Year").offsetLeft;
    var oStyle = this.domElem.style;
    oStyle.left = leftOffset + "px";
    oStyle.top  = parseInt(domCal.style.top,10)  + 23 + "px";
    oStyle.visibility = (useVisible) ? "visible" : "show";

    JSCal.hideElements("SELECT", this.domElem);
    JSCal.hideElements("APPLET", this.domElem);
};

JSCalYear.prototype.onclick = function (evt, year)
{
    this.hide();
    JSCal.curr.selectedY = year;
    JSCal.curr.buildCal();
    evt.cancelBubble = true;
};

JSCalYear.prototype.buildList = function (year, bHide)
{
    var sHTML = new StringBuffer();
    if (bHide) {
        this.hide();  // hide it while we generate the drop-down list.
    }

    sHTML.add("<table width='44' class='").
          add("calendar_dropdown_style").
          add("' cellspacing='0' ").
          add("onmouseover='JSCal.jsYear.clearTO()' ").
          add("onmouseout='JSCal.jsYear.resetTO(event)'>");

    // sets up the decrementor
    sHTML.add("<tr><td align='center' ").
          add("onclick='JSCal.jsYear.decYear()'").
          add(" onmouseover='this.className=\"").
          add("calendar_dropdown_select_style").
          add("\"' onmouseout='JSCal.jsYear.clearInt();this.className=\"").
          add("calendar_dropdown_normal_style").
          add("\"' onmousedown='JSCal.jsYear.setupScroll(true)' ").
          add("onmouseup='JSCal.jsYear.clearScroll()'>-</td></tr>");

    var i, sName;
    var j =  0;
    this.startYear = year - 4;
    for (i = year - 4; i <= (year + 4); i++) {
        sName = i;
        if (i === this.currYear) {
            sName = "<b>" + sName + "</b>";
        }
        sHTML.add("<tr><td onmouseover='this.className=\"").
              add("calendar_dropdown_select_style").
              add("\"' onmouseout='this.className=\"").
              add("calendar_dropdown_normal_style").
              add("\"' onclick='JSCal.jsYear.onclick(event,").
              add(i).add(")'>&nbsp;").add(sName).
              add("&nbsp;</td></tr>");
    }

    // sets up the incrementor
    sHTML.add("<tr><td align='center' ").
          add("onclick='JSCal.jsYear.incYear()'").
          add(" onmouseover='this.className=\"").
          add("calendar_dropdown_select_style").
          add("\"' onmouseout='JSCal.jsYear.clearInt();this.className=\"").
          add("calendar_dropdown_normal_style").
          add("\"' onmousedown='JSCal.jsYear.setupScroll(false)'").
          add(" onmouseup='JSCal.jsYear.clearScroll()'>+</td></tr>");

    sHTML.add("</table>");
    this.domElem.innerHTML = sHTML.toString();

};

function JSCal(sDir, showWN, showT, sPrefix)
{
    this.imgDir = sDir;
    this.showWNbr = showWN;
    this.showToday = showT;
    this.fixedX = -1;
    this.fixedY = -1;
    this.imgNrm = [];
    this.imgHgh = [];
    this.sDays = [];
    this.lDays = [];
    this.sMonths = [];
    this.lMonths = [];
    this.firstDOW = 0;
    this.todayTxt = "Today is:";
    this.weekNbrTxt = "Wk";
    this.gotoMsg = "Go To Current Month";
    this.prevAlt = "Prev";
    this.prevMsg = "Click to scroll to previous month. Hold mouse button to scroll automatically.";
    this.nextAlt = "Next";
    this.nextMsg = "Click to scroll to next month. Hold mouse button to scroll automatically.";
    this.monthAlt = " ";
    this.monthMsg = "Click to select a month.";
    this.yearAlt = " ";
    this.yearMsg = "Click to select a year.";
    this.closeAlt = "Close";
    this.closeMsg = "Close the Calendar";
    this.dateMsg = "Select [date] as date.";
    this.todayStr = null;

    if (!JSCal.init)
    {
        JSCal.init = true;
        Lifecycle.addPageLoadEvent(JSCal.prototype.onLoad);
    }

    this.initImages();
}

JSCal.init = false;
JSCal.isIE = document.all;
JSCal.isDOM = document.getElementById;
JSCal.domCal = null;
JSCal.jsMnth = null;
JSCal.jsYear = null;
JSCal.curr = null;
JSCal.bShow = false;
JSCal.imgIds = ["jscalChgLeft", "jscalChgRgt",
                 "jscalChgMth", "jsCalChgYr"];
JSCal.imgSrc = ["left", "right", "drop", "drop"];
JSCal.intervalID = 0;
JSCal.hideElementsId = 0;

JSCal.prototype.initDays = function (aDays, bShort)
{
    if (bShort) {
        this.sDays = aDays;
    } else {
        this.lDays = aDays;
    }
};

JSCal.prototype.initMonths = function (aMonths, bShort)
{
    if (bShort) {
        this.sMonths = aMonths;
    } else {
        this.lMonths = aMonths;
    }
};

JSCal.prototype.initDOW = function (iDOW)
{
    this.firstDOW = iDOW;
};

JSCal.prototype.setTodayTxt = function (str)
{
    this.todayTxt = str;
};

JSCal.prototype.setWeekTxt = function (str)
{
    this.weekNbrTxt = str;
};

JSCal.prototype.setGotoMsg = function (str)
{
    this.gotoMsg = str;
};

JSCal.prototype.setPrevAlt = function (str)
{
    this.prevAlt = str;
};

JSCal.prototype.setPrevMsg = function (str)
{
    this.prevMsg = str;
};

JSCal.prototype.setNextAlt = function (str)
{
    this.nextAlt = str;
};

JSCal.prototype.setNextMsg = function (str)
{
    this.nextMsg = str;
};

JSCal.prototype.setMonthAlt = function (str)
{
    this.monthAlt = str;
};

JSCal.prototype.setMonthMsg = function (str)
{
    this.monthMsg = str;
};

JSCal.prototype.setYearAlt = function (str)
{
    this.yearAlt = str;
};

JSCal.prototype.setYearMsg = function (str)
{
    this.yearMsg = str;
};

JSCal.prototype.setCloseAlt = function (str)
{
    this.closeAlt = str;
};

JSCal.prototype.setCloseMsg = function (str)
{
    this.closeMsg = str;
};

JSCal.prototype.setDateMsg = function (str)
{
    this.dateMsg = str;
};

JSCal.prototype.initImages = function ()
{
    var i, sBaseName;
    if (document.images) {
        for (i = 0; i < JSCal.imgIds.length; i++) {
            sBaseName = this.imgDir + JSCal.imgSrc[i];
            this.imgNrm[i] = new Image();
            this.imgNrm[i].src = sBaseName + "1.gif";
            this.imgHgh[i] = new Image();
            this.imgHgh[i].src = sBaseName + "2.gif";
        }
    }
};

JSCal.prototype.swapImage = function (indx, imgHgh, ctl)
{
    var imgName;
    if (document.images) {
        imgName = JSCal.imgIds[indx];
        if (imgHgh) {
            this.getElement(imgName).src = this.imgHgh[indx].src;
        } else {
            this.getElement(imgName).src = this.imgNrm[indx].src;
        }
    }
    if (imgHgh) {
        ctl.className = "calendar_title_select_style";
    } else {
        ctl.className = "calendar_title_normal_style";
        clearInterval(JSCal.intervalID);
        window.status = "";
    }
};

JSCal.prototype.getElement = function (id)
{
    var rtnVal;
    if (typeof(id) !== 'string') {
        rtnVal = id;
    } else if (JSCal.isDOM) {
        rtnVal = document.getElementById(id);
    } else if (JSCal.isIE) {
        rtnVal = document.all[id];
    } else {
        rtnVal = null;
    }
    return rtnVal;
};

JSCal.showElements = function (elemID)
{
    var i, obj, objs;
    if (JSCal.isIE) {
        objs = document.all.tags(elemID);
        for (i = 0; i < objs.length; i++) {
            obj = objs[i];
            if ( !obj || !obj.offsetParent ) {
                continue;
            }
            obj.style.visibility = "";
        }
    }
};

JSCal.hideElements = function (elemID, oDiv)
{
    var i, obj, objs, objLeft, objTop, objParent, objHeight, objWidth;
    if (JSCal.isIE) {
        objs = document.all.tags(elemID);
        for (i = 0; i < objs.length; i++ ) {
            obj = objs[i];
            if (!obj || !obj.offsetParent) {
                continue;
            }

            // Find the element's offsetTop and offsetLeft relative
            // to the BODY tag.
            objLeft = obj.offsetLeft;
            objTop  = obj.offsetTop;
            objParent = obj.offsetParent;

            while (objParent.tagName.toUpperCase() !== "BODY") {
                objLeft += objParent.offsetLeft;
                objTop  += objParent.offsetTop;
                objParent = objParent.offsetParent;
            }

            objHeight = obj.offsetHeight;
            objWidth = obj.offsetWidth;

            if ((oDiv.offsetLeft + oDiv.offsetWidth) <= objLeft) {
            } else if ((oDiv.offsetTop + oDiv.offsetHeight) <= objTop) {
            } else if (oDiv.offsetTop >= (objTop + objHeight)) {
            } else if (oDiv.offsetLeft >= (objLeft + objWidth )) {
            } else {
                obj.style.visibility = "hidden";
            }
        }
    }
};

JSCal.prototype.isVisible = function ()
{
    var vState = JSCal.domCal.style.visibility;
    return ((vState === "visible") || (vState === "show"));
};

JSCal.prototype.hide = function ()
{
        if (JSCal.prototype.isVisible()) {
            JSCal.jsYear.hide();
            JSCal.jsMnth.hide();
            JSCal.domCal.style.visibility = "hidden";
            JSCal.prototype.clearMonthScroll();
            JSCal.showElements("SELECT");
            JSCal.showElements("APPLET");
        }
};

JSCal.prototype.showCal = function (x,y)
{
    var oStyle = JSCal.domCal.style;
    oStyle.left = x;
    oStyle.top = y;
    oStyle.visibility =
        (JSCal.isIE || JSCal.isDOM) ? "visible" : "show";
    JSCal.hideElements("SELECT", JSCal.domCal);
    JSCal.hideElements("APPLET", JSCal.domCal);
    JSCal.bShow = true;
};

JSCal.prototype.close = function (d)
{
    this.hide();
    if (d >= 0) {
        var target = this.getElement(this.trgId);
        target.date = new Date(this.selectedY, this.selectedM, d);
        target.value = this.formatDate(this.dFmt,target.date);
        var onchangeStr = target.getAttribute("onchange");
        if (onchangeStr) {
            eval(onchangeStr);
        }
    }
};

JSCal.prototype.closeDelay = function ()
{
    var currCal = this;
    JSCal.bShow = false;
    var closeFunc = function()
    {
        JSCal.closeTimer = null;
        if (!JSCal.bShow) { currCal.close(-1); }
        JSCal.bShow = false;
    }

    JSCal.closeTimer = setTimeout(closeFunc, 200);
};

JSCal.prototype.showPopup = function (ctl, trgId, fmt, tFmt)
{
    if (JSCal.closeTimer) {
        clearTimeout(JSCal.closeTimer);
        JSCal.closeTimer = null;
       }

        if (!JSCal.prototype.isVisible()) {
            this.trgId = trgId;
            this.dFmt = fmt;
            this.tFmt = tFmt;
            this.setupDate();
            this.show(ctl);
        } else {
            this.hide();
            if (this !== JSCal.curr) {
                this.showPopup(ctl, trgId, fmt, tFmt);
            }
        }
        JSCal.curr = this;
};

JSCal.prototype.initDate = function (trgId, fmt, tFmt)
{
    this.trgId = trgId;
    this.dFmt = fmt;
    this.tFmt = tFmt;

    var element = this.getElement(this.trgId);
    element.date = null;

    if (this.setupDate()) {
        element.date = new Date(this.selectedY, this.selectedM, this.selectedD);
    }
};

JSCal.prototype.setupDate = function ()
{
    // save the current date off into its different parts...
    this.today = new Date();
    this.currY = this.today.getFullYear();
    this.currM = this.today.getMonth();
    this.currD = this.today.getDate();

    var fmtSep = "/";
    var sFmt = this.dFmt.replace(/[ ,.\/-]/g, fmtSep); // normalize.
    sFmt = sFmt.replace(/\/+/g, fmtSep);         // collapse multiples
    var aFmt = sFmt.split(fmtSep);
    if (aFmt.length < 3) {
        fmtSep = "";
    }

    var nbrFields =  0;
    var i, j, y, minY, cent, sData, aData;
    if (fmtSep !== "" ) {
        // found a separator so use user's date in target control.
        sData = this.getElement(this.trgId).value;
        sData = sData.replace(/[ ,.\/-]/g,"/").replace(/\/+/g,"/");
        aData = sData.split(fmtSep);

        for (i = 0; i < 3; i++) {
            if ((aFmt[i] === "d") || (aFmt[i] === "dd")) {
                this.selectedD = parseInt(aData[i], 10);
                nbrFields++;
            } else if ((aFmt[i] === "M") || (aFmt[i] === "MM")) {
                this.selectedM = parseInt(aData[i], 10) - 1;//zero-based
                nbrFields++;
            } else if (aFmt[i] === "yyyy") {
                this.selectedY = parseInt(aData[i], 10);
                nbrFields++;
            } else if (aFmt[i] === "yy") {
                y = parseInt(aData[i], 10);
                if (!isNaN(y)) {
                    if (aData[i].length < 3) {
                        minY = this.currY - 79;
                        cent = ((minY / 100) | 0) * 100;
                        y += cent;
                        y = (y < minY) ? y + 100 : y;
                    }
                }
                this.selectedY = y;
                nbrFields++;
            } else if (aFmt[i] === "MMM") { //short months
                for (j = 0; j < this.sMonths.length; j++) {
                    if (aData[i] === this.sMonths[j]) {
                        this.selectedM = j;
                        nbrFields++;
                        break;
                    }
                }
            } else if (aFmt[i] === "MMMM") { //long months
                for (j = 0; j < this.lMonths.length; j++) {
                    if (aData[i] === this.lMonths[j]) {
                        this.selectedM = j;
                        nbrFields++;
                        break;
                    }
                }
            }
        }
    }

    // If we could not parse the date in the target control we will
    // default to using the current date as the starting point...
    if ((nbrFields !== 3) || isNaN(this.selectedD) ||
        isNaN(this.selectedM) || isNaN(this.selectedY)) {
        this.selectedD = this.currD;
        this.selectedM = this.currM;
        this.selectedY = this.currY;
        return false;
    }
    return true;
};

JSCal.prototype.show = function (ctl)
{
    if (JSCal.closeTimer) {
        clearTimeout(JSCal.closeTimer);
        JSCal.closeTimer = null;
       }

    this.origD = this.selectedD;
    this.origM = this.selectedM;
    this.origY = this.selectedY;

    var target = this.getElement(this.trgId);

    var x = 0;
    var y = 0;
    var aTag = target;
    do {
        aTag = aTag.offsetParent;
        x += aTag.offsetLeft;
        y += aTag.offsetTop;
    } while (aTag.tagName !== "BODY");
    this.buildCal();
    this.showCal(
        (this.fixedX === -1) ? target.offsetLeft + x + "px" : this.fixedX,
        (this.fixedY === -1) ? target.offsetTop + y + target.offsetHeight + 2 + "px" : this.fixedY);
};

JSCal.prototype.buildCal = function ()
{
    var sHTML = new StringBuffer();
    sHTML.add("<table width='").
          add(this.showWNbr ? 250 : 220).
          add("' cellpadding='0' cellspacing='0'").
          add(" class='").
          add("calendar_table_style").add("'>");

    // build up the header row (as an embedded table)
    sHTML.add("<tr class='").
          add("calendar_title_background_style").
          add("'><td>").
          add("<table width='").add(this.showWNbr ? 248 : 218).
          add("'><tr>").
          add(this.buildCaption()).
          //add(this.buildClose()).
          add("</tr></table></td></tr>");

    // build up the calendar body
    sHTML.add("<tr><td class='").
          add("calendar_body_style'").
          add(">").
          add(this.buildBody()).
          add("</td></tr>");

    // build up the footer row if requested (current date)
    if (this.showToday) {
        sHTML.add("<tr class='").
              add("calendar_footer_style").
              add("'><td class='").
              add("calendar_today_lbl_style").add("'>").
              add(this.buildFooter()).
              add("</td></tr>");
    }

    // close up the enclosing table container
    sHTML.add("</table>");
    JSCal.domCal.innerHTML = sHTML.toString();
};

JSCal.prototype.buildCaption = function ()
{
    var sHTML = new StringBuffer();
    sHTML.add("<td class='").
          add("calendar_prevmonth_style").add("'>");

    // build up the scroll buttons
    sHTML.add(this.buildScrollBtn(true,  this.prevAlt, this.prevMsg, 0));

    sHTML.add("</td><td class='").add("calendar_currentmonth_style")
        .add("'>");

    // build up the drop-down list buttons
    sHTML.add(this.buildDropBtn("Month", this.monthAlt, this.monthMsg,
                                  2, this.lMonths[this.selectedM]));

   // sHTML.add("</td><td class='").add("calendar_currentyear_style")
     //   .add("'>");

    sHTML.add(this.buildDropBtn("Year", this.yearAlt, this.yearMsg,
                                  3, this.selectedY));

    sHTML.add("</td><td class='").add("calendar_nextmonth_style")
        .add("'>");

    sHTML.add(this.buildScrollBtn(false, this.nextAlt, this.nextMsg, 1));

    // close up the caption cell and return results.
    sHTML.add("</td>");
    return sHTML.toString();
};

JSCal.prototype.buildScrollBtn = function (decr, alt, msg, img)
{
    var sHTML = new StringBuffer();

    sHTML.add("<span class='").
          add("calendar_title_normal_style").
          add("' title='").add(alt).add("' ").
          add("onclick='JSCal.curr.bShow=true;JSCal.curr.updateMonth(").add(decr).add(")' ").
          //add("onmouseover='JSCal.curr.swapImage(").
          //    add(img).add(",true,this);").
          //add("window.status=\"").add(msg).add("\"' ").
          //add("onmouseout='JSCal.curr.swapImage(").
          //    add(img).add(",false,this)' ").
          //add("onmousedown='JSCal.curr.setupMonthScroll(").
          //    add(decr).add(")' ").
          //add("onmouseup='JSCal.curr.clearMonthScroll()'>&nbsp;").
          add(">").add(msg).add("</span>");

    return sHTML.toString();
};

JSCal.prototype.buildDropBtn = function (sID, alt, msg, img, txt)
{
    var sHTML = new StringBuffer();

    sHTML.add("<span id='jscal_").add(sID).add("' class='").
          add("calendar_title_normal_style").
          add("' title='").add(msg).add("' ").
          //add("onclick='JSCal.curr.popup").add(sID).add("()' ").
          //add("onmouseover='JSCal.curr.swapImage(").
          //    add(img).add(",true,this);").
          //add("window.status=\"").add(msg).add("\"' ").
          //add("onmouseout='JSCal.curr.swapImage(").
          //    add(img).add(",false,this)'>&nbsp;").
          add(">").add(txt).add("</span>");
          //add("<img id='").add(JSCal.imgIds[img]).
          //add("' src='").add(this.imgNrm[img].src).
          //add("' alt='").add(alt).
          //add("' width='12' height='10' border='0'>&nbsp;</span>&nbsp;");

    return sHTML.toString();
};

JSCal.prototype.buildClose = function ()
{
    var sHTML = new StringBuffer();
    sHTML.add("<td align=right>").
          add("<img src='").add(this.imgDir).
          add("close.gif' width='15' ").
          add("title='").add(this.closeMsg).add("' class='").
          add("calendar_close_style").
          add("' height='13' border='0' onclick='JSCal.curr.hide()' ").
          add("onmouseover='window.status=\"").
              add(this.closeMsg).add("\"' ").
          add("onmouseout='window.status=\"\"' alt='").
              add(this.closeAlt).
          add("'></td>");
    return sHTML.toString();
};

JSCal.prototype.buildFooter = function ()
{
    var dow = this.today.getDay() + 1;
    var sHTML = new StringBuffer();
    sHTML.add(this.todayTxt).
          add(" <span onmouseover='window.status=\"").
          add(this.gotoMsg).
          add("\";' onmouseout='window.status=\"\"' title='").
          add(this.gotoMsg).add("' class='").
          add("calendar_today_style").
          add("' onclick='JSCal.curr.selectCurrMonth();'>").
          add(this.formatToday()).add("</span>");
    return sHTML.toString();
};

JSCal.prototype.buildBody = function ()
{
    var startDate = new Date(this.selectedY, this.selectedM, 1);
    var endDate = new Date(this.selectedY, this.selectedM + 1, 1);
    endDate = new Date(endDate - 86400000);
    var numDaysInMonth = endDate.getDate();

    var sHTML = new StringBuffer();
    sHTML.add("<table border=0 cellpadding=0 cellspacing=0 class='").
          add("calendar_body_style").add("'>").
          add("<tr class='").add("calendar_dow_style").
          add("'>");

    // Add in the week number column header if it is to be included...
    if (this.showWNbr) {
        sHTML.add("<td width=27><b>").add(this.weekNbrTxt).
              add("</b></td>").
              add("<td width=1 rowspan=7 class='").
              add("calendar_weeknumber_div_style").
              add("'><img src='").add(this.imgDir).
              add("divider.gif' width=1></td>");
    }

    // Add in the days of the week headers
    var fdow = this.firstDOW;
    var ldow = (fdow + 6) % 7;
    var i;
    for (i = 0; i < 7; i++) {
        sHTML.add("<td>").
              add(this.sDays[((fdow + i) % 7) + 1]).add("</td>");
    }
    sHTML.add("</tr>");

    // Show week number on first date line, if requested
    if (this.showWNbr) {
        sHTML.add("<td>").
              add(this.weekNbr(startDate)).add("&nbsp;</td>");
    }

    // include enough blank days at beginning to get to first day.
    var dow = startDate.getDay() - 1;
    i = -dow; // -((dow < fdow) ? 7 - (fdow - dow) : dow - fdow);
    for (var w = 1; w <= 6; w++)
    {
        sHTML.add("<tr class='").add("calendar_week_style").
            add("'>");

        for (var d = 1; d <= 7; d++)
        {
            sHTML.add("<td>");
            if (i <= 0 || i > numDaysInMonth) { sHTML.add("&nbsp;"); }
            else
            {
                // roll through and code up each day.
                var date;
                var sStyle, sSelStyle;

                if ((i === this.currD) &&
                    (this.selectedM === this.currM) &&
                    (this.selectedY === this.currY)) {
                    sStyle = "calendar_current_day_style";
                } else if (dow === ldow) {
                    sStyle = "calendar_weekend_style";
                } else {
                    sStyle = "calendar_normal_day_style";
                }

                //selected day
                if ((i === this.origD) &&
                    (this.selectedM === this.origM) &&
                    (this.selectedY === this.origY)) {
                    sStyle += " " +
                              "calendar_selected_day_style";
                }

                sSelStyle = sStyle + " " +
                         "calendar_would_be_selected_day_style";

                date = new Date(this.selectedY, this.selectedM, i);
                sHTML.add("<span class='").add(sStyle).add("' ").
                      add(" onclick='JSCal.curr.close(").add(i).
                      add(")' onmouseover='this.className=\"").add(sSelStyle).
                      add("\";window.status=\"").
                      add(this.dateMsg.replace("[date]", this.formatDate(this.dFmt,date))).
                      add("\"' onmouseout='this.className=\"").
                      add(sStyle).add("\"; window.status=\"\"' ").
                      add(">").add(i).add("</span>");
             }
             sHTML.add("</td>");

             i++;
         }

         sHTML.add("</tr>");
    }
    sHTML.add("</table>");
    return sHTML.toString();
};

JSCal.prototype.padZero = function (num)
{
    return (num < 10) ? '0' + num : num;
};

JSCal.prototype.formatDate = function (fmt, date)
{
    var c, iStart, len;
    var y = date.getFullYear();
    var m = date.getMonth();
    var d = date.getDate();
    var sTmp = fmt;
    var sBfr = new StringBuffer();
    var i = 0;
    var inQuote = false;

    // roll through the format string and process each character.
    while (i < sTmp.length) {
        c = sTmp.charAt(i);
        if (inQuote && c !== "'") {
            // if in a quoted string, copy over verbatim.
            sBfr.add(c);
        } else {
            iStart = -1;
            switch (c)
            {
            case "'" :
                if ((i + 1 < sTmp.length) &&
                    (sTmp.charAt(i + 1) === c)) {
                    // found quote, need to check if it is
                    // escaped, and if so, add in a singe quote.
                    sBfr.add(c);
                    i++;
                } else {
                    inQuote = !inQuote;
                }
                break;
            case "d" : // fall through
            case "y" : // fall through
            case "E" : // fall through
            case "M" :
                iStart = i;
                break;
            default:
                sBfr.add(c);
                break;
            }

            if (i === iStart) {
                // Found a date field, the way the field is formatted
                // depends on the length of the field.  The following
                // rules apply (see SimpleDateFormat):
                // 1) if field is >= 4 chars, use long name.
                //    for the year that means the full year is specified
                // 2) if field is 3 chars, use short name.
                // 3) if field is 2 chars, use 2-digit w/ leading 0.
                // 4) if field is 1 char, use only needed digits
                while ((i + 1 < sTmp.length) &&
                       (sTmp.charAt(i + 1) === c)) {
                    i++;
                }
                len = i - iStart + 1;
                switch (c)
                {
                case "d":
                    if (len > 1) {
                        sBfr.add(this.padZero(d));
                    } else {
                        sBfr.add(d);
                    }
                    break;
                case "E":
                    if (len > 3) {
                        sBfr.add(this.lDays[date.getDay() + 1]);
                    } else {
                        sBfr.add(this.sDays[date.getDay() + 1]);
                    }
                    break;
                case "M":
                    if (len > 3) {
                        sBfr.add(this.lMonths[m]);
                    } else if (len === 3) {
                        sBfr.add(this.sMonths[m]);
                    } else if (len === 2) {
                        sBfr.add(this.padZero(m + 1));
                    } else {
                        sBfr.add(m + 1);
                    }
                    break;
                case "y":
                    if (len > 3) {
                        sBfr.add(y);
                    } else {
                        sBfr.add(this.padZero(y % 100));
                    }
                    break;
                }
            }
        }
        i++;
    }
    return sBfr.toString();
};

JSCal.prototype.formatToday = function ()
{
    if (!this.todayStr) {
        this.todayStr = this.formatDate(this.tFmt, this.today);
    }
    return this.todayStr;
};

JSCal.prototype.weekNbr = function (n)
{
    // From Klaus Tondering's Calendar document
    // http://www.tondering.dk/claus/calendar.html
    // Note that in the algorithm below that:
    //     Math.floor(expr) == (expr | 0)
    // Using the bitwise is a peformance enhancement and effectively
    // makes a division operation an integer division...
    //    ((1461 * y) >> 2) == (365 * y) + Math.floor(y / 4)
    // right shift by 2 much quicker than divide by 4 and floor()
    //
    var year = n.getFullYear();
    var month = n.getMonth() + 1;
    var day = n.getDate() + 1 - this.firstDOW;

    var a = ((14 - month) / 12) | 0;
    var y = year + 4800 - a;
    var m = month + 12 * a - 3;
    var b = ((1461 * y) >> 2) - ((y / 100) | 0) + ((y / 400) | 0);
    var J = day + (((153 * m + 2) / 5) | 0) + b - 32045;
    var d4 = (((J + 31741 - (J % 7)) % 146097) % 36524) % 1461;
    var L = (d4 / 1460) | 0;
    var d1 = ((d4 - L) % 365) + L;
    var week = ((d1 / 7) | 0) + 1;

    return week;
};

JSCal.prototype.clearMonthScroll = function ()
{
    clearInterval(JSCal.intervalID);
    clearTimeout(JSCal.hideElementsId);
};

JSCal.prototype.callbackMonScroll = function ()
{
    var _jscal = this;
    return function ()
    {
        _jscal.autoUpdate();
    };
};

JSCal.prototype.setupMonthScroll = function (decr)
{
    this.clearMonthScroll();
    this.intCnt = 0;
    this.interval = 500;
    this.decrScroll = decr;
    JSCal.hideElementsId = setTimeout(this.callbackMonScroll(), 500);
};

JSCal.prototype.newSpeed = function () {
    var bFlag = false;
    if ((this.intCnt++ % 12 === 0) && (this.interval > 50))
    {
        this.interval = (this.interval / 2) | 0; //Math.floor()
        clearInterval(JSCal.intervalID);
        bFlag = true;
    }
    return bFlag;
};

JSCal.prototype.autoUpdate = function ()
{
    if (this.newSpeed()) {
        JSCal.intervalID = setInterval(this.callbackMonScroll(),
                                       this.interval);
    }
    this.updateMonth(this.decrScroll);
};

JSCal.prototype.updateMonth = function (decr)
{
    JSCal.bShow = true;
    this.selectedM += (decr ? -1 : 1);
    if (this.selectedM > 11) {
        this.selectedM = 0;
        this.selectedY++;
    } else if (this.selectedM < 0) {
        this.selectedM = 11;
        this.selectedY--;
    }
    this.buildCal();
};

JSCal.prototype.selectCurrMonth = function ()
{
    this.selectedY = this.currY;
    this.selectedM = this.currM;
    this.selectedD = this.currD;
    this.buildCal();
};

JSCal.prototype.popupMonth = function ()
{
    JSCal.jsYear.hide();
    JSCal.jsMnth.show(JSCal.domCal, this.selectedM, this.lMonths,
                      (JSCal.isDOM || JSCal.isIE));
};

JSCal.prototype.popupYear = function ()
{
    JSCal.jsMnth.hide();
    JSCal.jsYear.show(JSCal.domCal, this.selectedY,
                      (JSCal.isDOM || JSCal.isIE));
};

JSCal.prototype.onKeypress = function ()
{
    var evt;
    try {
        if (window.event) {
            evt = window.event;
            if (JSCal.onkeyOrg) {
                JSCal.onkeyOrg();
            }
        } else {
            evt = arguments[0];
            if (JSCal.onkeyOrg) {
                JSCal.onkeyOrg(evt);
            }
        }
        if (evt && (evt.keyCode === 27)) {
            JSCal.prototype.hide();
        }
    } catch(e) {}
};

JSCal.prototype.onClick = function ()
{
    var evt;
    try {
        if (window.event) {
            evt = window.event;
            if (JSCal.onclickOrg) {
                JSCal.onclickOrg();
            }
        } else {
            evt = arguments[0];
            if (JSCal.onclickOrg) {
                JSCal.onclickOrg(evt);
            }
        }
    } catch(e) {}

    if (!JSCal.bShow) {
        JSCal.prototype.hide();
    }
    JSCal.bShow = false;
};

JSCal.prototype.initialize = function ()
{
    JSCal.domCal = JSCal.prototype.getElement("jscal");
    var domMonth = JSCal.prototype.getElement("jsmonth");
    var domYear = JSCal.prototype.getElement("jsyear");
    JSCal.domOK = (JSCal.domCal && domMonth && domYear);
    if (JSCal.domOK) {
        JSCal.jsMnth = new JSCalMonth(domMonth);
        JSCal.jsYear = new JSCalYear(domYear);
    }
};

JSCal.prototype.onLoad = function ()
{
    if (JSCal.onloadOrg) {
        JSCal.onloadOrg();
    }
    JSCal.prototype.initialize();
    JSCal.onkeyOrg = document.onkeypress;
    document.onkeypress = JSCal.prototype.onKeypress;
    JSCal.onclickOrg = document.onclick;
    document.onclick = JSCal.prototype.onClick;
};

/** HtmlDataColumnRenderer */

function HtmlDataColumnRenderer() {}
HtmlDataColumnRenderer.execute = function(id, action)
{
    // Get Hidden Field
    var actionField = document.getElementById(id + ":action");
    if (actionField === null || actionField.form === null)
    {
        return false;
    }

    // Set Action
    actionField.value = action || 0;

    // Disable Client Side Validation (immediate processing)
    Lifecycle.setValidateForm(false);

    // Get Form and Submit
    return actionField.form.submit();
};

/** HtmlPopupWindowRenderer */

function HtmlPopupWindowRenderer() {}
HtmlPopupWindowRenderer.popups = [];
HtmlPopupWindowRenderer.addPopup = function(id, clientId, width, height)
{
    var popup = new HtmlPopupWindowRenderer.PopupWindow(id, clientId, width, height);
    HtmlPopupWindowRenderer.popups[id] = popup;
    HtmlPopupWindowRenderer.popups[clientId] = popup;
};

HtmlPopupWindowRenderer.showPopup = function(id)
{
    var popup = HtmlPopupWindowRenderer.popups[id];
    if (!popup) { return false; }

    HtmlPopupWindowRenderer.currentPopup = popup;
    popup.show(true);
    return false;
}

HtmlPopupWindowRenderer.closePopup = function()
{
    var popup = HtmlPopupWindowRenderer.currentPopup;
    if (!popup) { return false; }

    popup.show(false);
    return false;
}

HtmlPopupWindowRenderer.PopupWindow = function(id, clientId, width, height)
{
    this.id = id;
    this.clientId = clientId;
    this.width = width;
    this.height = height;
}

HtmlPopupWindowRenderer.PopupWindow.prototype.show = function(visible)
{
    var mask = document.getElementById('HtmlPopupWindowRendererMask');
    var popup = document.getElementById(this.clientId + ":popup");
    if (!mask || !popup) { return false; }

    if (visible)
    {
        var viewportWidth = 0;
        var viewportHeight = 0;

        if (typeof window.innerWidth != 'undefined')
        {
            viewportWidth = window.innerWidth;
            viewportHeight = window.innerHeight;
        }

        else if (typeof document.documentElement != 'undefined' &&
                    typeof document.documentElement.clientWidth != 'undefined' &&
                    document.documentElement.clientWidth != 0)
        {
            viewportWidth = document.documentElement.clientWidth;
            viewportHeight = document.documentElement.clientHeight;
        }

        else
        {
            viewportWidth = document.getElementsByTagName('body')[0].clientWidth;
            viewportHeight = document.getElementsByTagName('body')[0].clientHeight;
        }

        mask.style.width = viewportWidth + 'px';
        mask.style.height = viewportHeight + 'px';
        mask.style.display = 'block';

        popup.style.width = this.width + 'px';
        popup.style.height = this.height + 'px';

        popup.style.left = ((document.getElementsByTagName('body')[0].clientWidth - this.width) / 2) + 'px';
        popup.style.top = ((viewportHeight - this.height) / 2) + 'px';

        popup.style.display = 'block';
    }
    else
    {
        popup.style.display = 'none';
        mask.style.display = 'none';
    }

    return true;
}

/** HtmlSelectBooleanMasterCheckboxRenderer */

function HtmlSelectBooleanMasterCheckboxRenderer() {}
HtmlSelectBooleanMasterCheckboxRenderer.prototype.decode =
    function(context, component)
{
    var clientId = component.getClientId();

    var mcbx = null;
    for (var i = 0; i < document.forms.length; i++)
    {
        mcbx = document.forms[i].elements[clientId];
        if (mcbx != null) { break; }
    }

    if (mcbx == null)
    {
        mcbx = document.getElementById(clientId);
    }

    var numChecked = 0;
    if (mcbx != null)
    {
        for (var i = 0; i < mcbx.childCheckboxes.length; i++)
        {
            var child = mcbx.childCheckboxes[i];
            if (child.checked)
            {
                numChecked++;
            }
        }
    }

    component.setSubmittedValue(numChecked);
};

function setupMasterChild(frmName, mcbxName)
{
    var frm = document.forms[frmName];
    var mcbx = frm.elements[mcbxName];
    var toggleChildren;
    mcbx.childCheckboxes = [];
    mcbx.checked = mcbx.checked ? true : false;

    mcbx.syncMaster = function()
    {
        var i;
        var child;
        var checked = true;

        if (mcbx.childCheckboxes.length > 0) {
            for(i = 0; i < mcbx.childCheckboxes.length; i++) {
                child = mcbx.childCheckboxes[i];
                if (!child.checked) {
                    checked = false;
                    break;
                }
            }

            if (mcbx.checked != checked) {
                mcbx.checked = checked;
            }
        }
    };

    mcbx.addChild = function(checkbox)
    {
        checkbox.checked = checkbox.checked ? true : false;
        mcbx.childCheckboxes.push(checkbox);
        mcbx.syncMaster();

        checkbox.toggleMaster = function()
        {
            var mfrm = document.forms[frmName];
            var mcbx2 = mfrm.elements[mcbxName];

            if ((!checkbox.checked) && (mcbx2.checked)) {
                mcbx2.checked = false;
            }
            else if ((checkbox.checked) && (!mcbx2.checked)) {
                mcbx2.syncMaster();
            }
        };

        if (typeof checkbox.onclick != 'function') {
            checkbox.onclick = function()
            {
                checkbox.toggleMaster();
            };
        }
        else {
            var origOnClick = checkbox.onclick;

            checkbox.onclick = function()
            {
                origOnClick();
                checkbox.toggleMaster();
            };
        }
    };

    mcbx.toggleChildren = function()
    {
        var i;
        var child;
        var checked = mcbx.checked ? true : false;

        for(i = 0; i < mcbx.childCheckboxes.length; i++) {
            child = mcbx.childCheckboxes[i];
            if (child.checked != checked) {
                child.checked = checked;
            }
        }
    };

    // Assign method to variable
    //toggleChildren = mcbx.toggleChildren;

    if (typeof mcbx.onclick != 'function')
    {
        mcbx.onclick = function()
        {
            mcbx.toggleChildren();
        };
    }
    else
    {
        var origOnClick = mcbx.onclick;
        mcbx.onclick = function()
        {
            origOnClick();
            mcbx.toggleChildren();
        };
    }
}

/** HtmlTableRenderer */

function HtmlTableRenderer() {}
HtmlTableRenderer.execute = function(id, action, param)
{
    var actionField = document.getElementById(id + ":action");
    var paramField = document.getElementById(id + ":param");
    if (actionField === null || paramField === null || actionField.form === null)
    {
        return false;
    }

    actionField.value = action || 0;
    paramField.value = param || "";

    Lifecycle.setValidateForm(false);

    return actionField.form.submit();
};
