Calendar = Class.create();
Calendar.prototype = {
   version: "1.2",
   type : "calendar",

   value: "",

   initialize: function(config) {
      //  fields
      //  ~~~
      this.name = config.id;
      this.id = config.id;
      this.divid = config.divid;

      this.readOnly = true;
      this.showWeekNumbers = true;
      this.weekStartsOn = 0; // -1 = Sunday, 0 = Monday
      this.internalScrollers = false;

      this.selectedDay = null;
      this.preSelectedDay = null;
      this.multipleSelect = false;

      this.fullMonthsOnly = true;
      this.scrollable = true;

      this.monthsTexts = "";
      this.weekdaysTexts = "";
      this.prevMonthHTML = "&laquo";
      this.nextMonthHTML = "&raquo";
      this.weekNoHTML    = "&nbsp;";

      this.howManyDays = 0;
   },

   prevMonth:function () {
      this.viewPeriodS.setDate(1);
      this.viewPeriodS.shiftM(-1);
      this.viewPeriodE.setDate(1);
      this.viewPeriodE.shiftD(-1);
      this.selectedDay = null;
      this.draw();
   },

   nextMonth:function () {
      this.viewPeriodS.setDate(1);
      this.viewPeriodS.shiftM(1);
      this.viewPeriodE.setDate(1);
      this.viewPeriodE.shiftM(2);
      this.viewPeriodE.setDate(1);
      this.viewPeriodE.shiftD(-1);
      this.selectedDay = null;
      this.draw();
   },

   setFullMonthsOnly:function(truefalse) {
      this.fullMonthsOnly = truefalse;
      if (this.fullMonthsOnly) {
         // loose time
         this.viewPeriodE = new Date(this.viewPeriodE.getFullYear(),this.viewPeriodE.getMonth()+1,1);
         this.viewPeriodE.setDate(1);
         this.viewPeriodE.shiftD(-1);
      }
   },

   setOneMonthOnly:function(truefalse) {
      // Set viewport to one full month
      this.oneMonthOnly = truefalse;
      if (this.oneMonthOnly) {
         this.viewPeriodS = new Date(this.viewPeriodS.getFullYear(),this.viewPeriodS.getMonth(), 1);
         this.viewPeriodE = new Date(this.viewPeriodS.getFullYear(),this.viewPeriodS.getMonth()+1,1);
         this.viewPeriodE.shiftD(-1);
      }
   },

   getHowManyDays:function() {
      //Set 1 day in milliseconds
      var one_day=86400000;
      var days = Math.ceil((this.viewPeriodE.getTime()-this.viewPeriodS.getTime())/(one_day))+1;
      return days;
   },

   setPreselectedDate:function(date) {
      // read date from given inputfields
      date = parseUserDateInput(date);
      if (date.getTime() < this.dataPeriodS.getTime()) {
         date = this.dataPeriodS;
      } else if (date.getTime() > this.dataPeriodE.getTime()) {
         date = this.dataPeriodE;
      }
      this.preSelectedDay = date;
      this.selectedDay = this.getCellName(date);
      this.viewPeriodS = new Date(date);
      this.viewPeriodS.setDate(1);

      this.viewPeriodE = new Date(date);
      this.viewPeriodE.setDate(1);
      this.viewPeriodE.shiftM(1);
      this.viewPeriodE.setDate(1);
      this.viewPeriodE.shiftD(-1);
   },

   /* scrolls calendar to its current date */
   jumpToValue:function() {
      this.setPreselectedDate(this.value);
   },

   hideCallBack:function() {
       if (typeof this.hideCallBackName != "undefined") {
         // da es nur 2 Kalender geben kann - letztes Zeichen des Namens (0 oder 1) nehmen
         var temp = this.name.charAt(this.name.length-1);
         temp = this.hideCallBackName+"('"+temp+"');";
         eval(temp);
       }
   },

   getCellName:function (date) {
       return this.name+"_df_"+date.getFullYear()+"-"+(date.getMonth())+"-"+date.getDate();
   },

// This function toggles the given date's style
   setDate:function (cell) {
    if (!this.readOnly) {
      var tempday = e(cell);

      toggleClassName(tempday,"active", "enabled");

      if (!this.multipleSelect) {
         // single selection : remove old selection - select ONE day only
         if (this.selectedDay != null) {
            var sDay = e(this.selectedDay);
            var c = (typeof this.bitfield != "undefined") ? "working" : "enabled";
            modifyClassName(sDay, "active", false);
            modifyClassName(sDay, c, true);
         }

         this.selectedDay = cell;
         var date = cell.substring((this.name.length)+4,cell.length);
         var temp = date.split("-");
         var year = 1*temp[0];
         var month = 1*temp[1];
         var day = 1*temp[2];

         this.value = new Date(year,month,day);

         this.notify(this);
         this.hideCallBack();
      }
    }
   },

   inPeriod:function(date, S, E) {
       return ((date.getTime() >= S.getTime()) && (date.getTime() <= E.getTime()));
   },

   drawHeader:function(current_row, tempdate) {
       if (this.scrollable) {
          if (this.internalScrollers) {
             var cell = document.createElement("TH");
             cell.id = this.name+"_heading_months_lt";
          } else {
             var cell = document.getElementById(this.name+"prev");
          }
          var td2 = new Date(tempdate);
          td2.setDate(1);
          td2.shiftD(-1);
          if (this.inPeriod(td2, this.dataPeriodS, this.dataPeriodE)) {
             cell.innerHTML=this.prevMonthHTML;
             cell.className = "prevMonth";
             if (this.internalScrollers) {
                cell.onclick = function() {
                   var calid = this.id.substring(0,this.id.indexOf("_heading_months_lt"));
                   calman.calcons[calid].calendar.prevMonth();
                }
             } else {
                cell.onclick = function() {
                   var calid = this.id.substring(0,this.id.indexOf("prev"));
                   calman.calcons[calid].calendar.prevMonth();
                }
             }
          } else {
             cell.innerHTML= "";
             cell.className = "disabled";
          }
          if (this.internalScrollers) {
             current_row.appendChild(cell);
          }
       }
       cell= document.createElement("TH");
       cell.colSpan = ( (this.scrollable) && (this.internalScrollers) ) ? 5 : 7;
       if (this.showWeekNumbers) { cell.colSpan++; }

       cell.innerHTML = this.monthsTexts[tempdate.getMonth()]+"&nbsp;"+tempdate.getFullYear();
       cell.textAlign = "center";
       cell.id = this.name+"_heading_months"+tempdate.getMonth();
       if (this.multipleSelect) {
          cell.className = "heading_months_enabled";
          cell.onclick = function() {
             var calid = this.id.substring(0,this.id.indexOf("_heading_months"));
             var month = this.id.substring(this.id.indexOf("_heading_months")+15,this.id.length);
             calman.calcons[calid].calendar.selectMonth(month);
          }
       } else {
          cell.className = "heading_months_disabled";
       }
       current_row.appendChild(cell);
       if (this.scrollable) {
          if (this.internalScrollers) {
             cell = document.createElement("TH");
             cell.id = this.name+"_heading_months_gt";
          } else {
             cell = document.getElementById(this.name+"next");
          }
          var td2 = new Date(tempdate);
          td2.setDate(1);
          td2.shiftM(1);
          if (this.inPeriod(td2, this.dataPeriodS, this.dataPeriodE)) {
             cell.innerHTML=this.nextMonthHTML;
             cell.className = "nextMonth";
             if (this.internalScrollers) {
                cell.onclick = function() {
                   var calid = this.id.substring(0,this.id.indexOf("_heading_months_gt"));
                   calman.calcons[calid].calendar.nextMonth();
                }
             } else {
                cell.onclick = function() {
                   var calid = this.id.substring(0,this.id.indexOf("next"));
                   calman.calcons[calid].calendar.nextMonth();
                }
             }
           } else {
             cell.innerHTML="";
             cell.className = "disabled";
          }
          if (this.internalScrollers) {
             current_row.appendChild(cell);
          }
       }
   },

// This function fills the calendar table with the days of
// the selected month and year.
   draw:function() {
      this.howManyDays = this.getHowManyDays();

      if (this.bitfield) {
         // calc difference in days between viewPeriodS and dataPeriodS
         // to find bitfield begin...
         var tempdate = new Date(this.dataPeriodS);
         var bitfieldindex = 0;
         if (tempdate.getTime() < this.viewPeriodS.getTime()) {
            while (tempdate.getTime() < this.viewPeriodS.getTime()) {
               bitfieldindex++;
               tempdate.shiftD(1);
            }
         } else {
            while (tempdate.getTime() > this.viewPeriodS.getTime()) {
               bitfieldindex--;
               tempdate.shiftD(-1);
            }
         }
      }
      var div = document.getElementById(this.divid);

      // create table if it does not already exist
      var table = document.getElementById(this.name+"_table");
      if (table == null) {
         table = document.createElement("TABLE");
         div.insertBefore(table,div.firstChild);
         table.setAttribute("cellSpacing", "0");
         // FIX for non IEs
         if (typeof isIE == "undefined") {
            table.style.width = "auto";
         }
         table.style.width= "100%";
         table.id = this.name+"_table";
         table.className = "calendar";
      }

      // Recycling: remove complete table body...it's recreated => fast delete?
      var tbody = document.getElementById(this.name+"_tbody");
      if (tbody != null) {
         tbody.parentNode.removeChild(tbody);
      }

      // (re-)create tbody
      tbody = document.createElement("TBODY");
      table.appendChild(tbody);
      tbody.id = this.name+"_tbody";
      // update header and status texts
      tempdate = new Date(this.viewPeriodS);

      // show month name above weekdays
      if (this.oneMonthOnly) {
         // create row for month names
         current_row = document.createElement("TR");

         this.drawHeader(current_row, tempdate);

         tbody.appendChild(current_row);
      }

      // write weekday names in first (or second) row
      var row = document.createElement("TR");

      // week numbers
      if (this.showWeekNumbers) {
         var cell = document.createElement("TH");
         cell.id = this.name+"_heading_"+d;
         cell.className = "heading_daynames";
         cell.innerHTML = this.weekNoHTML;
         row.appendChild(cell);
      }

      for (d = 0 ; d < 7 ; d++) {
         var cell = document.createElement("TH");
         cell.id = this.name+"_heading_"+d;
         if (d+this.weekStartsOn < 0) {
            cell.innerHTML = this.weekdaysTexts[6];
         } else {
            cell.innerHTML = this.weekdaysTexts[d+this.weekStartsOn];
         }
         if (this.multipleSelect) {
            cell.className = "enabled";
            cell.onclick = function() {
               var calid = this.id.substring(0,this.id.indexOf("_heading_"));
               var day = this.id.substring(this.id.indexOf("_heading_")+9,this.id.length);
               calman.calcons[calid].calendar.selectDays(day);
            }
         } else {
            cell.className = "heading_daynames";
         }
         row.appendChild(cell);
      }

      tbody.appendChild(row);

      var daysdrawn = 0;
      var newmonth = false;
      var oldtempcolspan = 0;
      var colspan = 1;

      var w = -1;
      var newWeekNeeded = true;
      while (newWeekNeeded) {
         w++;

         if (((tempdate.getDate() == 1 && newmonth) || (daysdrawn == 0)) && (tempdate.getTime() >= this.viewPeriodS.getTime())) {
            // a new month begins...

            if (this.weekStartsOn == 0) {
               // if tempdate is 0 (sunday) set to 6 as the week begins on monday
               var daystoskip = (tempdate.getDay()-1 < 0) ? 6 : tempdate.getDay()-1;
            } else {
               var daystoskip = tempdate.getDay();
            }

            if (this.oneMonthOnly == false) {
               // create row for month name
               current_row = document.createElement("TR");
               current_cell= document.createElement("TD");
               current_cell.colSpan = 7;
               current_cell.innerHTML = this.monthsTexts[tempdate.getMonth()]+" - "+tempdate.getFullYear();
               current_cell.id = this.name+"_heading_months"+tempdate.getMonth();
               if (this.multipleSelect) {
                  current_cell.className = "enabled";
                  current_cell.onclick = function() {
                     var calid = this.id.substring(0,this.id.indexOf("_heading_months"));
                     var month = this.id.substring(this.id.indexOf("_heading_months")+15,this.id.length);
                     calman.calcons[calid].calendar.selectMonth(month);
                  }
               } else {
                  current_cell.className = "disabled";
               }
               current_row.appendChild(current_cell);

               tbody.appendChild(current_row);
            }

         }

         current_row = document.getElementById(this.name+"_row_"+w);
         if (current_row == null) {
            current_row = document.createElement("TR");
            current_row.id = this.name+"_row_"+w;
            tbody.appendChild(current_row);
         }

         if (this.showWeekNumbers) {
            cell = document.createElement("TD");
            cell.className = "weekno";
            cell.innerHTML = getWeek(tempdate);
            current_row.appendChild(cell);
         }

         // draws week rows
         for (var d = 0; d < 7; d++) {

            if ((tempdate.getDate() == 1 && newmonth == false) && (daysdrawn != 0)) {
               newmonth = true;
               // append remaining empty cells
               for (var e = d; e < 7; e++) {
                  cell = document.createElement("TD");
                  cell.className = "disabled";
                  cell.innerHTML = "&nbsp;";
                  if (current_row != null) {
                     current_row.appendChild(cell);
                  }
               }
               break;
            }

            cell = document.createElement("TD");

            if (daystoskip <= 0 && daysdrawn < this.howManyDays) {
               newmonth = false;
               // Change table cells id to represent current displayed date
               cell.id = this.getCellName(tempdate);
               this.getDateClass(cell, tempdate);

               if ((bitfieldindex+daysdrawn >= 0) && (this.inPeriod(tempdate, this.dataPeriodS, this.dataPeriodE))) {
                  if (this.bitfield.charAt(bitfieldindex+daysdrawn) == "1") {
                     modifyClassName(cell, "working", true);
                     cell.onclick = function(){
                        var calid = this.id.substring(0,this.id.indexOf("_df"));
                        calman.calcons[calid].calendar.setDate(this.id);
                     };
                  } else {
                     modifyClassName(cell, "notworking", true);
                     cell.onclick = null;
                  }

               } else {
                  if (this.readOnly == true) { 
                     cell.className = "disabled" 
                  } else { 
                     modifyClassName(cell, "enabled", true);
                  }
                  cell.onclick = function(){
                     var calid = this.id.substring(0,this.id.indexOf("_df"));
                     calman.calcons[calid].calendar.setDate(this.id);
                  };
               }

               cell.innerHTML = tempdate.getDate();
               // increase already drawn days by one
               tempdate.shiftD(1);
               daysdrawn += 1;

               //  deactivate cell
            } else {
               // append empty cells before calendar start
               cell.className = "disabled";
               cell.innerHTML = "&nbsp;";
               cell.onclick = null;
               daystoskip -= 1;
            }

            // ensure correct period display
            tempdate.shiftD(-1);
            if (tempdate.getTime() < this.dataPeriodS.getTime()) {
               cell.className = "disabled before_period";
               cell.onclick = null;
            }
            if (tempdate.getTime() > this.dataPeriodE.getTime()) {
               cell.className = "disabled beyond_period";
               cell.onclick = null;
            }
            tempdate.shiftD(1);

            current_row.appendChild(cell);
         }
         if ((tempdate.getTime() > this.viewPeriodE.getTime()) || (daysdrawn >= this.howManyDays)) {
            newWeekNeeded = false;
         }

      }

      // always keep 5 rows...no optic changes
      if (w < 5) {
         var row = document.createElement("TR");
         for (var i=0; i <= 7; i++) {
            var cell = document.createElement("TD");
            cell.className = "disabled";
            cell.innerHTML = "&nbsp;";
            row.appendChild(cell);
         }
         tbody.appendChild(row);
      }

      // auto-correction of div size
      document.getElementById(this.divid).style.width = "auto";
      if (this.preSelectedDay != undefined) {
         tempday = document.getElementById(this.getCellName(this.preSelectedDay));
         if (tempday != undefined) {
            if ((!this.dataPeriodS) && (!this.dataPeriodE)) {
               modifyClassName(tempday, "active", true);
            } else {
               // should be preselect!!
               modifyClassName(tempday, "active", true);
            }
         }
      }

   }, // - END function Calendar_draw();

   getFromVKHEXBitfield:function(bitfield) {
      this.dataPeriodS = new Date("20"+bitfield.substr(4,2),bitfield.substr(2,2),bitfield.substr(0,2));
      this.dataPeriodS.shiftM(-1);

      this.dataPeriodE = new Date("20"+bitfield.substr(10,2),bitfield.substr(8,2),bitfield.substr(6,2));
      this.dataPeriodE.shiftM(-1);

      bitfield = bitfield.substring(12,bitfield.length);

      // convert hexadecimal to binary
      this.bitfield = "";
      var temp = "";

      for (var i=0; i < bitfield.length;i += 2) {
         temp = (parseInt(bitfield.substring(i,i+2),16)).toString(2);
         while (temp.length < 8) {
            temp = "0"+temp;
         }
         this.bitfield = this.bitfield + temp;
      }
      return this.bitfield;
   },

   getDateClass:function(cell, date, classname) {
     // mark the active day
     if (this.value.getTime() == date.getTime()) {
       modifyClassName(cell, "active", true);
     }
     // mark today
     if (this.today.getTime() == date.getTime()) {
       modifyClassName(cell, "today", true);
     }
   }

} // EOO - end of object


