function Calendar(cname, id, date, monthLabels, day1st, dayLabels) {	
    // The id of this calendar
    this.name = cname;
    
    // The first day of the week in the calendar (0-Sunday, 6-Saturday)
    this.firstDayOfWeek = day1st;
    
    // Fallback method
    this.fallback = this.fallback_both;
    
    // Sets the date and strips out time information
    this.calendarDate = date;
    this.calendarDate.setUTCHours(0);
    this.calendarDate.setUTCMinutes(0);
    this.calendarDate.setUTCSeconds(0);
    this.calendarDate.setUTCMilliseconds(0);
    
    // The field id that the calendar is attached to.
    this.attachedId = id;
    
    // The css classes for the calendar and header
    this.calendarStyle = "vv_cal_calendar";     // ok
    this.selectorsStyle = "vv_cal_selectors";
    this.calendarTableStyle = "vv_cal_calendarTable";    // ok
    this.headerStyle = "vv_cal_header";     // ok
    
    this.daySelectorStyle = "vv_cal_daySelector";
    this.monthYearSelectorStyle = "vv_cal_monthYearSelector";
    this.monthButtonStyle = "vv_cal_monthButton";
    
    // The css classes for the rows
    this.weekStyle = "vv_cal_week";
    this.evenWeekStyle = "vv_cal_evenweek";
    this.oddWeekStyle = "vv_cal_oddweek";
    
    // The css classes for the day elements
    this.dayStyle = "vv_cal_day";						// ok
    this.otherMonthStyle = "vv_cal_othermonth";         // ok
    this.weekendStyle = "vv_cal_weekend";               // ok
    this.holidayStyle = "vv_cal_holiday";            // ok
    this.todayStyle = "vv_cal_today";   // ok
    this.selectedDayStyle = "vv_cal_selected";  // ok
    this.hoverStyle = "vv_cal_hover";   // ok
    
    this.increaseMonthImg = "images/vv_cal_increaseMonth.png";
    this.decreaseMonthImg = "images/vv_cal_decreaseMonth.png";
    
    
    this.minDate = new Date();
    this.maxDate = new Date(this.minDate.getTime() + 365*24*60*60*1000);
    
    // specifies the labels for this calendar
    this.dayLabels = dayLabels;
    this.monthLabels = monthLabels;
    
    // Specifies the dates of any holiday. The holidays are to be defined as arrays,
    // with element 0 being the date and element 1 being the description.
    this.holidayDates = new Array();
    
    /*
    // Attach event handlers to any fallback fields.
    if (this.viewOnly == false) {
        //setFieldValue(this.attachedId, this.calendarDate);
        if ((this.fallback = this.fallback_both) || (this.fallback = this.fallback_single)) {
            eval("document.getElementsByName(\"" + this.attachedId + "\").onchange = function () {updateFromSingle("+this.name+", this);}");
        }
    }
     
    selectEvent = new Function();
     */
    
}

Calendar.prototype.addHoliday = Calendar_addHoliday;
function Calendar_addHoliday(year, month, date, text) {
    this.holidayDates[this.holidayDates.length] = new CalendarHoliday(year, month-1, date, text);
}

Calendar.prototype.updateMonthYear = Calendar_updateMonthYear;
function Calendar_updateMonthYear(monthYear) {
    if (isNaN(monthYear.value.substring(0, 2)) || isNaN(monthYear.value.substring(2, 6))) {
        return false;
    }
    this.calendarDate.setUTCMonth(monthYear.value.substring(0, 2));
    this.calendarDate.setUTCFullYear(monthYear.value.substring(2, 6));
    this.renderCalendar();
    setFieldValue(this.attachedId, this.calendarDate);
}

Calendar.prototype.updateDay = Calendar_updateDay;
function Calendar_updateDay(day) {
    if (isNaN(day.value)) {
        return false;
    }
    this.calendarDate.setUTCDate(day.value);
    this.renderCalendar();
    setFieldValue(this.attachedId, this.calendarDate);
}

