DateCalendar = (function($) { 

function DateCalendar(el, opts) {
	if (typeof(opts) != "object") opts = {};
	$.extend(this, DateCalendar.DEFAULT_OPTS, opts);

	this.el = $(el);
	this.bindMethodsToObj("selectDate");
	this.dayPosts = {};

	this.build();
	if (this.selected && this.selected != '') {
		date = this.selected.split('-');
		if (date[0] && date[1] && date[2]) {
			this.selectDate(this.selected);
		} else {
			if (!date[1]) date[1] = 1;
			date[2] = 1;
			this.selectMonth(this.stringToDate(date.join('-')));
		}
	}
	else
		this.selectDate();
};

DateCalendar.DEFAULT_OPTS = {
  month_names: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
  short_month_names: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
  short_day_names: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
  start_of_week: 1,
  posts: "posts: ",
  shownomonth: false, // Показывать дни из не текущего месяца
  baseUrl: '?'
};
DateCalendar.prototype = {
  build: function() {
	this.monthNameSpan = $(".navigation > .month", this.el);
	$(this.sel_prevMonth, this.el).click(this.bindToObj(function() {
		this.moveMonthBy(-1);
		return false;
	}));
	$(this.sel_nextMonth, this.el).click(this.bindToObj(function() {
		this.moveMonthBy(1);
		return false;
	}));

	this.yearNameSpan = $(".navigation > .year", this.el);
	$("a[href=#prev_year]", this.el).click(this.bindToObj(function() {
		this.moveMonthBy(-12);
		return false;
	}));
	$("a[href=#next_year]", this.el).click(this.bindToObj(function() {
		this.moveMonthBy(12);
		return false;
	}));

	this.tbody = $(".numbers", this.el);
  },

  selectMonth: function(date) {
    var newMonth = new Date(date.getFullYear(), date.getMonth(), 1);
    if (!this.currentMonth || !(this.currentMonth.getFullYear() == newMonth.getFullYear() &&
                                this.currentMonth.getMonth() == newMonth.getMonth())) {

	this.currentMonth = newMonth;

	var rangeStart = this.rangeStart(date), rangeEnd = this.rangeEnd(date);
	var numDays = this.daysBetween(rangeStart, rangeEnd);
	var dayCells = "";

	for (var i = 0; i <= numDays; i++) {
		var currentDay = new Date(rangeStart.getFullYear(), rangeStart.getMonth(), rangeStart.getDate() + i, 12, 00);
		var strCurDate = this.dateToString(currentDay);
		if (currentDay.getMonth() == date.getMonth()) {
			dayCells += '<div date="' + strCurDate + '" class="' + (this.isWeekend(currentDay) ? this.css_weekend : '') + (this.isSelected(strCurDate) ? this.css_selected : '') + '">' + currentDay.getDate() + '</div>';
		} else {
			dayCells += '<div class="' + (this.isWeekend(currentDay) ? this.css_weekend_nomonth : this.css_nomonth) + '">' + currentDay.getDate() + '</div>';
			//dayCells += '<div date="' + strCurDate + '">' + currentDay.getDate() + '</div>';
		}
	};
	this.tbody.empty().append(dayCells);
	var self = this;

	var mounthLink = this.currentMonth.getFullYear() + '-' + ((this.currentMonth.getMonth()) + 1);
	this.monthNameSpan
	.empty()
	.append(this.monthName(date))
	.attr('href', self.baseUrl + 'date=' + mounthLink)
	.click(function() {
		$(self.ajaxSelector).load($(this).attr('href') + '&ajax');
		return false;
	});

	var yearLink = this.currentMonth.getFullYear();
	this.yearNameSpan
	.empty()
	.append(this.currentMonth.getFullYear())
	.attr('href', self.baseUrl + 'date=' + yearLink)
	.click(function() {
		$(self.ajaxSelector).load($(this).attr('href') + '&ajax')
		return false;
	});

	$("[date=" + this.dateToString(new Date()) + "]", this.tbody).addClass(this.css_today);

	requestDate = date.getFullYear() + '-' + (date.getMonth()+1);
	if (this.tbody.data(requestDate)) {
		this._fillTable(this.tbody.data(requestDate));
	} else {
		$.post(this.pagesUrl, {date: requestDate}, function(json) {
			self._fillTable(json);
			self.tbody.data(requestDate, json);
		}, "json");
	}

    };
	},

	_fillTable: function(data) {
		var self = this;
		$('[date]', self.tbody).each(function() {
			if (data[$(this).text()]) {
				a_link = $('<a href="#"> ' + $(this).text() + '</a>')
					.attr({"href": self.baseUrl + 'date=' + $(this).attr('date'), 
						   "date": $(this).attr('date'),
						   "title": self.posts + data[$(this).text()],
						   "class": $(this).attr("class")})
					.click(function() {
						self.selectDate($(this).attr("date"));
						if (false == $(self.ajaxSelector).is(":visible"))
							return true;
						$(self.ajaxSelector).load($(this).attr('href') + '&ajax');
						$(this).blur();
						return false;
					});
				$(this).replaceWith(a_link);
			}
		});
	},

  selectDate: function(date) {
	if (typeof(date) == "undefined") {
		date = new Date();
    } else if (typeof(date) == "string") {
		date = this.stringToDate(date);
	}

    this.selectedDate = date;
	this.selectedDateString = this.dateToString(this.selectedDate);
	this.selectMonth(this.selectedDate);
	$('.' + this.css_selected, this.tbody).removeClass(this.css_selected);
	$('[date=' + this.selectedDateString + ']', this.tbody).addClass(this.css_selected);	
  },
  
  stringToDate: function(string) {
    var matches;
    if (matches = string.match(/^(\d{4,4})-(\d{1,2})-(\d{1,2})$/)) {
      return new Date(matches[1], (matches[2] - 1), matches[3], 12, 00);
    } else {
      return null;
    };
  },
  
  dateToString: function(date) {
	return date.getFullYear() + "-" + (date.getMonth() + 1) + "-" + date.getDate();
  },
  
  moveDateBy: function(amount) {
    var newDate = new Date(this.selectedDate.getFullYear(), this.selectedDate.getMonth(), this.selectedDate.getDate() + amount);
    this.selectDate(newDate);
  },
  
  moveDateMonthBy: function(amount) {
    var newDate = new Date(this.selectedDate.getFullYear(), this.selectedDate.getMonth() + amount, this.selectedDate.getDate());
    if (newDate.getMonth() == this.selectedDate.getMonth() + amount + 1) {
      
      newDate.setDate(0);
    };
    this.selectDate(newDate);
  },
  
  moveMonthBy: function(amount) {
    var newMonth = new Date(this.currentMonth.getFullYear(), this.currentMonth.getMonth() + amount, this.currentMonth.getDate());
    this.selectMonth(newMonth);
  },
  
  monthName: function(date) {
    return this.month_names[date.getMonth()];
  },
  
  bindToObj: function(fn) {
    var self = this;
    return function() { return fn.apply(self, arguments) };
  },
  
  bindMethodsToObj: function() {
    for (var i = 0; i < arguments.length; i++) {
      this[arguments[i]] = this.bindToObj(this[arguments[i]]);
    };
  },
  
  indexFor: function(array, value) {
    for (var i = 0; i < array.length; i++) {
      if (value == array[i]) return i;
    };
  },
  
  monthNum: function(month_name) {
    return this.indexFor(this.month_names, month_name);
  },
  
  shortMonthNum: function(month_name) {
    return this.indexFor(this.short_month_names, month_name);
  },
  
  shortDayNum: function(day_name) {
    return this.indexFor(this.short_day_names, day_name);
  },
  
  daysBetween: function(start, end) {
    start = Date.UTC(start.getFullYear(), start.getMonth(), start.getDate());
    end = Date.UTC(end.getFullYear(), end.getMonth(), end.getDate());
    return (end - start) / 86400000;
  },
  
  changeDayTo: function(dayOfWeek, date, direction) {
    var difference = direction * (Math.abs(date.getDay() - dayOfWeek - (direction * 7)) % 7);
    return new Date(date.getFullYear(), date.getMonth(), date.getDate() + difference);
  },
  
  rangeStart: function(date) {
    return this.changeDayTo(this.start_of_week, new Date(date.getFullYear(), date.getMonth()), -1);
  },
  
  rangeEnd: function(date) {
    return this.changeDayTo((this.start_of_week - 1) % 7, new Date(date.getFullYear(), date.getMonth() + 1, 0), 1);
  },
  
  isFirstDayOfWeek: function(date) {
    return date.getDay() == this.start_of_week;
  },
  
  isLastDayOfWeek: function(date) {
    return date.getDay() == (this.start_of_week - 1) % 7;
  },
  
  isWeekend: function(date) {
	if (date.getDay() == 6 || date.getDay() == 0)
		return true;
	return false;
  },
  
  isSelected: function(dateString) {
	if (this.selected && this.selected == dateString)
		return true;
	return false;
  },

  adjustDays: function(days) {
    var newDays = [];
    for (var i = 0; i < days.length; i++) {
      newDays[i] = days[(i + this.start_of_week) % 7];
    };
    return newDays;
  }
};

$.fn.dateCalendar = function(opts) {
  return this.each(function() { new DateCalendar(this, opts); });
};
$.dateCalendar = { initialize: function(el, opts) {
  $(el).dateCalendar(opts);
} };

return DateCalendar;
})(jQuery); 

function Dump(d,l) 
{
  if (l == null) l = 1;
  var s = '';
  if (typeof(d) == "object") {
    s += typeof(d) + " {\n";
    for (var k in d) {
      for (var i=0; i<l; i++) 
        s += "  ";
      s += k+": " + Dump(d[k],l+1);
    }
    for (var i=0; i<l-1; i++) s += "  ";
      s += "}\n"
  } else {
    s += "" + d + "\n";
  }
  return s;
}