/**
 * Kaizen Framework - JavaScript
 * 
 * @author Vasil Georgiev Dinkov - Kaizen Web-Productions (http://www.kaizen-web.com)
 * @version 1.0
 * @copyright Copyright(C), Kaizen Web-Productions, 2004-2008, All Rights Reserved.
 * @package KaizenFramework
 */

/**
 * Tooltip Functionality (DOM)
 * 
 * @author Vasil Georgiev Dinkov - Kaizen Web-Productions (http://www.kaizen-web.com)
 * @version 1.0
 * @copyright Copyright(C), Kaizen Web-Productions, 2004-2008, All Rights Reserved.
 * @package KaizenFramework
 * @subpackage Tooltip
 */

Kaizen.Tip = {

	// Class for the tooltip objects
	TooltipObject: function(className, defaultMouseXOffset, defaultMouseYOffset) {
		this.className = typeof className == 'string' ? className : '';
		this.mouseXOffset = defaultMouseXOffset; // default offset from mouse event
		this.mouseYOffset = defaultMouseYOffset;
		this.elm = typeof className == 'string' ? new Kaizen.Element('div', {'class':this.className}) : className;
	},

	// stores tooltip families - note that families['default'] will be used for the default tooltip
	families: {},

	/**
	 * Creates a tooltip object of a given family and stores it in families
	 * All arguments are optional. If none supplied, will create the default tooltip object.
	 *
	 * @param string		family			Family of the tooltip
	 * @param string/element	className		CSS class to use for the tooltip element OR an element to use as a tooltip
	 * @param number		defaultMouseXOffset	Default x offset from where the mouse event occured
	 * @param number		defaultMouseYOffset
	 */
	createTooltipObject: function(family, className, defaultMouseXOffset, defaultMouseYOffset) {
		if (!family)
			family = 'default';
		if (this.families[family])
			return;
		this.families[family] = new this.TooltipObject(className || 'KaizenTip', defaultMouseXOffset || 20, defaultMouseYOffset || 20);
		var elm = this.families[family].elm;
		if (!elm.parentNode || !elm.parentNode.tagName) {
			elm.style.display = 'none';
			document.body.appendChild(elm);
		}
	},

	/**
	 * Allows creating tooltip families (if an empty array is passed as the only agrument, the 'default' tooltip family would be created)
	 *
	 * @param array		family1Properties	Family properties - i.e. [familyName, className/element, defaultMouseXOffset, defaultMouseYOffset]
	 * @param array		family2Properties	Family properties - i.e. [familyName, className/element, defaultMouseXOffset, defaultMouseYOffset]
	 * @param array		...
	 */
	addTooltipFamilies: function() {
		var arr;
		for (var i = 0, l = arguments.length; i < l; i++) {
			arr = arguments[i];
			this.createTooltipObject(arr[0], arr[1], arr[2], arr[3]);
		}
	},

	/**
	 * Shows a tooltip
	 * Default x and y are mouse event position + mouseXOffset/mouseYOffset set when creating the tooltip object.
	 * But you can use the following keywords too: mouseX, mouseY, targetX, targetY, targetW, targetH, tooltipW, tooltipH - e.g.:
	 * Kaizen.Tip.show('Text for the tooltip', event, 'mouseX - 20', 'targetY + targetH')
	 * the target properties contain info about the target element on the page that calls the tooltip
	 *
	 * @param string/null		content		text/HTML to display inside the tooltip OR null if showing an element
	 * @param object/null		event		event OR null - if null, supply x and y (the keywords won't work except tooltipW/tooltipH)
	 * @param string		x		JS expression that returns the x position for the tooltip
	 * @param string		y		JS expression that returns the y position for the tooltip
	 * @param string		family		An identifier for the family of the tooltip ('default' is reserved for default)
	 */
	show: function(content, event, x, y, family) {
		// if no family specified use the default tooltip object stored at families['default']
		if (!family)
			family = 'default';
		var obj = this.families[family];
		if (!obj)
			return;
		var elm = obj.elm;
		if (typeof content == 'string' && content != '')
			elm.innerHTML = content;

		// if displayed at the moment, do nothing until it is hidden
		if(elm._tooltipActive)
			return;

		var elms = elm.style;
		elms.position = 'absolute';
		elms.visibility = 'hidden';
		elms.display = 'block';

		var w, h, mouseX, mouseY, t, targetX, targetY, targetW, targetH, tooltipW, tooltipH, C, vSize, vScroll;
		vSize = Kaizen.Viewport.getSize();
		vScroll = Kaizen.Viewport.getScrollOffsets();

		if (event) {
			mouseX = event.pageX || event.clientX + vScroll.x;
			mouseY = event.pageY || event.clientY + vScroll.y;
			if (!x || !/mouseX/.test(x))
				mouseX += obj.mouseXOffset;
			if (!y || !/mouseY/.test(y))
				mouseY += obj.mouseYOffset;
			t = event.target || event.srcElement;
			while (t.nodeType != 1)
				t = t.parentNode;
			C = Kaizen.DOM.getPosition(t);
			targetX = C.x;
			targetY = C.y;
			targetW = t.offsetWidth;
			targetH = t.offsetHeight;
		}
		w = elm.offsetWidth;
		h = elm.offsetHeight;
		tooltipW = w;
		tooltipH = h;
		x = !x ? mouseX : eval(x);
		y = !y ? mouseY : eval(y);

		// keep tooltip within the viewport
		// detect right edge
		if (x + w > vScroll.x + vSize.w)
			x = vScroll.x + vSize.w - w;
		// detect bottom edge
		if (y + h > vScroll.y + vSize.h)
			y = vScroll.y + vSize.h - h;

		elms.left = x + 'px';
		elms.top = y + 'px';
		Kaizen.DOM.addIFRAMEshim(elm);
		elms.visibility = 'visible';
		elm._tooltipActive = true;
	},

	/**
	 * Hides a tooltip
	 *
	 * @param string	family		An identifier for the family of the tooltip ('default' is reserved for default)
	 */
	hide: function(family) {
		if (!family)
			family = 'default';
		var obj = this.families[family];
		if (!obj)
			return;
		var elm = obj.elm;
		if(!elm._tooltipActive)
			return;
		elm.style.display = "none";
		Kaizen.DOM.removeIFRAMEshim(elm);
		elm._tooltipActive = false;
	}
};