Calendar.prototype.incrementMonth = Calendar_incrementMonth;
function Calendar_incrementMonth(){
    var newDate = new Date();
    if (this.calendarDate.getUTCMonth() == 11) {
        newDate.setUTCMonth(0);
        newDate.setUTCFullYear(this.calendarDate.getUTCFullYear() + 1);
    } else {
        newDate.setUTCMonth(this.calendarDate.getUTCMonth() + 1);
        newDate.setUTCFullYear(this.calendarDate.getUTCFullYear());
    }
    newDate.setDate(1);
    // Checks if the previous month has at least one day less than maxDay
    if (newDate <= this.maxDate) {
        this.calendarDate.setUTCFullYear(newDate.getUTCFullYear());
        this.calendarDate.setUTCMonth(newDate.getUTCMonth());
        this.renderCalendar();
        setFieldValue(this.attachedId, this.calendarDate);    
    }
}

Calendar.prototype.decrementMonth = Calendar_decrementMonth;
function Calendar_decrementMonth(){
    var newDate = new Date(this.calendarDate.valueOf());
    newDate.setDate(1);
    newDate = new Date(newDate - 24*60*60*1000);
    // Checks if the previous month has at least one day greater than minDay
    if (newDate >= this.minDate) {
        this.calendarDate.setUTCFullYear(newDate.getUTCFullYear());
        this.calendarDate.setUTCMonth(newDate.getUTCMonth());
        this.renderCalendar();
        setFieldValue(this.attachedId, this.calendarDate);  
    }
}

Calendar.prototype.getFirstCalendarDate = Calendar_getFirstCalendarDate;
function Calendar_getFirstCalendarDate() {
    return new Date(
    this.calendarDate.getUTCFullYear()
    , this.calendarDate.getUTCMonth()
    , 1);
}

Calendar.prototype.selectDate = Calendar_selectDate;
function Calendar_selectDate(year, month, day){
    this.calendarDate.setUTCFullYear(year);
    this.calendarDate.setUTCMonth(month);
    this.calendarDate.setUTCDate(day);
    this.renderCalendar();
    setFieldValue(this.attachedId, this.calendarDate);
}


function setFieldValue(fieldId, date) {
    if(date.getUTCMonth() < 10 ){
        month = "0" + date.getUTCMonth();
    } else {
        month = date.getUTCMonth();
    }
    
    year = date.getUTCFullYear();
    monthyear = month + " ";
    monthyear = monthyear.substring(0, monthyear.length-1);
    monthyear = monthyear + year;
    
    if(date.getUTCDate() < 10 ) {
        day = "0" + date.getUTCDate();
    } else {
        day = date.getUTCDate();
    }
    
    document.getElementById(fieldId).value = day + "/" + month + "/" + year;
    
    (document.getElementById(fieldId + "_day"))[parseInt(date.getUTCDate()-1)].selected = 1;
    element = document.getElementById(fieldId + "_monthyear");
    
    for(i=1; i < 12; i++){
        if(element[i].value == monthyear){
            element[i].selected = 1;
            break;
        }
    }
    
}

Calendar.prototype.renderCalendar = Calendar_renderCalendar;
function Calendar_renderCalendar(){
    currentDate = new Date();
    currentMonth = currentDate.getUTCMonth();
    currentYear = currentDate.getUTCFullYear();
    
    var calHtml = '';
    calHtml +=  '<div class="' + this.selectorsStyle + '">';
    calHtml +=      '<select class="' + this.daySelectorStyle + '" id="' + this.attachedId + '_day" onChange="updateDay(' + this.name + ', this);">';
    for(i = 1; i < 32; i++) {
        calHtml += '        <option value="' + i + '">' + i + '</option>';
    }
    calHtml +=      '</select>';
    calHtml +=      '<img src="' + this.decreaseMonthImg + '" class="' + this.monthButtonStyle + '" onClick="' + this.name + '.decrementMonth();">';
    calHtml +=      '<select class="' + this.monthYearSelectorStyle + '" id="' + this.attachedId + '_monthyear" onChange="' + this.name + '.updateMonthYear(this);">';
    value = '';
    option = '';
    do{
        value = currentMonth + '' + currentYear;
        if(currentMonth < 10){
            value = '0' + currentMonth + currentYear.toString();
        }
        option = this.monthLabels[currentMonth] + ' ' + currentYear;
        calHtml +=      '<option value="' + value + '">' + option + ' </option>';
        currentMonth = currentMonth + 1;
        if(currentMonth == 12){
            currentMonth = 0;
            currentYear = currentYear + 1;
        }
    } while(currentMonth != currentDate.getUTCMonth());
    calHtml +=      '</select>';
    calHtml +=      '<img src="' + this.increaseMonthImg + '" class="' + this.monthButtonStyle + '" onClick="' + this.name + '.incrementMonth();">';
    calHtml += '</div>';
    calHtml += this.renderCalendarTable();
    document.getElementById('cal_' + this.attachedId).innerHTML = calHtml;
    setFieldValue(this.attachedId, this.calendarDate);
}

