
function DateManager(formFields) {
  this.validDates = new Array();
  this.invalidDates = new Array();
  this.formFields = formFields;
  this.hasBlankMonth = (typeof formFields.hasBlankMonth != 'undefined' ? formFields.hasBlankMonth : false);
  this.hasBlankDay = (typeof formFields.hasBlankDay != 'undefined' ? formFields.hasBlankDay : false);
  this.onChange = (typeof formFields.onChange == 'function' ? formFields.onChange : null);

  if (this.formFields.months && this.formFields.days) {
    this.formFields.months.observe('change', this.doDays.bindAsEventListener(this));
  }
  if (this.formFields.days && this.formFields.hidden) {
    this.formFields.days.observe('change', this.updateHidden.bindAsEventListener(this));
  }
  if (this.formFields.after) {
    var afterArray = (new Array(this.formFields.after)).flatten();
    afterArray.each(function (after) {
      if (after.constructor == DateManager) {
        after.formFields.months.observe('change', this.doMonths.bindAsEventListener(this));
        after.formFields.days.observe('change', this.doMonths.bindAsEventListener(this));
        after.formFields.hidden.observe('dateManager:dateChange', this.doMonths.bindAsEventListener(this));
      }
    }, this);
  }
  if (this.formFields.before && this.formFields.before.constructor == DateManager) {
    this.formFields.before.formFields.months.observe('change', this.doMonths.bindAsEventListener(this));
    this.formFields.before.formFields.days.observe('change', this.doMonths.bindAsEventListener(this));
  }
  if (systemStartDate) this.invalidDates[this.invalidDates.length] = {
    dateFrom: null,
    dateTo: systemStartDate
  };
  if (systemEndDate) this.invalidDates[this.invalidDates.length] = {
    dateFrom: systemEndDate,
    dateTo: null
  };
  this.doMonths();
  if ($(this.formFields.hidden.id+"_link")) {
    this.formFields.calendar = $(this.formFields.hidden.id+"_link");
    this.formFields.calendar.observe('click', this.showCalendar.bindAsEventListener(this));
  } else {
    this.formFields.calendar = null;
  }
}

DateManager.prototype.MONTHS_PATTERN = "NNN yyyy";
DateManager.prototype.DAYS_PATTERN = "dd";


DateManager.prototype.addDisabledDates = function (fromDate, toDate) {
  if (calendar != null) calendar.hideCalendar();
  if (fromDate == null && toDate == null) return;
  this.invalidDates[ this.invalidDates.length] = {
    dateFrom: fromDate,
    dateTo: toDate
  };
  this.doMonths();
}

DateManager.prototype.updateHidden = function () {
  if (this.formFields == null || this.formFields.months == null|| this.formFields.months.type != 'select-one') return ;
  if (this.formFields == null || this.formFields.days == null|| this.formFields.days.type != 'select-one') return ;
  if (this.formFields == null || this.formFields.hidden == null) return;
  var curValue = $F(this.formFields.hidden);
  var d = this.getValue();
  if (d == null)
    this.formFields.hidden.value = '';
  else
    this.formFields.hidden.value = formatDate(this.getValue(), "yyMMdd");
  //if (this.onChange != null && ($F(this.formFields.hidden) != curValue))
  if (Object.isFunction(this.onChange)) this.onChange();
  this.formFields.hidden.fire("dateManager:dateChange");
}

DateManager.prototype.setValidDates = function (dateArray) {
  if (calendar != null) calendar.hideCalendar();
  this.validDates = $A(dateArray).flatten().compact();
  this.doMonths();
}

DateManager.prototype._evaluate = function(expr, minOrMax) {
  if (Object.isFunction(expr)) {
    return expr();
  } else if (expr.constructor == DateManager) {
    var result = expr.getValue();
    if (result == null)
      result = createDate($F(expr.formFields.months)+"01");
    return result;
  } else if (expr.constructor == Date) {
    return expr;
  } else if (typeof expr == "string" && expr.length == 6) {
    return this.createDate(expr)
  } else if (Object.isArray(expr) && expr.length > 0) {
    var result = this._evaluate(expr[0], minOrMax);
    for (var i = 1; i < expr.length; i++) {
      var test = this._evaluate(expr[i], minOrMax);
      if (result == null || (minOrMax == 'min' && test != null && test.getTime() < result.getTime())) result = test;
      else if (minOrMax == 'max' && test != null && test.getTime() > result.getTime()) result = test;
    }
    return result;
  } else {
    return null;
  }
}