/**
 * Class for the calendar
 *
 * @param string	calendarName	A name for the calendar
 * @param function	handler		The function that handles the clicked dates
 * @param object	options		Any custom options to override the default options - e.g. {'boxClass': 'customBoxClass'}
 */
Kaizen.Calendar = function(calendarName, handler, options) {
	var ref = this;

	this.calendarName = calendarName;

	this.options = {
		serverDate: '',	// Use server date in '2010-03-21' format instead of client-side (through JS Date()). PHP syntax is 'Y-m-d'
		markedDatesLoadURL: '',
		showButtons: true,
		weekStartsOnMonday: false,
		showWeekNumbers: true,
		weekNumbersLeadingZero: true,
		showCloseBtn: true,
		listBoxTimeout: 200,
		boxClass: 'KaizenCalendar',
		headerClass: 'KaizenCalendarHeader',
		monthClass: 'KaizenCalendarMonth',
		statusBarClass: 'KaizenCalendarStatusBar',
		prevYearBtnClass: 'KaizenCalendarPrevYearBtn',
		nextYearBtnClass: 'KaizenCalendarNextYearBtn',
		prevMonthBtnClass: 'KaizenCalendarPrevMonthBtn',
		nextMonthBtnClass: 'KaizenCalendarNextMonthBtn',
		todayBtnClass: 'KaizenCalendarTodayBtn',
		closeBtnClass: 'KaizenCalendarCloseBtn',
		listBoxClass: 'KaizenCalendarListBox',
		listBoxItemClass: 'KaizenCalendarListBoxItem',
		listBoxItemOverClass: 'KaizenCalendarListBoxItemOver',
		listBoxItemSelectedClass: 'KaizenCalendarListBoxItemSelected',
		weekNumbersClass: 'KaizenCalendarWeekNumbers',
		weekdaysClass: 'KaizenCalendarWeekdays',
		daysClass: 'KaizenCalendarDays',
		sundayClass: 'KaizenCalendarSunday',
		todayClass: 'KaizenCalendarToday',
		highlightWeekClass: 'KaizenCalendarHighlightWeek',
		dayOfPrevOrNextMonthClass: 'KaizenCalendarDayOfPrevOrNextMonth',
		Language: {					// An object containing any words that may be used
			'monthNames': ['January','February','March','April','May','June','July','August','September','October','November','December'],
			'weekdayNames': ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'],
			'todayBtn': 'Today',
			'prevYearBtn': '<<',
			'prevMonthBtn': '<',
			'nextMonthBtn': '>',
			'nextYearBtn': '>>',
			'prevYear': 'Previous year (click & hold for list)',
			'prevMonth': 'Previous month (click & hold for list)',
			'nextMonth': 'Next month (click & hold for list)',
			'nextYear': 'Next year (click & hold for list)',
			'showToday': 'Show today',
			'closeCalendar': 'Close the calendar',
			'W#': 'W#', // week number - heading cell text for week numbers column
			'defaultStatus': ''
		}
	};
	if (options)
		Kaizen.extendObject(this.options, options);

	if (this.options.serverDate) {
		this.serverDate = this.options.serverDate.split('-');
		this.serverDate[0] = parseInt(this.serverDate[0]); // year
		this.serverDate[1] = parseInt(this.serverDate[1].replace(/^0/,'')); // month (1-12)
		this.serverDate[2] = parseInt(this.serverDate[2].replace(/^0/,'')); // date (1-31)
	}

	this.showListTimer = 0;
	// stores marked date(s)
	this.markedDates = {};
	if(this.options.markedDatesLoadURL != '')
		this.AJAX = new Kaizen.AJAX.Request(this.options.markedDatesLoadURL, function(status,responseText){ref.storeMarkedDates(status,responseText)});

	this.elm = new Kaizen.Element('div', {'class':this.options.boxClass});
	this.header = new Kaizen.Element('div', {'class':this.options.headerClass, 'style':'position:relative;top:0;left:0;z-index:10;'});
	this.month = new Kaizen.Element('div', {'class':this.options.monthClass});
	this.buttonsHolder = new Kaizen.Element('div', '');
	this.prevYearBtn = new Kaizen.Element('input', {'type':'button', 'value':this.options.Language.prevYearBtn, 'style':'float:left;' + (!this.options.showButtons ? 'display:none;' : '' ), 'class':this.options.prevYearBtnClass,
		'onclick':function(){
			ref.stopListShowTimer();
			ref.elm.update(ref.month._curMonth, ref.month._curYear - 1);
		},
		'onmouseover':function(){
			ref.elm.showStatus(ref.options.Language.prevYear);
		},
		'onmouseout':function(){
			ref.elm.showStatus();
		},
		'onmousedown':function(e){
			ref.startListShowTimer(this, false, ref.month._curYear, false);
			if (Kaizen.Browser.Konqueror)
				Kaizen.DOM.eventPreventDefault(e);
		}
	});
	this.nextYearBtn = new Kaizen.Element('input', {'type':'button', 'value':this.options.Language.nextYearBtn, 'style':'float:right;' + (!this.options.showButtons ? 'display:none;' : '' ), 'class':this.options.nextYearBtnClass,
		'onclick':function(){
			ref.stopListShowTimer();
			ref.elm.update(ref.month._curMonth, ref.month._curYear + 1);
		},
		'onmouseover':function(){
			ref.elm.showStatus(ref.options.Language.nextYear);
		},
		'onmouseout':function(){
			ref.elm.showStatus();
		},
		'onmousedown':function(e){
			ref.startListShowTimer(this, false, ref.month._curYear, true);
			if (Kaizen.Browser.Konqueror)
				Kaizen.DOM.eventPreventDefault(e);
		}
	});
	this.todayBtn = new Kaizen.Element('input', {'type':'button', 'value':this.options.Language.todayBtn, 'style': (!this.options.showButtons ? 'display:none;' : '' ), 'class':this.options.todayBtnClass,
		'onclick':function(){
			ref.elm.update();
		},
		'onmouseover':function(){
			ref.elm.showStatus(ref.options.Language.showToday);
		},
		'onmouseout':function(){
			ref.elm.showStatus();
		}
	});
	this.prevMonthBtn = new Kaizen.Element('input', {'type':'button', 'value':this.options.Language.prevMonthBtn, 'style':'float:left;' + (!this.options.showButtons ? 'display:none;' : '' ), 'class':this.options.prevMonthBtnClass,
		'onclick':function(){
			ref.stopListShowTimer();
			ref.elm.update(ref.month._curMonth - 1 > 0 ? ref.month._curMonth - 1 : 12, ref.month._curMonth - 1 > 0 ? ref.month._curYear : ref.month._curYear - 1);
		},
		'onmouseover':function(){
			ref.elm.showStatus(ref.options.Language.prevMonth);
		},
		'onmouseout':function(){
			ref.elm.showStatus();
		},
		'onmousedown':function(e){
			ref.startListShowTimer(this, true, ref.month._curMonth, false);
			if (Kaizen.Browser.Konqueror)
				Kaizen.DOM.eventPreventDefault(e);
		}
	});
	this.nextMonthBtn = new Kaizen.Element('input', {'type':'button', 'value':this.options.Language.nextMonthBtn, 'style':'float:right;' + (!this.options.showButtons ? 'display:none;' : '' ), 'class':this.options.nextMonthBtnClass,
		'onclick':function(){
			ref.stopListShowTimer();
			ref.elm.update(ref.month._curMonth + 1 <= 12 ? ref.month._curMonth + 1 : 1, ref.month._curMonth + 1 <= 12 ? ref.month._curYear : ref.month._curYear + 1);
		},
		'onmouseover':function(){
			ref.elm.showStatus(ref.options.Language.nextMonth);
		},
		'onmouseout':function(){
			ref.elm.showStatus();
		},
		'onmousedown':function(e){
			ref.startListShowTimer(this, true, ref.month._curMonth, true);
			if (Kaizen.Browser.Konqueror)
				Kaizen.DOM.eventPreventDefault(e);
		}
	});
	this.clearer = new Kaizen.Element('span', {'text':' ','style':'display:block;clear:both;height:0;line-height:0;overflow:hidden;visibility:hidden;'});
	this.listBox = new Kaizen.Element('div', {'style':'position:absolute;visibility:hidden;', 'class':this.options.listBoxClass});
	if (this.options.showCloseBtn)
		this.closeBtn = new Kaizen.Element('a', {'href':'#', 'class':this.options.closeBtnClass, 'text':'x', 'onmouseover':function(){
			ref.elm.showStatus(ref.options.Language.closeCalendar);
		}, 'onmouseout':function(){
			ref.elm.showStatus();
		}, 'onclick':function(){
			Kaizen.Tip.hide(ref.calendarName);
			return false;
		}});
	this.calendarHolder = new Kaizen.Element('div', '');
	this.statusBar = new Kaizen.Element('div', this.options.statusBarClass);
	this.statusBar.innerHTML = this.options.Language.defaultStatus || '&nbsp;';
	this.buttonsHolder.append(this.prevYearBtn, this.nextYearBtn, this.prevMonthBtn, this.nextMonthBtn, this.todayBtn, this.clearer, this.listBox);
	if (this.options.showCloseBtn)
		this.buttonsHolder.append(this.closeBtn);
	this.header.append(this.month, this.buttonsHolder);
	this.elm.append(this.header, this.calendarHolder, this.statusBar);

	this.elm.calendarHandler = handler;

	// updates the calendar and sets the date to the given arguments if supplied
	this.elm.update = function(month, year) {
		var now = new Date();
		month = month || ref.serverDate && ref.serverDate[1] || now.getMonth() + 1;
		year = year || ref.serverDate && ref.serverDate[0] || now.getFullYear();
		ref.month._curMonth = month;
		ref.month._curYear = year;
		if (ref.serverDate)
			var today = month == ref.serverDate[1] && year == ref.serverDate[0] ? ref.serverDate[2] : 0;
		else
			var today = month == now.getMonth() + 1 && year == now.getFullYear() ? now.getDate() : 0;
		var daysM = [31,(year % 4 == 0 && year % 100 != 0 || year % 400 == 0 ? 29 : 28),31,30,31,30,31,31,30,31,30,31];
		var target = new Date(year, month - 1, 1);
		var targetDaysM = daysM[month - 1];
		var firstOfMonth = target.getDay() + (ref.options.weekStartsOnMonday ? 0 : 1);
		if (firstOfMonth == 0)
			firstOfMonth = 7;

		var html = '<table border="0" cellpadding="0" cellspacing="0"><tr>' + (ref.options.showWeekNumbers ? '<td class="' + ref.options.weekNumbersClass + '">' + ref.options.Language['W#'] + '</td>' : '' );
		for (var i = 0; i < 7; i++)
			html += '<th align="center" class="' + ref.options.weekdaysClass + '">' + ref.options.Language.weekdayNames[ref.options.weekStartsOnMonday ? i < 6 ? i + 1 : 0 : i] + '</th>';
		html += '</tr><tr onmouseover="this.className=\'' + ref.options.highlightWeekClass + '\'" onmouseout="this.className=\'\'">' + (ref.options.showWeekNumbers ? '<td class="' + ref.options.weekNumbersClass + '">' + ref.getIsoWeekNumber(year, month, !ref.options.weekStartsOnMonday && target.getDay() == 0 ? 2 : 1, ref.options.weekNumbersLeadingZero) + '</td>' : '' );

		var markedDays = ref.markedDates[year] && ref.markedDates[year][month];//alert(markedDays)
		var d = firstOfMonth - 1 + targetDaysM < 29 ? 28 : firstOfMonth - 1 + targetDaysM < 36 ? 35 : 42, fromPrevMonth, fromThisMonth, markedClass, markedTitle, realMonth, realYear;
		for (i = 1; i <= d; i++) {
			fromPrevMonth = i - firstOfMonth < 0;
			fromThisMonth = !fromPrevMonth && i - firstOfMonth < targetDaysM;
			cur = fromThisMonth ? i - firstOfMonth + 1 : fromPrevMonth ? i - firstOfMonth + 1 + (daysM[month - 2] || daysM[11]) : i - firstOfMonth + 1 - targetDaysM;
			if (fromThisMonth && markedDays && markedDays[cur]) {
				markedTitle = '';
				for (var j = 0, l = markedDays[cur].length; j < l; j++)
					markedTitle += markedDays[cur][j]['text'] ? markedDays[cur][j]['text'] + (j < l-1 ? '<br />' : '') : '';
				markedClass = markedDays[cur][l-1]['class'] ? ' ' + markedDays[cur][l-1]['class'] : '';
			} else {
				markedClass = markedTitle = '';
			};
			realMonth = fromPrevMonth ? month - 1 < 1 ? 12 : month - 1 : fromThisMonth ? month : month + 1 > 12 ? 1 : month + 1;
			realYear = fromPrevMonth ? month - 1 < 1 ? year - 1 : year : fromThisMonth ? year : month + 1 > 12 ? year + 1 : year;
			html += '<td align="center"><a href="#" onclick="var p=this.parentNode;while(!p.className||p.className!=\'' + ref.options.boxClass + '\')p=p.parentNode;if(p.calendarHandler(' + cur + ',' + realMonth + ',' + realYear +')){Kaizen.Tip.hide(\'' + ref.calendarName + '\');Kaizen.Tip.hide()}return false;" onmouseover="var p=this.parentNode;while(!p.className||p.className!=\'' + ref.options.boxClass + '\')p=p.parentNode;p.showStatus(\'' + ref.options.Language.weekdayNames[i % 7 ? !ref.options.weekStartsOnMonday ? i % 7 - 1 : i % 7 : !ref.options.weekStartsOnMonday ? 6 : 0] + ', ' + cur + ' ' + ref.options.Language.monthNames[realMonth - 1] + ', ' + realYear + '\');' + (markedTitle ? 'Kaizen.Tip.show(\'' + markedTitle + '\',event)' : '') + '" onmouseout="var p=this.parentNode;while(!p.className||p.className!=\'' + ref.options.boxClass + '\')p=p.parentNode;p.showStatus();' + (markedTitle ? 'Kaizen.Tip.hide()' : '') + '" class="' + ref.options.daysClass + (ref.options.weekStartsOnMonday && /^(7|14|21|28|35|42)$/.test(i) || !ref.options.weekStartsOnMonday && /^(1|8|15|22|29|36)$/.test(i) ? ' ' + ref.options.sundayClass : '') + (today == cur && fromThisMonth ? ' ' + ref.options.todayClass : '') + (fromPrevMonth || !fromThisMonth ? ' ' + ref.options.dayOfPrevOrNextMonthClass : '') + markedClass + '">' + cur + '</a></td>';
			if(i % 7 == 0 && i < d)
				html += '</tr><tr onmouseover="this.className=\'' + ref.options.highlightWeekClass + '\'" onmouseout="this.className=\'\'">' + (ref.options.showWeekNumbers ? '<td class="' + ref.options.weekNumbersClass + '">' + ref.getIsoWeekNumber(!ref.options.weekStartsOnMonday && cur + 2 > targetDaysM && realMonth == 12 ? realYear + 1 : realYear, !ref.options.weekStartsOnMonday && cur + 2 > targetDaysM ? realMonth == 12 ? 1 : realMonth + 1 : realMonth, ref.options.weekStartsOnMonday ? cur + 1 : cur + 2 > targetDaysM ? 1 : cur + 2, ref.options.weekNumbersLeadingZero) + '</td>' : '');
		}
		html += '</tr></table>';

		ref.calendarHolder.innerHTML = html;
		ref.month.innerHTML = ref.options.Language.monthNames[month-1] + ' ' + year;

		// load marked dates
		ref.loadMarkedDates();
	};
	this.elm.update();

	// fix auto width in some browsers
	var elmS = this.elm.style;
	elmS.position = 'absolute';
	elmS.top = '-100000px';
	document.body.appendChild(this.elm); // temporary insert in DOM so we can get the rendered width
	var width = this.calendarHolder.firstChild.offsetWidth + 'px';
	document.body.removeChild(this.elm); // remove from DOM after we have gotten the width
	this.header.style.width = this.statusBar.style.width = width;
	elmS.position = 'static';
	elmS.top = 'auto';

	// sets the status text at the bottom of the calendar widget
	this.elm.showStatus = function(message) {
		ref.statusBar.innerHTML = typeof message != 'undefined' ? message || '&nbsp;' : ref.options.Language.defaultStatus || '&nbsp;';
	};

	this.elm.showListBox = function(btn, showMonths, cur, nextBtn) {
		var items = '', i;
		if (showMonths) {
			// we are showing the months list
			for (i = 1; i <= 12; i++)
				items += '<div class="' + ref.options.listBoxItemClass + (cur == i ? ' ' + ref.options.listBoxItemSelectedClass : '') + '" onmouseup="var p=this.parentNode;while(!p.className||p.className!=\'' + ref.options.boxClass + '\')p=p.parentNode;p.hideListBox();p.update(' + i + ',p.firstChild.firstChild._curYear);" onmouseover="Kaizen.DOM.addClass(this,\'' + ref.options.listBoxItemOverClass + '\')" onmouseout="Kaizen.DOM.removeClass(this,\'' + ref.options.listBoxItemOverClass + '\')">' + ref.options.Language.monthNames[i - 1].substring(0, 3) + '</div>';
		} else {
			// we are showing the years list
			for (i = 1; i <= 10; i++)
				items += '<div class="' + ref.options.listBoxItemClass + '" onmouseup="var p=this.parentNode;while(!p.className||p.className!=\'' + ref.options.boxClass + '\')p=p.parentNode;p.hideListBox();p.update(p.firstChild.firstChild._curMonth,parseInt(this.innerHTML));" onmouseover="Kaizen.DOM.addClass(this,\'' + ref.options.listBoxItemOverClass + '\')" onmouseout="Kaizen.DOM.removeClass(this,\'' + ref.options.listBoxItemOverClass + '\')">' + (cur + (nextBtn ? i : -i)) + '</div>';
		}

		ref.listBox.innerHTML = items;

		var ls = ref.listBox.style;
		ls.top = ref.buttonsHolder.offsetTop + btn.offsetHeight + 'px';
		ls.left = btn.offsetLeft + (nextBtn ? btn.offsetWidth - ref.listBox.offsetWidth : 0) + 'px';
		ls.visibility = 'inherit';
	};

	this.elm.hideListBox = function() {
		ref.listBox.style.visibility = 'hidden';
	};

	// shows previous year - useful if the buttons are turned off
	this.elm.previousYear = this.prevYearBtn.onclick;
	// shows previous month
	this.elm.previousMonth = this.prevMonthBtn.onclick;
	// shows next month - useful if the buttons are turned off
	this.elm.nextMonth = this.nextMonthBtn.onclick;
	// shows next year - useful if the buttons are turned off
	this.elm.nextYear = this.nextYearBtn.onclick;

	// fix IE DOM leaks
	Kaizen.DOM.IEDOMleaks.push([this.elm, 'update', 'showStatus', 'showListBox', 'hideListBox', 'previousYear', 'previousMonth', 'nextMonth', 'nextYear']);

	Kaizen.DOM.addEvent(document, 'mouseup', function(){
		this.stopListShowTimer();
		this.elm.hideListBox();
	}.bind(this));

	return this.elm;
}

