/*
 * hafas_standard_calendar_combined.js
 * built: 27.10.2008 by MHEI
 */

function eId() {
   return document.getElementById(arguments[0]);
}

function isFunction(o) {
   return (typeof (o) == "function");
}

function isObject(a) {
   return (typeof a == 'object' && !!a) || isFunction(a);
}

function isArray(a) {
   return isObject(a) && a.constructor == Array;
}

function isDate(a) {
   return isObject(a) && a.constructor == Date;
}

function isString(a) {
   return typeof a == 'string';
}

// removes given element from position in DOM tree and appends it to the body
// (good for absolute positioning, ...)
function moveToBody(element) {
   if (isObject(element)) {
      // is object already in DOM tree?
      if (element.parentNode != null) {
         var child = element.parentNode.removeChild(element);
      } else {
         var child = element;
      }
      document.body.appendChild(child);
      return child;
   } else {
      return element;
   }
}

// Date object enhancements:
Date.prototype.isLeapYear = function() {
   var year = this.getFullYear();
   return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
}

Date.prototype.getDaysInMonth = function() {
   daysInMonth =
   [ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ];
   daysInMonth[1] = this.isLeapYear() ? 29 : 28;
   return Date.daysInMonth[this.getMonth()];
}

Date.prototype.getWeek = function() {
   var d = new Date(this);
   d.setDate(d.getDate() - (d.getDay() + 6) % 7 + 3); // Nearest Thu
   var ms = d.valueOf(); // GMT
   d.setMonth(0);
   d.setDate(4); // Thu in Week 1
   return Math.round((ms - d.valueOf()) / (7 * 864e5)) + 1;
}

Date.prototype.shiftD = function(value) {
   this.setDate(this.getDate() + value);
}

Date.prototype.shiftM = function(value) {
   this.setMonth(this.getMonth() + value);
}

Date.prototype.shiftY = function(value) {
   this.setYear(this.getYear() + value);
}

function parseUserDateInput(userInput,weekdaysTexts) {
  if (isString(userInput) && (userInput.length>0) && !isDate(userInput)) {

      if ((userInput.length > 2) || (userInput.indexOf("+") != -1)) {
         var matchReg = /(\d+)\D+(\d+)\D+(\d+)\D*/;
         if(matchReg.exec(userInput))
           {
           var day = 1 * RegExp.$1;
           var month = 1 * RegExp.$2;
           var year = 1 * RegExp.$3;

           // attention: month is 1-12-ranged!
           // ~~~
           if (month != "") {
              month -= 1;
              if (month < 0) {
                 month = 11;
              } else if (month > 11) {
                 month = 0;
              }
           }
           if (year != "") {
              if (year < 100) {
                 if (year < 50) {
                    year += 2000;
                 } else {
                    year += 1900;
                 }
              } else if (year < 1000) {
                 if (year < 200) {
                    year += 1900;
                 } else {
                    year += 1000;
                 }
              }
           }
           if ((year != 0) && (day != 0)) {
              return new Date(year, month, day);
           }
         }

      }

      // else if (userInput.length == 2) {
      //   this.mydoWeekday(userInput);
      //}
   } else if (isDate(userInput)) {
      return userInput;
   }
   if(typeof(parseUserDateInputNoCurrentDate) == "undefined")
     {
      return new Date();
     }
}

var Class =
{
   create : function() {
      return function() {
         this.initialize.apply(this, arguments);
      }
   }
}