Calendar.prototype.renderCalendarTable = renderCalendarTable;
function renderCalendarTable() {
    var Today = new Date();
    calHtml = '';
    
    currentDate = this.getFirstCalendarDate();
    while (currentDate.getUTCDay() != this.firstDayOfWeek){
        currentDate.setUTCDate(currentDate.getUTCDate() - 1);
    }
    // Prints header row
    var i = this.firstDayOfWeek;
    calHtml += '<table border="0" cellpadding="0" cellspacing="0" class="' + this.calendarTableStyle + '">';
    calHtml += ('<tr>');
    do{
        calHtml += '<td class="' + this.headerStyle + '">' + this.dayLabels[i] + '</td>';
        i = (i+1)%7;
    } while(i != this.firstDayOfWeek);
    calHtml += '</tr>';
    // Prints days row
    var row = 0;
    do {
        row += 1;
        calHtml += '<tr class="' + (((row%2)==0) ? this.evenWeekStyle : this.oddWeekStyle) + '">';
        for (i = 0;i < 7;i++){
            currentDayStyle = this.dayStyle;
            currentEventStyle = this.commonDayStyle;
            currentDateString = currentDate.getUTCFullYear() + "/" + currentDate.getUTCMonth()  + "/" + currentDate.getUTCDate();
            calHtml += this.renderDay(currentDate);
            currentDate.setUTCDate(currentDate.getUTCDate() + 1);	
        }
        calHtml += '</tr>';
    } while (row <= 5);
    calHtml += "</table>";
    return calHtml;
}




Calendar.prototype.renderDay = renderDay;
function renderDay(currentDate) {
    var html = '';
    var styleClass = '';
    var onMouseOver = 'Calendar_addClassName(this, \'' + this.hoverStyle + '\');';
    var onMouseOut = 'Calendar_removeClassName(this, \'' + this.hoverStyle + '\');';
    
    // Normal or Weekend
    if ((currentDate.getUTCDay() == 0) || (currentDate.getUTCDay() == 6)) {
        styleClass += ((styleClass.length > 0) ? ' ' : '') + this.weekendStyle;
    } else {
        styleClass += ((styleClass.length > 0) ? ' ' : '') + this.dayStyle;
    }
    
    // Holidays
    for (j=0; j < this.holidayDates.length; j++) {
        if (this.holidayDates[j].date == currentDate.getUTCDate() && this.holidayDates[j].month == currentDate.getUTCMonth() && this.holidayDates[j].year == currentDate.getUTCFullYear()) {
            styleClass += ((styleClass.length >= 0) ? ' ' : '') + this.holidayStyle;
            onMouseOver += ' popUp(event, \'vv_holiday\', \'' + this.holidayDates[j].text + '\');';
            onMouseOut += ' popUp(event, \'vv_holiday\');';
        }
    }
    
    // Other months
    if (currentDate.getUTCMonth() != this.calendarDate.getUTCMonth()) {
        styleClass += ((styleClass.length > 0) ? ' ' : '') + this.otherMonthStyle;
    }
    
    // Today
    if (this.isSameDate(currentDate, new Date())) {
        styleClass += ((styleClass.length > 0) ? ' ' : '') + this.todayStyle;
    }
    
    // Selected
    if (this.isSameDate(currentDate, this.calendarDate)) {
        styleClass += ((styleClass.length > 0) ? ' ' : '') + this.selectedDayStyle;
    }
    
    html += '<td class="' + styleClass + '" onmouseover="' + onMouseOver + '" onmouseout="' + onMouseOut + '">';
    if (currentDate >= this.minDate && currentDate <= this.maxDate) {
        html += '    <span class="vv_cal_enabled" onclick="' + this.name + '.selectDate(' + currentDate.getUTCFullYear() + ', ' + currentDate.getUTCMonth() + ', ' + currentDate.getUTCDate() + '); ">';
    } else {
        html += '    <span class="vv_cal_disabled">';
    }
    html +=          currentDate.getUTCDate();
    html += '    </span>';
    html += '</td>';
    return html;
}

