/**
 *  ** jsCalendar - Stefan Deser (03/2007) **
 *
 *  CSS-customziable JavaScript-calendar, on which you can easily adapt 
 *  everything to your own needs... 
 *  What should happen, when clicking a single day can be changed in the 
 *  function "this.getDayHref()".
 *  For a CSS-example see jsCalendar.css
 * 
 *  You may modify and redistribute the program under the terms of the GPL 
 *  (version 2 or later).  I provide no warranty for this program.
 *
 **/
 
function jsCalendar() {
 
  var daysNames =  new Array("So", "Mo", "Di", "Mi", "Do", "Fr", "Sa");
  var monthNames = new Array("Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"); 
 
 
  // This is the id of the calendars <div>-tag...
  var calendarId =  "jsCalendar";
  
  this.date = new Date();
  var self = this; // We need this (closure!)

  // jsCalendar itself...
  var jsCalendar = document.createElement("div");
  jsCalendar.setAttribute("id", calendarId);

  
  /** 
   * Here we build the calendar - by building a new one or replacing certain elements
   */
  this.buildCalendar = function(event) {
    
    // Header (month plus year)
    var divHeader = document.createElement("div");
    divHeader.setAttribute("id", "calHeader");
    var textHeader = monthNames[this.date.getMonth()] + " " + this.date.getFullYear();
    var textNodeHeader = document.createTextNode(textHeader);
    divHeader.appendChild(textNodeHeader);
    
    // Navigation
    var nav = document.createElement("div");
    nav.setAttribute("id", "calNavigation");
  
    // Create elements for navigation
    var navMonthFwd = document.createElement("div"); 
    var navMonthBack = document.createElement("div"); 
    var navYearFwd = document.createElement("div");
    var navYearBack = document.createElement("div"); 
    
    navMonthFwd.appendChild(document.createTextNode(">"));
    navMonthBack.appendChild(document.createTextNode("<"));
    navYearFwd.appendChild(document.createTextNode(">>"));
    navYearBack.appendChild(document.createTextNode("<<"));
  
    /** 
     * Now we're adding eventhandlers to our nav-elements...
     */
    navMonthFwd.onclick = function() {
      self.date.setMonth(self.date.getMonth()+1);
      self.buildCalendar();
    }
  
    navMonthBack.onclick = function() {
      self.date.setMonth(self.date.getMonth()-1);
      self.buildCalendar();
    }
  
    navYearFwd.onclick = function() {
      self.date.setYear(self.date.getFullYear()+1);
      self.buildCalendar();
    }

    navYearBack.onclick = function() {
      self.date.setYear(self.date.getFullYear()-1);
      self.buildCalendar();
    }

    // Finally we append them to their common parent... 
    nav.appendChild(navYearBack);
    nav.appendChild(navMonthBack);
    nav.appendChild(navMonthFwd);
    nav.appendChild(navYearFwd);
    
    // Now we create the table for displaying the single days
    var calTable = document.createElement("table");
    calTable.setAttribute("id", "calTable");
    
    // Let's begin a new row
    var rowCounter = 0; 
    currentRow = calTable.insertRow(rowCounter);
    
    // Labeling the "day-headline"
    for(var i=0; i < daysNames.length; i++) {
      textNode = document.createTextNode(daysNames[i]);
      currentRow.insertCell(i).appendChild(textNode);
    }
    
    var daysInMonth = this.date.getDaysOfMonth();
    var firstDayOfMonth = this.date.getFirstDayOfMonth();
  
    var currentDay = 1;   
    var cellCounter = 0; 
    
    currentRow = calTable.insertRow(++rowCounter);
    
    var today = new Date();
    var maxCellsForDays = 42; // We must have enough place
    
    for(var i=0; i < maxCellsForDays; i++) {
      
      if(i % 7 == 0) {
        currentRow = calTable.insertRow(rowCounter++);
        cellCounter = 0; 
      }
        
      var curTd = currentRow.insertCell(cellCounter);
  
      if( i >= firstDayOfMonth && i < (firstDayOfMonth + daysInMonth) ) {
        // If it's today, give the cell an unique id... 
        if( today.getFullYear() == this.date.getFullYear()
         && today.getMonth() == this.date.getMonth()
         && today.getDate() == currentDay ) {
          curTd.setAttribute("id", "today");
        }
        
        var a = document.createElement('a');
        a.href = this.getDayHref(currentDay, (1 + this.date.getMonth()), this.date.getFullYear());
        a.appendChild(document.createTextNode(currentDay++));
        curTd.appendChild(a);
      }
      cellCounter++; 
    }
    
    
    // Finally replace elements or if calender exists, build a new one...
    if( document.getElementById(calendarId) ) {
      
      jsCalendar.replaceChild(divHeader, document.getElementById('calHeader'));
      jsCalendar.replaceChild(calTable, document.getElementById('calTable')); 
    
    } else {
      
      jsCalendar.appendChild(divHeader);
      jsCalendar.appendChild(calTable);  
      jsCalendar.appendChild(nav);  
      document.body.appendChild(jsCalendar);
      
      // Check if it was a mouseclick or if we got focus (otherwise)...
      var x = 0; 
      var y = 0;

/** 
 * Therefore we would need the id of the parent element
 *
      if(event.type == "focus") {
        focussedElem = document.getElementById(parentElemId);
        x = focussedElem.offsetLeft;
        y = focussedElem.offsetTop + focussedElem.offsetHeight;
        var parent = focussedElem;
        while (parent.offsetParent) {
          parent = parent.offsetParent;
          x += parent.offsetLeft;
          y += parent.offsetTop;
        }
      }
 *
 */

      if(event.type == "click") {

        x = event.clientX; 
        y = event.clientY; 
 
        // Following code from: 
        // http://www.quirksmode.org/viewport/compatibility.html#link3
        
        // all except Explorer
        if (self.pageYOffset) {
          x += window.pageXOffset;
          y += window.pageYOffset;
        }
        
        // Explorer 6 Strict 
        else if (document.documentElement && document.documentElement.scrollTop) {
          x += document.documentElement.scrollLeft;
          y += document.documentElement.scrollTop;
        }
        
        // all other Explorers 
        else if (document.body) {
          x += document.body.scrollLeft;
          y += document.body.scrollTop;
        }
      
      }
      
      // Place the calender correctly 
      jsCalendar.style.position = "absolute";
      jsCalendar.style.left = x + "px";
      jsCalendar.style.top = y + "px"; 
    
    } // else
   
  }


  /**
   * Closes the calendar by removing the <div> from body
   * and the children from calendar... 
   */      
  this.close = function() {
    while(jsCalendar.hasChildNodes())
      jsCalendar.removeChild(jsCalendar.firstChild);
    document.getElementsByTagName('body')[0].removeChild(document.getElementById(calendarId));
  }


  /**
   * Here you can customize what should happen, when you click 
   * on one of the single days of the calendar... 
   *
   * @param day: the day of the clicked day (d)
   * @param month: the month of the clicked day (m)
   * @param year: the year of the clicked day (yyyy)
   */
  
  this.getDayHref = function(day, month, year) {
    // Change format to "dd" and "mm"
    if(day < 10) day = "0" + day;
    if(month < 10) month = "0" + month;
    
    var aHrefString = "javascript:";
    aHrefString += "document.getElementById('jsCalInput').value='" + day + '.' + month + '.' + year + "';";
    aHrefString += "cal.close();";
    return aHrefString;
  }

}


/** 
 * Extend the functionality of the Date-object
 */
Date.prototype.getDaysOfMonth = function() {
  var year = this.getFullYear(); 
  var month = this.getMonth();
  
  for(var days=28; days <= 31; ++days) {
    if( new Date(year,month,days).getMonth()
     != new Date(year,month,1).getMonth() )
    break;
  }
  
  return days - 1;
}

Date.prototype.getFirstDayOfMonth = function() {
  return (new Date(this.getFullYear(), this.getMonth(), 1)).getDay(); 
}  
