Date.prototype.isLeapYear = function() {
    var year = this.getFullYear();
        return !!((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
};
Date.prototype.before = function(fDate) {
    return this.getFullYear() < fDate.getFullYear() ||
           (this.getFullYear() == fDate.getFullYear() && this.getMonth() < fDate.getMonth()) ||
           (this.getFullYear() == fDate.getFullYear() && this.getMonth() == fDate.getMonth() && this.getDate() < fDate.getDate());
};
Date.prototype.equalsDate = function(fDate) {
    return fDate.getYear() == this.getYear() && fDate.getMonth() == this.getMonth() && fDate.getDate() == this.getDate()
}

Calendar = function(fElement, fDate, fConfig) {
      var pCurrentDate = new Date(fDate.getFullYear(), fDate.getMonth(), 1);

      var build = function(fYear, fMonth, fClear) {
         if(jQuery.isFunction(fConfig.beforeRebuild) && fConfig.beforeRebuild(fYear, fMonth) === false)
           return false;
         if(fClear)
            tUl.children("li:not(.day)").remove();
         var tDateStart = new Date(fYear, fMonth, 1);
         var tDateEnd = new Date(fYear, fMonth, Calendar.config.daysInMonth[fMonth] + (fMonth == 1 && tDateStart.isLeapYear()));
         
         tDateStart.setDate( tDateStart.getDate() - (Calendar.config.daysNames.length + tDateStart.getDay() - tDayStartWeek)%7 );
         tDateEnd.setDate(tDateEnd.getDate() + (Calendar.config.daysNames.length - 1 - tDateEnd.getDay() + tDayStartWeek)%7)
         while(!tDateEnd.before(tDateStart))
           {
              var tElDay = jQuery("<li>" + tDateStart.getDate() + "</li>");
              tElDay.get(0).xPrivDate = new Date(tDateStart);
              if(tDateStart.getMonth() != fMonth)
                tElDay.addClass('am');
              if(tDateStart.getMonth() == fDate.getMonth() && tDateStart.getDate() == fDate.getDate())
                tElDay.addClass('today');
              tElDay.hover(Calendar.internal.hover.inside, Calendar.internal.hover.outside);

              tUl.append(tElDay);
              tDateStart.setDate(tDateStart.getDate() + 1)
           }
         updateHeader(fYear, fMonth);
         tSelector.refreshSpecial(tUl);
         jQuery('li', tUl).click(function(){
           if(jQuery.isFunction(tConfig.click))
              {
                  if(typeof this.xPrivDate !== 'undefined')
                     tSelector.select(this);
                  if(tConfig.click(this, this.xPrivDate) !== false)
                     ;
                  //alert(typeof this.xPrivDate)
              }
         });
      }

      var updateHeader = function(fYear, fMonth) {
         tHeader.html(Calendar.config.monthNames[fMonth] + " " + fYear);
      }
      
      var tConfig = fConfig || {};
      var tDayStartWeek = 1;

      var tHeader = jQuery("<span class='header'>" + Calendar.config.monthNames[fDate.getMonth()] + " " + fDate.getFullYear() + "</span>");
      var tUl = jQuery("<ul class='calendarX boxOrange' style='padding-bottom:10px;'></ul>")
                   .append(jQuery("<a href='#' class='prev'>&laquo;</a>").click(function(){  pCurrentDate.setMonth(pCurrentDate.getMonth() - 1);build(pCurrentDate.getFullYear(), pCurrentDate.getMonth(), true); return false;}))
                   .append(jQuery("<a href='#' class='next'>&raquo;</a>").click(function(){  pCurrentDate.setMonth(pCurrentDate.getMonth() + 1);build(pCurrentDate.getFullYear(), pCurrentDate.getMonth(), true); return false;}))
                   .append(tHeader).append("<div style='clear:both;'></div>");
      
      for(var tC = 0; tC < Calendar.config.daysNames.length; tC++)
        tUl.append("<li class='day'>" + Calendar.config.daysNames[(tC + tDayStartWeek)%Calendar.config.daysNames.length] + "</li>");

      var tSelector = new Calendar.internal.Selector(fConfig.selector);
      build(fDate.getFullYear(), fDate.getMonth());
      //tSelector.refreshSpecial(tUl);
      tUl.calendar = this;
      jQuery(fElement).html("").append(tUl);

      this.refreshSpecial = function() {
          tSelector.refreshSpecial(tUl);
      }

      this.refreshSelected = function() {
          tSelector.refreshSelected(tUl);
      }
}

Calendar.config= {
       daysNames:['Âñ', 'Ïí', 'Âò', 'Ñð', '×ò', 'Ïò', 'Ñá']
      ,daysInMonth : [31,28,31,30,31,30,31,31,30,31,30,31]
      ,monthNames : [
        "ßíâàðü",
        "Ôåâðàëü",
        "Ìàðò",
        "Àïðåëü",
        "Ìàé",
        "Èþíü",
        "Èþëü",
        "Àâãóñò",
        "Ñåíòÿáðü",
        "Îêòÿáðü",
        "Íîÿáðü",
        "Äåêàáðü"
      ]
   };

Calendar.internal = {
        hover: {
            inside: function() {
                jQuery(this).addClass('hover');
            }
           ,outside: function() {
                jQuery(this).removeClass('hover');
            }
        }
       ,Selector:function(fConfig) {
           var tConfig = fConfig || {};
           var pStrategy = new Calendar.internal.selectorStrategies.getDefault();
           this.select = function(fElement){
              if(typeof fElement.xPrivDate == 'undefined')
                  return;
              var tDate = fElement.xPrivDate;
              /*if(this.isDisabled(tDate)) return;*/
              pStrategy.proceed(tDate);
              this.refreshSelected(jQuery(fElement).parents('ul:first').get(0));
           }
           this.refresh = function(){
               this.refreshSpecial();
               this.refreshSelected();
           };
           this.refreshSpecial = function(fUl) {
               if(jQuery.isFunction(tConfig.isSpecial) !== true)
                   return;
               jQuery(fUl).children('li:not(.day)').each(function(){
                   if(tConfig.isSpecial(this.xPrivDate))
                     jQuery(this).addClass('special')
                   else
                     jQuery(this).removeClass('special');
               });
           }
           this.refreshSelected = function(fUl) {
               jQuery(fUl).children('li:not(.day)').each(function(){
                   if(pStrategy.isSelected(this.xPrivDate))
                     jQuery(this).addClass('selected')
                   else
                     jQuery(this).removeClass('selected');
               });
           }
        }
       ,selectorStrategies: {
           getDefault:function(fConfig) { return new Calendar.internal.selectorStrategies.Single(); },
           Single:function(fConfig){
              var pDates = [];

              this.proceed = function(fDate){
                 if(this.isSelected(fDate))
                     { delete pDates; pDates = [];}
                 else
                     { delete pDates; pDates = [fDate];}
                 return pDates;
              };
              this.isSelected = function(fDate) {
                  if(typeof(fDate) != 'object')
                      return false;
                  for(var i = 0; i < pDates.length; i++)
                    if(pDates[i].equalsDate(fDate))
                       { return true; }
                  return false;
               }
           }
       }
    };

   Calendar.create = function(fElement, fDate, fConfig) {
      var tResult = new Calendar(fElement, fDate, fConfig);
      return tResult;
  }

