var DatePicker = Class.create({
  initialize: function(date, options) {
    this.options = options;
    this.horizontalPages = this.options.horizontalPages || 2;
    this.date = date || new Date();
    this.selectedElement = null;
    this.pageMargin = 5;
    this.buffer = 1;
    this.speed = 0;
    this.acceleration = 0;
    this.scrollOffset = 0;
    this.totalWidth = null;
    this.balloon = null;
    this.focusDate = this.date;
  },
  
  create: function() {
    var table = $(document.createElement("table"));
    table.className = "pages_table";
    
    var tbody = $(document.createElement("tbody"));
    table.appendChild(tbody);
    
    var row = $(document.createElement("tr"));
    tbody.appendChild(row);

		if (!this.options.noArrows) {
	    var leftArrow = $(document.createElement("td"));
	    leftArrow.className = "arrow_left";
	    leftArrow.observe("click", function(event) {
	      this.scrollPrevious();
	      var selection = window.getSelection ? window.getSelection() : null;
	      if (selection) {
	        selection.removeAllRanges();
	      }
	      Event.stop(event);
	      return false;
	    }.bind(this));
	    row.appendChild(leftArrow);
		}

    var pagesCell = $(document.createElement("td"));
    pagesCell.className = "pages_cell";
    row.appendChild(pagesCell);
    
    var pagesContainer = $(document.createElement("div"));
    pagesContainer.className = "pages_container";
    pagesContainer.style.position = "relative";
    pagesCell.appendChild(pagesContainer);
    this.pagesContainerElement = pagesContainer;

    var pagesElement = $(document.createElement("div"));
    pagesElement.className = "pages";
    this.pagesElement = pagesElement;
    this.pagesContainerElement.appendChild(this.pagesElement);
		
		if (!this.options.noArrows) {
	    var rightArrow = $(document.createElement("td"));
	    rightArrow.className = "arrow_right";
	    rightArrow.observe("click", function(event) {
	      this.scrollNext();
	      var selection = window.getSelection ? window.getSelection() : null;
	      if (selection) {
	        selection.removeAllRanges();
	      }
	      Event.stop(event);
	      return false;
	    }.bind(this));
	    row.appendChild(rightArrow);
		}
		var container = $(document.createElement("div"));
    container.className = "date_picker";
    container.appendChild(table);
    return container;
  },
  
  createPages: function(startDate, endDate) {
    var pages = [];
    for (var y = startDate.getFullYear(); y <= endDate.getFullYear(); y++) {
      for (var m = 0; m < 12; m++) {
        var date = new Date(y, m, 1);
        if (date.getTime() >= startDate.getTime() && date <= endDate.getTime()) {
          var page = this.createPage(date);
          pages.push(page);
        }
      }
    }
    return pages;
  },
  
  createPage: function(date) {
    var page = $(document.createElement("div"));
    page.className = "page";
    
    var startDate = new Date(date.getFullYear(), date.getMonth(), 1);
    while (startDate.getDay() != 1) {
      startDate.setDate(startDate.getDate() - 1);
    }
    var endDate = new Date(date.getFullYear(), date.getMonth() + 1, -1);
    while (endDate.getDay() < 6) {
      endDate.setDate(endDate.getDate() + 1);
    }

    var table = $(document.createElement("table"));
    page.appendChild(table);
    
    var tbody = $(document.createElement("tbody"));
    table.appendChild(tbody);

    var monthHeadingRow = $(document.createElement("tr"));
    var monthHeadingCell = $(document.createElement("th"));
    monthHeadingCell.colSpan = 7;
    monthHeadingCell.className = "month_heading";
    monthHeadingCell.appendChild(document.createTextNode(DatePicker.MONTH_NAMES[date.getMonth()]));
    monthHeadingCell.appendChild(document.createTextNode(" "));
    monthHeadingCell.appendChild(document.createTextNode(date.getFullYear()));
    monthHeadingRow.appendChild(monthHeadingCell);
    tbody.appendChild(monthHeadingRow);
    
    var daysOfWeek = [1, 2, 3, 4, 5, 6, 0];
    
    var headerRow = $(document.createElement("tr"));
    daysOfWeek.each(function(dow) {
      var cell = $(document.createElement("th"));
      cell.className = "day";
      if (dow == 0) {
        cell.className = cell.className + " holiday";
      }
      cell.appendChild(document.createTextNode(DatePicker.DAY_NAMES[dow].slice(0, 1)));
      headerRow.appendChild(cell);
    });
    tbody.appendChild(headerRow);

    var d = startDate;
    var today = new Date();
    var mouseOverFunction = function(event) { Event.element(event).addClassName("hover"); };
    var mouseOutFunction = function(event) { Event.element(event).removeClassName("hover"); };
    while (d <= endDate) {
      var row = $(document.createElement("tr"));
      daysOfWeek.each(function(dow) {
        var cell = $(document.createElement("td"));
        if (d.getMonth() == date.getMonth()) {
          cell.className = "day";
          if (d.getFullYear() == today.getFullYear() && d.getMonth() == today.getMonth() &&
            d.getDate() == today.getDate()) {
            cell.className = cell.className + " today";
          }
          if (dow == 0) {
            cell.className = cell.className + " holiday";
          }
          cell.appendChild(document.createTextNode(d.getDate()));
          cell.date = d;
          if (navigator.userAgent.match(/MSIE [0-6]/)) {
            cell.observe("mouseover", mouseOverFunction);
            cell.observe("mouseout", mouseOutFunction);
          }
          cell.observe("click", function(event) {
            var element = Event.element(event);
            this.selected(element.date, element);
          }.bind(this));
        }
        row.appendChild(cell);
        d = new Date(d);
        d.setDate(d.getDate() + 1);
      }.bind(this));
      tbody.appendChild(row);
    }
    return page;
  },
  
  selected: function(date, element) {
    if (this.selectedElement) {
      this.selectedElement.removeClassName("selected");
      this.selectedElement = null;
    }
    element.addClassName("selected");
    this.selectedElement = element;
    this.date = date;
    if (this.options.onSelect) {
      this.options.onSelect(date);
    }
    if (this.balloon) {
      this.balloon.close();
    }
  },
  
  scrollToDate: function(date) {
    if (date.getFullYear() != this.focusDate.getFullYear() ||
      date.getMonth() != this.focusDate.getMonth()) {
      var firstDate = this.dateWithRelativeMonth(this.focusDate, -1);
      var lastDate = this.dateWithRelativeMonth(this.focusDate, this.horizontalPages + 1);
      if (date < firstDate || date >= lastDate) {
        this.focusDate = this.dateWithRelativeMonth(date, 0);
        this.repopulate();
      } else {
        this.scrollRelative(date < this.focusDate ? -1 : 1);
      }
    }
  },
  
  scrollRelative: function(direction) {
    if (direction != 0) {
      direction = direction / Math.abs(direction);
      if (direction < 0) {
        new Effect.ScrollElementTo(this.pagesContainerElement, {
          toX: this.scrollOffsetForPage(-1), 
          duration: 0.5, 
          transition: Effect.Transitions.sinoidal,
          afterFinish: function() {
            $(this.pagesElement.lastChild).remove();
            this.focusDate = this.dateWithRelativeMonth(this.focusDate, direction);
            var firstDate = this.dateWithRelativeMonth(this.focusDate, -this.buffer);
            this.pagesElement.insertBefore(this.createPage(firstDate), this.pagesElement.firstChild);
            this.pagesContainerElement.scrollLeft = this.scrollOffsetForPage(0);
          }.bind(this),
          queue: 'end'
        });
      } else {
        new Effect.ScrollElementTo(this.pagesContainerElement, {
          toX: this.scrollOffsetForPage(1), 
          duration: 0.5, 
          transition: Effect.Transitions.sinoidal,
          afterFinish: function() {
            $(this.pagesElement.firstChild).remove();
            this.focusDate = this.dateWithRelativeMonth(this.focusDate, direction);
            var lastDate = this.dateWithRelativeMonth(this.focusDate, this.horizontalPages + this.buffer - 1);
            this.pagesElement.appendChild(this.createPage(lastDate));
            this.pagesContainerElement.scrollLeft = this.scrollOffsetForPage(0);
          }.bind(this),
          queue: 'end'
        });
      }
    }
  },
  
  scrollPrevious: function() {
    this.scrollRelative(-1);
  },

  scrollNext: function() {
    this.scrollRelative(1);
  },
  
  scrollOffsetForPage: function(pageIndex) {
    var scrollAdjust = this.pageMargin * 2;
    var offset = (this.buffer + pageIndex) * this.pageWidth;
    offset += scrollAdjust / 2;
    if (navigator.userAgent.match(/MSIE/)) {
      if (pageIndex == 1) offset += scrollAdjust / 2;
      offset += scrollAdjust;
    }
    if (pageIndex >= 0) offset += scrollAdjust / 2;
    return offset;
  },
  
  setBalloon: function(balloon) {
    this.balloon = balloon;
  },
  
  repopulate: function() {
    while (this.pagesElement.firstChild) {
      this.pagesElement.removeChild(this.pagesElement.firstChild);
    }
    this.populate();
  },
  
  populate: function() {
    if (!this.pageWidth) {
      var testPage = this.createPage(this.date);
      this.pagesElement.appendChild(testPage);
      this.pageWidth = testPage.getDimensions().width + this.pageMargin;
      this.pagesContainerElement.style.height = testPage.getDimensions().height + "px";
      this.pagesContainerElement.style.width = (this.horizontalPages * this.pageWidth) + "px";
      this.pagesElement.removeChild(testPage);
    }
    if (!this.pagesElement.firstChild) {
      var firstDate = this.dateWithRelativeMonth(this.focusDate, -this.buffer);
      var lastDate = this.dateWithRelativeMonth(this.focusDate, this.horizontalPages + this.buffer - 1);
      var pages = this.createPages(firstDate, lastDate);
      pages.each(function(page) {
        this.pagesElement.appendChild(page);
      }.bind(this));
      this.pagesContainerElement.scrollLeft = this.scrollOffsetForPage(0);
    }
  },
  
  dateWithRelativeMonth: function(date, month) {
    return new Date(date.getFullYear(), date.getMonth() + month, 1);
  },
  
  insertInto: function(element) {
    $(element).appendChild(this.create());
    this.populate();
  }
});

DatePicker.DAY_NAMES = [
  _("søndag"), _("mandag"), _("tirsdag"), _("onsdag"), _("torsdag"), _("fredag"), _("lørdag")
];

DatePicker.MONTH_NAMES = [
  _("januar"), _("februar"), _("mars"), _("april"), _("mai"), _("juni"), _("juli"), _("august"),
  _("september"), _("oktober"), _("november"), _("desember")
];

DatePicker.attachBalloon = function(picker, field) {
  field = $(field);

  var arrow = document.createElement("img");
  arrow.className = "date_picker_arrow";
  arrow.src = "/images/forms/date_picker_button.png";
  arrow.alt = "...";
  field.parentNode.insertBefore(arrow, field.nextSibling);

  var balloon = new Balloon({
    content: picker.create(),
    className: "date_picker_balloon",
    closeable: true,
    position: new Balloon.Position.Vertical(-145, 0),
    origin: field,
    tail: null,
    rounded: true,
    onMayShow: function() {
      return !field.disabled;
    },
    onShow: function() {
      picker.populate();
    }
  });
  balloon.attach(arrow);

  picker.setBalloon(balloon);
  return picker;
};