/*
 * Returns the default calendar width.
 */
function getDefaultCalendarWidth() {
    return 400;
}

/*
 * Returns the default calendar height.
 */
function getDefaultCalendarHeight() {
    return 200;
}

function getDefaultToIncrease() {
    return 1;
}

/*
 * Spawns a calendar window that interacts with a single
 * input field containing a complete date.
 * myField: The input field
 * months: Number of months to display (starting with the current month)
 * pattern: The date pattern used in the input field. See parseDate for allowed patterns.
 * width: width of the popup window (optional; defaults to 310)
 * height: height of the popup window (optional; defaults to 400)
 * validateCalendar: (optional) Indicates whether to modify an additional
 *                   date field after changes in the calendar
 * otherField: (optional) only sensible when validateCalendar is true
 */
function spawnInputFieldCalendarFromTextfield(myField, months, pattern, width, height, validateCalendar, otherField) {
    spawnInputFieldCalendar(myField, months, pattern, width, height, validateCalendar, otherField);
}

/*
 * Spawns a calendar window that interacts with a single
 * input field containing a complete date.
 * myField: The input field
 * months: Number of months to display (starting with the current month)
 * pattern: The date pattern used in the input field. See parseDate for allowed patterns.
 * width: width of the popup window (optional; defaults to 310)
 * height: height of the popup window (optional; defaults to 400)
 * validateCalendar: (optional) Indicates whether to modify an additional
 *                   date field after changes in the calendar
 * otherField: (optional) only sensible when validateCalendar is true
 */
function spawnInputFieldCalendar(myField, months, pattern, width, height, validateCalendar, otherField) {
   var fields = new Array();
   if (otherField != null) {
      fields = new Array(myField.name , otherField.name);
   } else {
     fields = new Array(myField.name);
   }
   var ds = myField.value;
   var start = parseDate(pattern, myField.value);
   var w = width;
   var h = height;
   var numberOfMonths = 12;
   if (months != null) numberOfMonths = months;
   if (isNaN(w) || w == null) w = getDefaultCalendarWidth();
   if (isNaN(h) || h == null) h = getDefaultCalendarHeight();
   var calWin = window.open("", "calWindow", "width=" + w + ",height=" + h);
   if (validateCalendar) {
    generateCal(calWin, 0, myField.form.name, fields, start, start, numberOfMonths, validateCalendar, -1, pattern, false, true);
   } else {
    generateCal(calWin, 0, myField.form.name, fields, start, start, numberOfMonths, validateCalendar, -1, pattern, false, true);
   }
   calWin.focus();
}




/*
 * Spawns a calendar window that interacts with two comboboxes: one with
 * days and one with a month-year combination. Values are expected to be in the
 * format "1", "2", ... "31" and "1.2004", "12.2005", ... respectively.
 * dayField: The day combobox
 * monthField: The month combobox
 * months: The number of months to display (starting with the current month) (defaults to 12)
 * width: width of the popup window (optional; defaults to 310)
 * height: height of the popup window (optional; defaults to 400)
 * validateCalendar: (optional) Indicates whether to modify additional
 *                   date fields (day and month combobox) after changes in the calendar
 * isDeparture: (optional) Indicates whether dayField and monthField form a departure day or not.
 *              Only valid if validateCalendar is true.
 * otherDayField: (optional) The other day combobox. Only valid if validateCalendar is true.
 * otherMonthField: (optional) The other month combobox. Only valid if validateCalendar is true.
 */
function spawnDayAndMonthComboboxCalendar(
    dayField, monthField, months, width, height,
    validateCalendar, isDeparture, otherDayField, otherMonthField) {
    var numberOfMonths;
   var fields = new Array();
   if (otherDayField != null && otherMonthField != null) {
     fields = new Array(dayField.name, monthField.name, otherDayField.name, otherMonthField.name);
   } else {
      fields = new Array(dayField.name, monthField.name);
   }

   // 12 is default if month undefined or zero
   if ((!isNaN(months)) && (months > 0)) {
      numberOfMonths = months;
   } else {
      if (monthField.length > 0) {
         numberOfMonths = monthField.length;
      } else {
         numberOfMonths = 12;
      }
   }

   var w = width;
   var h = height;
   if (isNaN(w) || w == null) w = getDefaultCalendarWidth();
   if (isNaN(h) || h == null) h = getDefaultCalendarHeight();


   var elements = monthField.options[monthField.selectedIndex].value.split(".");
   var start = new Date(elements[1], elements[0]-1, dayField.options[dayField.selectedIndex].value);
   var calWin = window.open("", "calWindow", "width=" + w + ",height=" + h);
   var mode = 0;

   if (isDeparture) mode = 2; else mode=3;
   if (validateCalendar) {
       generateCal(calWin, mode, dayField.form.name, fields, start, start, numberOfMonths, validateCalendar, -1, '', false);
   } else {
       generateCal(calWin, mode, dayField.form.name, fields, start, start, numberOfMonths, validateCalendar, -1, '', false);
   }
   calWin.focus();
}