CalUtils = Class.create();
CalUtils.prototype =
{

    initialize : function() { // intentionally left blank

    },

    getDimensions : function(el) {
       var display = el.style.display;
       var ret = new Object();
       var e = el;

       for ( ret.x = 0, ret.y = 0; e != null; ret.x += e.offsetLeft, ret.y += e.offsetTop, e = e.offsetParent)
          ;

       /* Safari bug */
       if (display != 'none' && display != null) {

          ret.w = el.offsetWidth;
          ret.h = el.offsetHeight;
       } else {

          /*
           *  All *Width and *Height properties give 0 on els with display none, so enable the el temporarily
           */
          var els = el.style;
          var orgVisibility = els.visibility;
          var orgPosition = els.position;
          var orgDisplay = els.display;
          els.visibility = 'hidden';
          els.position = 'absolute';
          els.display = 'block';

          ret.w = el.clientWidth;
          ret.h = el.clientHeight;

          els.display = orgDisplay;
          els.position = orgPosition;
          els.visibility = orgVisibility;
       }
       return ret;
    }

}

function inherits(base, extension) {
   for ( var property in base) {
      try {
         extension[property] = base[property];
      } catch (warning) {
      }
   }
}

function makeObservable(obj, observer) {
   inherits(new Observable(), obj);
   if (observer != undefined) {
      obj.addObserver(observer);
   }
}

Array.prototype.forEach = function(fn, thisObj) {
   var scope = thisObj || window;
   for ( var i = 0, j = this.length; i < j; ++i) {
      fn.call(scope, this[i], i, this);
   }
};

Array.prototype.filter = function(fn, thisObj) {
   var scope = thisObj || window;
   var a = [];
   for ( var i = 0, j = this.length; i < j; ++i) {
      if (!fn.call(scope, this[i], i, this)) {
         continue;
      }
      a.push(this[i]);
   }
   return a;
};

Observer = Class.create();
Observer.prototype =
{
    initialize : function() {// intentionally left blank
    },
    observe : function() {
    }
}

function Observable() {
   this.fns = [];
}

Observable.prototype =
{
    addObserver : function(fn) {
       this.fns.push(fn);
    },
    removeObserver : function(fn) {
       this.fns = this.fns.filter( function(el) {
          if (el !== fn) {
             return el;
          }
       });
    },
    notify : function(o, thisObj) {
       var scope = thisObj || window;
       this.fns.forEach( function(el) {
          // el.call(scope, o);
              el.observe(o);
           });
    }
};



function listenToEvent(node,eventHandler,func){
  if(node.addEventListener)
    {
    node.addEventListener(eventHandler,function(){func.apply(node,arguments);},false);
    }
  else if(node.attachEvent)
    {
    node.attachEvent("on"+eventHandler,function(){func.apply(node,arguments);});
    }
  }

/*
 *  functions to synchronize and manage datefields
 */
