;(function($) {
	$.widget('ui.calendar', {
		
		_parityDate: null,
		
		_getDay: function(_date) {
			
			var _day = _date.getDay();
			return (--_day) < 0 ? (_day + 7) : _day;
		},
		
		_strToDate: function(_str) {
			
			var _date_data = /(\d{4})\-(\d{1,2})\-(\d{1,2})/.exec(_str);
			
			var _date = new Date();
			
			if (_date_data && _date_data.length == 4) {
				var _year = parseInt(_date_data[1], 10), _month = parseInt(_date_data[2], 10), _day = parseInt(_date_data[3], 10);
				_date.setFullYear(_year);
				_date.setMonth(_month - 1, 1);
				_date.setDate(_day);
			} else {
				var _date_data = /(\d{1,2})\.(\d{1,2})\.(\d{4})/.exec(_str);
				if (_date_data && _date_data.length == 4) {
					var _year = parseInt(_date_data[3], 10), _month = parseInt(_date_data[2], 10), _day = parseInt(_date_data[1], 10);
					_date.setFullYear(_year);
					_date.setMonth(_month - 1, 1);
					_date.setDate(_day);
				}
			}
			_date.setHours(0);
			_date.setMinutes(0);
			_date.setSeconds(0);
			_date.setMilliseconds(0);

			return _date;
		},
		
		_getLastDayOfMonth: function(_date) {
			
			if (!(_date instanceof Date)) 
				return null;
			
			var _current_month = _date.getMonth(),
				_d = new _date.constructor(_date); //clone
			
			for (var _i = 28; _i <= 31; _i++) {
				_d.setDate(_i + 1);
				if (_d.getMonth() != _current_month)
					return _i;
			}
			
			return null;
		},
		
		_constructMonthDiv: function(_firstDay, _selectedDay) {
			
			var _e = this.element, _o = this.options, self = this;
			
			var _div = $('<div />').addClass('month');
			
			var _first_day_of_week = self._getDay(_firstDay);
			
			var _date_str  = '<h3>' + _o.monthLabels[parseInt(_firstDay.getMonth())] + '</h3>';
			
			_date_str += _o.daysPlate; 
			
			_date_str += '<ul>';
			
			var _selected_day = null;
			
			var _year = _firstDay.getFullYear(), _month = _firstDay.getMonth() + 1;
			
			var _min_date_here = false, _max_date_here = false, _all_month_disabled = false;
			
			if (_o.minDate) {
				var _min_date = self._strToDate(_o.minDate), _min_date_year = _min_date.getFullYear(), _min_date_month = _min_date.getMonth() + 1;
				if (_min_date_year == _year && _min_date_month == _month) {
					_min_date_here = true;
					var _min_day = _min_date.getDate();
				} else if (_min_date_year > _year || (_min_date_year == _year && _min_date_month > _month)) {
					_all_month_disabled = true;
				}
			}
			
			if (_o.maxDate) {
				var _max_date = self._strToDate(_o.maxDate), _max_date_year = _max_date.getFullYear(), _max_date_month = _max_date.getMonth() + 1;
				if (_max_date_year == _year && _max_date_month == _month) {
					_max_date_here = true;
					var _max_day = _max_date.getDate();
				} else if (_max_date_year < _year || (_max_date_year == _year && _max_date_month < _month)) {
					_all_month_disabled = true;
				}
			}
			
			if ((_selectedDay instanceof Date) && ((_selectedDay.getMonth() + 1) == _month) && (_selectedDay.getFullYear() == _year)) {
				
				_selected_day = parseInt(_selectedDay.getDate(), 10);
			}
			
			var _today_date = new Date();
			var _today = null;
			if ((_today_date.getFullYear() == _year) && ((_today_date.getMonth() + 1) == _month)) {
			
				_today = _today_date.getDate();
			}
			
			var _max_date = parseInt(self._getLastDayOfMonth(_firstDay)) + _first_day_of_week;
			
			for (var _i = 0; _i < _max_date; _i++) {
				var _cur_date = ((_i - _first_day_of_week) < 0) ? '' : (1 + _i - _first_day_of_week);
				_class = '';
				
				if (_cur_date === _selected_day) {
				
					_class = _o.activeDateClass;
				} else if (_cur_date === _today) {
				
					_class = _o.todayClass;
				} else if (_cur_date === '' || _all_month_disabled || (_min_date_here && parseInt(_cur_date, 10) < _min_day) || (_max_date_here && parseInt(_cur_date, 10) > _max_day)) {
					
					_class = _o.disabledClass;
				}
				
				_date_str += '<li';
				_date_str += ' class="' + _class + '"'; 
				_date_str += (_cur_date != '') ? ' date="' + _year + '-' + _month + '-' + _cur_date + '"' : '';
				_date_str += '>';
				_date_str += _cur_date;
				_date_str += '</li>';
			}
			
			_date_str += '</ul>';
			_div.html(_date_str);
			
			if (typeof(_o.onHoverIn) == 'function' && typeof(_o.onHoverOut) == 'function') {
				
				var hoverIn = function() {
					_o.onHoverIn.call(self, $(this), self.options.parityDate);					
				};
				
				var hoverOut = function() {
					_o.onHoverOut.call(self, _div);					
				};
								
				$('li', _div).hover(hoverIn, hoverOut);
			}
			
			return _div;
		},
		
		_fillContent: function(_date, _marked_date, _animation_direction) {
			
			var _e = this.element, _o = this.options, self = this;
			
			var removed_months = _e.find('div.month');
			var new_months = [];
						
			for (var _j = 0; _j < _o.monthSimultaneously; _j++) {
				
				var _first_day = new Date(_date.getFullYear(), _date.getMonth(), 1, 0, 0, 0, 0);
				
				_first_day.setMonth(_first_day.getMonth() + _j);
				var _month_div = self._constructMonthDiv(_first_day, _marked_date);
				_month_div.attr('month', _first_day.getMonth() + 1);
				_month_div.hide();
				new_months.push(_month_div);
				_e.append(_month_div); 
			}

	        if(_o.animation && typeof(_animation_direction)!="undefined"){
		        var anim_param = -50;
		        if(_animation_direction<0){
		          anim_param *= -1;
		        }
		        removed_months.eq(0).animate({
		            marginLeft: anim_param+'px'
		          }, 100, "linear", 
		          function(){
		            removed_months.remove();
		            _e.find('div.month').fadeIn();
		          }
		        );
	        
	        } else {
		        removed_months.remove();
		        _e.find('div.month').show();
	        }
	        
	        
	        var _first_day = new Date(_date.getFullYear(), _date.getMonth(), 1, 0, 0, 0, 0);
	        
	        if (_first_day < this._strToDate(this.options.minDate)) {
	        
	        	$('.prev', this.element).addClass('disabled');
			} else {
				$('.prev', this.element).removeClass('disabled');
			}
	        
	        self._redrawSelected();
	        
	        if (typeof(_o.onDisplay) == 'function') {
				_o.onDisplay.call(self);
	        }	        
		},
		
		_selectMonth: function(_i) {
			
			this.options._active_date.setMonth(this.options._active_date.getMonth() + _i);
			this._fillContent(this.options._active_date, this.options._current_date, _i);
		},
		
		_redrawSelected: function() {
			
			if (!this.options.parityDate) {
				return; 
			}
			
			var _currentDate = this.options._current_date,
				_parityDate = this.options.parityDate,
				_startDate = null, _endDate = null,
				_today_date = new Date(),
				_days_elements = this.element.find('.month').find('li[date]'),
				_days_diff = 0, _offset = 0,
				_class = '', _alt_class = '',
				_months = this.element.find('.month'),
				_left_month_element = _months.eq(0),
				_right_month_element = _months.eq(1);
			
			
			_days_elements.removeClass(this.options.intermediateClass);			
			_days_elements.removeClass(this.options.parityDateClass);
			_days_elements.removeClass(this.options.activeDateClass);
			
			if (_currentDate < _parityDate) {
				_startDate = _currentDate;
				_endDate = _parityDate;	
				
				_class = this.options.activeDateClass;
				_alt_class = this.options.parityDateClass;	
			} else if (_currentDate > _parityDate) {
				_startDate = _parityDate;
				_endDate = _currentDate;
				
				_class = this.options.parityDateClass;
				_alt_class = this.options.activeDateClass;
			} else {
				return;
			}
			
			var _is_present = false;
			
			_months.each(function(index, element) { 	
				var m = $(element).attr('month') - 1;
				
				_is_present = _is_present || _startDate.getMonth() <= m || _endDate.getMonth() >= m;				
			});
						
			if (!_is_present) {
				return;
			}

			
			var show_start = true, show_end = true;
			if (_startDate.getMonth() < (_left_month_element.attr('month') - 1)) {
				_startDate = new _startDate.constructor(_startDate); //clone
				
				_startDate.setMonth(_left_month_element.attr('month') - 1);
				_startDate.setDate(1);
				
				show_start = false;
			} 
			
			if (_endDate.getMonth() > (_right_month_element.attr('month') - 1)) {
				_endDate = new _endDate.constructor(_endDate); //clone
				
				_endDate.setMonth(_right_month_element.attr('month') - 1);
				_endDate.setDate(this._getLastDayOfMonth(_endDate));
				
				show_end = false;
			} 
			
			var _startDateStr = _startDate.getFullYear() + "-" + (_startDate.getMonth()+1) + "-" + _startDate.getDate(), 
				_endDateStr = _endDate.getFullYear() + "-" + (_endDate.getMonth()+1) + "-" + _endDate.getDate(),
				_startDateElement = _days_elements.filter("[date='"+_startDateStr+"']"),
				_endDateElement = _days_elements.filter("[date='"+_endDateStr+"']");
			
			
			
			_days_diff = (_endDate - _startDate) / (1000 * 24 * 3600);
			_offset = _startDate.getDate() -1;
			if (_days_diff && _startDateElement.closest('.month').attr('month') == _endDateElement.closest('.month').attr('month')
					   	   && _left_month_element.attr('month') != _endDateElement.closest('.month').attr('month')) {
				
				_offset += _left_month_element.find('li[date]').length;
			}
			
			if (show_start) {			
				_days_elements.eq(_offset).addClass(_class);
			}
			
			while (_days_diff>= 0) {
				
				_days_elements.eq(_offset++).addClass(this.options.intermediateClass);
				_days_diff--;
			}
			
			if (show_end) {
				_days_elements.eq(_offset-1).addClass(_alt_class);
			}
		},
		
		_init: function() {
			
			var _e = this.element, _o = this.options, self = this;
			
			this.options._current_date = self._strToDate(_o.currentDate);
			
			if (_o.parityDate && !(_o.parityDate instanceof Date)) {
				_o.parityDate = self._strToDate(_o.parityDate);
			}
			
			var _prev_month = $('<a href="#" class="prev"/>');
			var _next_month = $('<a href="#" class="next"/>');
			_e.addClass(_o.calendarClass).append(_prev_month).append(_next_month);
			
			this.options._active_date = new Date(this.options._current_date.getFullYear(), this.options._current_date.getMonth(), this.options._current_date.getDate(), 0, 0, 0);
			
			_next_month.click(function(_ev) {
				_ev.preventDefault();
				_ev.stopPropagation();
				if ($(this).hasClass('disabled')) {
					return;
				}
				self._selectMonth(self.options.monthScrollerDiff);
			});
			_prev_month.click(function(_ev) {
				_ev.preventDefault();
				_ev.stopPropagation();
				if ($(this).hasClass('disabled')) {
					return;
				}
				self._selectMonth(-1 * self.options.monthScrollerDiff);
			});
			this.goNextMonth = function(){
				self._selectMonth(1)
			}
			this.goPrevMonth = function(){
				self._selectMonth(-1)
			}
      
			this.options.onSelectStack = [];
			
			if (typeof(_o.onSelect) == 'function') {
				this.options.onSelectStack.push(_o.onSelect);
			}				
			
			_e.click(function(_ev) {

				var _li = $(_ev.target);
				
				if (!_li.filter('li:not(.' + _o.disabledClass + ')').length) {
					return;
				}
				
				if (_o.readOnly) {
					return;
				}
				
				var _date = self._strToDate(_li.attr('date'));

				self.options._current_date = _date;
				$('li.' + _o.activeDateClass, _e).removeClass(_o.activeDateClass);
				_li.addClass(_o.activeDateClass);
				
				if (self.options.onSelectStack.length) {
					for (var _k = 0; _k < self.options.onSelectStack.length; _k++) {
						self.options.onSelectStack[_k].call(_li, _date);
					}
				}
			});
			
			self._fillContent(self.options._active_date, self.options._current_date);						
		},
		
		setMinDate: function(_date) {
			this.options.minDate = _date;
			var _min_date = this._strToDate(_date);
			if (_min_date instanceof Date && _min_date > this.options._current_date) {
				this.options._active_date = this.options._current_date = _min_date//new Date(_min_date.getFullYear(), _min_date.getMonth(), _min_date.getDate());
				if (this.options.onSelectStack.length)
					for (var _k = 0; _k < this.options.onSelectStack.length; _k++)
						this.options.onSelectStack[_k].call(this.element, this.options._current_date);
			}
			this._fillContent(this.options._active_date, this.options._current_date);
		},
		
		setMaxDate: function(_date) {
			this.options.maxDate = _date;
			var _max_date = this._strToDate(_date);
			if (_max_date instanceof Date && _max_date < this.options._current_date) {
				this.options._active_date = this.options._current_date = new Date(_max_date.getFullYear(), _max_date.getMonth(), _max_date.getDate());
				if (this.options.onSelectStack.length)
					for (var _k = 0; _k < this.options.onSelectStack.length; _k++)
						this.options.onSelectStack[_k].call(this.element, this.options._current_date);
			}
			this._fillContent(this.options._active_date, this.options._current_date);
		},
		
		moveDateUp: function(_date) {
			_date = this._strToDate(_date);
			if (_date instanceof Date && _date > this.options._current_date) {
				this.options._active_date = this.options._current_date = new Date(_date.getFullYear(), _date.getMonth(), _date.getDate());
				if (this.options.onSelectStack.length)
					for (var _k = 0; _k < this.options.onSelectStack.length; _k++)
						this.options.onSelectStack[_k].call(this.element, this.options._current_date);
			}
			this._fillContent(this.options._active_date, this.options._current_date);
		},
		
		moveDateDown: function(_date) {
			_date = this._strToDate(_date);
			if (_date instanceof Date && _date < this.options._current_date) {
				this.options._active_date = this.options._current_date = new Date(_date.getFullYear(), _date.getMonth(), _date.getDate());
				if (this.options.onSelectStack.length)
					for (var _k = 0; _k < this.options.onSelectStack.length; _k++)
						this.options.onSelectStack[_k].call(this.element, this.options._current_date);
			}
			this._fillContent(this.options._active_date, this.options._current_date);
		},
		
		setParityDate: function(_d) {
			
			this.options.parityDate = this._strToDate(_d);
						
			//this._redrawSelected();
		},
		
		addEventOnSelect: function(_f) {
			if (typeof(_f) == 'function') {
				this.options.onSelectStack.push(_f);
			}
		},
		
		redraw: function() {
			this.options._active_date = new Date(this.options._current_date.getFullYear(), this.options._current_date.getMonth(), this.options._current_date.getDate());
			this._fillContent(this.options._active_date, this.options._current_date);
		},
		
		goNextMonth: function(){
			
			this._selectMonth(1)
		}
	});
})(jQuery);

$.extend($.ui.calendar, {
	defaults: {
		minDate: null,
		maxDate: null,
		monthLabels: [ 'ßíâàðü', 'Ôåâðàëü', 'Ìàðò', 'Àïðåëü', 'Ìàé', 'Èþíü', 'Èþëü', 'Àâãóñò', 'Ñåíòÿáðü', 'Îêòÿáðü', 'Íîÿáðü', 'Äåêàáðü' ],
		dayLabels: [ 'Ïí', 'Âò', 'Ñð', '×ò', 'Ïò', 'Ñá', 'Âñ' ],
		daysPlate: '',
		onSelect: null,
		onHoverIn: null,
		onHoverOut: null,
		onDisplay: null,
		currentDate: null,
		calendarClass: 'b-calendar',
		monthSimultaneously: 2,
		readOnly: false,
		animation: false,
		monthScrollerDiff: 1,
		
		disabledClass: 'disabled',
		todayClass: 'current_date',
		activeDateClass: 'to_date',
		parityDateClass: 'from_date',
		intermediateClass: 'selected_dates',
			
		parityDate: null	
	}
});