/*
 * Spawns a calendar window that interacts with a combobox containing
 * complete dates. Values are expected to be in the format
 * "dd.MM.yyyy". The Calendar will only contain the months for which dates are
 * available the combobox and only dates available in the combobox will be selectable.
 * dateField: The combobox
 * booleanSubmitForm
 * width: width of the popup window (optional; defaults to 310)
 * height: height of the popup window (optional; defaults to 400)
 */

function spawnDateComboboxCalendar(dateField, booleanSubmitForm, width, height) {
   var numberOfMonths;
   var start;
   var today = new Date();
   var dxe = parseDate('dd.MM.yyyy', dateField.options[dateField.length - 1].value);
   numberOfMonths =((dxe.getFullYear() - today.getFullYear()) * 12) + (dxe.getMonth() - today.getMonth()) + 1;

   if (dateField.selectedIndex == -1) {
      start = new Date();
   } else if (dateField.selectedIndex == 0) {
      start = parseDateInsecure('dd.MM.yyyy', dateField.options[0].value);
      if (start == null) {
        start = parseDate('dd.MM.yyyy', dateField.options[1].value);
      }
   } else {
      start = parseDate('dd.MM.yyyy', dateField.options[dateField.selectedIndex].value);
   }

   var w = width;
   var h = height;
   if (isNaN(w)) w = getDefaultCalendarWidth();
   if (isNaN(h)) h = getDefaultCalendarHeight();

   var calWin = window.open("", "calWindow", "width=" + w + ",height=" + h);
   var fields = new Array(dateField.name);
   generateCal(calWin, 1, dateField.form.name, fields, start, start, numberOfMonths, false, -1, '', booleanSubmitForm);
   calWin.focus();
}

/*
 * Change the selected month in the calendar window.
 * See generateCal for the params.
 */
function calendarChooseMonth(window, mode, formname, formelements, originalChosenTime, chosenTime, numberOfMonths, validateCalendar, selectedArea, pattern, submit) {

   var chosen = new Date();
   var originalChosen = new Date();
   originalChosen.setTime(originalChosenTime);
   chosen.setTime(chosenTime);
   chosen.setTime(window.document.calForm.monthBox.options[window.document.calForm.monthBox.selectedIndex].value);
   generateCal(window, mode, formname, formelements, originalChosen, chosen, numberOfMonths, validateCalendar, selectedArea, pattern, submit);
}

/*
 * Returns a String representing the given date using the given pattern.
 * See source for allowed patterns.
 * day: Day
 * month: Month
 * year: Year
 * pattern: The date pattern, e.g. "dd.MM.yyyy"
 */
function formatDate(day, month, year, pattern) {
   var dayString = day < 10 ? '0' + day : day;
   var monthString = (month+1) < 10 ? '0' + (month+1) : (month+1);

   if (pattern == 'dd.MM.yyyy') {
    return dayString + "." + monthString + "." + year;
   } else if (pattern == 'dd/MM/yyyy') {
    return dayString + "/" + monthString + "/" + year;
   } else if (pattern == 'MM/dd/yyyy') {
    return monthString + "/" + dayString + "/" + year;
   }
   return "";
}

/*
 * Sets the given date into the given input field after
 * formatting it using the given pattern.
 * See formatData for allowed patterns.
 */
function setDateToFreeTextField(formname, fieldName, day, month, year, pattern) {
    var field = document.forms[formname].elements[fieldName];
    field.value = formatDate(day, month, year, pattern);
}

/*
 * Sets the given date into the given day- and monthYear-combobox.
 */