CalendarControl = Class.create();
CalendarControl.prototype =
{
    version :"1.1",
    type :"calendarcontrol",

    value :"",
    today :"",
    fieldName :"",
    returnFormname :"",
    viewPeriodS :"",
    viewPeriodE :"",
    dataPeriodS :"",
    dataPeriodE :"",
    monthsTexts :null,
    weekdaysTexts :null,
    useWeekdays :true,
    closeText   :null,
    calendar :null,
    calendar_config :null,
    bitfield :null,

    initialize : function(calconfig) {
       inherits(new Observer(), this);
       inherits(calconfig, this);
       if (!isDate(this.value)) {
          this.value = this.today;
       }
       if (!isDate(this.today)) {
          this.today = new Date();
          this.value = this.today;
       }

    },

    getNewCalendar : function(calendar_config) {
       if (typeof calendar_config == "object") {
          var c = new Calendar(calendar_config);
       } else if (typeof this.calendar_config == "object") {
          var c = new Calendar(this.calendar_config);
       } else {
          alert("no calendar configuration found!");
       }

       c.viewPeriodS = this.viewPeriodS;
       c.viewPeriodE = this.viewPeriodE;
       c.dataPeriodS = this.dataPeriodS;
       c.dataPeriodE = this.dataPeriodE;
       c.bitfield = this.bitfield;
       c.bitfieldS = this.bitfieldS;
       c.bitfieldE = this.bitfieldE;
       c.monthsTexts = this.monthsTexts;
       c.weekdaysTexts = this.weekdaysTexts;
       c.useWeekdays = this.useWeekdays;
       c.closeText = this.closeText;
       c.value = this.value;
       c.today = this.today;
       c.myparent = this;
       c.id = this.id;
       c.name= this.id;

       c.setOneMonthOnly(true);
       inherits(calendar_config, c);
       makeObservable(c, this);
       listenToEvent(document.forms[this.formName.replace(/document\./,"")].elements[this.fieldName],"blur",function(){this.notify(this);});

       c.jumpToValue();

       var pdiv = document.createElement("DIV");
       pdiv.id = "calendar"+this.id;
       pdiv.className = this.styleClass;
       pdiv.style["display"] = "none";
       var myparent = eId(this.referenceObject).parentNode;
       myparent.appendChild(pdiv);

       c.div = document.createElement("DIV");
       var cal = eId("calendar"+this.id);
       var div = document.createElement("DIV");
       //div.style = "padding: 0px 0px 5px 0px; font-weight: bold;";

       var tt = document.createElement("TABLE");
       tt.style["width"] = "100%";
       var t = document.createElement("TBODY");
       var tr = document.createElement("TR");
       var td = document.createElement("TD");
       tr.appendChild(td);

       td = document.createElement("TD");
       td.innerHTML = "<a href=\"javascript:calman.toggleDisplay('"+this.id+"');void(0);\">"+this.closeText+"</a>";
       td.style["textAlign"] = "right";
       tr.appendChild(td);
       t.appendChild(tr);
       tt.appendChild(t);
       div.appendChild(tt);

       cal.appendChild(div);

       eId("calendar"+this.id).appendChild(c.div);

       c.draw();

       this.calendar = c;
       return c;
    },

    getStartDateFrom : function(ioField) {
       eval("userInput = " + this.formName + "." + ioField + ".value;");
       this.getStartDateFromString(userInput);
    },

    getStartDateFromString : function(datestring) {
       if (datestring == "today") {
          this.viewPeriodS = new Date();
       } else {
          this.viewPeriodS = parseUserDateInput(datestring);
          if (this.viewPeriodS == undefined) {
             this.viewPeriodS = new Date();
          }
       }
    },

    getEndDateFrom : function(ioField) {
       eval("userInput = " + this.returnForm + "." + ioField + ".value;");
       this.getEndDateFromString(userInput);
    },

    getEndDateFromString : function(datestring) {
       this.viewPeriodE = parseUserDateInput(datestring);
    },

    mydoWeekday : function(aValue) {
       if ((aValue.length == 2) && (aValue.indexOf("+") == -1)) {
         var wDay = this.weekdaysTexts.join("|").toLowerCase();
         var reg = eval("/^ *(" + wDay + ") */");
         aValue = aValue.toLowerCase();
         var test = aValue.match(reg);
         if (test != null) {
           var date = new Date();
           var cwdidx = date.getDay() - 1;
           cwdidx = (cwdidx == -1) ? cwdidx = 6 : cwdidx;
           var nwdidx = (wDay.indexOf(test[0]) / 3);
           if (nwdidx < cwdidx) {
              nwdidx = nwdidx + 7 - cwdidx;
           } else {
              nwdidx = nwdidx - cwdidx;
           }
            date.shiftD(nwdidx);
            return date;
         } else {
            return aValue;
         }
       } else if (aValue.indexOf("+") == 0) {
           var date = new Date();
           date.shiftD(1*aValue.slice(1));
           return date;
       }
       else
         {
         var date = parseUserDateInput(aValue);
         return date;
         }

    },

    // prepare for display
    formatDate : function(date, showShortYear, showDayNames) {
       if (isDate(date)) {

          var d = date.getDate();
          var m = date.getMonth() + 1;
          var y = date.getFullYear();

          if (d < 10) {
             d = "0" + d;
          }
          if (m < 10) {
             m = "0" + m;
          }

          /* has to be after the previous step for interpreting purposes */
          if (showShortYear) {
             y -= 2000;
             if (y < 10) {
                y = "0" + y;
             }
          }
          if (showDayNames) {
             var dayT = date.getDay() - 1;
             dayT = (dayT == -1) ? dayT = 6 : dayT;
             return this.weekdaysTexts[dayT] + ", " + d + "." + m + "." + y;
          } else {
             return d + "." + m + "." + y;
          }
       } else {
          return "";
       }
    },

    setDate : function(date) {
       if (!isDate(date)) {
          date = parseUserDateInput(date);
       }
       this.value = date;
       if (typeof this.calendar == "object") {
          this.calendar.value = date;
          this.calendar.jumpToValue();
          this.calendar.draw();
       }
    },

    setDateFromField : function() {
       v = document.forms[this.formName.replace(/document\./,"")].elements[this.fieldName].value;
       this.setDate(v);
    },

    toggleDisplay : function(topflip) {
       this.setDateFromField();

       var calid = this.id;
       var isShadow = false;

       var distyle = "inline";
       //var calendar = calman.calcons[calid].referenceObject;
       var callink = eId(calman.calcons[calid].referenceObject);
      // var callink = eId("callink" + calid);

       /*
        * take element in link as reference, since links seem to have always the same height
        */
       if (callink.hasChildNodes()) {
          var callink = callink.firstChild;
       }

       var div = eId("calendar" + calid);
       moveToBody(div);
       div.style.position = "absolute";

       if (isShadow) {
          var shadow = eId("calendarshadow" + calid);
          if (!isObject(shadow)) {
             shadow = document.createElement("DIV");
          }
          moveToBody(shadow);
          shadow.style.position = "absolute";
       }

       var iframe = eId("calendariframe" + calid);
       if (iframe == null) {
          iframe = document.createElement("iframe");
       }
       document.body.appendChild(iframe);
       iframe.id = "calendariframe" + calid;
       iframe.style.position = "absolute";
       calUtils = new CalUtils();

       var divDim = calUtils.getDimensions(div);

       iframe.width = divDim.w + "px";
       iframe.height = divDim.h + "px";

       var dim = calUtils.getDimensions(callink);

       if (!topflip) {
          div.style.top = (dim.y - 1) + "px";
          div.style.left = (dim.x - 1) + "px";

          if (isShadow) {
             shadow.style.top = (dim.y + 1) + "px";
             shadow.style.left = (dim.x + 1) + "px";
          }

          iframe.style.top = (dim.y + 1) + "px";
          iframe.style.left = (dim.x + 1) + "px";
       } else {
          div.style.top = (dim.y + dim.h - divDim.h) + "px";
          div.style.left = (dim.x - 1) + "px";
          if (isShadow) {
             shadow.style.top = (dim.y + 4 + dim.h - divDim.h) + "px";
             shadow.style.left = (dim.x - 1) + "px";
          }
          iframe.style.top = (dim.y + dim.h - divDim.h) + "px";
          iframe.style.left = (dim.x - 1) + "px";
       }

       /* display: */
       div.style.display = (div.style.display != "none") ? "none" : distyle;
       if (isShadow) {
          shadow.style.display = div.style.display;
       }
       iframe.style.display = div.style.display;
       return false;
//       return this.calendar.hideCallBack(topflip);
    }

}

