

if (!jcalendars) 
{
  var jcalendars = [];
};

padZero=function (n) 
{
  n = parseInt(n, 10);
  return n < 10 ? '0' + n : n;
}

sign = function (num)
{
    var ret = 1;

    if( num != 0 )
    {
        ret = Math.abs(num) / num;
    }
    else
        ret = 1;
    
    return ret;
}

var monthesArray;
var daysArray;
var baseDir;
var imgDir;
var cssDir;
var lang='en';
var am='AM';
var pm='PM';
var dayHeaderBGColor;
var dayBGColorActive;
var dayBGColorOver;
var clearButtonValue ;
var drawedControls = new Array();
found =function(id)
  {
   for(var i=0;i<drawedControls.length;i++)
   {
    if(drawedControls[i]==id) return true;
   }
   return false;
  }
initCalendar=function (id,isTimeOnly,isSecondary,enableClear,readOnly,rowIndex)
{

    myCalendar = new Calendar();
    
    myCalendar.months   = monthesArray;
    myCalendar.days     = daysArray;
    myCalendar.am       = am;
    myCalendar.pm       = pm;
    myCalendar.language = lang;
    myCalendar.baseDir  = baseDir;
    myCalendar.imgDir   = imgDir;
    myCalendar.cssDir   = cssDir;
    myCalendar.withTime = isTimeOnly; 
    myCalendar.isTimeOnly=isTimeOnly;
    myCalendar.isSecondary=isSecondary;
    myCalendar.rowIndex = rowIndex;
    myCalendar._clearButtonActive=enableClear;
    myCalendar.readOnly  = readOnly;
    myCalendar.draw(id);
   
    return myCalendar.HTMLValue;
    
}
Calendar=function() 
{
  
  this._isDrawed = false;
  this._isRendered= false;
  this._clearButtonActive = false;
  this._clearButtonStr = "display:block";
  this.readOnly = false;
  this.realId;
  this._id;
  this._objectId;
  this.fieldId;
  this.fieldName;
  this._visibleFieldId;
  this.baseDir;   //for further use
  this.imgDir;
  this.cssDir;
  this.autoClose  = true;
  this.language;
  this.isSecondary=false;
  this.rowIndex=0;
  this.isTimeOnly=false;
  this.months = new Array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December');
  this.monthNumChars = 0;
  this.weekStart = 1;   //not used yet
  this.days = new Array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday');
  this.daysNumChars = 3;
  this.useYearField = 3;
  this.useMonthField = 2;
  this.useSpinEditForYear	= true;
  this.useArrows = false;
  this.useButtonToday = false;
  this.dayHeaderFontColor = 'white';
  this.dayHeaderBgColor   = dayHeaderBGColor;//'#5B96CE';
  this.dayFontColor       = 'black';
  this.dayBgColor         = 'white';
  this.dayFontColorActive = 'black';
  this.dayBgColorActive   = dayBGColorActive;//'#C3DDF6';
  this.dayTableBgColor    = 'white';
  this.dayBgColorOver     = dayBGColorOver;//'#C3DDF6';
  this.dayTableAttributeString = 'width="100%" border="0" cellspacing="0" cellpadding="3"';
  this.width = 190;
  this._dateFormat = 'eu';  
  this.withTime = false;  
  this.dayClassNameByDay = new Array();
  this.allowedWeekdays = new Array(true, true, true, true, true, true, true);
  this._currentDate  = '';  
  this._currentTime  = '';
  this._currentYear  = 0;
  this._currentMonth = 0;  
  this._currentDay   = 0;
  this._currentHour = '09';
  this._currentMinute   = '00';
  this._currentSeconds  = '00';
  this._currentAMPM = this.am="AM";
  this.am="AM";
  this.pm="PM";
  this.dateToday = new Date();
  this.holidays = new Array(new Array(null, 1, 1), new Array(null, 12, 31));
  this.maxYear = 2100;
  this.minYear = 1800;  
  this.is24H = false;	    
  this.hourMarker = ":";  
  this.timeMarker = " ";  
  this.minuteInc = 1;	
  this.secInc = 1;
  this._dateTimeLong;
  this.submittedDateFormat = 'dmy';   //dmy : dd/mm/yy 
  this.annoyingElementsTags = new Array("applet", "iframe", "select","object");
  this.annoyingElementsIds;
  this._hidden = true;
  
  this._constructor = function() 
  {
    
    this._id = jcalendars.length;
    jcalendars[jcalendars.length] = this;
    this._objectId = "jcalendar_" + padZero(this._id);    
    
    
  }  
  
  this.getDate = function(format) //0: full date format, 1: submitted date format, 2: displayed date format
  {

    switch(format)
    {
      case 0:
        if(!this.withTime)
          currentDate = new Date(this._currentYear, this._currentMonth, this._currentDay, 0, 0, 0);
        else if(this.is24H)
          currentDate = new Date(this._currentYear, this._currentMonth, this._currentDay, this._currentHour, this._currentMinute, this._currentSeconds);
        else
          currentDate = new Date(this._currentYear, this._currentMonth, this._currentDay, this.stretchHour(this._currentHour), this._currentMinute, this._currentSeconds);
        break;
      case 1:
        currentDate = this._dateTimeLong;
        break;
      case 2:
        currentDate = this._currentDate;
        if(this.withTime)
          currentDate += " " + this._currentTime;
        break;
      default:
        return '';
    }
    return currentDate;
  }
  
  this.resetDate = function()
  {
    var fld = document.getElementById(this.fieldId);
    fld.value = '';
    this.setDateTime(fld);
    
    var vfld = document.getElementById(this._visibleFieldId);
    vfld.value = '';
    
    this._reRenderCalendar();
  }
  
  this.toggleSelector = function() 
  {
   
    var div = document.getElementById(this._objectId + '_div');
    
    if(!this._isRendered)
    {
     div.innerHTML = this.renderDatePicker();
     this._isRendered=true;
    }
    if (div.style.display == 'none') 
    {
     // hideCombosInCalenderRegion(this._objectId, this.isSecondary, this.rowIndex);
      this._hidden = false;
      div.style.display = 'block';      
      var inputField = document.getElementById(this._visibleFieldId);
      if (inputField.offsetLeft > div.offsetLeft) 
      {
        div.style.marginLeft = inputField.offsetLeft + 'px';
      }
      this.hideAnnoyingColleagues();
      this.hideShowAnnoyingElements();
    } 
    else 
    {      
  //  showCombosInCalenderRegion(this._objectId, this.isSecondary, this.rowIndex);
      this.hideShowAnnoyingElements();
      this._hidden = true;
      div.style.display = 'none';
      var vf = document.getElementById(this._visibleFieldId)
      if(vf.value == '')
        this._dateTimeLong = '';
      else
        this.updateInputField();
    }
    
    //this.hideShowAnnoyingElements();
  }

  this.setDisabled = function(bool) 
  {
    try 
    {     
      if (bool) 
        document.getElementById('toggleButton').disabled = true;
      else 
        document.getElementById('toggleButton').disabled = false;
    } 
    catch (e) 
    {}
  }     
  
  this.hide = function()
  {    
    var div = document.getElementById(this._objectId + '_div');
    div.style.display = 'none';
    this._hidden = true;
    this.hideShowAnnoyingElements();
  }
 var objX;
 var objY;
 var objWidth;
 var objHeight;
 var objDirection="ltr";
 function findLeftOffset(obj)
 {
 	var curleft = 0;
 	if (obj.offsetParent)
 	{
 		while (obj.offsetParent)
 		{
 			curleft += obj.offsetLeft
 			obj = obj.offsetParent;
 		}
 	}
 	else 
 		curleft = obj.offsetTop;
 	return curleft;
 }
function findTopOffset(obj)
{
	var curtop = 0;
	if (obj.offsetParent)
	{
		while (obj.offsetParent)
		{
			curtop += obj.offsetTop
			obj = obj.offsetParent;
		}
	}
	else 
		curtop = obj.offsetTop;
	return curtop;
}
this.draw = function(visibleFieldId) 
  {
    if(this._clearButtonActive)
        this._clearButtonStr = "display:block"; 
    else
        this._clearButtonStr = "display:none"; 
    var visibleField = document.getElementById(visibleFieldId);

    if( visibleField.offsetWidth )
    {
      objWidth=visibleField.offsetWidth ;
      objHeight=visibleField.offsetHeight;
    }
    else
    {
      objWidth=visibleField.scrollWidth;
      objHeight=visibleField.scrollHeight;
    }

   // var pos = getAbsolutePos(visibleField)
    if(this.isSecondary){
        objY=visibleField.offsetTop;//findTopOffset(visibleField);
        objX=findLeftOffset(visibleField);
        //objX = visibleField.style.left;
       // objY= visibleField.style.top;
        
    }else{
     objY=visibleField.offsetTop;
     objX=visibleField.offsetLeft;
     objDirection=visibleField.style.direction;
    }
   // objY=visibleField.offsetTop; //findTopOffset(visibleField);
    //objX=findLeftOffset(visibleField);
    
    if ((visibleField == null) || !visibleField) 
      return false; 
    
    this.setDateTime(visibleField);        
    this._visibleFieldId = visibleFieldId;   
    
    visibleField.value=this._dateTimeLong;
    if(this.isSecondary)
     this.fieldId = "jcalendar_" + visibleField.id;   
    else
     this.fieldId = "jcalendar_" + visibleField.name;   
    this.fieldName = visibleField.name;
    var rendered = this.render(getOuterHTML(visibleField));
    this.HTMLValue= rendered;
    setOuterHTML(visibleField, rendered);
    return true;
  } 
  
  this.render = function(InputFieldCode) 
  {
    
    this.loadSkin();   
    
    if(objDirection == 'rtl')
    {
    	imageX=objX-20;
    }else{
    	imageX=objX+objWidth+5;
    }
    imageY=objY+objHeight/8;
    var ret = new Array();
      if(this.isSecondary){
           ret[ret.length] = ' <table border="0" cellspacing="0" cellpadding="0" width="100%" >';
           ret[ret.length] = ' <tr><td nowrap="nowrap">';       
           ret[ret.length] = InputFieldCode+'</td>';
           if(!this.readOnly)
            ret[ret.length] = ' <td nowrap="nowrap"><img  id="toggleButton" border="0" width="12" height="12" onclick="jcalendars['+this._id+'].toggleSelector();" src="'+this.imgDir+'/calendar.gif"></td>';
    	   ret[ret.length] = ' </td></tr></table>';
           ret[ret.length] = '<div id="' + this._objectId + '_div"';
           ret[ret.length] = ' style=" width:' + this.width + 'px; position:absolute; display:none;z-index=1000"';      
           ret[ret.length] = ' class="BsDp_div"';
           ret[ret.length] = '>';
      }else{

        ret[ret.length] = ' <table border="0" cellspacing="0" cellpadding="0" width="100%" >';
        ret[ret.length] = ' <tr><td nowrap="nowrap">';       
        ret[ret.length] = InputFieldCode;
        if(!this.readOnly)
            ret[ret.length] = ' <img style="position:absolute;top:'+imageY+'px;left:'+imageX+'px" id="toggleButton'+this._id+'" border="0" onclick="jcalendars['+this._id+'].toggleSelector();" src="'+this.imgDir+'/calendar.gif">';
    	ret[ret.length] = ' </td></tr></table>';
        ret[ret.length] = '<div id="' + this._objectId + '_div"';
        ret[ret.length] = ' style="top:'+(objY+objHeight)+'px;left:'+objX+'px; width:' + this.width + 'px; position:absolute; display:none;z-index=1000"';      
        ret[ret.length] = ' class="BsDp_div"';
        ret[ret.length] = '>';
      }
    
    
   // ret[ret.length] = this.renderDatePicker();
    ret[ret.length] = '</div>'; 
    drawedControls[drawedControls.length]=this._visibleFieldId;
    return ret.join('');
   
  }
 this.clearField = function()
 {
  var fld = document.getElementById(this._visibleFieldId);
  fld.value="";
  
 }
  this.renderDatePicker = function() 
  {  
  
    var dateStr = this._getCurrentDateFormatted();
    var currentDay   = dateStr.substr(0, 2);
    var currentMonth = dateStr.substr(3, 2);
    var currentYear  = dateStr.substr(6, 4);
    
    var ret = new Array();
    if (this._currentDate.length == 0) 
    {
      this.seedInternalWithCurrentDate();
    }
    ret[ret.length] = '<div class="BsDp_monthYearDiv">';
    ret[ret.length] = '<table border="0" width="100%" cellpadding="0" cellspacing="0" align="center"><tr>';
   
    if (this.useArrows) 
    {
      ret[ret.length] = '<td align="center" onclick="jcalendars['+this._id+'].dateCalc(0, -1);" style="cursor:hand;cursor:pointer;" class="BsDp_arrowLeft">';
      ret[ret.length] = '&nbsp;';
      ret[ret.length] = '<img src="' + this.imgDir + '/arrowLeft.gif' + '" align="middle" border="0"/>';
      ret[ret.length] = '&nbsp;';
      ret[ret.length] = '</span>';
      ret[ret.length] = '</td><td align="center">';
    } 
    else 
    {
      ret[ret.length] = '<td align="center">';
    }
    if(!this.isTimeOnly){
    if (this.useMonthField == 1) 
    {
      ret[ret.length] = '<span class="BsDp_monthText">' + this.months[this._currentMonth -1] + '</span>';
    } 
    else if (this.useMonthField == 2) 
    {
      ret[ret.length] = '<select name="' + this.fieldId + '_month"';
      ret[ret.length] = ' id="' + this._objectId + '_month" size="1"';
      ret[ret.length] = ' onChange="jcalendars['+this._id+'].updateByMonth();"';
      ret[ret.length] = ' class="BsDp_month"';
      ret[ret.length] = '>';
      var i = 1;
      for (var m = 0; m < this.months.length; m++) 
      {
        ret[ret.length] = '<option value="' + i + '"';
        if (currentMonth == i)
          ret[ret.length] = ' selected';
        ret[ret.length] = '>';
        if (this.monthNumChars > 0)
        {
          ret[ret.length] = this.months[m].substr(0, this.monthNumChars);
        } 
        else
        {
          ret[ret.length] = this.months[m];
        }
        ret[ret.length] = '</option>';i++;
      }
      ret[ret.length] = '</select>';
    }
    ret[ret.length] = '</td><td>&nbsp;&nbsp;';

    if (this.useYearField == 1) 
    {
      ret[ret.length] = '<span class="BsDp_yearText">' + this._currentYear + '</span>';
    } 
    else if (this.useYearField >= 2) 
    {      
      ret[ret.length] = '<input type="text" name="' + this.fieldId + '_year"';
      ret[ret.length] = ' id="' + this._objectId + '_year" value="' + currentYear + '"';
      ret[ret.length] = ' size="4" maxlength="4" onKeyUp="jcalendars['+this._id+'].updateByYearChange();"';
      ret[ret.length] = ' onBlur="jcalendars['+this._id+'].updateByYearBlur();"';
      ret[ret.length] = ' class="BsDp_year"';
      ret[ret.length] = '></td>';            
      if (this.useSpinEditForYear) 
      {
        ret[ret.length] = '<td><img onclick="jcalendars['+this._id+'].incYear();" style="margin-bottom: 2px" src="'+this.imgDir+'/arrowBlackUp.gif">';
        ret[ret.length] = '<br>';
        ret[ret.length] = '<img onclick="jcalendars['+this._id+'].decYear();" style="margin-top: 2px" src="'+this.imgDir+'/arrowBlackDown.gif"></td>';
      }
    }
    ret[ret.length] = '<td>&nbsp;&nbsp;</td><td><img src="'+this.imgDir+'/Deleted.gif" alt="'+clearButtonValue+'" onClick="jcalendars['+this._id+'].clearField();jcalendars['+this._id+'].toggleSelector();" name="ClearButton_"'+this._objectId+' id="ClearButton_"'+this._objectId+' style="'+this._clearButtonStr+'" /></td>';
    
    //  Hashem start on 15/08/2007
    //  I needed to add an empty cell as a space then add a cell that contains the close button for the date only
    
    if( !this.isTimeOnly )
    {
        ret[ret.length] = '<td>&nbsp;</td>';
        ret[ret.length] = '<td><img border="0" onclick="jcalendars['+this._id+'].toggleSelector();" src="'+this.imgDir+'/calclose.gif"></td>';
    }
    
    //  Hashem end
    
    if (this.useArrows) 
    {
      ret[ret.length] = '<td align="center" onclick="jcalendars['+this._id+'].dateCalc(0, 1);" style="cursor:hand;cursor:pointer;" class="BsDp_arrowRight">';
      ret[ret.length] = '&nbsp;';
      ret[ret.length] = '<img src="' + this.imgDir + '/arrowRight.gif' + '" align="middle" border="0"/>';
      ret[ret.length] = '&nbsp;';
    }
    ret[ret.length] = '</tr></table>';
    ret[ret.length] = '</div>';
    ret[ret.length] = '<div id="' + this._objectId + '_dayDiv" class="BsDp_dayTableDiv">';
    ret[ret.length] = this.renderDayTable(currentYear, currentMonth, currentDay);
    ret[ret.length] = '</div>';
    if (this.useButtonToday) 
    {
      ret[ret.length] = '<div class="BsDp_buttonsDiv">';
      ret[ret.length] = '<table align="center" border="0" cellpadding="1" cellspacing="0" width="100%">';
      ret[ret.length] = '<tr><td>';
      ret[ret.length] = '<img src="' + this.imgDir + '/en_btnToday.gif' + '" align="middle" border="0"';
      ret[ret.length] = ' onclick="jcalendars['+this._id+'].setDateByObject(jcalendars['+this._id+'].dateToday);"';
      ret[ret.length] = ' style="cursor:hand; cursor:pointer;"';
      ret[ret.length] = '/></td><td>&nbsp;&nbsp;</td>';
    } 
     
}
    if (this.withTime) 
    {
     
      ret[ret.length] = this.renderTimePicker()
    } 
    else
    {
      ret[ret.length] = '</td></tr></table></div>';
    }
    return ret.join('');
  }  

  this.renderDayTable = function(currentYear, currentMonth, currentDay) 
  {
    var day = 1;
    var lastDayOfMonth = this.getNumberOfDays(currentYear, currentMonth);
    var ret = new Array();    
    
    ret[ret.length] = '<table ' + this.dayTableAttributeString +' bgcolor="' + this.dayTableBgColor + '" class="BsDp_dayTable">';
    
    ret[ret.length] = '<tr bgcolor="' + this.dayHeaderBgColor + '">';      
    for (var d = 0; d < this.days.length; d++) 
    {
      ret[ret.length] = '<td width="14%" bgcolor="' + this.dayHeaderBgColor + '" align="right"';
      ret[ret.length] = ' title="' + this.days[d] + '"';
      ret[ret.length] = ' class="BsDp_dayHeader"';
      ret[ret.length] = ' style="color:' + this.dayHeaderFontColor + '; cursor:default;">';
      if(this.language == 'ar' || (!this.daysNumChars) || this.daysNumChars == 0)
        ret[ret.length] = this.days[d];
      else
        ret[ret.length] = this.days[d].substr(0, this.daysNumChars);
      ret[ret.length] = '</td>';
    }
    ret[ret.length] = '</tr>';
    
    var dateObjFirst = new Date(currentYear, currentMonth-1, 1, 0, 0, 0);
    var weekDayFirst = dateObjFirst.getDay();
    //Start
      //To be replaced by some algorithm realizing this.weekStart
    if (weekDayFirst == 0)
      weekDayFirst = 1;
    else if (weekDayFirst == 6)
      weekDayFirst = 0;
    else
      weekDayFirst++;
    var firstDayIndex = weekDayFirst;
    //End
            
    for (var i=0; i<6; i++) 
    {
      ret[ret.length] = '<tr>';
      
      for (var j=0; j<7; j++) 
      {
        var isSelectableDate = this.isDateSelectable(this._currentYear, this._currentMonth, day);
        
        if ((day > lastDayOfMonth) || ((i == 0) && (j < firstDayIndex))) 
        {
          ret[ret.length] = '<td>&nbsp;</td>';
        } 
        else 
        {
          ret[ret.length] = '<td " ';
          ret[ret.length] = ' id="' + this._objectId + '_td' + day + '"';
          ret[ret.length] = ' align="center"';
          if (isSelectableDate) 
          {
            ret[ret.length] = ' onMouseOver="jcalendars['+this._id+'].dayMouseOver(' + day + ');"'; 
            ret[ret.length] = ' onMouseOut="jcalendars['+this._id+'].dayMouseOut(' + day + ');"';
            ret[ret.length] = ' onClick="jcalendars['+this._id+'].updateByDay(' + day + ');"';
          }
          var classArr = new Array();
          classArr[classArr.length] = 'BsDp_day';
          if (typeof(this.dayClassNameByDay[day]) != 'undefined') 
            classArr[classArr.length] = this.dayClassNameByDay[day];
          if (this.isHoliday(this._currentYear, this._currentMonth, day)) 
          {
            classArr[classArr.length] = 'BsDb_holiday';
          }
          if ((this.dateToday.getDate() == day) && (this.dateToday.getMonth() == (this._currentMonth -1)) && (this.fixYear(this.dateToday.getYear()) == this._currentYear)) 
          {
            classArr[classArr.length] = 'BsDp_dayToday';
          }
          if (!isSelectableDate) 
            classArr[classArr.length] = 'BsDp_dayUnselectable';
          if (classArr.length > 0) 
          {
            ret[ret.length] = ' class="' + classArr.join(' ') + '"';
            ret[ret.length] = ' style="';
          } 
          else 
          {
            ret[ret.length] = ' style="font-family:arial; font-size:11px;';
          }
          if (isSelectableDate) 
          {
            ret[ret.length] = 'cursor:hand; cursor:pointer;';
          } 
          else 
          {
            ret[ret.length] = 'cursor:default;';
          }
          if (day == currentDay) 
          {
            ret[ret.length] = ' color:' + this.dayFontColorActive + '; background-color:' + this.dayBgColorActive + ';';
          } 
          else 
          {
          }
          ret[ret.length] = '">';
          ret[ret.length] = day;
          ret[ret.length] = '</td>';
          day++;
        }
      }
      ret[ret.length] = '</tr>';
      if (day >= (lastDayOfMonth +1)) 
        break;
    }
    ret[ret.length] = '</table>';    
    return ret.join('');
  }
  
  this.renderTimePicker = function()
  {    
    var ret = new Array();
   
    if(!this.useButtonToday)
    {
      ret[ret.length] = '<div  class="BsDp_monthYearDiv">';
      ret[ret.length] = '<table align="center" border="0" cellpadding="0" cellspacing="0" width="100%">';
      ret[ret.length] = '<tr><td>&nbsp;</td>';
    }
    if(this.language == 'ar')
    {
     //seconds
      ret[ret.length] = '<td><img onclick="jcalendars['+this._id+'].incSec();" style="margin-bottom: 2px" src="'+this.imgDir+'/arrowBlackUp.gif">';
      ret[ret.length] = '<br>';
      ret[ret.length] = '<img onclick="jcalendars['+this._id+'].decSec();" style="margin-top: 2px" src="'+this.imgDir+'/arrowBlackDown.gif"></td>';
      ret[ret.length] = '<td><input type="text" id="secF'+this._objectId+'" name="secF'+this._objectId+'" value="'+ this._currentSeconds +'" size="2" maxlength="2" style="width:21px; font-size:10px; height:18px; background-color:white;" onchange="jcalendars['+this._id+'].updateTimeStr()"></td>';
      
      ret[ret.length] = '<td nowrap>&nbsp;'+this.hourMarker+'</td>';
      //Minute    
      ret[ret.length] = '<td><img onclick="jcalendars['+this._id+'].incMin();" style="margin-bottom: 2px" src="'+this.imgDir+'/arrowBlackUp.gif">';
      ret[ret.length] = '<br>';
      ret[ret.length] = '<img onclick="jcalendars['+this._id+'].decMin();" style="margin-top: 2px" src="'+this.imgDir+'/arrowBlackDown.gif"></td>';
      ret[ret.length] = '<td><input type="text" id="minF'+this._objectId+'" name="minF'+this._objectId+'" value="'+ this._currentMinute +'" size="2" maxlength="2" style="width:21px; font-size:10px; height:18px; background-color:white;" onchange="jcalendars['+this._id+'].updateTimeStr()"></td>';
      // :
      ret[ret.length] = '<td nowrap>&nbsp;'+this.hourMarker+'</td>';
      //Hour
      ret[ret.length] = '<td><img onclick="jcalendars['+this._id+'].incHour();" style="margin-bottom: 2px" src="'+this.imgDir+'/arrowBlackUp.gif">'
      ret[ret.length] = '<br>'
      ret[ret.length] = '<img onclick="jcalendars['+this._id+'].decHour();" style="margin-top: 2px" src="'+this.imgDir+'/arrowBlackDown.gif"></td>';
      ret[ret.length] = '<td><input type="text" id="hourF'+this._objectId+'" name="hourF'+this._objectId+'" value="'+ this._currentHour +'" size="2" maxlength="2" style="width:21px; font-size:10px; height:18px; background-color:white;" onchange="jcalendars['+this._id+'].updateTimeStr()"></td>';    
    }
    else
    {
      //Hour
      ret[ret.length] = '<td><input type="text" id="hourF'+this._objectId+'" name="hourF'+this._objectId+'" value="'+ this._currentHour +'" size="2" maxlength="2" style="width:21px; font-size:10px; height:18px; background-color:white;" onchange="jcalendars['+this._id+'].updateTimeStr()"></td>';
      ret[ret.length] = '<td><img onclick="jcalendars['+this._id+'].incHour();" style="margin-bottom: 2px" src="'+this.imgDir+'/arrowBlackUp.gif">'
      ret[ret.length] = '<br>'
      ret[ret.length] = '<img onclick="jcalendars['+this._id+'].decHour();" style="margin-top: 2px" src="'+this.imgDir+'/arrowBlackDown.gif"></td>';
      // :
      ret[ret.length] = '<td nowrap>'+this.hourMarker+'&nbsp;</td>';
      //Minute
      ret[ret.length] = '<td><input type="text" id="minF'+this._objectId+'" name="minF'+this._objectId+'" value="'+ this._currentMinute +'" size="2" maxlength="2" style="width:21px; font-size:10px; height:18px; background-color:white;" onchange="jcalendars['+this._id+'].updateTimeStr()"></td>';
      ret[ret.length] = '<td><img onclick="jcalendars['+this._id+'].incMin();" style="margin-bottom: 2px" src="'+this.imgDir+'/arrowBlackUp.gif">';
      ret[ret.length] = '<br>';
      ret[ret.length] = '<img onclick="jcalendars['+this._id+'].decMin();" style="margin-top: 2px" src="'+this.imgDir+'/arrowBlackDown.gif"></td>';
      
      ret[ret.length] = '<td nowrap>'+this.hourMarker+'&nbsp;</td>';
      //seconds
      ret[ret.length] = '<td><input type="text" id="secF'+this._objectId+'" name="secF'+this._objectId+'" value="'+ this._currentSeconds +'" size="2" maxlength="2" style="width:21px; font-size:10px; height:18px; background-color:white;" onchange="jcalendars['+this._id+'].updateTimeStr()"></td>';
      ret[ret.length] = '<td><img onclick="jcalendars['+this._id+'].incSec();" style="margin-bottom: 2px" src="'+this.imgDir+'/arrowBlackUp.gif">';
      ret[ret.length] = '<br>';
      ret[ret.length] = '<img onclick="jcalendars['+this._id+'].decSec();" style="margin-top: 2px" src="'+this.imgDir+'/arrowBlackDown.gif"></td>';
      
    }
    //AM-PM
    ret[ret.length] = (this.is24H?'':'<td>'+this.timeMarker+'&nbsp;</td><td><input type="Text" id="ampm'+this._objectId+'" value="'+ this._currentAMPM +'" name="ampm'+this._objectId+'" size="2" maxlength="2" style="width:21px; font-size:10px; height:18px; background-color:white;" readonly onclick="jcalendars['+this._id+'].flipAmPm();this.blur()"></td>');
    ret[ret.length] = '<td>&nbsp;&nbsp;</td>';
     
    if(this.isTimeOnly)
    {
     
    ret[ret.length]='<td><img src="'+this.imgDir+'/Deleted.gif" alt="'+clearButtonValue+'" onClick="jcalendars['+this._id+'].clearField();jcalendars['+this._id+'].toggleSelector();" name="ClearButton_"'+this._objectId+' id="ClearButton_"'+this._objectId+' style="'+this._clearButtonStr+'" /></td>'
    }
    ret[ret.length] = '<td>&nbsp;</td>';
    ret[ret.length] = '<td><img border="0" onclick="jcalendars['+this._id+'].toggleSelector();" src="'+this.imgDir+'/close.gif"></td>';
    
    ret[ret.length] = '</tr></table>';
    ret[ret.length] = '</div>';
    return ret.join('');
  }  
  
  this._reRenderCalendar = function() 
  {
    var div = document.getElementById(this._objectId + '_div');
    if ((div == null) || !div) 
      return;
    div.innerHTML = this.renderDatePicker();
  }
    
  this.updateDayTable = function() 
  {
    document.getElementById(this._objectId + '_dayDiv').innerHTML = this.renderDayTable(this._currentYear, this._currentMonth, this._currentDay);
  }
 
 this.setDateTime = function(inputField) 
   {
     if(inputField.value == '')
     {      
       this.seedInternalWithCurrentDate();
       this.seedInternalWithCurrentTime();
       this._dateTimeLong = '';
       this.updateCurrentDate();
       if(this.withTime)
         this.updateCurrentTime();
     }
     else if(!this.isTimeOnly)
     {      
       this._dateTimeLong = inputField.value;
       this._currentDay    = parseInt(this._dateTimeLong.substr(0, 2), 10);
       this._currentMonth  = parseInt(this._dateTimeLong.substr(3, 2), 10);
       this._currentYear   = parseInt(this._dateTimeLong.substr(6, 4), 10);  
       if(!this.is24H)
         this._currentHour   = this.fixHour(this._dateTimeLong.substr(11, 2));        
       else
         this._currentHour   = this._dateTimeLong.substr(11, 2);
       this._currentMinute = this._dateTimeLong.substr(14, 2);        
       this._currentSeconds = this._dateTimeLong.substr(19,2);
       this._currentAMPM = this._dateTimeLong.substr(23,2);
       this.updateCurrentDate();
       inputField.value = this._getCurrentDateFormatted();
       if(this.withTime)
       {
         this.updateCurrentTime(); 
         inputField.value += " " + this._getCurrentTimeFormatted();    
       }
     } else {
       this._dateTimeLong = inputField.value;
       if(!this.is24H)
         this._currentHour   = this.fixHour(this._dateTimeLong.substr(0, 2));        
       else
         this._currentHour   = this._dateTimeLong.substr(0, 2);
       this._currentMinute = this._dateTimeLong.substr(3, 2); 
       this._currentSeconds = this._dateTimeLong.substr(6, 2); 
        this._currentAMPM = this._dateTimeLong.substr(9, 2);
       this.updateCurrentTime(); 
       inputField.value = this._getCurrentTimeFormatted();    
     }
   }
 
 
 
  this._getCurrentDateFormatted = function() 
  {  
    if(this._currentDate == '')
      return '';
    switch (this._dateFormat) 
    {
      case 'us':
        var ret = '';
        if (this._currentMonth < 10) 
          ret += '0';
        ret += this._currentMonth + '.';
        if(this._currentDay < 10) 
          ret += '0';
        ret += this._currentDay + '.';
        ret += this._currentYear;
        break;
      case 'eu':
        var ret = '';
        if (this._currentDay < 10) 
          ret += '0';
        ret += this._currentDay + '/';
        if (this._currentMonth < 10)
          ret += '0';
        ret += this._currentMonth + '/';
        ret += this._currentYear;
        break;
      default:
        var ret = this._currentDate;
    }
    return ret;
  }
  
  this._getCurrentTimeFormatted = function() 
  {
    if(this._currentTime == '')
      return '';
    var ret = this._currentHour + this.hourMarker + this._currentMinute + this.hourMarker + this._currentSeconds;    
    if(!this.is24H)
      ret += this.timeMarker + this._currentAMPM;
    return ret;
  }
  
  this.seedInternalWithCurrentDate = function() 
  {    
    var dateNow = new Date();
    this._currentYear  = this.fixYear(dateNow.getYear());
    this._currentMonth = dateNow.getMonth() + 1;
    this._currentDay   = dateNow.getDate();
    this.updateCurrentDate();    
  } 
 
  this.updateInputField = function() 
  {
    var fld = document.getElementById(this.fieldId);
    
    if ((fld == null) || !fld) 
      return;
    var currentDate = this._getCurrentDateFormatted();
    if(this.submittedDateFormat == 'mdy')  
    {
      this._dateTimeLong = currentDate.substr(3, 2) + "/";
      this._dateTimeLong += currentDate.substr(0, 2) + "/";
      this._dateTimeLong += currentDate.substr(6);
    }
    else if (this.submittedDateFormat == 'ymd')  
    {
      this._dateTimeLong  = currentDate.substr(6, 4) + "/";
      this._dateTimeLong += currentDate.substr(3, 2) + "/";
      this._dateTimeLong += currentDate.substr(0, 2);
      this._dateTimeLong += currentDate.substr(11);
    }
    else 
      this._dateTimeLong = currentDate;      
    
    if(this.withTime)
    {
      var hr = this._currentHour;
      if(!this.is24H)
      {
        hr = this.stretchHour(this._currentHour);
      }
      this._dateTimeLong += " " + hr 
      this._dateTimeLong += this.hourMarker + this._currentMinute + this._currentSeconds;
      this._dateTimeLong += this.hourMarker + "00";
    }
    fld.value = this._dateTimeLong;
  }
  
  this.stretchHour = function(shortHour)
  {
    var hr = parseInt(shortHour, 10);
    if(this._currentAMPM == this.am && hr == 12)
      hr = 0;
    else if (this._currentAMPM == this.pm && hr < 12)
      hr += 12
    return padZero(hr);
  }
  
  this.updateVisibleInputField = function() 
  {
   
    var fld = document.getElementById(this._visibleFieldId);
    if ((fld == null) || !fld) 
      return;
    if(!this.isTimeOnly){
    fld.value = this._getCurrentDateFormatted();
    if(this.withTime)
      fld.value += " " +this._getCurrentTimeFormatted();
    }else{
   
     fld.value=this._getCurrentTimeFormatted();
    }
  }
  
  this.updateByDay = function(day) 
  {
    try 
    {
      var oldTd = document.getElementById(this._objectId + '_td' + this._currentDay);
      oldTd.style.backgroundColor = this.dayBgColor;
      oldTd.style.color           = this.dayFontColor;
    } 
    catch (e) 
    {}
    var oldTd = document.getElementById(this._objectId + '_td' + day);
    oldTd.style.backgroundColor = this.dayBgColorActive;
    oldTd.style.color           = this.dayFontColorActive;
    this._currentDay = parseInt(day, 10);
    this.updateCurrentDate();
    this.updateVisibleInputField();
    if (this.autoClose) 
      this.toggleSelector();
  }

  this.updateByMonth = function() 
  {
    var monthSelect = document.getElementById(this._objectId + '_month');
    this._currentMonth = parseInt(monthSelect.value, 10);
    this.updateCurrentDate();
    this.updateDayTable();
    this.updateVisibleInputField();
  }

  this.updateByYearChange = function() 
  {
    var tmpYear = parseInt(document.getElementById(this._objectId + '_year').value, 10);
    if ((tmpYear < 2100) && (tmpYear > 1800)) 
    {
      this.updateByYearBlur();
    }
  }

  this.updateByYearBlur = function() 
  {
    var yearFld = document.getElementById(this._objectId + '_year');      
    var tempYear = parseInt(yearFld.value, 10);
    tempYear = this.fixYear(tempYear);
    
    var currentYear = parseInt(this._currentYear, 10);
    currentYear = this.fixYear(currentYear);
    if (tempYear == currentYear) 
      return;
    
    var isDateOk = this.isValidDate(tempYear, this._currentMonth, this._currentDay);
    if (isDateOk) 
    {
      if(tempYear < this.minYear)
        this._currentYear = this.minYear;
      else if(tempYear > this.maxYear)
        this._currentYear = this.maxYear;
      else
        this._currentYear = tempYear;
      
      this.updateCurrentDate();      
      this.updateVisibleInputField();
      this.updateDayTable();
    } 
    yearFld.value = this._currentYear;
  }
  
  this.updateCurrentDate = function() 
  {
    if ((0 == this._currentYear) && (0 == this._currentMonth) && (0 == this._currentDay) ) 
    {
      this._currentDate = "";
    } 
    else 
    {
      this._currentDate += this._currentDay + '/';   
      this._currentDate += this._currentMonth + '/';
      this._currentDate = this._currentYear; 
    }
  }
    
  this.dayMouseOver = function(day) 
  {
    var td = document.getElementById(this._objectId + '_td' + day);
    if (td.style.backgroundColor.toLowerCase() == this.dayBgColor.toLowerCase()) 
    {
      td.style.backgroundColor = this.dayBgColorOver;
      td.style.color = '#719e19';
    }
  }
  
  this.dayMouseOut = function(day) 
  {
    var td = document.getElementById(this._objectId + '_td' + day);
    if (day != this._currentDay) 
    {
      td.style.backgroundColor = this.dayBgColor;
      td.style.color = this.dayFontColor;
    }
  }

  this.isHoliday = function(year, month, day) 
  {
    year  = parseInt(year);
    month = parseInt(month);
    day   = parseInt(day);
    var holidays = this.holidays;
    for (var i=0; i<holidays.length; i++) 
    {
      if ((holidays[i][0] != null) && (holidays[i][0] != year))  
        continue;
      if ((holidays[i][1] != null) && (holidays[i][1] != month)) 
        continue;
      if ((holidays[i][2] != null) && (holidays[i][2] != day))   
        continue;
      return true;
    }
    return false;
  }

  this.loadSkin = function() 
  {
    try 
    {
      var oLink = document.createElement("link")
      oLink.href = this.cssDir + '/calendar-main.css';
      oLink.rel  = "stylesheet";
      oLink.type = "text/css";
      document.body.appendChild(oLink);
    } 
    catch (e) 
    {}    
    return false;
  }
  
  this.isDateSelectable = function(year, month, day) 
  {    
    var isSelectableDate = false;
    do 
    {
      var checkWeekday = false;
      for (var i=0; i<7; i++) 
      {
        if (!this.allowedWeekdays[i]) 
        {
          checkWeekday = true;
          break;
        }
      }
      if (checkWeekday) 
      {
        var dateObj = new Date(year, month-1, day);
        var weekday = dateObj.getDay();
        weekday--; 
        if (weekday < 0) 
          weekday = 6;
        if (!this.allowedWeekdays[weekday]) 
          break;
      }
      isSelectableDate = true;
    } 
    while (false);
    return isSelectableDate;
  }

  this.isValidDate = function(year, month, day) 
  {
    return bs_isValidDate(year, month, day);
  }

  this.fixYear = function(year) 
  {
    return bs_fixYear(year);
  }

  this.getNumberOfDays = function(year, month) 
  {
    return bs_getNumberOfDays(year, month);
  }

  this.dateToIsoDate = function(someDate, allowTime) 
  {
    return bs_dateToIsoDate(someDate, allowTime);
  }
  
  this.isLeapYear = function(year) 
  {
    return bs_isLeapYear(year);
  }

  this.dateCalc = function(addDays, addMonths, addYears, reRender) 
  {
    if (typeof(reRender) == 'undefined') 
      reRender = true;
    if (this._currentDay   == 0) 
      return false;
    if (this._currentMonth == 0) 
      return false;
    if (this._currentYear  == 0) 
      return false;
    if (typeof(addDays)   == 'undefined') 
      addDays = 0;
    if (typeof(addMonths) == 'undefined') 
      addMonths = 0;
    if (typeof(addYears)  == 'undefined') 
      addYears  = 0;
    var tmpDate = new Date(this._currentYear+addYears, this._currentMonth-1+addMonths, this._currentDay+addDays);
    this.setDateByChunks(tmpDate.getYear(), tmpDate.getMonth()+1, tmpDate.getDate(), reRender);
    return true;
  }

  this.incYear = function()
  {
    var yearF = document.getElementById(this._objectId + '_year');
    var y=parseInt(yearF.value,10);
    if (++y > this.maxYear) 
      y = this.maxYear;
    yearF.value = y;    
    this.updateByYearBlur();
  }
  
  this.decYear = function()
  {
    var yearF = document.getElementById(this._objectId + '_year');
    var y=parseInt(yearF.value,10);
    if (--y > this.maxYear) 
      y = this.minYear;
    yearF.value = y;
    this.updateByYearBlur();
  }   
  
  this.fixHour = function(longHour)
  {
    var h = parseInt(longHour, 10);
    if(!this.is24H)
    {
      this._currentAMPM = this.am;
      if(h == 12 )
      {
        this._currentAMPM = this.pm;
      }
      else if(h == 0 )
      {
        h = 12;        
        this._currentAMPM = this.am;  
      }
      else if (h > 12) 
      {
        h = h % 12;
        this._currentAMPM = this.pm;  
      } 
    }
    return padZero(h)
  }
  
  this.seedInternalWithCurrentTime = function()
  {
    var dateNow = new Date();
    if(!this.is24H)
        this._currentHour = this.fixHour(dateNow.getHours());
      else
        this._currentHour = padZero(dateNow.getHours());
    this._currentMinute = padZero(dateNow.getMinutes());  
    this._currentSeconds = padZero(dateNow.getSeconds());  
    this.updateCurrentTime();
  }  
  
  this.updateCurrentTime = function() 
  {
    if ((0 == this._currentHour) && (0 == this._currentMinute) && (0 == this._currentSeconds))  
    {
      this._currentTime = "";
    } 
    else 
    {      
      this._currentTime = this._currentHour + this.hourMarker + this._currentMinute + this._currentSeconds;
      if(!this.is24H)
        this._currentTime += this.timeMarker + this._currentAMPM;
    }
  }

  this.time2str = function(hour, minute, ampm) 
  { 
    // format time and round it according to interval
    return padZero(hour)+this.hourMarker+padZero(Math.floor(minute/this.minuteInc)*this.minuteInc)+(this.is24H?'':this.timeMarker+ampm);
  }

  this.updateTimeStr = function() 
  {	
  
    var hourF = document.getElementById('hourF'+this._objectId);
    var minF = document.getElementById('minF'+this._objectId);
    var secF = document.getElementById('secF'+this._objectId);
    var hv = parseInt(hourF.value,10);
    var mv = parseInt(minF.value,10);
    var sv = parseInt(secF.value,10);
    if (this.is24H)   
      hourF.value = hv >= 0 && hv <= 23 ? padZero(hv) : "00";
    else  
    {      
      hourF.value = hv >= 1 && hv <= 12 ? padZero(hv) : "12";
      var ampm = document.getElementById('ampm'+this._objectId);
      this._currentAMPM = ampm.value;
    }
    
    minF.value = mv >= 0 && mv <= 59 ? padZero(Math.floor(mv / this.minuteInc) * this.minuteInc) : "00";
    secF.value = sv >= 0 && sv <= 59 ? padZero(Math.floor(sv / this.secInc) * this.secInc) : "00";
   
    this._currentHour = hourF.value;
    this._currentMinute = minF.value;
    this._currentSeconds = secF.value;
    
    this.updateCurrentTime();
    this.updateVisibleInputField();
  }

  this.incMin = function()
  {    
    var minF = document.getElementById('minF'+this._objectId);
    var m=parseInt(minF.value,10)+this.minuteInc;
    if (m>59) 
    { 
      m=0; 
      this.incHour(); 
    }
    minF.value=padZero(m);
    this.updateTimeStr();
  }
  
  this.decMin = function()
  {
    var minF = document.getElementById('minF'+this._objectId);
    var m=parseInt(minF.value,10)-this.minuteInc;
    if (m<0) 
    { 
      m=60-this.minuteInc; 
      this.decHour(); 
    }
    minF.value=padZero(m);
    this.updateTimeStr();
  }
  
  this.incSec = function()
  {    
    var secF = document.getElementById('secF'+this._objectId);
    var s=parseInt(secF.value,10)+this.secInc;
    if (s>59) 
    { 
      s=0; 
      this.incHour(); 
    }
    secF.value=padZero(s);
    this.updateTimeStr();
  }
  
  this.decSec = function()
  {
    var secF = document.getElementById('secF'+this._objectId);
    var s=parseInt(secF.value,10)-this.secInc;
    if (s<0) 
    { 
      s=60-this.minuteInc; 
      this.decHour(); 
    }
    secF.value=padZero(s);
    this.updateTimeStr();
  }
  
  this.incHour = function()
  {
    var hourF = document.getElementById('hourF'+this._objectId);
    var h = parseInt(hourF.value,10), maxh = this.is24H?23:12;
    if (++h>maxh) 
      h=this.is24H?0:1;
    if (h==12) 
      this.flipAmPm();
    hourF.value=padZero(h);
    this.updateTimeStr();
  }
  
  this.decHour = function()
  {
    var hourF = document.getElementById('hourF'+this._objectId);
    var h = parseInt(hourF.value, 10);
    if (this.is24H) 
    {
      if (--h < 0) 
        h = 23;
    } 
    else if (--h == 0) 
      h = 12;
    if (h == 11) 
      this.flipAmPm();
    hourF.value = padZero(h);
    this.updateTimeStr();
  }  
  
  this.flipAmPm = function() 
  {
    if (this.is24H) 
      return;
    var ampmField = document.getElementById('ampm'+this._objectId); 
    ampmField.value = ampmField.value==this.am?this.pm:this.am;
    this.updateTimeStr();
  }    
  
  this.hideShowAnnoyingElements = function()
  {
    var el = document.getElementById(this._objectId + '_div');
    var p = this.getAbsolutePos(el);
    var EX1 = p.x;
  	var EX2 = el.offsetWidth + EX1;
  	var EY1 = p.y;
    var EY2 = el.offsetHeight + EY1;
    
    var elems;
    for(var i = 0; i < this.annoyingElementsTags.length; i++)    
    {
      elems = document.getElementsByTagName(this.annoyingElementsTags[i]);
      var cc = null;
      var cc_old_vis = null;
      
      for(var j = 0; j < elems.length; j++)
      {
        cc = elems[j];
        
        if(cc.id == this._objectId + '_month')  //  this should be his months combobox :D :D too smart fellow here
          continue;

        p = this.getAbsolutePos(cc);

        var CX1 = p.x;
        var CX2 = cc.offsetWidth + CX1;
        var CY1 = p.y;
        var CY2 = cc.offsetHeight + CY1;
        
        if ( (sign(CY1 - EY2) != sign(CY2 - EY1)) && (sign(CX1 - EX2) != sign(CX2 - EX1)) ) //  overlap
        {
            //alert( el.name + " ovelaps with " + cc.name);
            
            if( !cc.getAttribute("jup_vis") )
                {
                    cc.setAttribute("jup_vis", getVisib(cc));
                    //alert("visibility was : " + getVisib(cc));
                    cc.style.visibility = "hidden";
                }
                else    //if( cc.getAttribute("jup_vis") )
                {
                    cc_old_vis = cc.getAttribute("jup_vis");
                    cc.removeAttribute("jup_vis");
                    cc.style.visibility = cc_old_vis;
                    
                    //alert("back");
                }
            }
        
//        if (this._hidden || ((CX1 > EX2) || (CX2 < EX1)) || (CY1 > EY2) || (CY2 < EY1))
//        {
//          if (!cc.__msh_save_visibility) 
//          {
//            cc.__msh_save_visibility = getVisib(cc);
//          }
//          cc.style.visibility = cc.__msh_save_visibility;
//          } 
//          else 
//          {
//          if (!cc.__msh_save_visibility) 
//          {
//            cc.__msh_save_visibility = getVisib(cc);
//          }
//          cc.style.visibility = "hidden";
//        }
      }
    }
  }
  
  this.hideAnnoyingColleagues = function()
  {
    
  }
  
  this.getAbsolutePos = function(el) 
  {
    var sl = 0, st = 0;
    var is_div = /^div$/i.test(el.tagName);
    if (is_div && el.scrollLeft)
      sl = el.scrollLeft;
    if (is_div && el.scrollTop)
      st = el.scrollTop;
    var r = { x: el.offsetLeft - sl, y: el.offsetTop - st };
    if (el.offsetParent) 
    {
        var tmp = this.getAbsolutePos(el.offsetParent);
  		r.x += tmp.x;
      r.y += tmp.y;
    }
    return r;
  }

  function getVisib(obj)
  {
        var value = obj.style.visibility;
    if (!value) {
      if (document.defaultView && typeof (document.defaultView.getComputedStyle) == "function") { // Gecko, W3C
        if (!Calendar.is_khtml)
          value = document.defaultView.
            getComputedStyle(obj, "").getPropertyValue("visibility");
        else
          value = '';
      } else if (obj.currentStyle) { // IE
        value = obj.currentStyle.visibility;
      } else
        value = '';
    }
    return value;
  };

  this._constructor();
}

