Calendar = Class.create();
Calendar.prototype = {
   version: "1.0",
   type : "calendar",

   value: "",
   
   initialize: function(config) {
      //  fields
      //  ~~~
      this.name = config.id;
      this.id = config.id;
      this.divid = config.divid;

      this.useDataPeriod = true;
      this.readOnly = true;
      this.showWeekNumbers = true;
      this.internalScrollers = false;

      this.selectedDay = null;
      this.preSelectedDay = null;
      this.multipleSelect = false;

      this.fullMonthsOnly = true;
      this.scrollable = true;

      this.monthsTexts = new Array();
      this.weekdaysTexts = new Array();
      this.prevMonthHTML = "&lt;";
      this.nextMonthHTML = "&gt;";
      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() {
     // loose time...
     var tempdate = new Date( this.viewPeriodS.getFullYear(),this.viewPeriodS.getMonth(),this.viewPeriodS.getDate() );
     var days = 0;
     while (tempdate.getTime() <= this.viewPeriodE.getTime()) {
        days++;
        tempdate.shiftD(1);
     }
     return days;
   },

   setPreselectedDate:function(date) {
      // read date from given inputfields
       date = parseUserDateInput(date);
          if (date < this.datePeriodS) {
             date = this.datePeriodS;
          } else if (date > this.datePeriodE) {
             date = this.datePeriodE;
          }
      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);
   },
   
   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) {
  // set the colors by style
   if (!this.readOnly) {
      if (this.multipleSelect) {
         var tempday = e(cell);
         tempday.className = (tempday.className == "active") ? "enabled" : "active";
      } else {
         // remove old selection - select ONE day only
         if (this.selectedDay != null) {
            tempday = e(this.selectedDay);
            //tempday.className = (tempday.className == "active") ? "enabled" : "active";
            if (typeof this.bitfield != "undefined") {
               tempday.className = "working";
            } else {
               tempday.className = "enabled";
            }
         }
         this.selectedDay = cell;
         tempday = e(cell);
         tempday.className = (tempday.className == "active") ? "enabled" : "active";

         var dayField = "input_day"+this.name.substr(6,1);
         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();
      }
    }
   },