DateManager.prototype.getMinDate = function() {
  var minDate = new Date();
  for (var i = 0; i < this.invalidDates.length; ++i) {
    if (this.invalidDates[i].dateFrom == null && this.invalidDates[i].dateTo.getTime() > minDate.getTime())
      minDate = this.invalidDates[i].dateTo;
  }

  if (this.formFields.after != null) {
    var afterDate = this._evaluate(this.formFields.after, 'min');
    if (afterDate != null) {
      if (this.formFields.afterOffset && this.formFields.afterOffset >0 )
        afterDate = new Date(afterDate.getTime() + this.formFields.afterOffset * 24*60*60*1000);
      if (afterDate.getTime() > minDate.getTime())
        minDate = afterDate;
    }
  }
  
  if (this.validDates.length > 0) {
    var minValid = '999999'; var curMinDate = formatDate(minDate, 'yyMMdd');
    for (var i = 0; i< this.validDates.length; i++)
      if (this.validDates[i] < minValid && this.validDates[i] > curMinDate) minValid = this.validDates[i];
    if (this.createDate(minValid).getTime() > minDate.getTime())
      minDate = this.createDate(minValid);
  }
  log("minDate: " + minDate)
  return minDate;
}

DateManager.prototype.getValue = function() {
  if (this.formFields == null || this.formFields.months == null|| this.formFields.months.type != 'select-one') return null;
  if (this.formFields == null || this.formFields.days == null|| this.formFields.days.type != 'select-one') return null;
  var date = $F(this.formFields.months) + "" + $F(this.formFields.days);
  if (date.length != 6) return null;
  return this.createDate(date);
}

DateManager.prototype.setValue = function (year, month, day) {
  var date = parseDate(year + "-" + month+"-"+day);
  var monthYear = formatDate(date, 'yyMM');
  AniteDDB.setValue(this.formFields.months, monthYear);
  this.doDays();
  AniteDDB.setValue(this.formFields.days, day.toPaddedString(2));
  this.updateHidden();
}

DateManager.prototype.getMaxDate = function() {
  var maxDate = null;
  for (var i = 0; i < this.invalidDates.length; ++i) {
    if (this.invalidDates[i].dateTo == null && (maxDate == null || this.invalidDates[i].dateFrom.getTime() < maxDate.getTime()))
      maxDate = this.invalidDates[i].dateFrom;
  }

  if (this.formFields.before != null && this.formFields.before.constructor == DateManager) {
    var beforeDate = this.formFields.before.getValue();
    if (beforeDate.getTime() < maxDate.getTime()) maxDate = beforeDate;
  }

  if (this.validDates.length > 0) {
    var maxValid = '000000'; var curMaxDate = (maxDate == null ? '999999' : formatDate(maxDate, 'yyMMdd'));
    for (var i = 0; i < this.validDates.length; i++)
      if (this.validDates[i] > maxValid && this.validDates[i] < curMaxDate) maxValid = this.validDates[i];
    if (maxDate == null || this.createDate(maxValid).getTime() < maxDate.getTime())
      maxDate = this.createDate(maxValid);
  }

  if (maxDate == null) maxDate = new Date(this.getMinDate().getTime() + 365.25 * 24*60*60*1000); // About a year

  return maxDate;
}

DateManager.prototype.doMonths = function () {
  if (calendar != null) calendar.hideCalendar();
  if (this.formFields == null || this.formFields.months == null|| this.formFields.months.type != 'select-one') return;
  var curSel = $F(this.formFields.months);
  AniteDDB.clear(this.formFields.months);
  if (this.hasBlankMonth)
    this.formFields.months.options[0] = new Option(' ',' ');
  var minDate = this.getMinDate();
  var maxDate = this.getMaxDate();
  var curDate = new Date(minDate.getTime());
  curDate.setDate(1);
  while (curDate.getTime() < maxDate.getTime()) {
    this.formFields.months.options[this.formFields.months.options.length] = new Option(formatDate(curDate, this.MONTHS_PATTERN), formatDate(curDate, 'yyMM'));
    var m = curDate.getMonth(); m++;
    if (m == 12) {
      m = 0;
      curDate.setFullYear(curDate.getFullYear()+1);
    }
    curDate.setMonth(m);
  }
  AniteDDB.setValue(this.formFields.months, curSel);
  if ($F(this.formFields.months) == null) {
    AniteDDB.setSelectedIndex(this.formFields.months, 0);
  }
  this.doDays(); 
}

DateManager.prototype.doDays = function() {
  if (calendar != null) calendar.hideCalendar();
  if (this.formFields == null || this.formFields.days == null|| this.formFields.days.type != 'select-one') return;
  var curSel = $F(this.formFields.days);
  AniteDDB.clear(this.formFields.days);
  if (this.hasBlankDay)
    this.formFields.days.options[0] = new Option(' ',' ');
  var month = parseFloat($F(this.formFields.months).substring(2,4))-1;
  var year = parseFloat($F(this.formFields.months).substring(0,2)) + 2000;
  var days = this.getDays(month, year);
  days.each(function(d){
    var dayStr = d.toPaddedString(2);
    this.formFields.days.options[this.formFields.days.options.length] = new Option(d, d.toPaddedString(2),false, (dayStr == curSel))
  }, this);
  AniteDDB.setValue(this.formFields.days, curSel);
  this.updateHidden();
}