function setOuterHTML(element, toValue)
{
	if (typeof(element.outerHTML) != 'undefined')
		element.outerHTML = toValue;
	else
	{
		var range = document.createRange();
		range.setStartBefore(element);
		element.parentNode.replaceChild(range.createContextualFragment(toValue), element);
	}
}

function getOuterHTML(node)
{
	if (typeof(node.outerHTML) != 'undefined')
		return node.outerHTML;

	var str = '';

	switch (node.nodeType)
	{
	// An element.
	case 1:
		str += '<' + node.nodeName;

		for (var i = 0; i < node.attributes.length; i++)
		{
			if (node.attributes[i].nodeValue != null)
				str += ' ' + node.attributes[i].nodeName + '="' + node.attributes[i].nodeValue + '"';
		}

		if (node.childNodes.length == 0 && in_array(node.nodeName.toLowerCase(), ['hr', 'input', 'img', 'link', 'meta', 'br']))
			str += ' />';
		else
			str += '>' + getInnerHTML(node) + '</' + node.nodeName + '>';
		break;

	// 2 is an attribute.

	// Just some text..
	case 3:
		str += node.nodeValue;
		break;

	// A CDATA section.
	case 4:
		str += '<![CDATA' + '[' + node.nodeValue + ']' + ']>';
		break;

	// Entity reference..
	case 5:
		str += '&' + node.nodeName + ';';
		break;

	// 6 is an actual entity, 7 is a PI.

	// Comment.
	case 8:
		str += '<!--' + node.nodeValue + '-->';
		break;
	}

	return str;
}

function in_array(needle, haystack, strict) {
    // http://kevin.vanzonneveld.net
    // +   original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // *     example 1: in_array('van', ['Kevin', 'van', 'Zonneveld']);
    // *     returns 1: true
 
    var found = false, key, strict = !!strict;
 
    for (key in haystack) {
        if ((strict && haystack[key] === needle) || (!strict && haystack[key] == needle)) {
            found = true;
            break;
        }
    }
 
    return found;
}
