// original: simple_hex_h_calendar.js
function Calendar(returnPath, instancename, startday, startmonth, startyear) {
   //  methods
   //  ~~~
   this.getHowManyDays         = Calendar_getHowManyDays;
   this.setFullMonthsOnly      = Calendar_setFullMonthsOnly;
   this.setOneMonthOnly        = Calendar_setOneMonthOnly;
   this.setScrollable          = Calendar_setScrollable;
   this.nextMonth              = Calendar_nextMonth;
   this.prevMonth              = Calendar_prevMonth;
   this.draw                   = Calendar_draw;
   this.setDate                = Calendar_setDate;
   this.getStartDateFromString = Calendar_getStartDateFromString;
   this.getStartDateFrom       = Calendar_getStartDateFrom;
   this.getEndDateFromString   = Calendar_getEndDateFromString;
   this.getEndDateFrom         = Calendar_getEndDateFrom;
   this.parseUserDateInput     = Calendar_parseUserDateInput;
   this.getFromVKHEXBitfield   = Calendar_getFromVKHEXBitfield;


   //  fields
   //  ~~~
   this.name = instancename;
   this.refReturnField = returnPath;
   this.useDataPeriod = true;
   this.readOnly = true;

   this.viewPeriodS = new Date(startyear,startmonth,startday);
   this.viewPeriodE = new Date(startyear,startmonth,startday);
   this.dataPeriodS = null;
   this.dataPeriodE = null;

   // check start date parameters - default: today
   if (!this.viewPeriodS.getDate()) {
      this.viewPeriodS = new Date();
      // PeriodEnd is set in setOneMonthOnly() ...
   }

   if ((this.refReturnField == null) || (this.refReturnField == "")) {
      parameters=String(window.location.search).split("&");
      for (i= 1; i<parameters.length; i++) {
         if (parameters[i].indexOf("field=")==0) {
            var returnTextfield = parameters[i].substr(6)
         }
         if (parameters[i].indexOf("form=")==0) {
            var returnForm = parameters[i].substr(5);
         }
      }
      // try to auto-detect parent window (which ultimately holds the inputfield)
      // ~~
      var returnWindow = (window.opener != null) ? "window.opener.document" : "window.document";
      
      this.refReturnField = returnWindow+"."+returnForm+"."+returnTextfield;
   }

   this.selectedDay = this.name+"_df_"+this.viewPeriodS.getFullYear()+"/"+(this.viewPeriodS.getMonth())+"/"+this.viewPeriodS.getDate();
   this.multipleSelect = false;

   this.fullMonthsOnly = true;
   this.setOneMonthOnly(true);
   this.scrollable = false;

   this.monthsTexts = new Array();
   this.weekdaysTexts = new Array();
   this.prevMonthHTML = "&lt;";
   this.nextMonthHTML = "&gt;";

   this.closeOnSetDate = false;
   this.showShortYear = false;
   this.howManyDays = 0;
}

function Calendar_prevMonth() {
   this.viewPeriodS.setMonth(this.viewPeriodS.getMonth()-1);
   this.viewPeriodE.setDate(1);
   this.viewPeriodE.setDate(this.viewPeriodE.getDate()-1);
   this.selectedDay = null;
   this.draw();
}

function Calendar_nextMonth() {
   this.viewPeriodS.setMonth(this.viewPeriodS.getMonth()+1);

   this.viewPeriodE.setDate(1);
   this.viewPeriodE.setMonth(this.viewPeriodE.getMonth()+2);
   this.viewPeriodE.setDate(1);
   this.viewPeriodE.setDate(this.viewPeriodE.getDate()-1);
   this.selectedDay = null;
   this.draw();
}

function Calendar_setFullMonthsOnly(truefalse) {
   this.fullMonthsOnly = truefalse;
   if (this.fullMonthsOnly) {
      this.viewPeriodE = new Date(this.viewPeriodE.getFullYear(),this.viewPeriodE.getMonth()+1,1);
      this.viewPeriodE.setDate(this.viewPeriodE.getDate()-1);
   }
}

function Calendar_setOneMonthOnly(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.setDate(this.viewPeriodE.getDate()-1);
   }
}

function Calendar_setScrollable(truefalse) {
   this.scrollable = truefalse;
}

