function Calendar(){
  this.yearStart = '';
  this.yearMax = '';
  this.firstWeekDay = 'Sun';
  this.defYear = '';
  this.defMonth = '';
  this.defDate = '';
  this.defHour = '';
  this.defMinute = '';
  this.defSecond = '';
  this.txtField = '';
  this.dateFormat = '';
  this.top = 100;
  this.left = 100;
  this.btn = '';
  this.onSelect = function(){return false};
  this.onClose = function(){return false};
}

Calendar.prototype = {
  initialize : function(el_AS_Object){
    var self = this, today = new Date(), tblOuter = new Table(3,1), captionTable = new Table(1,2);
    var month, year, date, hour, minute, second, day, objDefDate, yearStart, yearMax, tblDates, status, hotCell;
    var WeekDays=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"];
    var Months=["January","February","March","April","May","June","July","August","September","October","November","December"];
    var lastDates = [31,28,31,30,31,30,31,31,30,31,30,31];
    
    self.btn.disabled = true;
    
    this.container = el_AS_Object || document.body;
    this.divOuter = new Div();
    
    year = this.defYear || today.getFullYear();
    month = (this.defMonth?this.defMonth-1 :today.getMonth());
    date = this.defDate || today.getDate();
    hour = this.defHour || today.getHours();
    minute = this.defMinute || today.getMinutes();
    second = this.defSeconds || today.getSeconds();
    yearStart = this.yearStart || 1900;
    yearMax = this.yearMax || today.getFullYear();
    
    objDefDate = new Date(year, month, date, hour, minute, second);
    day = objDefDate.getDay();
    
    var statusBar = function(str){
      misc.setInnerText(status, str);
    }
    
    var highLight = function(cell_AS_Object){
      var el = cell_AS_Object;
      if(el==hotCell)return;
      
      if(hotCell){
        with(hotCell){
          removeAttribute('style');
        }
      }
      
      hotCell = el;
      with(hotCell.style){
        border = '1px solid orange';
        background = '#eee';
        color = '#000000';
      }
    }
    
    var WriteDates = function(){
      var currDate = new Date(year, month, date, hour, minute, second);
      var reWrite = false;
      
      if(tblDates){
        reWrite = true;
        while(tblDates.rows[1])misc.removeElement(tblDates.rows[1]);
        statusBar(currDate.FormatDate(self.dateFormat));
      }
      else{
        tblDates = new Table(1,7);
        status = captionTable.rows[0].cells[0];
      }
      
      //checking for leap year.
      if((year%4)==0)lastDates[1]=29;
      else lastDates[1]=28;
      
      with(tblDates){
        if(!reWrite){
          width = '100%';
          with(rows[0]){
            WeekDays.Each(function(val, i){
              with(cells[i]){
                align = 'center';
                width = '20px';
                height = '16px';
              }
              misc.setInnerText(cells[i], val);
            });
          }
        }
        
        var currentMonth = new Date(year, month, 1);
        var firstDay = currentMonth.getDay();
        var dates = 1;
        var writeDates = false;
        for(var r=1; r<7; r++){ //controlling rows
          if(dates>lastDates[month])break;
          var tr = insertRow(r);
          for(var c=0; c<7; c++){ //controlling cols
            var td = tr.insertCell(c);
            if(firstDay==c)writeDates = true;
            
            with(td){
              align = 'center';
              with(style){
                if(dates==date)highLight(td);
              }
            }
            
            if(writeDates && dates<=lastDates[month]){
              misc.setInnerText(td, dates++);
              td.onclick = function(){
                highLight(this);
                date = misc.getInnerText(this);
                currDate = new Date(year, month, date, hour, minute, second);
                statusBar(currDate.FormatDate(self.dateFormat));
              }
              td.ondblclick = function(){
                var selDate = new Date(cmbYear.value, cmbMonth.value, misc.getInnerText(this));
                selDate = selDate.FormatDate(self.dateFormat);
                self.txtField.value = selDate;
                misc.removeElement(self.divOuter);
                self.onSelect();
              }
            }
            else td.innerHTML = '&nbsp;';
          }
        }
      }
    };
    
    WriteDates();
    
    with(captionTable){
      style.width = '100%';
      //rows[0].cells[0] is set to status in line 73
      with(status){
        align = 'left';
        width = '100%';
        noWrap = 'noWrap';
      }
      
      status.onmouseover = function(){
        with(this.style){
          textDecoration = 'underline';
        }
      };
      
      status.onmouseout = function(){
        this.removeAttribute('style');
      };
      
      status.onclick = function(){
        self.txtField.value = misc.getInnerText(this);
        misc.removeElement(self.divOuter);
        self.onSelect();
      }
      
      var closeButton = rows[0].cells[1];
      with(closeButton){
        align = 'right';
        noWrap = 'noWrap';
      }
      
      misc.setInnerText(closeButton, 'Close');
      
      closeButton.onmouseover = function(){
        with(this.style){
          textDecoration = 'underline';
        }
      };
      
      closeButton.onmouseout = function(){
        this.removeAttribute('style');
      };
      
      closeButton.onclick = function(){
        this.removeAttribute('style');
        misc.removeElement(self.divOuter);
        self.onClose();
      };
    }
    
    with(tblOuter){
      //border = '1';
      style.borderLeft = '1px solid #CCCCCC';
      style.borderTop = '1px solid #CCCCCC';
      style.borderRight = '2px solid #999999';
      style.borderBottom = '2px solid #999999';
      bgColor = '#FFFFFF';
      with(rows[0].cells[0]){
        appendChild(captionTable);
      }
      with(rows[1]){
        var innerTable = new Table(1,2);
        with(innerTable){
          //border = 1;
          cellPadding = 0;
          cellSpacing = 1;
          //width = '100%';
          with(rows[0]){
            with(cells[0]){
              align = 'center';
              var formatTable = new Table(1,3);
              var cmbMonth = new Select();
              var divPrev = new Div();
              var divNext = new Div();
              var signPrev = document.createTextNode('\u25c4'); //Previous Year
              var signNext = document.createTextNode('\u25ba'); //Next Year
              
              with(signPrev)style.color = '#666666';
              with(signNext)style.color = '#666666';
              
              with(divPrev)appendChild(signPrev);
              with(divNext)appendChild(signNext);
              
              divPrev.onmouseup = function(){
                var currentIndex = cmbMonth.selectedIndex;
                var maxIndex = cmbMonth.options.length-1;
                
                if(currentIndex==0)return;
                
                cmbMonth.selectedIndex = --currentIndex;
                cmbMonth.onchange();
              }
              
              divNext.onmouseup = function(){
                var currentIndex = cmbMonth.selectedIndex;
                var maxIndex = cmbMonth.options.length-1;
                
                if(currentIndex==maxIndex)return;
                
                cmbMonth.selectedIndex = ++currentIndex;
                cmbMonth.onchange();
              }
              
              with(cmbMonth){ //Combo Month
                with(style)font = 'normal 10px Tahoma';
                
                Months.Each(function(val, i){
                  options[options.length] = new Option(val, i);
                });
                selectedIndex = month;
              }
              
              cmbMonth.onchange = function(){
                month = this.value;
                this.blur();
                WriteDates();
              };
              
              with(formatTable){
                cellSpacing = 0;
                cellPadding = 0;
                with(rows[0]){
                  cells[0].appendChild(divPrev);
                  cells[1].appendChild(cmbMonth);
                  cells[2].appendChild(divNext);
                }
              }
              
              appendChild(formatTable);
            }
            
            with(cells[1]){
              align = 'center';
              var formatTable = new Table(1,3);
              var cmbYear = new Select();
              var divPrev = new Div();
              var divNext = new Div();
              var signPrev = document.createTextNode('\u25c4'); //Previous Year
              var signNext = document.createTextNode('\u25ba'); //Next Year
              
              with(signPrev)style.color = '#666666';
              with(signNext)style.color = '#666666';
              
              with(divPrev)appendChild(signPrev);
              with(divNext)appendChild(signNext);
              
              divPrev.onmouseup = function(){
                var currentIndex = cmbYear.selectedIndex;
                var maxIndex = cmbYear.options.length-1;
                
                if(currentIndex==0)return;
                
                cmbYear.selectedIndex = --currentIndex;
                cmbYear.onchange();
              }
              
              divNext.onmouseup = function(){
                var currentIndex = cmbYear.selectedIndex;
                var maxIndex = cmbYear.options.length-1;
                
                if(currentIndex==maxIndex)return;
                
                cmbYear.selectedIndex = ++currentIndex;
                cmbYear.onchange();
              }
              
              with(cmbYear){ //Combo Year
                with(style){
                  font = 'normal 10px Tahoma';
                }
                for(var s=yearStart, m=yearMax, i=0; s<=m; s++){
                  options[options.length]=new Option(s, s);
                  if(s==year)selectedIndex = i;
                  i++;
                }
              }
              
              cmbYear.onchange = function(){
                year = this.value;
                this.blur();
                WriteDates();
              }
              
              with(formatTable){
                cellSpacing = 0;
                cellPadding = 0;
                with(rows[0]){
                  cells[0].appendChild(divPrev);
                  cells[1].appendChild(cmbYear);
                  cells[2].appendChild(divNext);
                }
              }
              
              appendChild(formatTable);
            }
          }
        }
        cells[0].appendChild(innerTable);
      }
      
      with(rows[2]){
        with(cells[0]){
          appendChild(tblDates);
        }
      }
      
      statusBar((objDefDate).FormatDate(self.dateFormat));
    }
    
    with(self.divOuter){
      var _xy = misc.getXY(self.txtField);
      with(style){
        font = 'normal 10px Tahoma';
        MozUserSelect = 'none';
        cursor = 'default';
        height = '1px';
        position = 'absolute';
        width = '177px';
        /*top = (xy[1] || self.top) + 'px';
        left = ((xy[0]+self.btn.offsetWidth || self.left)+2) + 'px';*/
        
        //top = (xy[1] || self.top) + 'px';
        
        top = (self.top || _xy[1]) + 'px';
        left = (self.left || _xy[0]+self.txtField.offsetWidth+2) + 'px';
        overflow = 'visible';
      }
      appendChild(tblOuter);
    }
    
    misc.noTextSelection(self.divOuter);
    self.container.appendChild(self.divOuter);
    animation.SlideDown(self.divOuter, tblOuter.offsetHeight, 30);
    self.btn.disabled = false;
  }
}