function setDateToDayAndMonthYearCombobox(formname, dayComboName, monthyearComboName, day, month, year) {

    // There is a problem if the combobox days is filled appropriate to the months -
    // e.g. you cannot select the 31st if it is not in the list ...

    var dayCombo = document.forms[formname].elements[dayComboName];
    var monthYearCombo = document.forms[formname].elements[monthyearComboName];

    foundfield = 0;
    var dayOldIndex = -1;
    var dayNewIndex = -1;

    var monthyearOldIndex = -1;
    var monthyearNewIndex = -1;

    for (var index = 0; index < dayCombo.options.length; index++) {
        var opt = dayCombo.options[index];
        if (opt.selected == true) {
            dayOldIndex = index;
        }
        if (opt.value == day) {
            dayNewIndex = index;
        }
    }

    for (var index = 0; index < monthYearCombo.options.length; index++) {
        var opt = monthYearCombo.options[index];
        var vall = (month + 1) + "." + year;
        if (opt.selected == true) {
            monthyearOldIndex = index;
        }
        if (opt.value.indexOf(vall) == 0) {
            monthyearNewIndex = index;
        }
    }

    if ((dayNewIndex != -1) && (monthyearNewIndex != -1)) {
       dayCombo.options[dayOldIndex].selected = false;
       dayCombo.options[dayNewIndex].selected = true;
       monthYearCombo.options[monthyearOldIndex].selected = false;
       monthYearCombo.options[monthyearNewIndex].selected = true;
    }
}

/*
 * Selects an index in the given combobox.
 * formname: Name of the form of the combobox
 * comboname: Name of the combobox
 * index: Index to select
 */

function setDateToDateCombobox(formname, comboname, index) {
    var combo = document.forms[formname].elements[comboname];
    combo.options[combo.selectedIndex].selected = false;
    combo.options[index].selected = true;
}

/*
 * Checks whether a given combobox contains a given date.
 * Returns -1 if not, the index otherwise.
 * t: a Date
 * formname: name of a form
 * comboname: name of a combobox
 */
function comboboxContainsDay(t, formname, comboname) {
   var txd = "" + t.getDate();
   if (txd.length < 2) txd = "0" + txd;
   var txm = "" + (t.getMonth() + 1);
   if (txm.length < 2) txm = "0" + txm;
   var txy = "" + t.getFullYear();

   var combo = document.forms[formname].elements[comboname];

   for (i = 0; i < combo.options.length; i++) {
      if ((txd + "." + txm + "." + txy) == combo.options[i].value) {
         return i;
      }
   }

   return -1;
};

/*
 * Checks whether a given combobox (containing complete dates) contains the month
 * of the given date. Returns false if not, true otherwise.
 * t: a Date
 * formname: name of a form
 * comboname: name of a combobox
 * date pattern
 */
function comboboxContainsMonth(t, formname, comboname) {
   var txm = "" + (t.getMonth() + 1);
   if (txm.length < 2) txm = "0" + txm;
   var txy = "" + t.getFullYear();

   var combo = document.forms[formname].elements[comboname];

   for (i = 0; i < combo.options.length; i++) {
      if ((txm + "." + txy) == combo.options[i].value.substring(3)) {
         return true;
      }
   }
   return false;
};

/*
 * Parses a date string given in the parameter value
 * according to the given pattern.
 * Allowed patterns (in java.text.SimpleDateFormat syntax)
 * are "dd.MM.yyyy", "dd/MM/yyyy" and "MM/dd/yyyy".
 * The optional parameter allowPast indicates whether dates
 * in the past are allowed.
 * Returns a Date object representing the given date
 * or today if an error occured.
 * If the pattern is unrecognized, an alert-box is displayed.
 */

function parseDate(pattern, value, allowPast) {
    var d = parseDateInsecure(pattern, value, allowPast);
    if (d == null) d = new Date();
    return d;
}

/*
 * Parses a date string given in the parameter value
 * according to the given pattern.
 * Allowed patterns (in java.text.SimpleDateFormat syntax)
 * are "dd.MM.yyyy", "dd/MM/yyyy" and "MM/dd/yyyy".
 * The optional parameter allowPast indicates whether dates
 * in the past are allowed.
 * Returns a Date object representing the given date
 * or null if an error occured.
 * If the pattern is unrecognized, an alert-box is displayed.
 */