function Calendar_getHowManyDays() {
   var tempdate = new Date( this.viewPeriodS.getFullYear(),this.viewPeriodS.getMonth(),this.viewPeriodS.getDate() );
   var days = 0;
   while (tempdate.getTime() <= this.viewPeriodE.getTime()) {
      days++;
      tempdate.setDate(tempdate.getDate()+1);
   }
   return days;
}

function Calendar_getStartDateFrom(ioField) {
   eval("userInput = "+this.returnWindow+"."+this.returnForm+"."+ioField+".value;");
   this.getStartDateFromString(userInput);
}

function Calendar_getStartDateFromString(datestring) {
   this.viewPeriodS = this.parseUserDateInput(datestring);
}

function Calendar_getEndDateFrom(ioField) {
   eval("userInput = "+this.returnWindow+"."+this.returnForm+"."+ioField+".value;");
   this.getEndDateFromString(userInput);
}


function Calendar_getEndDateFromString(datestring) {
   this.viewPeriodE = this.parseUserDateInput(datestring);
}


function Calendar_parseUserDateInput(userInput){
   var matchReg = /(\d+)\D+(\d+)\D+(\d+)\D*/;
   matchReg.exec( userInput );

   userInput_day   = RegExp.$1;
   userInput_month = RegExp.$2;
   userInput_year  = RegExp.$3;

   userInput_day *= 1; userInput_month *= 1; userInput_year *= 1;
   // attention: userInput_month is 1-12-ranged!
   // ~~~
   if (userInput_month!="") {
      userInput_month -= 1;
      if (userInput_month<0) {
         userInput_month = 11;
      } else if (userInput_month>11) {
         userInput_month = 0;
      }
   }
   if (userInput_year!="") {
      if (userInput_year<100) {
         if (userInput_year<50) {
            userInput_year+=2000;
         } else {
            userInput_year+=1900;
         }
      } else if (userInput_year < 1000) {
         if (userInput_year<200) {
            userInput_year+=1900;
         } else {
            userInput_year+=1000;
         }
      }
   }
   return new Date(userInput_year, userInput_month, userInput_day);
}

//
// This function toggles the given date's style
//
function Calendar_setDate(cell) {
   // set the colors by style
   if (!this.readOnly) {
      if (this.multipleSelect) {
         (document.getElementById(cell)).className = (tempday.className == "active") ? "enabled" : "active";
      } else {
         // select only ONE day
         if (this.selectedDay != null) {
            (document.getElementById(this.selectedDay)).className = (tempday.className == "active") ? "enabled" : "active";
         }
         this.selectedDay = cell;
         tempday = document.getElementById(cell);
         tempday.className = (tempday.className == "active") ? "enabled" : "active";

         date = cell.substring((this.name.length)+4,cell.length);
         temp = date.split("/");
         year = temp[0];
         month = temp[1];
         day = temp[2];
         //  implicit typecasting...
         day *= 1; month *= 1; year *= 1;

         // prepare for display
         month = month + 1;
         if (day < 10) {
            day = "0"+day;
         }
         if (month < 10) {
            month = "0"+month;
         }

         // has to be after the previous step for interpreting purposes
         if (this.showShortYear) {
            year -= 2000;
            if (year < 10) {
               year = "0"+year;
            }
         }
         date = day+"/"+month+"/"+year;

         // calculate weekday & begin week with monday
         weekday = (new Date(year,month-1,day)).getDay()-2;
         if (weekday == -1) weekday = 6;
         if (weekday == -2) weekday = 5;

         temp = this.refReturnField+".value = this.weekdaysTexts[weekday]+\", \"+date;";
         eval(temp);

         if (this.closeOnSetDate) {
            if (window.opener) {
               window.opener.focus();
               window.close();
            }
         }
      }
   }
}