//function toggleDivCal(calid, topflip) {
//}

Calendar = Class.create();
Calendar.prototype =
{
    version :"1.0",
    type :"calendar",

    value :"",

    initialize : function(config) {
       if (isObject(config)) {
         this.name = config.id;
         this.id = config.id;
         if (isDate(config.value)) {
            this.value = config.value;
         }
       }

       this.useDataPeriod = true;
       this.readOnly = false;
       this.showWeekNumbers = false;
       this.internalScrollers = true;

       this.selectedDay = null;
       this.preSelectedDay = null;
       this.multipleSelect = false;

       this.fullMonthsOnly = true;
       this.scrollable = true;

       this.monthsTexts = null;
       this.weekdaysTexts = null;
       this.closeText = null;
       this.prevMonthHTML = "&laquo;";
       this.nextMonthHTML = "&raquo;";
       this.weekNoHTML = "&nbsp;";

       this.howManyDays = 0;
       // this.hideCallBackName = "toggleDivCal";
    },

    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) {
          /* set time to 00:00 */
          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 time to 00:00 */
       var tmpdt = new Date(this.viewPeriodS.getFullYear(), this.viewPeriodS.getMonth(), this.viewPeriodS.getDate());
       var days = 0;
       while (tmpdt.getTime() <= this.viewPeriodE.getTime()) {
          days++;
          tmpdt.shiftD(1);
       }
       return days;
    },

    setPreselectedDate : function(dateparam) {
       /* read date from given inputfields */

       var date = parseUserDateInput(dateparam);

       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") {
     if (isString(this.hideCallBackName)) {
      /* da es nur 2 Kalender geben kann - letztes Zeichen des Namens (0 oder 1) nehmen */
      //var temp = this.name.charAt(this.name.length - 1);
      var temp = this.id;

      /*  falls es nur einen Kalender gibt, hat dieser kein Suffix */
      if (isNaN(temp)) temp = "";
      temp = this.hideCallBackName + "('" + temp + "');";
      eval(temp);
     } else {
      alert("No callback method (hideCallBackName) defined!");
     }
    },

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 = eId(cell);
         tempday.className = (tempday.className == "active") ? "enabled" : "active";
      } else {
         /* remove old selection - select ONE day only */
         if (this.selectedDay != null) {
            tempday = eId(this.selectedDay);
            tempday.className = (typeof this.bitfield != "undefined") ? "working" : "enabled";
         }
         this.selectedDay = cell;
         tempday = eId(cell);
         tempday.className = (tempday.className == "active") ? "enabled" : "active";

         this.name = ""+this.name;
         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.myparent.toggleDisplay();
      }
   }
},
/* This function fills the calendar table with the days of the selected month and year. */
draw : function() {
   this.howManyDays = this.getHowManyDays();

   /*
    * calc difference in days between viewPeriodS and dataPeriodS to find
    * bitfield begin...
    */
   if (this.bitfield && this.useDataPeriod) {

      var tmpdt = new Date(this.dataPeriodS);
      var bitfieldindex = 0;
      if (tmpdt.getTime() < this.viewPeriodS.getTime()) {
         while (tmpdt.getTime() < this.viewPeriodS.getTime()) {
            bitfieldindex++;
            tmpdt.shiftD(1);
         }
      } else {
         while (tmpdt.getTime() > this.viewPeriodS.getTime()) {
            bitfieldindex--;
            tmpdt.shiftD(-1);
         }
      }
   }
   //var div = eId(this.divid);
   var div = this.div;

   /* create table if it does not already exist */
   var table = eId(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 = eId(this.name + "_tbody");
   if (tbody != null) {
      tbody.parentNode.removeChild(tbody);
   }

   tbody = document.createElement("TBODY");
   table.appendChild(tbody);
   tbody.id = this.name + "_tbody";
   /* update header and status texts */
   tmpdt = new Date(this.viewPeriodS);

   /* show month name above weekdays */
   if (this.oneMonthOnly) {
      /* create row for month name */
      var current_row = document.createElement("TR");
      if (this.scrollable) {
         if (this.internalScrollers) {
            var current_cell = document.createElement("TH");
            current_cell.id = this.name + "_heading_months_lt";
         } else {
            var current_cell = eId(this.name + "prev");
         }
         var tmpdt2 = new Date(tmpdt);
         tmpdt2.setDate(1);
         if (((!this.useDataPeriod) || (!this.dataPeriodS) || (this.dataPeriodS && (tmpdt2.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);
                  calman.calcons[calid].calendar.prevMonth();
               }
            } else {
               current_cell.onclick = function() {
                  var calid = this.id.substring(0, this.id.indexOf("prev"));
                  //var test = eval('calid') + ".prevMonth();";
                  //eval(test);
                  calman.calcons[calid].calendar.prevMonth();
               }
            }
         } else {
            current_cell.innerHTML = "";
            current_cell.className = "disabled";
         }
         if (this.internalScrollers) {
            current_row.appendChild(current_cell);
         }
      }
      current_cell = document.createElement("TH");
      var colSpan = ((this.scrollable) && (this.internalScrollers)) ? 6 : 8;
      if (!this.showWeekNumbers) {
         colSpan = colSpan - 1;
      }
      current_cell.colSpan = colSpan;
      current_cell.innerHTML = this.monthsTexts[tmpdt.getMonth()] + "&nbsp;" + tmpdt.getFullYear();
      current_cell.textAlign = "center";
      current_cell.id = this.name + "_heading_months" + tmpdt.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);
            calman.calcons[calid].calendar.selectMonth(month);
         }
      } 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 = eId(this.name + "next");
         }
         var tmpdt2 = new Date(tmpdt);
         tmpdt2.setDate(1);
         tmpdt2.shiftM(1);
         tmpdt2.shiftD(-1);
         if ((!this.useDataPeriod) || (!this.dataPeriodE) || (this.dataPeriodE && (tmpdt2.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();";
                  //eval(test);
                  calman.calcons[calid].calendar.nextMonth();
               }
            } else {
               current_cell.onclick = function() {
                  var calid = this.id.substring(0, this.id.indexOf("next"));
                  //var test = eval('calid') + ".nextMonth();";
                  //eval(test);
                  calman.calcons[calid].calendar.nextMonth();
               }
            }
         } 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);
            calman.calcons[calid].calendar.selectDays(day);
         }
      } 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
    */
   var daystoskip = (tmpdt.getDay() - 1 < 0) ? 6 : tmpdt.getDay() - 1;

   var daysdrawn = 0;
   var newmonth = false;
   var oldtempcolspan = 0;
   var colspan = 1;

   var w = -1;
   var startweek = tmpdt.getWeek();
   var newWeekNeeded = true;
   while (newWeekNeeded) {
      w++;

      if (((tmpdt.getDate() == 1 && newmonth) || (daysdrawn == 0)) && (tmpdt.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 = (tmpdt.getDay() - 1 < 0) ? 6 : tmpdt.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[tmpdt.getMonth()] + " - " + tmpdt.getFullYear();
            current_cell.id = this.name + "_heading_months" + tmpdt.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);
                  calman.calcons[calid].calendar.selectMonth(month);
               }
            } else {
               current_cell.className = "disabled";
            }
            current_row.appendChild(current_cell);

            tbody.appendChild(current_row);
         }

      }

      current_row = eId(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 ((tmpdt.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(tmpdt);

            if ((this.useDataPeriod) && (bitfieldindex + daysdrawn >= 0) && (this.dataPeriodS) && (this.dataPeriodE) && (tmpdt.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);
                     calman.calcons[calid].calendar.setDate(this.id);
                  };
               } else {
                  cell.className = "notworking";
                  cell.onclick = null;
               }
               /* mark today and the active day */
               if (this.today.getTime() == tmpdt.getTime()) {
                  cell.className = cell.className + " today";
               }
               if (this.value.getTime() == tmpdt.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);
                  //alert(this.id);
                  calman.calcons[calid].calendar.setDate(this.id);
               };
            }
            cell.innerHTML = tmpdt.getDate();
            /* increase already drawn days by one */
            tmpdt.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 */
         tmpdt.shiftD(-1);
         if (tmpdt.getTime() < this.dataPeriodS.getTime()) {
            cell.className = "disabled before_period";
            cell.onclick = null;
         }
         if (tmpdt.getTime() > this.dataPeriodE.getTime()) {
            cell.className = "disabled beyond_period";
            cell.onclick = null;
         }
         tmpdt.shiftD(1);

         current_row.appendChild(cell);
      }
      if ((tmpdt > 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 <= colSpan; i++) {
         var cell = document.createElement("TD");
         cell.className = "disabled";
         cell.innerHTML = "&nbsp;";
         row.appendChild(cell);
      }
      tbody.appendChild(row);
   }

   /* auto-correction of div size */
   //eId(this.divid).style.width = "auto";
   this.div.style.width = "auto";
   if (this.preSelectedDay != undefined) {
      tempday = eId(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: Calendar  */

CalendarManager = Class.create();
CalendarManager.prototype =
{
    type :"CalendarManager",
    calcons :new Array(),

    initialize : function() {
    },

    getNewCalCon : function(calcon_config) {
       var calcon = new CalendarControl(calcon_config);
       inherits(this.config, calcon);
       calcon.myparent = this;
       this.calcons[calcon_config.referenceObject] = calcon;
       calcon.id = calcon_config.referenceObject;

       calcon.observe = function (aValue)
          {
            parseUserDateInputNoCurrentDate = true;
            //console.log("OBSERVED: "+aValue.id);
            var date = aValue.value;
            // check special input types
            if (aValue.type == "text") {
            // Weekday advance (eg. so, fr,...)
              date = this.mydoWeekday(date);
            }

            // do date fields syncronisations
            if(isDate(date))
              {
              this.setDate( date );
              }

            if (isDate(date)) {
              document.forms[this.formName.replace(/document\./,"")].elements[this.fieldName].value = this.formatDate(this.value,this.showShortYear,this.useWeekdays);
            }

            // set backward date to departure date
            /*
            var id = this.id.substring(this.id.length-1,this.id.length);
            if (id == 0) {
              var id2 = this.id.substring(0,this.id.length-1)+"1";
              var ret = calman.calcons[id2];
              // NO typeof HERE!!
              if (isObject(ret) && ret.type == "calendarcontrol") {
                var retdate = ret.value;
                if (date > retdate) {
                  ret.setDate(date);
     						  ret.observe(ret);
	  						}
							}
						}
            */
           if((this.returnCalId) && (calman.calcons[this.returnCalId]))
             {
             var ret = calman.calcons[this.returnCalId];
              // NO typeof HERE!!
              if (isObject(ret) && ret.type == "calendarcontrol") {
                retField = document.forms[ret.formName.replace(/document\./,"")].elements[ret.fieldName];
                var tmpDate = parseUserDateInput(retField.value);
                if((retField) && !(retField.value.match(/^\s*$/)) && (typeof(tmpDate) != "undefined"))
                  {
                  var retdate = ret.value;
                  var tmpDate = new Date(date);
                  if(this.returnCalShift)
                    tmpDate.setDate(tmpDate.getDate()+this.returnCalShift)
                  if (tmpDate > retdate) {
                    ret.setDate(date);
                    if(this.returnCalShift)
                      ret.value.shiftD(this.returnCalShift);
                    ret.observe(ret);
                  }
	  						}
							}
             }

           if (this.callback != null) {
              this.callback(aValue);
           }

          delete parseUserDateInputNoCurrentDate;
          }
       // observe input field
       makeObservable(document.forms[calcon.formName.replace(/document\./,"")].elements[calcon.fieldName], calcon);

       return calcon;
    },

    createCalendar : function(calcon_config){
        var calcon = calman.getNewCalCon(calcon_config);
        calcon.getNewCalendar();
        return calcon.id;
    },

    shiftDate : function(id, value) {
      var calcon = this.calcons[id];
      calcon.setDateFromField();
      var date = calcon.value;
      date.shiftD(value);
      calcon.observe(calcon);
    },

    toggleDisplay : function(id) {
        this.calcons[id].toggleDisplay();
    }
}

// initialize global CalendarManager
// DO NOT RENAME - ONLY GLOBAL OBJECT
calman = new CalendarManager();