Calendar.prototype.isSameDate = Calendar_isSameDate;
function Calendar_isSameDate(date1, date2) {
    if (date1.getUTCFullYear() == date2.getUTCFullYear() 
    && date1.getUTCMonth() == date2.getUTCMonth()
    && date1.getUTCDate() == date2.getUTCDate()) {
        return true;
    } else {
        return false;
    }
}

function Calendar_removeClassName(object, className) {
    var rep=object.className.match(' '+className)?' '+className:className;
    object.className=object.className.replace(rep,'');
}

function Calendar_addClassName(object, className) {
    if(!RegExp('\\b'+className+'\\b').test(object.className)) {
        object.className+=object.className?' '+className:className;
    }
}



function CalendarHoliday(year, month, date, text) {
    this.year = year;
    this.month = month;
    this.date = date;
    this.text = text;
}

// Extended Tooltip Javascript
// copyright 9th August 2002, 3rd July 2005
// by Stephen Chapman, Felgall Pty Ltd

var DH = 0;
var an = 0;
var al = 0;
var ai = 0;
if (document.getElementById) {
    ai = 1; 
    DH = 1;
} else {
    if (document.all) {
        al = 1; 
        DH = 1;
    } else { 
        browserVersion = parseInt(navigator.appVersion); 
        if ((navigator.appName.indexOf('Netscape') != -1) && (browserVersion == 4)) {
            an = 1; DH = 1;
        }
    }
} 

function fd(oi, wS) {
    if (ai) 
        return wS ? document.getElementById(oi).style:document.getElementById(oi); 
        if (al) 
            return wS ? document.all[oi].style: document.all[oi]; 
            if (an) 
                return document.layers[oi];
            
}
function pw() {
    return window.innerWidth != null ? window.innerWidth: document.body.clientWidth != null ? document.body.clientWidth:null;
}

function mouseX(evt) {
    if (evt.pageX) 
        return evt.pageX; 
    else if (evt.clientX)
        return evt.clientX + (document.documentElement.scrollLeft ?  document.documentElement.scrollLeft : document.body.scrollLeft); 
    else 
        return null;
}

function mouseY(evt) {
    if (evt.pageY) 
        return evt.pageY; 
    else if (evt.clientY)
        return evt.clientY + (document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop); else return null;
}

function popUp(evt,oi,text) {
    if (DH) {
        var wp = pw(); 
        ds = fd(oi,1); 
        dm = fd(oi,0); 
        st = ds.visibility; 
        if (dm.offsetWidth) {
            ew = dm.offsetWidth;
        } else if (dm.clip.width) {
            ew = dm.clip.width; 
        } 
        if (st == "visible" || st == "show") { 
            ds.visibility = "hidden"; 
        } else {
            tv = mouseY(evt) + 20; 
            lv = mouseX(evt) - (ew/4); 
            if (lv < 2) {
                lv = 2; 
            } else if (lv + ew > wp) {
                lv -= ew/2;
            } if (!an) {
                lv += 'px';tv += 'px';
            } 
            ds.left = lv; 
            ds.top = tv; 
            ds.visibility = "visible";
            dm.innerHTML = text;
        }
    }
}


