function Calendar(){
	this.baseConstructor.apply(this, arguments);
}

Calendar.inheritFrom(Draggable, {
	_default: { //current date
		year: (new Date()).getFullYear(),
		month: (new Date()).getMonth()+1,
		submit: "."
	},
	oninit: function(){
		var oThis = this;
		this.hSetting = {};
		jQuery.extend(this.hSetting, this._default, arguments[1] ? arguments[1] : {});

		jQuery.extend(this.is, {
			animate: false,
			controls: false,
			controlsState: false
		});
		
		this.months = {
			first: ['Январь', 'Февраль', 'Март', 'Апрель', 'Май', 'Июнь', 'Июль', 'Август', 'Сентябрь', 'Октябрь', 'Ноябрь', 'Декабрь'],
			second: ['января', 'февраля', 'марта', 'апреля', 'мая', 'июня', 'июля', 'августа', 'сентября', 'октября', 'ноября', 'декабря']
		}
		this.week_days = ['воскресенье', 'понедельник', 'вторник', 'среда', 'четверг', 'пятница', 'суббота'];
		
		this.aMonths = [];
		
		this.ptr.append("<div class='calendar-current'>" + getDateText(new Date()) + "</div>")
		this.ptr.append(
			"<div class='calendar-body'>" +
				"<div class='calendar-button calendar-button-left'><i></i></div>" +
				"<div class='calendar-button calendar-button-right'><i></i></div>" +
				"<div class='calendar-week'></div>" +
			"</div>"
		);
		this.ptr.append(
			"<div class='calendar-controls'><div class='calendar-control-in'>" +
				"<span class='calendar-clear'>Отменить</span>" +
				'<div class="button-wrapper"><div class="button-block"><div class="left"><div class="in"></div></div><div class="center">' + 
					'<p><span>Показать</span></p>' +
				'</div><div class="right"><div class="in"></div></div></div></div>' +
			"</div></div>"
		);

		this.ptr.append(
			'<form class="calendar-form" method="post" action="' + this.hSetting.submit + '">' +
				'<input type="hidden" name="dates" />' +
				'<input type="hidden" name="month" />' +
				'<input type="hidden" name="year" />' +
			'</form>'
		);
		
		this.ptr = this.ptr.find("div.calendar-body");
		var curr = this.createMonth(this.hSetting);
		this.ptr.append(curr.ptr);

		if(curr.count > 35)
			this.ptr.css({ height: 180 });
			
		curr.current = true;
		this.aMonths.push(curr);
		this.redraw(curr);
		
		this.resize();

		function getDateText(date){
			return date.getDate() + ' ' + oThis.months.second[date.getMonth()] + ', ' + oThis.week_days[date.getDay()];
		}
	},
	resize: function(){
		var _offset = this.ptr.offset();

		this.current = this.getCurrent();
		for(var key in this.current.items){
			var ptr = this.current.items[key].ptr;
			var _o = ptr.offset();
			this.current.items[key].left = _o.left - _offset.left;
			this.current.items[key].top = _o.top - _offset.top;
		}
		
		this.cx = _offset.left;
		this.cy = _offset.top;
	},
	events: function(){
		var oThis = this;
		this.ptr.find("div.calendar-button").mousedown(function(){
			jQuery(this).addClass("calendar-button-down");
		}).mouseup(function(evt){
			jQuery(this).removeClass("calendar-button-down");
			if(!oThis.is.animate)
				oThis.onclick(this, evt);
		});

		jQuery(document)
			.mousemove(function(evt){
				oThis._onmousemove(evt);
				return false;
			})

		new Button(this.ptr.parents("div.calendar").find("div.button-wrapper").click(function(){
			var form = oThis.ptr.parents("div.calendar").find("form.calendar-form");
			
			var dates = '';
			for (var i=0; i < oThis.aMonths.length; i++) {
				for(var k in oThis.aMonths[i].items){
					var curr = oThis.aMonths[i].items[k];
					if(curr.selected){
						var d = new Date(k);
						dates += oThis.dateString(d) + ',';
					}
				}
			};
			dates = dates.replace(/,$/, '');
			
			var curr = oThis.getCurrent();
			form.
				find("input[name='dates']").val(dates);
			form.
				find("input[name='month']").val(curr.date.getMonth()+1);
			form.
				find("input[name='year']").val(curr.date.getFullYear())
			
			form.submit();
		
		}))
		
		this.ptr.parents("div.calendar").find("span.calendar-clear").click(function(){
			oThis.empty();
			oThis.redraw(oThis.getCurrent());
		})
		
		jQuery(window).resize(function(){
			oThis.resize();
		})
		
		this.oArrow = this.ptr.parents("div.calendar").find("div.calendar-week").click(function(evt){
			oThis.selectByWeek(evt);
		})
	},
	onmousedown: function(evt){
		this.resize();
		
		var _s = this.getDay(this.current, evt.pageX-this.cx, evt.pageY-this.cy);
		if(_s){
			if(!evt.shiftKey)
				this.empty(this.current)

			this.start = new Date(_s);

			var curr = this.current.items[_s];
			if(curr.selected){
				curr.ptr.removeClass("selected");
				curr._selected = false;
				this.remove = true;
			} else {
				curr.ptr.addClass("selected");
				curr._selected = true;
				this.remove = false;
			}
			this.redraw(this.current);
			this.is.controls = true
		}
	},
	_onmousemove: function(evt){
		var week = this.getWeek(this.current, evt.pageY - this.cy);
		if(week)
			this.oArrow.css({ left: week.left-20, top: week.top }).show()
		else
			this.oArrow.hide();
	},
	onmousemove: function(evt, x, y){
		if(this.start){
			this.end = new Date(this.getDay(this.current, x, y));
			for(var k in this.current.items){
				var d = new Date(k);
				var curr = this.current.items[k];
				if(this.start < this.end)
					if(d >= this.start && d <= this.end) _mark(curr, this);
					else _back(curr);
				else
					if(d <= this.start && d >= this.end) _mark(curr, this);
					else _back(curr);
			}
			this.redraw(this.current);
		}

		function _mark(curr, obj){
			if(obj.remove){
				curr.ptr.removeClass("selected");
				curr._selected = false;
			} else {
				curr.ptr.addClass("selected");
				curr._selected = true;
			}
		}
		function _back(curr){
			curr._selected = curr.selected;
			if(curr.selected)
				curr.ptr.addClass("selected");
			else
				curr.ptr.removeClass("selected");
		}
	},
	onmouseup: function(){
		for(var k in this.current.items){
			var curr = this.current.items[k];
			curr.selected = curr._selected ? curr._selected : false;
		}
		this.redraw(this.current);
		
		if(this.is.controls)
			this.showControls()
		
		this.start = null;
		this.end = null;
	},
	onclick: function(obj, evt){
		var oThis = this;
		this.is.animate = true;
		
		var direction = 1;
		if(jQuery(obj).is(".calendar-button-left"))
			direction = -1;
		
		this.current = this.getCurrent();
		this.current.ptr.css({ position: "absolute", left: 0, top: 0 });
		var date = new Date(this.current.date.getFullYear(), this.current.date.getMonth()+direction);
		var newMonth = { year: date.getFullYear(), month: date.getMonth()+1 };
		if(!exist(newMonth)){
			newMonth = this.createMonth(newMonth);
			newMonth.ptr.css({ position: "absolute", left: direction*240, top: 0 });
			this.ptr.append(newMonth.ptr);
		} else {
			newMonth = getMonth(newMonth);
		}

		this.redraw(newMonth);

		newMonth.ptr.show();
		this.current.ptr.animate({ left: -1*direction*240 }, function(){
			jQuery(this).hide();
		});
		newMonth.ptr.animate({ left: 0 }, function(){
			oThis.is.animate = false;
		});
		if(newMonth.count != this.current.count){
			if(this.current.count < newMonth.count)
				this.ptr.animate({ height: 180 })
			else
				this.ptr.animate({ height: 160 })
		}

		this.aMonths.push(newMonth);
		setCurrent(newMonth);
		
		function setCurrent(month){
			for (var i=0; i < oThis.aMonths.length; i++) {
				oThis.aMonths[i].current = false;
			};
			month.current = true;
		}
		
		function exist(hDate){
			var date = new Date(hDate.year, hDate.month-1)
			for (var i=0; i < oThis.aMonths.length; i++) {
				if(oThis.aMonths[i].date.valueOf() == date.valueOf())
					return true;
			};
			return false;
		}
		
		function getMonth(hDate){
			var date = new Date(hDate.year, hDate.month-1);
			for (var i=0; i < oThis.aMonths.length; i++) {
				if(oThis.aMonths[i].date.valueOf() == date.valueOf())
					return oThis.aMonths[i];
			};
		}
	},
	
	showControls: function(){
		if(!this.is.controlsState){
			this.is.controlsState = true;
			this.ptr.parents("div.calendar").find("div.calendar-controls").css({ height: 0, overflow: "hidden" }).show()
				.animate({ height: 40 });
		}
	},
	selectByDay: function(day, evt){

		if(!evt.shiftKey)
			this.empty(this.current)

		var k;
		jQuery(day).parent().find("li").each(function(i){
			if(day == this)
				k = i;
		})
		k++;
		if(k == 7) k = 0;
		this.current = this.getCurrent();
		for(var key in this.current.items){
			var date = new Date(key);
			if(date.getDay() == k){
				this.current.items[key]._selected = true;
				this.current.items[key].ptr.addClass("selected");
			}
		}
		this.is.controls = true

		this.redraw(this.current);
		this.onmouseup();
	},
	
	selectByWeek: function(evt){
		var week = this.getWeek(this.current, evt.pageY - this.cy);

		if(!evt.shiftKey)
			this.empty(this.current)

		for(var key in this.current.items){
			if(this.current.items[key].top == week.top){
				this.current.items[key]._selected = true;
				this.current.items[key].ptr.addClass("selected");
			}
		}

		this.is.controls = true

		this.redraw(this.current);
		this.onmouseup();
		
	},
	redraw: function(month){
		for(var k in month.items){
			var curr = month.items[k];
			removeClasses(curr);
			if(curr.ptr.is(".selected")){
				var d = new Date(k);
				
				var sClass = '';
				add(-7);
				add(0, 1)
				add(7);
				add(1,-1);
				add(1,-8);
				
				curr.ptr.addClass(sClass);
				
			}
		}
		function check(d){
			return month.items[d.toString()] && month.items[d.toString()].ptr.is('.selected');
		}
		function add(){
			if(arguments.length > 1){
				if(d.getDay() == arguments[0]) sClass += 'o'
				else add(arguments[1]);
			} else {
				var _d = new Date(d.getFullYear(), d.getMonth(), d.getDate()+arguments[0]);
				if(check(_d)) sClass += 'f'
				else sClass += 'o';
			}
		}
		function removeClasses(day){
			var s = day.ptr.is(".selected")
			day.ptr.attr("class", day.sClass);
			if(s) day.ptr.addClass("selected")
		}
	},
	empty: function(month){
		this.hSetting.dates = []
		for (var i=0; i < this.aMonths.length; i++) {
			for(var k in this.aMonths[i].items){
				var curr = this.aMonths[i].items[k];
				curr.selected = curr._selected = false;
				curr.ptr.removeClass("selected");
			}
		};
	},

	getCurrent: function(){
		for (var i=0; i < this.aMonths.length; i++) {
			if(this.aMonths[i].current){
				return this.aMonths[i];
			}
		};
		return this.aMonths[0];
	},
	getDay: function(month, x, y){
		for(var k in month.items){
			if(((x >= month.items[k].left && x < month.items[k].left+20) || (x == null)) && y >= month.items[k].top && y < month.items[k].top+20)
				return k;
		}
	},
	getWeek: function(month, y){
		var k = this.getDay(month, null, y);
		return k ? month.items[k] : null;
	},

	createMonth: function(oDate){
		var oThis = this;
		
		var now = new Date();
		now = new Date(now.getFullYear(), now.getMonth(), now.getDate());
		var date = new Date(oDate.year, oDate.month-1, 1);
		var next = new Date(oDate.year, oDate.month, 0);
		var month = {
		 	ptr: jQuery("<div class='calendar-month'><div class='calendar-month-in'><h1>" + this.months.first[date.getMonth()] + ((date.getFullYear() != now.getFullYear()) ? (', ' + date.getFullYear()) : '') + "</h1><ul class='calendar-week-days'><li>ПН</li><li>ВТ</li><li>СР</li><li>ЧТ</li><li>ПТ</li><li class='calendar-free'>СБ</li><li class='calendar-free'>ВС</li></ul><ul class='calendar-days'></ul></div></div>"),
			date: new Date(date.getFullYear(), date.getMonth()),
			items: {},
			current: false
		}
		var days = month.ptr.find("ul.calendar-days");

		date.setDate(- (date.getDay() == 0 ? 7 : date.getDay()) + 1);
		
		var diff = next.valueOf() - date.valueOf();
		var to = Math.round(diff/1000/60/60/24 + (7-(next.getDay() == 0 ? 7 : next.getDay())));
		month.count = to;

		for (var i=0; i < to; i++) {
			var sId = '';
			var sClass = '';
			date.setDate(date.getDate()+1);
			if(date.valueOf() == now.valueOf())
				sId += " id='calendar-current'";
				
			if(date.valueOf() < now.valueOf())
				sClass += " past";
				
			if(date.getMonth() != oDate.month-1)
				sClass += " another";
			
			var day = jQuery("<li" + sId + " class='" + sClass + "'>" + (sId.length ? '<b>' : '') + date.getDate() + (sId.length ? '</b>' : '') + "</li>");
			var sDate = this.dateString(date);
			var bCheck = getDate(sDate);
			if(bCheck) day.addClass("selected");
			month.items[date.toString()] = { ptr: day, sClass: sClass, selected: bCheck ? true : false, _selected: bCheck ? true : false };
			days.append(day);
		};
		return events(month);
		
		function getDate(sDate){
			if(oThis.hSetting.dates)
				for (var i=0; i < oThis.hSetting.dates.length; i++) {
					if(oThis.hSetting.dates[i] == sDate) return true;
				};
			return false;
		}
		
		function events(month){
			month.ptr.find("ul.calendar-week-days li").click(function(evt){
				oThis.selectByDay(this, evt);
			})
			return month;
		}
	},
	
	dateString: function(date){
		return ((date.getDate() < 10) ? ('0' + date.getDate()) : date.getDate()) + "-" + (((date.getMonth()+1) < 10) ? ('0' + (date.getMonth()+1)) : (date.getMonth()+1)) + "-" + date.getFullYear();
	}

})