// This function fills the calendar table with the days of
// the selected month and year.
   draw:function() {
      this.howManyDays = this.getHowManyDays();

      if (this.bitfield && this.useDataPeriod) {
         // 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 = "hafas_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 name
         current_row = document.createElement("TR");
         if (this.scrollable) {
            if (this.internalScrollers) {
               current_cell= document.createElement("TH");
               current_cell.id = this.name+"_heading_months_lt";
            } else {
               current_cell = document.getElementById(this.name+"prev");
            }
            var tempdate2 = new Date(tempdate);
            tempdate2.setDate(1);
            if ( ( (!this.useDataPeriod) ||
                   (!this.dataPeriodS) ||
                   (this.dataPeriodS && (tempdate2.getTime() > this.dataPeriodS.getTime())))
               ) {
               current_cell.innerHTML=this.prevMonthHTML;
               current_cell.className = "prevMonth";
               if (this.internalScrollers) {
                  current_cell.onclick = function() {
                     var calid = this.id.substring(0,this.id.indexOf("_heading_months_lt"));
                     var test = eval('calid')+".prevMonth();";
                     eval(test);

                  }
               } else {
                  current_cell.onclick = function() {
                     var calid = this.id.substring(0,this.id.indexOf("prev"));
                     var test = eval('calid')+".prevMonth();";
                     eval(test);
                  }
               }
            } else {
               current_cell.innerHTML= "";
               current_cell.className = "disabled";
            }
            if (this.internalScrollers) {
               current_row.appendChild(current_cell);
            }
         }
         current_cell= document.createElement("TH");
         current_cell.colSpan = ( (this.scrollable) && (this.internalScrollers) ) ? 6 : 8;
         current_cell.innerHTML = this.monthsTexts[tempdate.getMonth()]+"&nbsp;"+tempdate.getFullYear();
         current_cell.textAlign="center";
         current_cell.id = this.name+"_heading_months"+tempdate.getMonth();
         if (this.multipleSelect) {
            current_cell.className = "heading_months_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);
               var test = eval('calid')+".selectMonth(month);";
               eval(test);
            }
         } else {
            current_cell.className = "heading_months_disabled";
         }
         current_row.appendChild(current_cell);
         if (this.scrollable) {
            if (this.internalScrollers) {
               current_cell = document.createElement("TH");
               current_cell.id = this.name+"_heading_months_gt";
            } else {
               current_cell = document.getElementById(this.name+"next");
            }
            var tempdate2 = new Date(tempdate);
            tempdate2.setDate(1);
            tempdate2.shiftM(1);
            tempdate2.shiftD(-1);
            if ( (!this.useDataPeriod) ||
                 (!this.dataPeriodE) ||
                 (this.dataPeriodE && (tempdate2.getTime() < this.dataPeriodE.getTime() ))
               ) {
               current_cell.innerHTML=this.nextMonthHTML;
               current_cell.className = "nextMonth";
               if (this.internalScrollers) {
                  current_cell.onclick = function() {
                     var calid = this.id.substring(0,this.id.indexOf("_heading_months_gt"));
                     var test = eval('calid')+".nextMonth();";
                     //alert(calid+": "+document.getElementById(calid).type);
                     eval(test);
                  }
               } else {
                  current_cell.onclick = function() {
                     var calid = this.id.substring(0,this.id.indexOf("next"));
                     var test = eval('calid')+".nextMonth();";
                     eval(test);
                  }
               }
             } else {
               current_cell.innerHTML="";
               current_cell.className = "disabled";
            }
            if (this.internalScrollers) {
               current_row.appendChild(current_cell);
            }
         }

         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;
         cell.innerHTML = this.weekdaysTexts[d];
         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);
               var test = eval('calid')+".selectDays(day);";
               eval(test);
            }
         } else {
            cell.className = "heading_daynames";
         }
         row.appendChild(cell);
      }

      tbody.appendChild(row);

      // Calculate skip between first table cell and first one with content (which
      // weekday does the calendar start with)
      // if it is 0 (sunday) set to 6 as the week begins on monday
      daystoskip = (tempdate.getDay()-1 < 0) ? 6 : tempdate.getDay()-1;

      var daysdrawn = 0;
      var newmonth = false;
      var oldtempcolspan = 0;
      var colspan = 1;

      var w = -1;
      var startweek = tempdate.getWeek();
      var newWeekNeeded = true;
      while (newWeekNeeded) {
         w++;

         if (((tempdate.getDate() == 1 && newmonth) || (daysdrawn == 0)) && (tempdate.getTime() >= this.viewPeriodS.getTime())) {
            // a new month begins...

            // which weekday is the current date (e.g. 1st April 2005 is a Friday (5))?
            // if it is 0 (sunday) set to 6 as the week begins on monday
            daystoskip = (tempdate.getDay()-1 < 0) ? 6 : tempdate.getDay()-1;

            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);
                     var test = eval('calid')+".selectMonth(month);";
                     eval(test);
                  }
               } 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 = startweek++;
            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);

               if ((this.useDataPeriod) && (bitfieldindex+daysdrawn >= 0) && (this.dataPeriodS) && (this.dataPeriodE) && (tempdate.getTime() <= this.dataPeriodE.getTime())) {
                  if (this.bitfield.charAt(bitfieldindex+daysdrawn) == "1") {
                     cell.className = "working";
                     cell.onclick = function(){
                        var calid = this.id.substring(0,this.id.indexOf("_df"));
                        var test = eval('calid')+".setDate(this.id);";
                        eval(test);
                     };
                  } else {
                     cell.className = "notworking";
                     cell.onclick = null;
                  }
                  // mark today and the active day
                  if (this.today.getTime() == tempdate.getTime()) {
                     cell.className = cell.className+" today";
                  }
                  if (this.value.getTime() == tempdate.getTime()) {
                     cell.className = cell.className+" active";
                  }

               } else {
                  cell.className = (this.readOnly == true) ? "disabled" : "enabled";
                  cell.onclick = function(){
                     var calid = this.id.substring(0,this.id.indexOf("_df"));
                     var test = eval('calid')+".setDate(this.id);";
                     eval(test);
                  };
               }
               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 > this.viewPeriodE) || (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)) {
               tempday.className = tempday.className+" active";
            } else {
               // should be preselect!!
               tempday.className = tempday.className+" active";
            }
         }
      }

   }, // - 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;
   }

} // EOO - end of object