function parseDateInsecure(pattern, value, allowPast) {
    var pattern;
    var day;
    var month;
    var year;

    if (pattern=='dd.MM.yyyy') {
         pattern = /^(\d\d)\.(\d\d)\.(\d\d\d\d)$/;
         if (pattern.exec(value) != null) {
            year = RegExp.$3;
            month = RegExp.$2-1;
            day = RegExp.$1;
         } else {
            return null;
         }
    } else if (pattern=='dd/MM/yyyy') {
         pattern = /^(\d\d)\/(\d\d)\/(\d\d\d\d)$/;
         if (pattern.exec(value) != null) {
            year = RegExp.$3;
            month = RegExp.$2-1;
            day = RegExp.$1;
         } else {
            return null;
         }
    } else if (pattern=='MM/dd/yyyy') {
         pattern = /^(\d\d)\.(\d\d)\.(\d\d\d\d)$/;
         if (pattern.exec(value) != null) {
            year = RegExp.$3;
            month = RegExp.$1-1;
            day = RegExp.$2;
         } else {
            return null;
         }
    } else {
        alert("Unsupported pattern " + pattern);
        return null;
    }

    if (!allowPast) {
        var today = new Date();
        if (year < today.getFullYear()) return null;
        if (year == today.getFullYear()) {
            if (month < today.getMonth()) return null;
            if (month == today.getMonth()) {
                if (day < today.getDate()) return null;
            }
        }
    }

    if ((month >= -1)
            && (month<=11)
            && (day >= 1)
            && (day <= 31)) {
        return new Date(year, month, day);
    }

    return null;
}

/*
 * Fills the given combobox with entries for each day of the month.
 */
function setDays(combobox, month, year){
   var isLeapYear=false;
    var daysPerMonth = new Array ("31", "28", "31", "30", "31","30", "31", "31", "30", "31", "30", "31");

   isLeapYear = (((year % 4 == 0) && (year % 100 != 0)) || ( year % 400 == 0))

   if (isLeapYear)
       daysPerMonth[1] = 29;
  else
      daysPerMonth[1] = 28;
   with (combobox) {
        if (length > daysPerMonth[month]) {
            for(i = length-1; i >= daysPerMonth[month]; i--)
                options[i] = null;
        } else if (length < daysPerMonth[month]) {
            for(i=length; i < daysPerMonth[month]; i++)
                options[i] = new Option("" + (i + 1), "" + (i + 1), false, false);

        }
   }
  return true;
}

/*
 * Returns a date being toIncrease days later than the given date.
 * If toIncrease is not set, 1 is used.
 */
function increaseDay(templDate, toIncrease) {
  var retVal;
  retVal = new Date();
  if (toIncrease == null ) {
    //toIncrease = 1;
    toIncrease = getDefaultToIncrease();
  }
  retVal.setFullYear(templDate.getFullYear(), templDate.getMonth(), templDate.getDate() + toIncrease);

  return retVal;
}

/*
 * Returns a date being toDecrease days earlier than the given date.
 * If toDecrease is not set, 1 is used.
 */
function decreaseDay(templDate, toDecrease){
    if (toDecrease == null)
        return increaseDay(templDate, -1);
    else
        return increaseDay(templDate, -1 * toDecrease);
}

/*
 * Convenience method for the validateVacationDateDayAndMonthCombobox.
 * See there for parameters.
 * This method expects objects, while the next method expects elements names!
 */
function validateVacationDateDayAndMonthComboboxByFields(
    changed, depDay, depMonth, retDay, retMonth) {
        if ((retDay == null) || (retMonth == null)) {
            return;
        }
        validateVacationDateDayAndMonthCombobox(
            changed.form.name, changed.name,
            depDay.name, depMonth.name,
            retDay.name, retMonth.name);
}

/*
 * Returns the number of days that should be added to a start date in order
 * to propose a return date.
 */
function getValidateVacationDateReturnOffset() {
    return 1;
}


/*
 * Performs the magic of changing the values of a date input field
 * according to the new value of another date input field.
 * pattern: The date pattern used in the input field. See parseDate for allowed patterns.
 * formName: Name of the form containing the four comboboxes
 * changedElementName: Indicates which element was changed. Has to match one of the
 *                     two fields given in the next four parameters.
 * depField: Name of the departure date input field
 * retField: Name of the return date input field
 */