Kaizen.Calendar.prototype.loadMarkedDates = function() {
	if(!this.AJAX)
		return;
	var month = this.month._curMonth;
	var year = this.month._curYear;
	if (!this.markedDates[month + ':' + year + '_loaded']) {
		this.AJAX.load('calendar=' + this.calendarName + '&fetch=' + month + ':' + year, 'GET');
		this.markedDates[month + ':' + year + '_loaded'] = 1;
	}
}

Kaizen.Calendar.prototype.storeMarkedDates = function(status, responseText) {
	if (status == 200 && responseText && responseText.isJSON()) {
		eval('var obj = ' + responseText);
		for (var i in obj) {
			if (!this.markedDates[i]) {
				this.markedDates[i] = obj[i];
			} else {
				for (var j in obj[i])
					if (!this.markedDates[i][j])
						this.markedDates[i][j] = obj[i][j];
			}
		}
		this.elm.update(this.month._curMonth, this.month._curYear);
	}
}

Kaizen.Calendar.prototype.getIsoWeekNumber = function(y, m, d, leadingZero) {
	var date = new Date(y, m - 1, d);
	date.setDate(d - 3 + (14 - date.getDay()) % 7); // nearest Thursday - we use it as the first Thursday of the year is in week 1 according to ISO
	var janFourth = new Date(date.getFullYear(), 0, 4); // January 4th - it is always in week 1 according to ISO
	var daysDiff = (date - janFourth) / 86400000;
	var weekNum = parseInt(daysDiff / 7) + 1;
	if (daysDiff % 7 > 3)
		weekNum++;
	if (leadingZero && weekNum < 10)
		weekNum = '0' + weekNum;
	return weekNum;
}

Kaizen.Calendar.prototype.startListShowTimer = function(btn, showMonths, cur, nextBtn) {
	this.showListTimer = setTimeout(this.elm.showListBox.bind(this, btn, showMonths, cur, nextBtn), this.options.listBoxTimeout);
}

Kaizen.Calendar.prototype.stopListShowTimer = function() {
	if (this.showListTimer) {
		clearTimeout(this.showListTimer);
		this.showListTimer = 0;
	}
}