//
// This function fills the calendar table with the days of
// the selected month and year.
//
function Calendar_draw() {
   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.setDate(tempdate.getDate()+1);
         }
      } else {
         while (tempdate.getTime() > this.viewPeriodS.getTime()) {
            bitfieldindex--;
            tempdate.setDate(tempdate.getDate()-1);
         }
      }
   }

   var div = document.getElementById(this.name);

   // 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");
      table.style.width = "100%";
      table.id = this.name+"_table";
   }

   // 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.getFullYear(),this.viewPeriodS.getMonth(),this.viewPeriodS.getDate());

   // show month name above weekdays
   if (this.oneMonthOnly) {
      // create row for month name
      current_row = document.createElement("TR");
      if (this.scrollable) {
         current_cell= document.createElement("TH");
         current_cell.id = this.name+"_heading_months_lt";

         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 = "enabled";
            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.innerHTML= "";
            current_cell.className = "disabled";
         }

         current_row.appendChild(current_cell);
      }
      current_cell= document.createElement("TH");
      if (this.scrollable) {
        current_cell.colSpan = 5;
      }
      else
      {
         current_cell.colSpan = 7;

      }
      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 = "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);

      if (this.scrollable) {
         current_cell = document.createElement("TH");
         current_cell.id = this.name+"_heading_months_gt";
         var tempdate2 = new Date(tempdate);
         tempdate2.setDate(1);
         tempdate2.setMonth(tempdate2.getMonth()+1);
         tempdate2.setDate(tempdate2.getDate()-1);
         if ((!this.useDataPeriod) || (!this.dataPeriodE) || (this.dataPeriodE && (tempdate2.getTime() < this.dataPeriodE.getTime()))) {
            current_cell.innerHTML=this.nextMonthHTML;
            current_cell.className = "enabled";
            current_cell.onclick = function() {
               var calid = this.id.substring(0,this.id.indexOf("_heading_months_gt"));
               var test = eval('calid')+".nextMonth();";
               eval(test);
            }
         } else {
            current_cell.innerHTML="";
            current_cell.className = "disabled";
         }
         current_row.appendChild(current_cell);
      }

      tbody.appendChild(current_row);
   }

   // write weekday names in first (or second) row
   var row = document.createElement("TR");

   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 = "disabled";
      }
      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 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 = "<b>"+this.monthsTexts[tempdate.getMonth()]+" - "+tempdate.getFullYear()+"</b>";
            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);
      }
      // 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.name+"_df_"+tempdate.getFullYear()+"/"+(tempdate.getMonth())+"/"+tempdate.getDate(); //+"-"+((w*7)+d+1);

            if ( (this.useDataPeriod) && (bitfieldindex+daysdrawn >= 0) && (this.dataPeriodS) && (this.dataPeriodE) && (tempdate.getTime() <= this.dataPeriodE.getTime())) {
               cell.className = (this.bitfield.charAt(bitfieldindex+daysdrawn) == "1") ? "working" : "notworking";
            } else {
               cell.className = (this.readOnly == true) ? "disabled" : "enabled";
            }
            cell.innerHTML = tempdate.getDate(); //+":"+(bitfieldindex+daysdrawn)+"-"+this.bitfield.charAt(bitfieldindex+daysdrawn);
            cell.onclick = function(){
               var calid = this.id.substring(0,this.id.indexOf("_df"));
               var test = eval('calid')+".setDate(this.id);";
               eval(test);
            };
            // increase already drawn days by one
            tempdate.setDate(tempdate.getDate()+1);
            daysdrawn += 1;

            //  deactivate cell
         } else {
            cell.className = "disabled";
            cell.innerHTML = "&nbsp;";
            cell.onclick = null;
            daystoskip -= 1;
         }

         current_row.appendChild(cell);
      }
      if ((tempdate > this.viewPeriodE) || (daysdrawn >= this.howManyDays)) {
         newWeekNeeded = false;
      }

   }

   // auto-correction of div size
   document.getElementById(this.name).style.width = "auto";
   // select initial date
   tempday = document.getElementById(this.selectedDay);
   if (tempday != null) {
      tempday.className = "active";
   }
} // - END function Calendar_draw();

function isLeapYear(y){if ((y%4)==0 && (y%100)!=0 || (y%400)==0) return true;}

function Calendar_getFromVKHEXBitfield(bitfield) {
   this.dataPeriodS = new Date("20"+bitfield.substr(4,2),bitfield.substr(2,2),bitfield.substr(0,2));
   this.dataPeriodS.setMonth(this.dataPeriodS.getMonth() - 1);

   this.dataPeriodE = new Date("20"+bitfield.substr(10,2),bitfield.substr(8,2),bitfield.substr(6,2));
   this.dataPeriodE.setMonth(this.dataPeriodE.getMonth() - 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;
   }
}