DateManager.prototype.getDays = function (month, year) {
  year = 2000 + (year%100);
  var d = new Date(year, month, 1);
  var l = this.monthLength(d.getMonth(), d.getFullYear());
  var result = new Array();
  for (var i = 1; i < l+1; i++){
    result[result.length] = i;
  }
  var minDate = this.getMinDate();
  var maxDate = this.getMaxDate();
  if (month == maxDate.getMonth() && year == maxDate.getFullYear()) {
    result = result.slice(0, maxDate.getDate());
  }
  if (month == minDate.getMonth() && year == minDate.getFullYear()) {
    result = result.slice(minDate.getDate()-1, result.length);
  }
  if (this.validDates != null && this.validDates.length > 0) {
    for (var i = 0; i < result.length; ++i) {
      var d2 = formatDate(new Date(year, month, result[i]), "yyMMdd");
      if (this.validDates.indexOf(d2) < 0) result[i]= null;
    }
    result = result.compact();
  }

  return result;
}

DateManager.prototype.monthLength = function(month, year) {
  var monthDays = new Array(31,28,31,30,31,30,31,31,30,31,30,31);
  if (month != 1)	{
    return monthDays[month];
  }	else	{
    if (((year%400)  == 0) || (((year%100) != 0) && ((year%4) == 0))) {
      return 29;
    } else {
      return 28;
    }
  }
}

DateManager.prototype.createDate = function (strDate) {
  if (strDate == null || typeof strDate != "string" || strDate.length != 6) return null;
  var theYear = parseFloat(strDate.substr(0,2));
  if (theYear < 46) theYear += 2000;
  else theYear += 1900;
  var theMonth = parseFloat(strDate.substr(2,2) - 1);
  var theDay = parseFloat(strDate.substr(4,2));
  var newDate = new Date(theYear, theMonth, theDay);

  return newDate;
}

DateManager.prototype.disable = function() {
  this.formFields.months && this.formFields.months.disable();
  this.formFields.months && this.formFields.days.disable();
  this.formFields.hidden && (this.formFields.hidden.value = '');
  this.formFields.calendar && disableCalendar(this.formFields.hidden.id);
}

DateManager.prototype.enable = function() {
  this.formFields.months && this.formFields.months.enable();
  this.formFields.months && this.formFields.days.enable();
  this.formFields.calendar && enableCalendar(this.formFields.hidden.id);
  this.updateHidden();
}

DateManager.prototype.showCalendar = function() {
  if (calendar != null) calendar.hideCalendar();
  var calendarButton = this.formFields.calendar;

  if ($('popupCalendar') == null) new Insertion.Bottom(document.body, '<div id="popupCalendar"></div>');

  calendar = new CalendarPopup("popupCalendar");
  calendar.offsetX = 20;
  calendar.offsetY = 0;

  this.invalidDates.each(function(d){
    calendar.addDisabledDates((d.dateFrom == null ? null : formatDate(d.dateFrom, 'yyyy-MM-dd')), (d.dateTo == null ? null : formatDate(d.dateTo, 'yyyy-MM-dd')));
  })


  if (this.validDates.length > 1) {
    for (var i = 1; i < this.validDates.length; i++) {
      var disableEndDate = formatDate(addToDate(this.validDates[i], -1), 'yyyy-MM-dd');
      var disableStartDate = formatDate(addToDate(this.validDates[i-1], 1), 'yyyy-MM-dd');;
      if (disableEndDate >= disableStartDate) calendar.addDisabledDates(disableStartDate, disableEndDate);
    }
    calendar.addDisabledDates(formatDate(addToDate(this.validDates[this.validDates.length-1], 1), 'yyyy-MM-dd'), null);
  }
  
  calendar.addDisabledDates(null, formatDate(addToDate(this.getMinDate(), -1), 'yyyy-MM-dd'));
  calendar.addDisabledDates(formatDate(addToDate(this.getMaxDate(), 1), 'yyyy-MM-dd'), null);

  if (Prototype.Browser.IE) {
    var appVersion = navigator.appVersion;
    appVersion = parseFloat(appVersion.substr(appVersion.indexOf("MSIE")+5, 4));
    if (appVersion <= 6) {
      calendar.offsetX=75; calendar.offsetY=0;
    }
  }

  var curValue = this.getValue();
  if (curValue == null) curValue = this.getMinDate();

  calendar.setReturnFunction("setDateFromCalendar");
  calendar.showCalendar(calendarButton.id, formatDate(curValue, 'yyyy-MM-dd'));
  calendar.dateManager = this;
  calendarInput = this.formFields.hidden;
}
