var DatePicker = Class.create({
  months: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
  days: ['S', 'M', 'T', 'W', 'T', 'F', 'S'],

  initialize: function(element) {
    this.element = element;
    this.target = new Element('img', { src: '/images/calendar_popup.gif', alt: '', width: 24, height: 24, 'class': 'date_picker_target' });
    this.popup = new Element('div', { 'class': 'date_picker_popup', style: 'display: none; position: absolute; z-index: 10;' });

    // call togglePopup() when target is clicked
    this.target.observe('click', this.togglePopup.bindAsEventListener(this));
    this.target.setStyle({ cursor: 'pointer' });

    // insert the calendar icon and hidden popup div after the form element
    this.element.insert({ after: this.target });
    this.target.insert({ after: this.popup });
  },

  togglePopup: function(event) {
    if (this.popup.style.display == 'none') {
      this.renderPopup(this.getFormDate());
      this.registerClickHandlers();
      this.popup.clonePosition(this.target, { setWidth: false, setHeight: false, offsetLeft: 28 });
      this.popup.show();
    } else {
      this.popup.hide();
      this.unregisterClickHandlers();
    }
  },

  renderPopup: function(date) {
    // remember the rendered date
    this.date = date;

    var buffer =
      '<table cellspacing="0">' +
      '<tr class="r0">' +
      '<th class="date_picker_prev"><img src="/images/arrow_left.gif" alt="&lt;" height="13" width="13" border="0" /></th>' +
      '<th colspan="5">' + this.months[date.getMonth()] + ' ' + date.getFullYear() + '</th>' +
      '<th class="date_picker_next"><img src="/images/arrow_right.gif" alt="&gt;" height="13" width="13" border="0" /></th>' +
      '</tr>' +
      '<tr class="r1">';
    for (var i = 0; i < this.days.length; i++)
      buffer += '<th>' + this.days[i] + '</th>';
    buffer += '</tr>';

    var dayInWeek = new Date(date.getFullYear(), date.getMonth(), 1).getDay();
    var daysInMonth = new Date(date.getFullYear(), date.getMonth() + 1, 0).getDate();
    var today = new Date();

    buffer += '<tr class="r2">';

    if (dayInWeek > 0)
      buffer += '<td colspan="' + dayInWeek + '">&nbsp;</td>';

    for (var i = 1; i <= daysInMonth; i++) {
      var classes = ['date_picker_day'];

      if (
        today.getFullYear() == date.getFullYear() &&
        today.getMonth() == date.getMonth() &&
        today.getDate() == i
      ) {
        classes[classes.length] = 'date_picker_today';
      }

      buffer += '<td class="' + classes.join(' ') + '">' + i + '</td>';

      dayInWeek++;
      if (dayInWeek == this.days.length) {
        buffer += '</tr>';
        if (i != daysInMonth)
          buffer += '<tr class="r2">';
        dayInWeek = 0;
      }
    }

    if (dayInWeek > 0)
      buffer += '<td colspan="' + (7 - dayInWeek) + '">&nbsp;</td>';

    buffer +=
      '</tr>' +
      '</table>';

    // update DOM all at once for better performance
    this.popup.update(buffer);
  },

  registerClickHandlers: function() {
    var date_picker = this;
    this.popup.select('.date_picker_prev').each(
      function(element) {
        element.observe('click', date_picker.renderPrev.bindAsEventListener(date_picker));
        element.setStyle({ cursor: 'pointer' });
      }
    );
    this.popup.select('.date_picker_next').each(
      function(element) {
        element.observe('click', date_picker.renderNext.bindAsEventListener(date_picker));
        element.setStyle({ cursor: 'pointer' });
      }
    );
    this.popup.select('.date_picker_day').each(
      function(element) {
        element.observe('click', date_picker.selectDate.bindAsEventListener(date_picker));
        element.setStyle({ cursor: 'pointer' });
      }
    );
  },

  unregisterClickHandlers: function() {
    this.popup.select('.date_picker_prev').each(
      function(element) { element.stopObserving(); }
    );
    this.popup.select('.date_picker_next').each(
      function(element) { element.stopObserving(); }
    );
    this.popup.select('.date_picker_day').each(
      function(element) { element.stopObserving(); }
    );
  },

  renderPrev: function(event) {
    this.unregisterClickHandlers();
    this.renderPopup(new Date(this.date.getFullYear(), this.date.getMonth() - 1, this.date.getDate()));
    this.registerClickHandlers();
  },

  renderNext: function(event) {
    this.unregisterClickHandlers();
    this.renderPopup(new Date(this.date.getFullYear(), this.date.getMonth() + 1, this.date.getDate()));
    this.registerClickHandlers();
  },

  selectDate: function(event) {
    this.setFormDate(new Date(this.date.getFullYear(), this.date.getMonth(), event.element().innerHTML));
    this.togglePopup(event);
  },

  getFormDate: function() {
    var value = $F(this.element);
    if (value != '') {
      var parts = value.split('-');
      if (parts.length == 3)
        return new Date(parts[0], Number(parts[1]) - 1, parts[2])
    }
    return new Date();
  },

  setFormDate: function(date) {
    var month = date.getMonth() + 1;
    var day = date.getDate();

    if (month < 10) month = '0' + String(month);
    if (day < 10) day = '0' + String(day);

    this.element.value = date.getFullYear() + '-' + month + '-' + day;
  }
});

Event.observe(window, 'load',
  function(event) {
    $$('input.date_picker').each(
      function(element) { new DatePicker(element); }
    );
  }
);