function validateVacationDateField(
    pattern, formName, changedElementName, depField, retField) {
  var theForm = document.forms[formName];
  var newDate;
  var changedDate;
  var selectedStartDate;
  var selectedEndDate;

  changedDate = parseDate(pattern, theForm.elements[changedElementName].value);
  if (changedElementName == depField) {
     previousDate = parseDateInsecure(pattern, theForm.elements[retField].value);
     if ((previousDate == null) || (previousDate.getTime() < changedDate.getTime())) {
        newDate = increaseDay(changedDate, getValidateVacationDateReturnOffset());
        theForm.elements[retField].value = formatDate(newDate.getDate(), newDate.getMonth(), newDate.getFullYear(), pattern);
     }
  } else {
     // nothing to do yet
  }
}

/*
 * Performs the magic of changing the values of a day/monthYear combobox combination
 * according to the new value of another day/monthYear combobox combination.
 * formName: Name of the form containing the four comboboxes
 * changedElementName: Indicates which element was changed. Has to match one of the
 *                     four comboboxes given in the next four parameters.
 * depDayName: Name of the departure day combobox
 * depMonthName: Name of the departure month-year combobox
 * retDayName: Name of the return combobox
 * retMonthName: Name of the return month-year combobox
 */
function validateVacationDateDayAndMonthCombobox(
    formName, changedElementName, depDayName, depMonthName, retDayName, retMonthName) {
  var theForm = document.forms[formName];
  var nowDate;
  var selectedStartDate;
  var selectedEndDate;

  var selStartMonthYear;
  var selEndMonthYear;

  var startOutput;
  var startChange = "";
  var endOutput;
  var endChange = "";

  nowDate = new Date();

    //parse choosen Dates
    var depMonth = theForm.elements[depMonthName];
    var retMonth = theForm.elements[retMonthName];
    var depDay = theForm.elements[depDayName];
    var retDay = theForm.elements[retDayName];

    if ((depMonth == null) || (retMonth == null)) {
        return;
    }

    selStartMonthYear = depMonth.options[depMonth.selectedIndex].value;
    selEndMonthYear = retMonth.options[retMonth.selectedIndex].value;

    var ix = selStartMonthYear.indexOf('.');
    var sm = selStartMonthYear.substring(0, ix);
    var sy = selStartMonthYear.substring(ix + 1, selStartMonthYear.length);

    ix = selEndMonthYear.indexOf('.');
    var em = selEndMonthYear.substring(0, ix);
    var ey = selEndMonthYear.substring(ix + 1, selEndMonthYear.length);

    selectedStartDate = new Date(sy, sm - 1, (depDay.options[depDay.selectedIndex].value));
    selectedEndDate = new Date(ey, em - 1, (retDay.options[retDay.selectedIndex].value));

    switch (changedElementName) {
        case depDayName:
        case depMonthName:
            if (selectedStartDate.getTime() < nowDate.getTime()) {
                selectedStartDate = nowDate;
            }
            if (selectedEndDate.getTime() <= selectedStartDate.getTime()){
                selectedEndDate = increaseDay(selectedStartDate);
            }

            if (selectedEndDate.getTime() <= nowDate.getTime()) {
                selectedStartDate = increaseDay(nowDate);
                selectedEndDate = increaseDay(selectedStartDate);
            }
            break;
        case retDayName:
        case retMonthName:
            if (selectedEndDate.getTime() <= increaseDay(selectedStartDate)) {
                //selectedStartDate = increaseDay(nowDate);
                selectedEndDate = increaseDay(selectedStartDate);
            }
            break;
    }
    //fill Days for Month
    setDays(depDay, selectedStartDate.getMonth(), selectedStartDate.getFullYear());
    setDays(retDay, selectedEndDate.getMonth(), selectedEndDate.getFullYear());
    //set Values for Selectboxes
    retDay.value = selectedEndDate.getDate();
    depDay.value = selectedStartDate.getDate();
    var valueEndMonth = (selectedEndDate.getMonth() + 1) + "." +  selectedEndDate.getFullYear();
    var valueStartMonth = (selectedStartDate.getMonth() + 1) + "." +  selectedStartDate.getFullYear();
    retMonth.value = valueEndMonth;
    depMonth.value = valueStartMonth;


  return true;
}

/**
 * This function can be called for the onBlur event of input fields
 * containing date information in order to bring the entered date
 * information into a defined format.
 * Default implementation is empty, overwrite it in the brand component
 * if necessary.
 */
function calendarFormatDateFieldFromTextfield(field) {
    // nothing to do by default
}
