/*
 * Date converter interface plugin
 * 
 * @author slava
 */
(function($){
	$.widget("ui.dateConverter", {
		_init: function() {
			var o = this.options;
			var el = this.element;
			var self = this;
			
			var dates = this.dates = [];
			
			this.allDates = el.find('.date');
			
			var convNum = this.setDefaults();
			
			this.allDates.each(function(i) {
				dates[i] = {};
				var date = dates[i].date = $(this);
				
				// calendar
				var calendar = dates[i].calendar = date.find('select.calendar').bind('change', self, self.change);
				calendar.selectmenu({
					close: self.selectmenuClose,
					destroy: self.selectmenuDestroy,
					open: self.selectmenuOpen,
					select: self.selectmenuSelect,
					style: 'dropdown',
					transferClasses: true
				});
				
				dates[i].dow = date.find('.dow');
				
				dates[i].day = date.find('input.day').bind('keyup input', self, self.change);
				
				// month
				var month = dates[i].month = date.find('select.month').bind('change', self, self.change);
				month.selectmenu({
					close: self.selectmenuClose,
					destroy: self.selectmenuDestroy,
					open: self.selectmenuOpen,
					select: self.selectmenuSelect,
					style: 'dropdown',
					transferClasses: true
				});
				
				dates[i].year = date.find('input.year').bind('keyup input', self, self.change);
				dates[i].year = date.find('input.year').bind('keyup input', function() {
					self.setYearWidth($(this));
				});
				dates[i].year.after('<span class="year-helper"></span>');
				
				// era
				var era = dates[i].era = date.find('select.era').bind('change', self, self.change);
				era.selectmenu({
					close: self.selectmenuClose,
					open: self.selectmenuOpen,
					select: self.selectmenuSelect,
					style: 'dropdown',
					transferClasses: true
				});
				
				if(self.isEra(calendar.val())) {
					date.find('a.era').show();
				} else {
					date.find('a.era').hide();
				}
				
				dates[i].prevDate = {
					d: 0,
					m: 0,
					y: 0
				};
				dates[i].prevCal = '';
			});
			
			el.find('.equal').click(function(){
				self.viceVersa();
			});
			
			el.css('visibility', 'visible');
			
			el.find('input.year').each(function() {
				self.setYearWidth($(this));
			})
			
			dates[0].date.width('auto');
			
			this.convert(convNum);
		},
		
		setDefaults: function() {
			var o = this.options;
			var el = this.element;
			var dates = el.find('.date');
			
			// split hash
			var hash = location.hash.toString().replace('#', '').toLowerCase().split('_');
			var url = document.location.toString().replace(/^.*converter\/?/, '').replace(/#.*$/, '');
			if(url.indexOf('?') != -1) {
				url = url.substring(0, url.indexOf('?'));
			}
			var urlArr = url.replace(/\/$/, '').split('/');
			if(urlArr[0] != '') {
				hash = urlArr;
				if(hash[1] && hash[2]) {
					var tmp = hash[2];
					hash[2] = hash[1];
					hash[1] = tmp;
				}
			}
			//console.log(hash);
			
			if(!hash[0]) hash = [];
			switch (hash.length) {
				case 1:
				case 2:
					// only right calendar
					
					// right calendar
					dates.eq(1).find('.calendar option[value="' + hash[0] + '"]').attr('selected', 'selected');
					
					if(hash.length == 2) {
						var dateArr = hash[1].split('.');
						
						var date = {
							d: parseInt(dateArr[0], 10),
							m: parseInt(dateArr[1], 10),
							y: parseInt(dateArr[2], 10)
						};
					} else {
						var date = this.getToday(hash[0]);
					}
					
					dates.eq(1).find('.day').val(date.d);
					
					var options = this.getMonthOptions(hash[0], date.m);
					var month = dates.eq(1).find('select.month').empty().append(options);
					
					var year = parseInt(date.y, 10);
					var era = this.era(hash[0], year);
					
					if (era === 0) {
						dates.eq(1).find('.year').val(year);
						dates.eq(1).find('.era').val('1');
					} else {
						dates.eq(1).find('.year').val(Math.abs(year));
						dates.eq(1).find('.era').val(era);
					}
					
					// left calendar
					var calendar = hash[0] == o.defaultCalendars[0] ? o.defaultCalendars[1] : o.defaultCalendars[0];
					dates.eq(0).find('.calendar option[value="' + calendar + '"]').attr('selected', 'selected');
					options = this.getMonthOptions(calendar);
					dates.eq(0).find('select.month').empty().append(options);
					
					return 1;
					break;
					
				case 3:
					// left calendar - left date - right calendar
					
					// left calendar
					dates.eq(0).find('.calendar option[value="' + hash[0] + '"]').attr('selected', 'selected');
					
					var dateArr = hash[1].split('.');
					var date = dates.eq(0);
					date.find('.day').val(parseInt(dateArr[0], 10));
					
					var options = this.getMonthOptions(hash[0], parseInt(dateArr[1], 10));
					var month = dates.eq(0).find('select.month').empty().append(options);
					
					var year = parseInt(dateArr[2], 10);
					var era = this.era(hash[0], year);
					
					if (era === 0) {
						date.find('.year').val(year);
						date.find('.era').val('1');
					} else {
						date.find('.year').val(Math.abs(year));
						date.find('.era').val(era);
					}
					
					// right calendar
					dates.eq(1).find('.calendar option[value="' + hash[2] + '"]').attr('selected', 'selected');
					options = this.getMonthOptions(hash[2]);
					dates.eq(1).find('select.month').empty().append(options);
					return 0;
					break;
					
				default:
					// left calendar
					dates.eq(0).find('.calendar option[value="' + o.defaultCalendars[0] + '"]').attr('selected', 'selected');
					
					var today = this.getToday(o.defaultCalendars[0]);
					
					dates.eq(0).find('.day').val(today.d);
					
					var options = this.getMonthOptions(o.defaultCalendars[0], today.m);
					dates.eq(0).find('select.month').empty().append(options);
					
					dates.eq(0).find('.year').val(today.y);
					
					//right calendar
					dates.eq(1).find('.calendar option[value="' + o.defaultCalendars[1] + '"]').attr('selected', 'selected');
					
					options = this.getMonthOptions(o.defaultCalendars[1]);
					dates.eq(1).find('select.month').empty().append(options);; 
					return 0;
					break;
			}
		},
		
		/**
		 * Gets today date with needed calendar
		 * 
		 * @param {String} calendar
		 */
		getToday: function(calendar){
			var o = this.options;
			
			if(!calendar) calendar = o.defaultCalendars[0];
			var today = new Date();
			var date = {
				d: today.getDate(),
				m: today.getMonth() + 1,
				y: today.getFullYear()
			}
			
			return o.converter.convert(date, 'gregorian', calendar);
		},
		
		selectmenuClose: function(event, selectmenu) {
			$(document).trigger('hideCluetip');
			content.height('');
			selectmenu.list.shadow('hide');
		},
		
		selectmenuDestroy: function(event, selectmenu) {
			selectmenu.list.shadow('destroy');
		},
		
		selectmenuOpen: function(event, selectmenu) {
			var list = selectmenu.list;
			list.css('top', selectmenu.newelement.children().offset().top);
			if (!IE6) {
				list.width('auto');
			}
			
			if (list.height() + list.offset().top > content.height() + content.offset().top) {
				content.height(list.height() + list.offset().top - content.offset().top);
			}
			list.shadow();
			list.shadow('show');
		},
		
		selectmenuSelect: function(event, selectmenu) {
			selectmenu.close();
		},
		
		getMonthOptions: function(calendar, selected) {
			var o = this.options;
			var months = o.locale[calendar].months;
			var options = '';
			for(var i in months) {
				options += '<option' + (selected && selected - 1 == i ? ' selected="selected"' : '') + ' value="' + (parseInt(i, 10) + 1) + '">' + months[i].genitive + '</option>'; 
			}
			return options;
		},
		
		convert: function(dateNum){
			var o = this.options;
			var el = this.element;
			
			this.allDates.removeClass(o.error).removeClass(o.disabled);
			
			var inDateObj = this.dates[dateNum];
			var outDateObj = this.dates[1 - dateNum];
			
			this.setYearWidth(inDateObj.year);
			
			if(this.isEmpty(inDateObj)) {
				var inDate = this.isDate(inDateObj, true);
				if(inDate) {
					var inCal = inDateObj.calendar.val();
					
					if(inDate.dow) {
						inDateObj.dow.text(o.locale[inCal].dow[inDate.dow].nominative);
					} else {
						inDateObj.dow.html('&nbsp');
					}
					
					var outCal = outDateObj.calendar.val();
					var outDate = o.converter.convert(inDate, inCal, outCal);
					
					if(outDate) {						
						if (outDate.dow) {
							outDateObj.dow.text(o.locale[outCal].dow[outDate.dow].nominative)
						} else {
							outDateObj.dow.html('&nbsp');
						}
						
						outDateObj.day.val(outDate.d);
						outDateObj.month.selectmenu('value', outDate.m - 1);
						var outEra = this.era(outCal, outDate.y);
						if (outEra) {
							outDateObj.year.val(Math.abs(outDate.y));
							outDateObj.era.val(outEra);
							outDateObj.era.selectmenu('value', outDateObj.era[0].selectedIndex);
							outDateObj.date.find('a.era').show();
						} else {
							outDateObj.year.val(outDate.y);
							outDateObj.date.find('a.era').hide();
						}
						
						this.setYearWidth(outDateObj.year);
						
						if(o.calendar) {
							var calDate = dateNum ? inDate : outDate;
							var calDateObj = dateNum ? inDateObj : outDateObj;
							o.calendar.calendar('show');
							
							var sDateObj = this.dates[0];
							var fDateObj = this.dates[1];
							
							if (calDate.m == calDateObj.prevDate.m && calDate.y == calDateObj.prevDate.y && sDateObj.calendar.val() == sDateObj.prevCal) {
								o.calendar.calendar('setDay', dateNum ? inDate.d : outDate.d);
							} else {
								o.calendar.calendar('setDate', dateNum ? inDate : outDate, this.dates[1].calendar.val(), this.dates[0].calendar.val());
							}
						}
						
						outDateObj.prevDate = outDate;
						outDateObj.prevCal = outCal;
					} else {
						this.disable(outDateObj);
						o.calendar.calendar('hide');
					}
					
					inDateObj.prevDate = inDate;
					inDateObj.prevCal = inCal;
				} else {
					this.error(inDateObj);
					o.calendar.calendar('hide');
				}
			}
		},
		
		/**
		 * Callback function, calls when date changes
		 */
		change: function(event) {
			if (event) {
				var self = event.data;
			} else {
				var  self = this;
			}
			var el = self.element;
			var index = el.find('.date').index($(this).closest('.date')[0]);
			
			// if changing calendar
			if($(event.target).hasClass('calendar')) {
				var options = self.getMonthOptions(self.dates[index].calendar.val())
				self.dates[index].month.selectmenu('destroy').hide().html(options);
				self.dates[index].month.selectmenu({
					close: self.selectmenuClose,
					destroy: self.selectmenuDestroy,
					open: self.selectmenuOpen,
					select: self.selectmenuSelect,
					style: 'dropdown',
					transferClasses: true
				});
				index = 1 - index;
			}
			
			self.convert(index);
		},
		
		viceVersa: function() {
			var calendar = this.dates[0].calendar.val();
			
			this.dates[0].calendar.val(this.dates[1].calendar.val());
			this.dates[0].calendar.selectmenu('value', this.dates[0].calendar[0].selectedIndex);
			this.dates[0].calendar.change();
			
			this.dates[1].calendar.val(calendar);
			this.dates[1].calendar.selectmenu('value', this.dates[1].calendar[0].selectedIndex);
			this.dates[1].calendar.change();
		},
		
		error: function(dateObj) {
			var o = this.options;
			var el = this.element;
			this.allDates.addClass(o.disabled);
			dateObj.date.removeClass(o.disabled).addClass(o.error);
		},
		
		disable: function(dateObj) {
			var o = this.options;
			var el = this.element;
			dateObj.date.addClass(o.disabled);
		},
		
		isEmpty: function(dateObj) {			
			if(dateObj.day.val() != '' && dateObj.year.val() != '' && dateObj.year.val() != '-') {
				return true;
			} else {
				return false;
			}
		},
		
		isDate: function(dateObj, sameDate) {
			var o = this.options;
			var flag = false;
			
			var calendar = dateObj.calendar.val();
			
			var date = {
				d: dateObj.day.val(),
				m: parseInt(dateObj.month.val(), 10),
				y: dateObj.year.val()
			}
			
			var isEra = this.isEra(calendar)
			
			if (isEra) {
				var yearPattern = /^\d+$/;
			} else {
				var yearPattern = /^-?\d+$/;
			}
			
			if (date.d.toString().search(/^\d+$/) != -1 && date.y.toString().search(yearPattern) != -1) {
				date.d = parseInt(date.d, 10);
				if (isEra) {
					date.y = parseInt(date.y, 10) * parseInt(dateObj.era.val(), 10);
				}
				
				var convDate = o.converter.convert(date, calendar, calendar);
				
				if (convDate) {
					flag = convDate;
					
					if (sameDate && !(date.d == convDate.d && date.m == convDate.m && date.y == convDate.y)) {
						flag = false;
					}
				}
			}
			
			return flag;
		},
		
		/**
		 * Return era value if exist, otherwise return 0 (false)
		 * 
		 * @param {String} calendar
		 * @param {Integer} year
		 */
		era: function(calendar, year) {
			var  flag = 0;
			
			if(calendar == 'gregorian' || calendar == 'julian') {
				if(year < 0) {
					flag = -1;
				} else {
					flag = 1;
				}
			}
			
			return flag;
		},
		
		/**
		 * Checks if the calendar has era or not
		 * 
		 * @param {String} calendar
		 */
		isEra: function(calendar) {
			if (calendar == 'gregorian' || calendar == 'julian') {
				return true;
			} else {
				return false;
			}
		},
		
		setYearWidth: function(year) {
			var value = '1' + year.val();
			var helper = year.next().text(value);
			year.width(helper.width());
		},
		
		setDate: function(newDate) {
			var date = this.dates[1];
			
			date.day.val(newDate.d);
			
			date.month.val(newDate.m);
			date.month.selectmenu('value', date.month[0].selectedIndex);
			
			var year = newDate.y;
			var era = this.era(date.calendar.val(), year);
			
			if (era) {
				date.year.val(Math.abs(year));
				date.era.val(era);
				date.era.selectmenu('value', date.era[0].selectedIndex);
				date.date.find('a.era').show();
			} else {
				date.year.val(year);
				date.date.find('a.era').hide();
			}
			
			this.convert(1);
		},
		
		setCalendar: function(calendar) {
			var date = this.dates[1];
			date.calendar.val(calendar);
			date.calendar.selectmenu('value', date.calendar[0].selectedIndex);
			date.calendar.change();
		},
		
		setDay: function(day) {
			var date = this.dates[1];
			date.day.val(day);
			this.convert(1);
		}
	});
	
	$.extend($.ui.dateConverter, {
		defaults: {
			converter: dateConverter,
			defaultCalendars: ['gregorian', 'julian'],
			disabled: 'disabled',
			error: 'error'
		}
	});
})(jQuery);

/* end: Date converter interface plugin */


/* Calendar plugin */
(function($){
	$.widget("ui.calendar", {
		_init: function() {
			var o = this.options;
			var el = this.element;
			var self = this;
			
			this.oldIE = $.browser.msie && $.browser.versionX < 8;// || $.browser.safari && $.browser.versionX == 3;
			
			this.converts = 0;
			
			this.head = {};
			
			var month = this.head.month = el.find('.header select.month').change(function() {
				var newDate = $.extend({}, self.date, {m: parseInt(this.value, 10)});
				o.dateConverter.dateConverter('setDate', newDate);
			});
			
			var year = this.head.year = el.find('.header input.year').bind('keyup input', function() {
				self.setYearWidth($(this));
				
				if (self.isYear(this.value)) {
					var newDate = $.extend({}, self.date, {y: parseInt(this.value, 10)});
					
					o.dateConverter.dateConverter('setDate', newDate);
				}
			});
			year.after('<span class="year-helper"></span>');
			
			var era = this.head.era = el.find('.header select.era').change(function() {
				var newDate = {};
				newDate = $.extend(newDate, self.date);
				newDate.y = Math.abs(newDate.y) * this.value;
				
				o.dateConverter.dateConverter('setDate', newDate);
			});
			era.selectmenu({
				close: self.selectmenuClose,
				open: self.selectmenuOpen,
				destroy: self.selectmenuDestroy,
				select: self.selectmenuSelect,
				style: 'dropdown',
				transferClasses: true,
				width: 'auto'
			});
			
			var calendar = this.head.calendar = el.find('.header select.calendar').change(function() {
				o.dateConverter.dateConverter('setCalendar', this.value);
			});
			calendar.selectmenu({
				close: self.selectmenuClose,
				destroy: self.selectmenuDestroy,
				select: self.selectmenuSelect,
				open: self.selectmenuOpen,
				style: 'dropdown',
				transferClasses: true
			});
			
			this.head.prep = el.find('.header .calendar-prep');
			this.head.after = el.find('.header .calendar-after');
			
			this.events = el.find('#events');
			this.datesTab = el.find('#dates');
			
			el.find('.controls a').click(function() {
				var direction = $(this).parent().hasClass('next') ? +1 : -1;
				
				var months = o.locale[self.fCalendar].months.length;
				var newDate = {};
				newDate = $.extend(newDate, self.date);
				
				newDate.m += direction;
			
				if (direction > 0 && newDate.m == months + 1) {
					newDate.m = 1;
					newDate.y++;
					
					if (newDate.y == 0 && self.era(self.fCalendar, newDate.y)) 
						newDate.y++;
				} else {
					if (direction < 0 && newDate.m == 0) {
						newDate.m = months;
						newDate.y--;
						
						if (newDate.y == 0 && self.era(self.fCalendar, newDate.y))
							newDate.y--;
					}
				}
				
				o.dateConverter.dateConverter('setDate', newDate);
			});
			
			this.foot = {};
			this.foot.legend = el.find('tfoot .legend');
			this.foot.fCal = el.find('tfoot .fCal');
			this.foot.sCal = el.find('tfoot .sCal');
			this.foot.lines = el.find('tfoot .lines');
			this.foot.cell = el.find('tfoot .cell');
			
			this.current = {} 
			this.current.t = $('<div class="cc cc-t"></div>');
			this.current.b = $('<div class="cc cc-b"></div>');
			this.current.l = $('<div class="cc cc-l"></div>');
			this.current.r = $('<div class="cc cc-r"></div>');
			
			this.hover = {} 
			this.hover.t = $('<div class="ch ch-t"></div>');
			this.hover.b = $('<div class="ch ch-b"></div>');
			this.hover.l = $('<div class="ch ch-l"></div>');
			this.hover.r = $('<div class="ch ch-r"></div>');
			
			for(var i in this.current) {
				$('body').append(this.current[i]);
			}
			
			for(var i in this.hover) {
				$('body').append(this.hover[i]);
			}
			
			this.tabs = el.find('.tabs').tabs({
				cookie: { expires: 1 },
				show: function(event, ui) {
					if(ui.panel.id == 'calendar') {
						self.showCurrent();
					} else {
						self.hideCurrent();
						self.hideHover();
					}
				}
			});
		},
		
		selectmenuClose: function(event, selectmenu) {
			$(document).trigger('hideCluetip');
			content.height('');
			selectmenu.list.shadow('hide');
		},
		
		selectmenuDestroy: function(event, selectmenu) {
			selectmenu.list.shadow('destroy');
		},
		
		selectmenuOpen: function(event, selectmenu) {
			var list = selectmenu.list;
			list.css('top', selectmenu.newelement.children().offset().top);
			if (!IE6) {
				list.width('auto');
			}
			
			if (list.height() + list.offset().top > content.height() + content.offset().top) {
				content.height(list.height() + list.offset().top - content.offset().top);
			}
			list.shadow();
			list.shadow('show');
		},
		
		selectmenuSelect: function(event, selectmenu) {
			selectmenu.close();
		},
		
		setDate: function(date, fCalendar, sCalendar) {
			var o = this.options;
			var el = this.element;
			var self = this;
			
			if (date) {
				this.date = date;
			} else {
				date = this.date;
			}
			
			if (fCalendar) {
				this.fCalendar = fCalendar;
			} else {
				fCalendar = this.fCalendar;
			}
			
			if (sCalendar) {
				this.sCalendar = sCalendar;
			} else {
				sCalendar = this.sCalendar;
			}
			
			if(fCalendar == 'gregorian' && sCalendar == 'gregorian') {
				el.addClass('calendar-table-gregorian');
			} else {
				el.removeClass('calendar-table-gregorian');
			}
			
			this.head.calendar.val(fCalendar).selectmenu('value', this.head.calendar[0].selectedIndex);
			var parts = this.getCalParts(fCalendar);
			 
			this.head.prep.text(' ' + parts.prep + ' ');
			this.head.after.text(' ' + parts.after);
			
			var options = this.getMonthOptions(fCalendar);
			this.head.month.selectmenu('destroy').hide().html(options);
			
			function setMonth() {
				self.head.month.val(date.m);
				self.head.month.selectmenu({
					close: self.selectmenuClose,
					destroy: self.selectmenuDestroy,
					open: self.selectmenuOpen,
					select: self.selectmenuSelect,
					style: 'dropdown',
					transferClasses: true
				});
			};
			
			if(IE6) {
				setTimeout(setMonth, 1);
			} else {
				setMonth();
			}
			
			var era = this.era(fCalendar, date.y);
			if (era) {
				this.head.year.val(Math.abs(date.y));
				this.head.era.val(era);
				this.head.era.selectmenu('value', this.head.era[0].selectedIndex);
				el.find('a.era').show();
			} else {
				this.head.year.val(date.y);
				el.find('a.era').hide();
			}
			
			this.setYearWidth(this.head.year);
			
			var months = this.head.month.find('option');
			
			var next = this.head.next = el.find('.controls .next');
			this.setControl(next, fCalendar, date, +1);			
			var prev = this.head.prev = el.find('.controls .prev');
			this.setControl(prev, fCalendar, date, -1);
			
			this.redrawBody(date, fCalendar, sCalendar);
			this.setLegend();
			
			this.setEvents(date, fCalendar);
			this.setDates(date, fCalendar);
			
			//this.setHash();
			this.setResultLinks();
			
			this.converts++;
		},
		
		redrawBody: function(curDate, fCalendar, sCalendar) {
			var o = this.options;
			var el = this.element;
			var self = this;
			
			el.find('tbody tr:has(td)').remove();
			
			var curDate = this.date;
			
			var date = $.extend({}, curDate, {d: 1});
			var startGDate = o.converter.convert(date, self.fCalendar, 'gregorian');
			
			var html = '<tr>';
			
			for(var i = 1; i < startGDate.dow; i++) {
				html += '<td class="bg bg-h36 unselectable"></td>';
			}
			
			var colPos = startGDate.dow;
			var i = 1;
			var convDate = o.converter.convert(date, fCalendar, fCalendar);
			
			while(this.isSameDate(date, convDate)) {
				var sDate = o.converter.convert(date, fCalendar, sCalendar);
				if(sCalendar == 'gregorian') {
					var gDate = sDate;
				} else if(fCalendar == 'gregorian') {
					var gDate = date;
				} else {
					var gDate = o.converter.convert(date, fCalendar, 'gregorian');
				}
				var fMonth = o.locale[fCalendar].months[date.m - 1].genitive;
				
				var fTitle = i + ' ' + fMonth;
				if (fCalendar != sCalendar) {
					var sTitle = sDate.d + ' ' + o.locale[sCalendar].months[sDate.m - 1].genitive + ' &mdash; ';
				} else {
					var sTitle = '';
				}
				
				var className = 'bg bg-h36 day';
				if(curDate.d == i) className += ' current';
				if(i == 1) className += ' month-start';
				if(gDate.d == 1 || (sCalendar != 'gregorian' && sDate.d == 1)) className += ' s-month-start';
				html += '<td class="' + className + '" rel=".calendar-table .bubble-content">';
				html += '<div class="bubble-content">' + sTitle + fTitle + '</div>';
				html += '<div class="cell">';
				
				html += '<div class="f">';
				html += '<div class="day">' + i + '</div>';
				html += '<div class="month' + (fMonth.length > 8 ? ' month-smaller' : '') + '">' + fMonth + '</div>';
				html += '</div>';
				
				html += '<div class="s">';
				if (
					sCalendar == 'gregorian' && fCalendar != 'gregorian' ||
					fCalendar != 'gregorian' && sCalendar != 'gregorian'
				) {
					html += '<span class="day">' + gDate.d + '</span>';
					html += '<span class="month">' + o.locale['gregorian'].months[gDate.m - 1].genitive + '</span>';
					
				} else if(fCalendar == 'gregorian' && sCalendar != 'gregorian') {
					
					html += '<span class="day">' + sDate.d + '</span>';
					var sMonth = o.locale[sCalendar].months[sDate.m - 1].genitive;
					html += '<span class="month' + (sMonth.length > 8 ? ' month-smaller' : '') + '">' + sMonth + '</span>';
						
				} else if(i == 1) {
					html += '<span class="month">' + o.locale['gregorian'].months[gDate.m - 1].nominative + '</span>';
				}
				html += '</div>';
				
				html += '</div>';
				html += '</td>';
				
				if(colPos % 7 == 0) {
					html += '</tr><tr>';
				}
				colPos++;
				i++;
				date.d++;
				convDate = o.converter.convert(date, fCalendar, fCalendar);
			}
			
			colPos--;
			while(colPos % 7 != 0) {
				html += '<td class="unselectable"></td>';
				colPos++;
			}
			
			html += '</tr>';
			
			el.find('tbody').append(html);
			
			var days = el.find('tbody td.day');
			days.filter(':last').addClass('month-end');
			
			days.bind('click', function() {
				var $this = $(this);
				
				if(!$this.hasClass('current')) {
					o.dateConverter.dateConverter('setDay', $this.find('.f .day').text());
				}
			});
			
			days.cluetip({
				activation: 'hover'/*,
				hoverIntent: {    
					sensitivity: 3,
					interval: 100
    			}*/
			});
			
			if (this.oldIE) {
				var hover = self.hover;
				days.hover(function(){
					var  $this = $(this);
					
					if (!$this.hasClass('current')) {
						var offset = $this.offset();
						var height = Math.floor($this.outerHeight());
						var width = Math.floor($this.outerWidth());
						
						self.hover.t.css({
							left: (Math.floor(offset.left) - 8) + 'px',
							top: (Math.floor(offset.top) - 8) + 'px',
							width: (width + 16) + 'px'
						});
						
						self.hover.b.css({
							left: (Math.floor(offset.left) - 8) + 'px',
							top: (Math.floor(offset.top) + height) + 'px',
							width: (width + 16) + 'px'
						});
						
						self.hover.l.css({
							height: (height + 16) + 'px',
							left: (Math.floor(offset.left) - 8) + 'px',
							top: (Math.floor(offset.top) - 8) + 'px'
						});
						
						self.hover.r.css({
							height: (height + 16) + 'px',
							left: (Math.floor(offset.left) + width) + 'px',
							top: (Math.floor(offset.top) - 8) + 'px'
						});
						
						for (var i in self.hover) {
							self.hover[i].show();
						}
					}
				}, function(){
					var  $this = $(this);
					
					for(var i in self.hover) {
						self.hover[i].hide();
					}
				});
			}
			
			this.showCurrent();
		},
		
		hideHover: function() {
			if (this.oldIE) {
				for (var i in this.hover) {
					this.hover[i].hide();
				}
			}
		},
		
		hideCurrent: function() {
			if (this.oldIE && this.current) {
				for (var i in this.current) {
					this.current[i].hide();
				}
			}
		},
		
		showCurrent: function () {
			if (this.oldIE && !this.element.find('#calendar').hasClass('ui-tabs-hide')) {
				var self = this;
				$this = this.element.find('td.current');
				
				if ($this.length) {
					var offset = $this.offset();
					var height = Math.floor($this.outerHeight());
					var width = Math.floor($this.outerWidth());
					
					self.current.t.css({
						left: (Math.floor(offset.left) - 7) + 'px',
						top: (Math.floor(offset.top) - 7) + 'px',
						width: (width + 14) + 'px'
					});
					
					self.current.b.css({
						left: (Math.floor(offset.left) - 7) + 'px',
						top: (Math.floor(offset.top) + height) + 'px',
						width: (width + 14) + 'px'
					});
					
					self.current.l.css({
						height: (height + 14) + 'px',
						left: (Math.floor(offset.left) - 7) + 'px',
						top: (Math.floor(offset.top) - 7) + 'px'
					});
					
					self.current.r.css({
						height: (height + 14) + 'px',
						left: (Math.floor(offset.left) + width) + 'px',
						top: (Math.floor(offset.top) - 7) + 'px'
					});
					
					for (var i in self.current) {
						self.current[i].show();
					}
				}
			}
		},
		
		setLegend: function() {
			var o = this.options;
			var foot = this.foot;
			var fCalendar = this.fCalendar;
			var sCalendar = this.sCalendar;
			
			var html;
			if(fCalendar == 'bahai') {
				html = '<span class="first">' + s('calendar') + '</span><br />' + o.locale[fCalendar].name.nominative;
			} else {
				html = '<span class="first">' + o.locale[fCalendar].name.nominative + '</span><br />' + s('calendar');
			}
			foot.fCal.html(html);
			
			if(sCalendar == 'bahai') {
				html = '<span class="first">' + s('calendar') + '<br />' + o.locale[sCalendar].name.nominative;
			} else {
				html = '<span class="first">' + o.locale[sCalendar].name.nominative + '</span><br />' + s('calendar') + '';
			}
			foot.sCal.html(html);
			
			if(fCalendar == 'gregorian' && sCalendar == 'gregorian') {
				foot.sCal.hide();
				foot.lines.addClass('line');
			} else {
				foot.sCal.show();
				foot.lines.removeClass('line');
			}
			
			var cell = this.element.find('.current .cell').html();
			foot.cell.html(cell);
		},
		
		setDay: function(day) {
			var o = this.options;
			var el = this.element;
			
			this.date.d = day;
			el.find('tbody td.current').removeClass('current');
			el.find('tbody td.day:eq(' + (day - 1) + ')').addClass('current');
			
			if(this.oldIE) {
				this.hideHover();
				this.showCurrent();
			}
			
			this.setLegend();
			
			//this.setHash();
			this.setResultLinks();
			
			this.converts++;
		},
		
		isSameDate: function(date, date2) {
			if(date.d == date2.d && date.m == date2.m && date.y == date2.y) {
				return true;
			} else {
				return false;
			}
		},
		
		getMonthOptions: function(calendar) {
			var o = this.options;
			var months = o.locale[calendar].months;
			var options = '';
			for(var i in months) {
				options += '<option value="' + (parseInt(i, 10) + 1) + '">' + months[i].nominative + '</option>'; 
			}
			return options;
		},
		
		setControl: function(control, calendar, date, direction) {
			var o = this.options;
			var months = o.locale[calendar].months.length;
			
			var newDate = {}; 
			newDate = $.extend(newDate, date);
			newDate.d = 1;
			
			newDate.m += direction;
			
			if (direction > 0 && newDate.m == months + 1) {
				newDate.m = 1;
				newDate.y++;
				
				if (newDate.y == 0 && this.era(calendar, newDate.y)) 
					newDate.y++;
			} else {
				if (direction < 0 && newDate.m == 0) {
					newDate.m = months;
					newDate.y--;
					
					if (newDate.y == 0 && this.era(calendar, newDate.y))
						newDate.y--;
				}
			}
			
			control.find('.month').text(o.locale[calendar].months[newDate.m - 1].nominative);
			
			var era = this.era(calendar, newDate.y);
			
			if (date.y != newDate.y) {
				if (era) {
					control.find('.year').text(Math.abs(newDate.y) + ' ' + this.head.era.find('option[value="' + era + '"]').text() + ' ');
				} else {
					control.find('.year').text(newDate.y);
				}
			} else {
				control.find('.year').text('');
			}
		},
		
		/**
		 * Return era value if exist, otherwise return 0 (false)
		 * 
		 * @param {String} calendar
		 * @param {Integer} year
		 */
		era: function(calendar, year) {
			var  flag = 0;
			
			if(calendar == 'gregorian' || calendar == 'julian') {
				if(year < 0) {
					flag = -1;
				} else {
					flag = 1;
				}
			}
			
			return flag;
		},
		
		setYearWidth: function(year) {
			var value = year.val() + '0';
			var helper = year.next().text(value);
			year.width(helper.width());
		},
		
		isYear: function(year) {
			if (this.fCalendar == 'gregorian' || this.fCalendar == 'julian') {
				var yearPattern = /^\d+$/;
			} else {
				var yearPattern = /^-?\d+$/;
			}
			
			if (year.search(yearPattern) != -1) {
				return true;
			} else {
				return false;
			}
		},
		
		setEvents: function(date, calendar) {
			var o = this.options;
			var el = this.element;
			var self = this;
			
			var disabled = self.tabs.tabs('option', 'disabled');
			
			if (calendar == 'gregorian' && o.scheduleEvents) {
				if(o.scheduleEvents[date.y] && o.scheduleEvents[date.y][date.m] && o.scheduleEvents[date.y][date.m].length) {
					var events = o.scheduleEvents[date.y][date.m];
					var html = '';
					
					for(var i in events) {
						var event = events[i];
						var content = event.since;
						if(event.to) {
							content += ' &mdash; ' + event.to;
						}
						content += ' ' + o.locale[calendar].months[date.m - 1].genitive;
						content += '. ' + event['name'];
						html += '<dt>' + content + '</dt><dd></dd>';
						
						el.find('td.day:eq(' + (event.since - 1) + ')').addClass('holiday');
						el.find('.bubble-content:eq(' + (event.since - 1) + ')').append('<br />' + content);
						if(event.to) {
							el.find('td.day:lt('+event.to+')').filter(':gt('+(event.since - 1)+')').addClass('holiday');
							el.find('.bubble-content:lt('+event.to+')').filter(':gt('+(event.since - 1)+')').append('<br />' + content);
						}
					}
					
					this.events.find('h3').text(events.length > 1 ? s('holiday in month') : s('holiday in month'));
					this.events.find('dl').html(html).show();
					disabled = self.removeFromArray(disabled, 1);
					this.tabs.data('disabled.tabs', disabled);
					this.tabs.find('ul li:eq(1) a').text(s('Holidays'));
				} else {
					this.events.find('h3').text(s('no holidays in month'));
					this.events.find('dl').empty().hide();
					disabled.push(1);
					this.tabs.data('disabled.tabs', disabled);
					this.tabs.find('ul li:eq(1) a').text(s('no holidays'));
				}
			} else {
			
				var url = '/time/api/dates';
				
				$.get(url, {
					calendar: calendar,
					month: date.m,
					year: date.y
				}, function(xml){
					var events = $(xml).children('events').children('item');
					
					if (events.length) {
						var eventCount = 0;
						var popups = el.find('.bubble-content');
						var days = el.find('td.day');
						
						var html = '';
						events.each(function(){
							var $this = $(this);
							
							var isEvent = false;
							types = $this.children('types').children('item');
							types.each(function(){
								var text = $(this).text();
								if (text == 'holiday' || text == 'dayoff') 
									isEvent = true;
							})
							
							if (isEvent) {
								eventCount++;
								
								var since = $this.children('since');
								var to = $this.children('to');
								
								var sinceDay = parseInt(since.attr('day'), 10);
								var sinceMonth = parseInt(since.attr('month'), 10);
								
								var toDay = parseInt(to.attr('day'), 10);
								var toMonth = parseInt(to.attr('month'), 10);
								
								html += '<dt>' + $this.children('since').attr('day');
								var name = $this.children('since').attr('day');
								
								if (to.attr('day') == since.attr('day') && to.attr('month') == since.attr('month')) {
									html += ' ' + o.locale[calendar].months[$this.children('since').attr('month') - 1].genitive;
									name += ' ' + o.locale[calendar].months[$this.children('since').attr('month') - 1].genitive;
								} else {
								
									if ($this.children('to').attr('month') != $this.children('since').attr('month')) {
										html += ' ' + o.locale[calendar].months[$this.children('since').attr('month') - 1].genitive;
										name += ' ' + o.locale[calendar].months[$this.children('since').attr('month') - 1].genitive;
									}
									
									if ($this.children('to').attr('day') != $this.children('since').attr('day')) {
										if (to.attr('month') == since.attr('month')) {
											html += '&mdash;';
											name += '&mdash;';
										} else {
											html += ' &mdash; ';
											name += ' &mdash; ';
										}
										html += $this.children('to').attr('day') + ' ';
										name += $this.children('to').attr('day') + ' '
										html += o.locale[calendar].months[$this.children('to').attr('month') - 1].genitive;
										name += o.locale[calendar].months[$this.children('to').attr('month') - 1].genitive;
									}
								}
								
								html += '. ' + $this.children('name').text();
								name += '. ' + $this.children('name').text();
								html += '</dt>';
								if ($this.children('description')) {
									html += '<dd>' + $this.children('description').text() + '</dd>';
								}
								
								if (sinceMonth == date.m) {
									if (sinceDay == toDay) {
										el.find('.bubble-content:eq(' + (sinceDay - 1) + ')').append('<br />' + name);
										el.find('td.day:eq(' + (sinceDay - 1) + ')').addClass('holiday');
									} else {
										if (sinceMonth == toMonth) {
											var ltPopups = el.find('.bubble-content:lt(' + toDay + ')');
											var ltDays = el.find('td.day:lt(' + toDay + ')');
											if (sinceDay != 1) {
												ltPopups.filter(':gt(' + (sinceDay - 2) + ')').append('<br />' + name);
												ltDays.filter(':gt(' + (sinceDay - 2) + ')').addClass('holiday');
											} else {
												ltPopups.append('<br />' + name);
												ltDays.addClass('holiday');
											}
										} else {
											el.find('.bubble-content:gt(' + (sinceDay - 2) + ')').append('<br />' + name);
											el.find('td.day:gt(' + (sinceDay - 2) + ')').addClass('holiday');
										}
									}
								} else {
									el.find('.bubble-content:lt(' + toDay + ')').append('<br />' + name);
									el.find('td.day:lt(' + toDay + ')').addClass('holiday');
								}
								
							}
						});
						
						if (eventCount) {
							self.events.find('h3').text(eventCount > 1 ? s('holiday in month') : s('holiday in month'));
							self.events.find('dl').html(html).show();
							disabled = self.removeFromArray(disabled, 1);
							self.tabs.data('disabled.tabs', disabled);
							self.tabs.find('ul li:eq(1) a').text(s('Holidays'));
						} else {
							self.events.find('h3').text(s('no holidays in month'));
							self.events.find('dl').empty().hide();
							disabled.push(1);
							self.tabs.data('disabled.tabs', disabled);
							self.tabs.find('ul li:eq(1) a').text(s('no holidays'));
						}
					} else {
						self.events.find('h3').text(s('no holidays in month'));
						self.events.find('dl').empty().hide();
						disabled.push(1);
						self.tabs.data('disabled.tabs', disabled);
						self.tabs.find('ul li:eq(1) a').text(s('no holidays'));
					}
				}, 'xml');
			}
		},
		
		setDates: function(date, calendar) {
			var o = this.options;
			var el = this.element;
			var self = this;
			
			var url = '/time/api/dates';
			$.get(
				url,
				{
					calendar: calendar,
					month: date.m,
					type: 'event'
				},
				function(xml){
					var events = $(xml).children('events').children('item');
					var disabled = self.tabs.tabs('option', 'disabled');
					if (events.length) {
						var eventCount = 0;
						var days = el.find('td.day');
						
						var html = '';
						events.each(function(){
							var $this = $(this);
							
							var isEvent = false;
							var types = $this.children('types').children('item');
							var year = $this.children('since').attr('year');
							types.each(function() {
								var text = $(this).text();
								if(text == 'event' && year <= date.y)
									isEvent = true;
							})
							
							if (isEvent) {
								eventCount++;
								
								var since = $this.children('since');
								var to = $this.children('to');
								
								var sinceDay = parseInt(since.attr('day'), 10);
								var sinceMonth = parseInt(since.attr('month'), 10);
                                var sinceYear = parseInt(since.attr('year'), 10);
								
								var toDay = parseInt(to.attr('day'), 10);
								var toMonth = parseInt(to.attr('month'), 10);
								
								html += '<dt><em>' + $this.children('since').attr('day');
								
								if (to.attr('day') == since.attr('day') && to.attr('month') == since.attr('month')) {
									html += ' ' + o.locale[calendar].months[$this.children('since').attr('month') - 1].genitive;
								} else {
								
									if ($this.children('to').attr('month') != $this.children('since').attr('month')) {
										html += ' ' + o.locale[calendar].months[$this.children('since').attr('month') - 1].genitive;
									}
									
									if ($this.children('to').attr('day') != $this.children('since').attr('day')) {
										if (to.attr('month') == since.attr('month')) {
											html += '&mdash;';
										} else {
											html += ' &mdash; ';
										}
										html += $this.children('to').attr('day') + ' ';
										html += o.locale[calendar].months[$this.children('to').attr('month') - 1].genitive;
									}
								}
								
								html += ' ' + sinceYear + '</em> <h4>' + $this.children('name').text();
								html += '</h4></dt>';
								if ($this.children('description')) {
									html += '<dd>' + $this.children('description').text() + '</dd>';
								}
							}
						});
						
						if (eventCount) {
							self.datesTab.find('h3').text(eventCount > 1 ? s('memorials in month') : s('memorial in month'));
							self.datesTab.find('dl').html(html).show();
							disabled = self.removeFromArray(disabled, 2);
							self.tabs.data('disabled.tabs', disabled);
							self.tabs.find('ul li:eq(2) a').text(s('memorials'));
						} else {
							self.datesTab.find('h3').text(s('no memorials in month'));
							self.datesTab.find('dl').empty().hide();
							disabled.push(2);
							self.tabs.data('disabled.tabs', disabled);
							self.tabs.find('ul li:eq(2) a').text(s('no memorials'));
						}
					} else {
						self.datesTab.find('h3').text(s('no memorials in month'));
						self.datesTab.find('dl').empty().hide();
						disabled.push(2);
						self.tabs.data('disabled.tabs', disabled);
						self.tabs.find('ul li:eq(2) a').text(s('no memorials'));
					}
				}, 'xml'
			);
		},
		
		removeFromArray: function(arr, el) {
			var newArr = [];
			for(var i = 0; i < arr.length; i++) {
				if(arr[i] != el) {
					newArr.push(arr[i]);
				}
			}
			return newArr;
		},
		
		hide: function() {
			this.element.hide();
			this.hideCurrent();
			this.hideHover();
		},
		
		show: function() {
			this.element.show();
			//this.current.show();
			//this.hover.show();
		},
		
		getCalParts: function(calendar) {
			if(calendar == 'bahai') {
				return {prep: s('on calendar bahai prep'), after: s('on calendar bahai after')};
			} else {
				return {prep: s('on calendar prep'), after: s('on calendar after')};
			}
		},
		/*
		setHash: function() {
			var o = this.options;
			var date = o.converter.convert(this.date, this.fCalendar, this.sCalendar);
			var hash = '#' + this.sCalendar + '_' + date.d + '.' + date.m + '.' + date.y + '_' + this.fCalendar;
			if(this.converts)
				document.location.hash = hash;
		},
		*/
		setResultLinks: function() {
			var o = this.options;
			var date = o.converter.convert(this.date, this.fCalendar, this.sCalendar);
			//var url = document.location.toString().replace(/#.*$/, '') + '#' + this.sCalendar + '_' + date.d + '.' + date.m + '.' + date.y + '_' + this.fCalendar;
			var url = document.location.toString().replace(/^(.*\/converter\/).*$/, '$1') + this.sCalendar + '/' + this.fCalendar + '/' + date.d + '.' + date.m + '.' + date.y;
			var codeText = '';
			
			var resultLinks = $(o.resultLinks);
			
			var era = this.era(this.sCalendar, date.y);
			var parts = this.getCalParts(this.fCalendar);

			codeText = s('calendar link text', ordinal_number(date.d), o.locale[this.sCalendar].months[date.m - 1].genitive, (era ? Math.abs(date.y) : date.y), (era ? this.head.era.find('option[value="' + era + '"]').text() : ''), parts.prep, o.locale[this.fCalendar].name.prepositional, parts.after);
			
			resultLinks.find('#result-link-url').val(url);
			resultLinks.find('#result-link-code').val('<a href="' + url + '">' + codeText + '</a>');			         
		}
	});
	
	$.extend($.ui.calendar, {
		defaults: {
			converter: dateConverter,
			resultLinks: '#result-links'
		}
	});
})(jQuery);
/* end: Calendar plugin */
