    // DCal.registerInput([FORM_OBJECT], [INPUT_FIELD_NAME], [DEPENDING_FROM_INPUT_FIELD_NAME], [DEPENDING_TO_INPUT_FIELD_NAME], [SLAVE_CHILD_FIELD]);
    // DCal.registerAttachedOpener([FORM_OBJECT], [INPUT_FIELD_NAME], [ATTACHED_OBJECT_ID]);

    function DCalendar() {

        this.friendlyMonths = new Array("Januari", "Februari", "Mars", "April", "Maj", "Juni", "Juli", "Augusti", "September", "Oktober", "November", "December");
        this.isCalendarInitialised = false;
        this.currentInputObject = null;
        this.selectMonthObject = null;
        this.registeredInputFields = new Array();
        this.calendarDiv = null;
        this.serverDate = null;

        this.init = function(serverDate) {

            if (this.isCalendarInitialised)
                return;

            this.serverDate = serverDate;

            // set populated directly to prevent other calls to do the same again...
            this.isCalendarInitialised = true;

            document.write('<div id="dCal">');
            document.write('	<form action="" name="dCalForm" style="margin:0;padding:0;" onsubmit="return false;">');
            document.write('	<div id="dCalSelection">');
            document.write('	    <a href="javascript:DCal.moveMonth(-1)" title="Föregående månad">&lArr;</a>&nbsp;&nbsp;');
            document.write('	    <select name="dCalMontsSel" onkeyup="DCal.populate(this.options[this.selectedIndex].value)" onchange="DCal.populate(this.options[this.selectedIndex].value)"></select>');
            document.write('	    &nbsp;&nbsp;<a href="javascript:DCal.moveMonth(1)" title="Nästa månad">&rArr;</a>');
            document.write('	<div style="clear:both;"></div></div>');
            document.write('	<div id="dCalDaysHead">');
            document.write('		<div class="dCalRow">');
            document.write('			<div class="dCalWeek">Vecka</div>');
            document.write('			<div class="dCalDay">Mån</div>');
            document.write('			<div class="dCalDay">Tis</div>');
            document.write('			<div class="dCalDay">Ons</div>');
            document.write('			<div class="dCalDay">Tor</div>');
            document.write('			<div class="dCalDay">Fre</div>');
            document.write('			<div class="dCalDay">Lör</div>');
            document.write('			<div class="dCalDay">Sön</div>');
            document.write('			<div class="dCalClearer"></div>');
            document.write('		</div>');
            document.write('	</div>');
            document.write('	<div id="dCalDays">');
            document.write('		<div id="dCalWeekRow1" class="dCalRow"><div id="dCalWeek1" class="dCalWeek"></div><div id="dCalDays1" class="dCalDay"></div><div id="dCalDays2" class="dCalDay"></div><div id="dCalDays3" class="dCalDay"></div><div id="dCalDays4" class="dCalDay"></div><div id="dCalDays5" class="dCalDay"></div><div id="dCalDays6" class="dCalDay"></div><div id="dCalDays7" class="dCalDay"></div><div class="dCalClearer"></div></div>');
            document.write('		<div id="dCalWeekRow2" class="dCalRow"><div id="dCalWeek2" class="dCalWeek"></div><div id="dCalDays8" class="dCalDay"></div><div id="dCalDays9" class="dCalDay"></div><div id="dCalDays10" class="dCalDay"></div><div id="dCalDays11" class="dCalDay"></div><div id="dCalDays12" class="dCalDay"></div><div id="dCalDays13" class="dCalDay"></div><div id="dCalDays14" class="dCalDay"></div><div class="dCalClearer"></div></div>');
            document.write('		<div id="dCalWeekRow3" class="dCalRow"><div id="dCalWeek3" class="dCalWeek"></div><div id="dCalDays15" class="dCalDay"></div><div id="dCalDays16" class="dCalDay"></div><div id="dCalDays17" class="dCalDay"></div><div id="dCalDays18" class="dCalDay"></div><div id="dCalDays19" class="dCalDay"></div><div id="dCalDays20" class="dCalDay"></div><div id="dCalDays21" class="dCalDay"></div><div class="dCalClearer"></div></div>');
            document.write('		<div id="dCalWeekRow4" class="dCalRow"><div id="dCalWeek4" class="dCalWeek"></div><div id="dCalDays22" class="dCalDay"></div><div id="dCalDays23" class="dCalDay"></div><div id="dCalDays24" class="dCalDay"></div><div id="dCalDays25" class="dCalDay"></div><div id="dCalDays26" class="dCalDay"></div><div id="dCalDays27" class="dCalDay"></div><div id="dCalDays28" class="dCalDay"></div><div class="dCalClearer"></div></div>');
            document.write('		<div id="dCalWeekRow5" class="dCalRow"><div id="dCalWeek5" class="dCalWeek"></div><div id="dCalDays29" class="dCalDay"></div><div id="dCalDays30" class="dCalDay"></div><div id="dCalDays31" class="dCalDay"></div><div id="dCalDays32" class="dCalDay"></div><div id="dCalDays33" class="dCalDay"></div><div id="dCalDays34" class="dCalDay"></div><div id="dCalDays35" class="dCalDay"></div><div class="dCalClearer"></div></div>');
            document.write('		<div id="dCalWeekRow6" class="dCalRow"><div id="dCalWeek6" class="dCalWeek"></div><div id="dCalDays36" class="dCalDay"></div><div id="dCalDays37" class="dCalDay"></div><div id="dCalDays38" class="dCalDay"></div><div id="dCalDays39" class="dCalDay"></div><div id="dCalDays40" class="dCalDay"></div><div id="dCalDays41" class="dCalDay"></div><div id="dCalDays42" class="dCalDay"></div><div class="dCalClearer"></div></div>');
            document.write('	</div>');
            document.write('	</form>');
            document.write('</div>');

            this.calendarDiv = getDocObjectById("dCal");

            this.selectMonthObject = document.forms["dCalForm"]["dCalMontsSel"];
            var BASE_DATE = dCalBaseDate(dCalNow().getSelectYearMonthFormat());
            for (var i=0; i < 12; i++) {
                var newOpt = new Option();
                newOpt.value = BASE_DATE.getSelectYearMonthFormat();
                newOpt.text = BASE_DATE.getSelectYearMonthFriendlyFormat();
                DCal.selectMonthObject.options[DCal.selectMonthObject.options.length] = newOpt;
                BASE_DATE.setMonth(BASE_DATE.getMonth()+1);
            }
            
            document.onmousedown = function (e) {
                if (!DCal.currentInputObject)
                    return;
                var clickLocation = (e && e.target) || (event && event.srcElement);
                var clickOutside = true;
                while (clickLocation.parentNode) {
                    if (DCal.calendarDiv == clickLocation) {
                        clickOutside = false;
                        break;
                    }
                    clickLocation = clickLocation.parentNode;
                }
                if (clickOutside) {
                    displayDiv("dCal", false);
                    DCal.currentInputObject = null;
                }
            };
        };

        this.registerInput = function(formObj, fieldName, startRangeDependence, endRangeDependence, slaveChildField) { var io = new Array(); io[0] = formObj.id+"|"+fieldName; io[1] = new dCalInputObject(formObj, fieldName, startRangeDependence, endRangeDependence, slaveChildField); this.registeredInputFields[this.registeredInputFields.length] = io; };
        this.registerAttachedOpener = function(formObj, fieldName, objId) { var obj = getDocObjectById(objId); if (obj) { obj.onclick = function(){DCal.open(formObj[fieldName]);}; }; };
        this.setCurrentInputObject = function(formObj, fieldName) { for (var i=0; i < this.registeredInputFields.length; i++) { if (this.registeredInputFields[i][0] == formObj.id+"|"+fieldName) { this.currentInputObject = this.registeredInputFields[i][1]; break; } }; return null; };
        this.getInputObject = function(formObj, fieldName) { for (var i=0; i < this.registeredInputFields.length; i++) { if (this.registeredInputFields[i][0] == formObj.id+"|"+fieldName) { return this.registeredInputFields[i][1]; } }; return null; };

        this.selectMonth = function(dateSelected) {
            if (this.currentInputObject && this.currentInputObject.getInputField()) {
                var parsedDate = dCalParsedDate(dateSelected);
                this.currentInputObject.getInputField().value = parsedDate.getSelectFullDateFriendlyFormat();
                if (this.currentInputObject.getSlaveChildFieldName()) {
                    // populate slave input (only if slave doesn't already have a value!)
                    var slaveInputObject = this.getInputObject(this.currentInputObject.getInputField().form, this.currentInputObject.getSlaveChildFieldName());
                    if (slaveInputObject) {
                        var slaveDate = dCalParsedDate(slaveInputObject.getInputField().value);
                        if (slaveDate.isBeforeDate(parsedDate))
                           slaveInputObject.getInputField().value = parsedDate.getSelectFullDateFriendlyFormat();
                    }
                }
                displayDiv("dCal", false);
                this.currentInputObject = null;
            }
        };

        this.moveMonth = function(move) {
            if (this.selectMonthObject && move && !isNaN(move)) {
                var newIdx = this.selectMonthObject.options.selectedIndex+move;
                if (newIdx >= 0 && newIdx < this.selectMonthObject.options.length) {
                    this.selectMonthObject.options.selectedIndex = newIdx;
                    this.populate(this.selectMonthObject.options[this.selectMonthObject.selectedIndex].value);
                }
            }
        };

        this.open = function(inputObj) {
            // position and display the calendar
            DCal.calendarDiv.style.left = (getObjectLeftPos(null, inputObj))+"px";
            DCal.calendarDiv.style.top = (getObjectTopPos(null, inputObj)+getObjectHeight(null, inputObj))+"px";
            displayDiv("dCal", true);

            // resolve selected field and current date
            DCal.setCurrentInputObject(inputObj.form, inputObj.name);
            DCal.currentInputObject.setCurrentSelectedDate(dCalNow());
            DCal.currentInputObject.getCurrentSelectedDate().parseDate(inputObj.value);
            var preDefinedMonth = this.getPreSelectedMonth(inputObj);

            // populate calendar, including selectbox
            this.populate(preDefinedMonth.getSelectYearMonthFormat());
            if (preDefinedMonth) {
                for (var i=0; i < DCal.selectMonthObject.options.length; i++) {
                    if (DCal.selectMonthObject.options[i].value == preDefinedMonth.getSelectYearMonthFormat()) {
                        DCal.selectMonthObject.selectedIndex = i;
                        break;
                    }
                }
            } else
                DCal.selectMonthObject.selectedIndex = 0;
            DCal.selectMonthObject.focus();
        };

        this.getPreSelectedMonth = function(inputObj) {
            var clingOnField = (DCal.currentInputObject ? DCal.currentInputObject.getStartRangeDepandanceInput() : null);
            if (clingOnField) {
                if (clingOnField.value && !inputObj.value)
                    return dCalParsedDate(clingOnField.value);
                else if (!clingOnField.value && inputObj.value)
                    return dCalParsedDate(inputObj.value);
                else {
                    var clingOnDate = dCalNow();
                    clingOnDate.parseDate(clingOnField.value);
                    var inputDate = dCalNow();
                    inputDate.parseDate(inputObj.value);
                    return (inputDate.isBeforeMonth(clingOnDate) ? clingOnDate : inputDate);
                }
            }
            return dCalParsedDate(inputObj.value);
        };

        this.getCompareDates = function() {
            var compareDates = new Array(dCalNow(), dCalYearFromNow());
            // alert("# 1: " + compareDates[0] + "\n"+ "# 2: " + compareDates[1])
            if (DCal.currentInputObject) {
                if (DCal.currentInputObject.getStartRangeDepandanceInput() && !DCal.currentInputObject.getEndRangeDepandanceInput()) {
                    if (DCal.currentInputObject.getStartRangeDepandanceInput().value) {
                        var clingOnDate = dCalNow();
                        clingOnDate.parseDate(DCal.currentInputObject.getStartRangeDepandanceInput().value);
                        compareDates[0] = clingOnDate;
                    }
                } else if (DCal.currentInputObject.getStartRangeDepandanceInput() && DCal.currentInputObject.getEndRangeDepandanceInput()) {
                    if (DCal.currentInputObject.getStartRangeDepandanceInput().value) {
                        var dependencyFromDate = dCalNow();
                        dependencyFromDate.parseDate(DCal.currentInputObject.getStartRangeDepandanceInput().value);
                        compareDates[0] = dependencyFromDate;
                    }
                    if (DCal.currentInputObject.getEndRangeDepandanceInput().value) {
                        var dependencyToDate = dCalNow();
                        dependencyToDate.parseDate(DCal.currentInputObject.getEndRangeDepandanceInput().value);
                        compareDates[1] = dependencyToDate;
                    }
                }
            }
            return compareDates;
        };

        this.populate = function(preDefined) {
            var i, j;
            var COMPARE_DATES = this.getCompareDates();
            var COMPARE_DATE_START = COMPARE_DATES[0];
            var COMPARE_DATE_END = COMPARE_DATES[1];
            var CURRENT_PRINT_DATE = dCalBaseDate(preDefined);
            var WEEK_BASE_DATE = dCalBaseDate(preDefined);
            var currentYearMonth = WEEK_BASE_DATE.getFullYear()+"-"+dCalDateFriendlyDigits(WEEK_BASE_DATE.getMonth()+1)+"-";
            // populate calendar
            var startDay = (WEEK_BASE_DATE.getDay() == 0 ? 7 : WEEK_BASE_DATE.getDay());
            var endDay = dCalDaysInMonth(WEEK_BASE_DATE.getMonth(), WEEK_BASE_DATE.getFullYear());
            var calIdx = 0;
            var dayCounter = 1;
            var divWeekObj, divWeekRowObj, divObj, isDayNotInMonth, isNonSelectable;
            // alert(COMPARE_DATE_START+"\n"+COMPARE_DATE_END+"\n"+preDefined+"\n"+CURRENT_PRINT_DATE+"\n"+WEEK_BASE_DATE);
            for (i=1; i < 7; i++) {
                for (j=1; j < 8; j++) {

                    if (j == 1) {
                        divWeekObj = getDocObjectById("dCalWeek"+i);
                        divWeekObj.innerHTML = "v"+WEEK_BASE_DATE.getWeek();
                        divWeekObj.onclick = function() { void(0); };
                        WEEK_BASE_DATE.setDate(WEEK_BASE_DATE.getDate()+7);

                        divWeekRowObj = getDocObjectById("dCalWeekRow"+i);
                        divWeekRowObj.style.display = ((endDay+startDay) < calIdx+2) ? "none" : "block";
                    }

                    CURRENT_PRINT_DATE.setDate(dayCounter);
                    calIdx++;
                    divObj = getDocObjectById("dCalDays"+calIdx);
                    isNonSelectable = CURRENT_PRINT_DATE.isBeforeDate(COMPARE_DATE_START) || CURRENT_PRINT_DATE.isAfterDate(COMPARE_DATE_END);
                    isDayNotInMonth = (startDay > calIdx || (endDay+startDay-1) < calIdx);
                    if (isDayNotInMonth || isNonSelectable) {
                        divObj.innerHTML = (isNonSelectable && !isDayNotInMonth ? dayCounter++ : "&nbsp;");
                        divObj.className = "dCalDayInactive";
                        divObj.style.cursor = "default";
                        divObj.onclick = function() { void(0); };
                    } else {
                        divObj.innerHTML = dayCounter++;
                        divObj.className = (CURRENT_PRINT_DATE.isThisDay(DCal.currentInputObject.getCurrentSelectedDate()) ? "dCalDay dCalSelectedDay" : "dCalDay");
                        divObj.style.cursor = "pointer";
                        divObj.onclick = function() { DCal.selectMonth(currentYearMonth+dCalDateFriendlyDigits(this.innerHTML)); };
                    }
                }
            }
        };
    }

    /**
     * Parameters:
     *  formObj                 - the form object (NOTE! The object, not just the form name!)
     *  fieldName               - the name of the date input field
     *  startRangeDependence    - the name of the date input field that the valid start date in the calendar are based on
     *  endRangeDependence      - the name of the date input field that the valid end date in the calendar are based on
     *  slaveChildField         - the name of a child input field that is pre-populated with the value from this field
     */
    function dCalInputObject(formObj, fieldName, startRangeDependence, endRangeDependence, slaveChildField) {
        this.FORM = formObj;
        this.FIELD_NAME = fieldName;
        this.START_RANGE_DEPANDANCE_INPUT = startRangeDependence;
        this.END_RANGE_DEPANDANCE_INPUT = endRangeDependence;
        this.CURRENT_SELECTED_DATE = "";
        this.SLAVE_CHILD_FIELD = slaveChildField;
        this.setCurrentSelectedDate = function(selectedDate) { this.CURRENT_SELECTED_DATE = selectedDate; };
        this.getCurrentSelectedDate = function() { return this.CURRENT_SELECTED_DATE; };
        this.getInputField = function() { return this.FORM[this.FIELD_NAME]; };
        this.getStartRangeDepandanceInput = function() { if (this.START_RANGE_DEPANDANCE_INPUT) { return this.FORM[this.START_RANGE_DEPANDANCE_INPUT]; } else { return null; } };
        this.getEndRangeDepandanceInput = function() { if (this.END_RANGE_DEPANDANCE_INPUT) { return this.FORM[this.END_RANGE_DEPANDANCE_INPUT]; } else { return null; } };
        this.getSlaveChildFieldName = function() { return this.SLAVE_CHILD_FIELD; };
        this.FORM[this.FIELD_NAME].onfocus = function(){DCal.open(this);};
    }

	// Date "help" functions
	Date.prototype.getWeek = function () { var year = this.getFullYear(); var month = this.getMonth()+1; var day = this.getDate(); var a = Math.floor((14-(month))/12); var y = year+4800-a; var m = (month)+(12*a)-3; var jd = day + Math.floor(((153*m)+2)/5) + (365*y) + Math.floor(y/4) - Math.floor(y/100) + Math.floor(y/400) - 32045; var d4 = (jd+31741-(jd%7))%146097%36524%1461; var L = Math.floor(d4/1460); var d1 = ((d4-L)%365)+L; return Math.floor(d1/7) + 1; };
    Date.prototype.isBeforeMonth = function (thisIsNow) { return (this.getFullYear() < thisIsNow.getFullYear() || (this.getFullYear() == thisIsNow.getFullYear() && this.getMonth() < thisIsNow.getMonth())); };
    Date.prototype.isBeforeDate = function (checkDate) { if (!checkDate) checkDate = dCalNow(); return (this.getFullYear() < checkDate.getFullYear() || (this.getFullYear() <= checkDate.getFullYear() && this.getMonth() < checkDate.getMonth()) || (this.getFullYear() <= checkDate.getFullYear() && this.getMonth() <= checkDate.getMonth() && this.getDate() < checkDate.getDate())); };
    Date.prototype.isAfterDate = function (checkDate) { if (!checkDate) {return false;}else{ return ((this.getFullYear() > checkDate.getFullYear()) || (this.getFullYear() >= checkDate.getFullYear() && this.getMonth() > checkDate.getMonth()) || (this.getFullYear() >= checkDate.getFullYear() && this.getMonth() >= checkDate.getMonth() && this.getDate() > checkDate.getDate())); }; };
    Date.prototype.isThisDay = function (thisIsNow) { if (!thisIsNow) thisIsNow = dCalNow(); return (this.getFullYear() == thisIsNow.getFullYear() && this.getMonth() == thisIsNow.getMonth() && this.getDate() == thisIsNow.getDate()); };
    Date.prototype.getSelectYearMonthFormat = function() { return this.getFullYear()+"-"+dCalDateFriendlyDigits(this.getMonth()+1); };
    Date.prototype.getSelectYearMonthFriendlyFormat = function() { return DCal.friendlyMonths[this.getMonth()]+" "+this.getFullYear(); };
    Date.prototype.getHiddenYearMonthFormat = function() { return this.getFullYear()+""+dCalDateFriendlyDigits(this.getMonth()+1); };
    Date.prototype.getHiddenDayFormat = function() { return dCalDateFriendlyDigits(this.getDate()); };
    Date.prototype.getSelectFullDateFriendlyFormat = function () { return this.getFullYear()+"-"+dCalDateFriendlyDigits(this.getMonth()+1)+"-"+dCalDateFriendlyDigits(this.getDate()); };
    Date.prototype.parseDate = function (dateStr) {
        if (!dateStr) return;
        var parsedDay = dateStr.length == 7 ? 1 : dCalDateAsInt((dateStr.substr(8,2)));
        var parsedMonth = dCalDateAsInt((dateStr.substr(5,2)))-1;
        var parsedYear = parseInt(dateStr.substr(0,4));
        // NOTE! "Clearing" day and month before setting the values to avoid end of month overlappings...
        this.setMonth(1); this.setDate(1); this.setYear(parsedYear); this.setMonth(parsedMonth); this.setDate(parsedDay);
    };
    function dCalNow() { var now = new Date(); if (DCal.serverDate) { now.parseDate(DCal.serverDate); }; return now; }
    function dCalYearFromNow() { var d = dCalNow(); d.setDate(d.getDate()+365); return d; }
    function dCalParsedDate(parseString) { var d = dCalNow(); d.parseDate(parseString); return d; }
    function dCalBaseDate(preDefined) { var DATE = dCalNow(); if (preDefined) { DATE.parseDate(preDefined, "YYYY-MM"); }; return DATE; }
	function dCalDaysInMonth(iMonth, iYear) { return 32 - new Date(iYear, iMonth, 32).getDate(); };
	function dCalDateFriendlyDigits(s) { return (s < 10 ? "0" : "")+s; };
	function dCalDateAsInt(s) { return parseInt( (s.substr(0,1) == "0" ? s.substr(1,2) : s) ); };
	function dCalDaysBetween(date1, date2) { return Math.round(Math.abs(date2.getTime()-date1.getTime())/(1000*60*60*24)) }

    DCal = new DCalendar();
