if(!window.LOG){
	window.LOG = {warn:function(){}};
}

if(typeof Effect == 'undefined')
  throw("calendar.js requires including script.aculo.us' effects.js library");

if (!window.Richfaces) window.Richfaces={};

Richfaces.Calendar={};
Richfaces.Calendar.setElementPosition = function(element, baseElement, jointPoint, direction, offset)
{
	// parameters:
	// baseElement: Dom element or {left:, top:, width:, height:};
	// jointPoint: {x:,y:} or ('top-left','top-right','bottom'-left,'bottom-right')
	// direction:  ('top-left','top-right','bottom'-left,'bottom-right', 'auto')
	// offset: {dx:,dy:}
	
	if (!offset) offset = {dx:0,dy:0};
	
	var elementDim = Richfaces.Calendar.getOffsetDimensions(element);
	var baseElementDim;
	var baseOffset;
	
	if (baseElement.left!=undefined)
	{
		baseElementDim = {width: baseElement.width, height: baseElement.height};
		baseOffset = [baseElement.left, baseElement.top];
		
	} else
	{
		baseElementDim = Richfaces.Calendar.getOffsetDimensions(baseElement);
		baseOffset = Position.cumulativeOffset(baseElement);
	}
	
	var windowRect = Richfaces.Calendar.getWindowViewport();
	
	
	// jointPoint
	var ox=baseOffset[0];
	var oy=baseOffset[1];
	var re = /^(top|bottom)-(left|right)$/;
	var match;
	
	if (typeof jointPoint=='object') {ox = jointPoint.x; oy = jointPoint.y}
	else if ( jointPoint && (match=jointPoint.toLowerCase().match(re))!=null )
	{
		if (match[2]=='right') ox+=baseElementDim.width;
		if (match[1]=='bottom') oy+=baseElementDim.height;
	} else
	{
		// ??? auto 
	}
	
	// direction
	if (direction && (match=direction.toLowerCase().match(re))!=null )
	{
		var d = direction.toLowerCase().split('-');
		if (match[2]=='left') ox-=elementDim.width+offset.dx; else if (match[2]=='right') ox+=offset.dx;
		if (match[1]=='top') oy-=elementDim.height+offset.dy; else if (match[1]=='bottom') oy+=offset.dy; 
	} else
	{
		// auto
		var theBest = {square:0};
		// jointPoint: bottom-right, direction: bottom-left
		var basex = baseOffset[0]-offset.dx;
		var basey = baseOffset[1]+offset.dy;
		var rect = {right: basex + baseElementDim.width, top: basey + baseElementDim.height};
		rect.left = rect.right - elementDim.width;
		rect.bottom = rect.top + elementDim.height;
		ox = rect.left; oy = rect.top;
		var s = Richfaces.Calendar.checkCollision(rect, windowRect);
		if (s!=0)
		{
			if (ox>=0 && oy>=0 && theBest.square<s) theBest = {x:ox, y:oy, square:s};
			// jointPoint: top-right, direction: top-left
			basex = baseOffset[0]-offset.dx;
			basey = baseOffset[1]-offset.dy;
			rect = {right: basex + baseElementDim.width, bottom: basey};
			rect.left = rect.right - elementDim.width;
			rect.top = rect.bottom - elementDim.height;
			ox = rect.left; oy = rect.top;
			s = Richfaces.Calendar.checkCollision(rect, windowRect);
			if (s!=0)
			{
				if (ox>=0 && oy>=0 && theBest.square<s) theBest = {x:ox, y:oy, square:s};
				// jointPoint: bottom-left, direction: bottom-right
				basex = baseOffset[0]+offset.dx;
				basey = baseOffset[1]+offset.dy;
				rect = {left: basex, top: basey + baseElementDim.height};
				rect.right = rect.left + elementDim.width;
				rect.bottom = rect.top + elementDim.height;
				ox = rect.left; oy = rect.top;
				s = Richfaces.Calendar.checkCollision(rect, windowRect);
				if (s!=0)
				{
					if (ox>=0 && oy>=0 && theBest.square<s) theBest = {x:ox, y:oy, square:s};
					// jointPoint: top-left, direction: top-right
					basex = baseOffset[0]+offset.dx;
					basey = baseOffset[1]-offset.dy;
					rect = {left: basex, bottom: basey};
					rect.right = rect.left + elementDim.width;
					rect.top = rect.bottom - elementDim.height;
					ox = rect.left; oy = rect.top;
					s = Richfaces.Calendar.checkCollision(rect, windowRect);
					if (s!=0)
					{
						// the best way selection
						if (ox<0 || oy<0 || theBest.square>s) {ox=theBest.x; oy=theBest.y}
					}
				}
			}
			
		}
	}
	
	var els = element.style;
	var originalVisibility = els.visibility;
	var originalPosition = els.position;
	var originalDisplay = els.display;
	els.visibility = 'hidden';
	els.position = 'absolute';
	els.display = '';
	
	if (element.offsetParent && element.offsetParent!=document.body)
	{
		var parentOffset=Position.cumulativeOffset(element.offsetParent);
		ox -= parentOffset[0];
		oy -= parentOffset[1];
	}

	els.display = originalDisplay;
	els.position = originalPosition;
	els.visibility = originalVisibility;
	
	element.style.left = ox + 'px';
	element.style.top = oy + 'px';
};

Richfaces.Calendar.getOffsetDimensions = function(element) {
	// from prototype 1.5.0 // Pavel Yascenko
    element = $(element);
    var display = $(element).getStyle('display');
    if (display != 'none' && display != null) // Safari bug
      return {width: element.offsetWidth, height: element.offsetHeight};

    // All *Width and *Height properties give 0 on elements with display none,
    // so enable the element temporarily
    var els = element.style;
    var originalVisibility = els.visibility;
    var originalPosition = els.position;
    var originalDisplay = els.display;
    els.visibility = 'hidden';
    els.position = 'absolute';
    els.display = 'block';
    var originalWidth = element.offsetWidth; // was element.clientWidth // Pavel Yascenko
    var originalHeight = element.offsetHeight; // was element.clientHeight // Pavel Yascenko
    els.display = originalDisplay;
    els.position = originalPosition;
    els.visibility = originalVisibility;
    return {width: originalWidth, height: originalHeight};
};
 
Richfaces.Calendar.checkCollision = function(elementRect, windowRect, windowOffset)
{
	if (elementRect.left >= windowRect.left &&
		elementRect.top >= windowRect.top &&
		elementRect.right <= windowRect.right &&  
		elementRect.bottom <= windowRect.bottom)
		return 0;
	
	var rect = {left:   (elementRect.left>windowRect.left ? elementRect.left : windowRect.left),
				top:    (elementRect.top>windowRect.top ? elementRect.top : windowRect.top),
				right:  (elementRect.right<windowRect.right ? elementRect.right : windowRect.right),
				bottom: (elementRect.bottom<windowRect.bottom ? elementRect.bottom : windowRect.bottom)};
	return (rect.right-rect.left)* (rect.bottom-rect.top);
};


Richfaces.Calendar.getWindowDimensions = function() {
    var w =  self.innerWidth
                || document.documentElement.clientWidth
                || document.body.clientWidth
                || 0;
    var h =  self.innerHeight
                || document.documentElement.clientHeight
                || document.body.clientHeight
                || 0;
	return {width:w, height: h};
};

Richfaces.Calendar.getWindowScrollOffset = function() {
    var dx =  window.pageXOffset
                || document.documentElement.scrollLeft
                || document.body.scrollLeft
                || 0;
    var dy =  window.pageYOffset
                || document.documentElement.scrollTop
                || document.body.scrollTop
                || 0;
	return {left:dx, top: dy};
};

Richfaces.Calendar.getWindowViewport = function() {
	var windowDim = Richfaces.Calendar.getWindowDimensions();
	var windowOffset = Richfaces.Calendar.getWindowScrollOffset();
	return {left:windowOffset.left, top:windowOffset.top, right: windowDim.width+windowOffset.left, bottom: windowDim.height+windowOffset.top};
};

Richfaces.Calendar.joinArray = function(array, begin, end, separator)
{
	var value = '';
	if (array.length!=0) value = begin+array.pop()+end;
	while (array.length)
		value = begin+array.pop()+end+separator+value;
	return value;
};

Richfaces.Calendar.getMonthByLabel = function (monthLabel, monthNames)
{
	var i=0;
	while (i<monthNames.length) if (monthNames[i]==monthLabel) return i; else i++;
};

Object.extend(Event, {
	findElementByAttr : function(event, tagName, attribute, value, flag) {
    	var element = Event.findElement(event, tagName);
    	while (!element[attribute] || (flag ? element[attribute].indexOf(value)!=0 : element[attribute]!=value) )
    	{
	      	element = element.parentNode;
	    }
    	return element;
	}
});

Object.extend(Element, {
	replaceClassName : function (element, whichClassName, toClassName) {
		if (!(element = $(element))) return;
	    var e = Element.classNames(element);
	    e.remove(whichClassName);
	    e.add(toClassName);
	    return element;
	}
});

/* Year:
 *	y,yy - 00-99
 *	yyy+ - 1999
 * Month:
 *	M - 1-12
 *	MM - 01-12
 *	MMM - short (Jul)
 *	MMMM+ - long (July)
 * Date:
 *	d - 1-31
 *	dd+ - 01-31 */
Object.extend(Date, {
	getDefaultMonthNames: function(shortNames)
	{
		return (shortNames
				? ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec']
				: ['January','February','March','April','May','June','July','August','September','October','November','December']);
	},
	
	parseDate: function(dateString, pattern, monthNames, monthNamesShort)
	{
		if (!monthNames) monthNames = Date.getDefaultMonthNames();
		if (!monthNamesShort) monthNamesShort = Date.getDefaultMonthNames(true);
		
		var counter=1;
		var y,m,d;
		var shortLabel=false;
		
		pattern = pattern.replace(/([.*+?^<>=!:${}()|[\]\/\\])/g, '\\$1');
		pattern = pattern.replace(/(y+|M+|d+)/g,
			function($1) {
				switch ($1) {
		            case 'y'  :
		            case 'yy' : y=counter; counter++; return '(\\d{2})';
		            case 'MM' : m=counter; counter++; return '(\\d{2})';
		            case 'M'  : m=counter; counter++; return '(\\d{1,2})';
		            case 'd'  : d=counter; counter++; return '(\\d{1,2})';
		            case 'MMM': m=counter; counter++; shortLabel=true; return '('+monthNamesShort.join('|')+')';
				}
		        // y+,M+,d+
				var ch = $1.charAt(0);
				if (ch=='y') {y=counter; counter++; return '(\\d{4})'};
				if (ch=='M') {m=counter; counter++; return '('+monthNames.join('|')+')'};
				if (ch=='d') {d=counter; counter++; return '(\\d{2})'};
			}
		);
			
		var re = new RegExp(pattern,'i');
		var match = dateString.match(re);
		if (match!=null)
		{
			var yy = parseInt(match[y],10); if (isNaN(yy)) return null; else if (yy<70) yy+=2000; else if (yy<100) yy+=1900;
			var mm = parseInt(match[m],10); if (isNaN(mm)) mm = Richfaces.Calendar.getMonthByLabel(match[m], shortLabel ? monthNamesShort : monthNames); else if (--mm<0 || mm>11) return null;
			var dd = parseInt(match[d],10); if (isNaN(dd) || dd<1 || dd>daysInMonth(yy, mm)) return null;
			return new Date(yy, mm, dd);
		}
		return null;
	}
});
Object.extend(Date.prototype, {
	
	format : function(pattern, monthNames, monthNamesShort) {
		if (!monthNames) monthNames = Date.getDefaultMonthNames();
		if (!monthNamesShort) monthNamesShort = Date.getDefaultMonthNames(true);
		var d = this; var mm; var dd;
	    return pattern.replace(/(y+|M+|d+)/g,
	        function($1) {
				switch ($1) {
		            case 'y':
		            case 'yy': return str = d.getYear().toString().slice(-2);
		            case 'M':  return d.getMonth()+1;
		            case 'MM': return (mm = d.getMonth()+1)<10 ? '0'+mm : mm;
		            case 'MMM': return monthNamesShort[d.getMonth()];
			        case 'd':   return d.getDate();
				}
		        // y+,M+,d+
				var ch = $1.charAt(0);
				if (ch=='y') return d.getFullYear();
				if (ch=='M') return monthNames[d.getMonth()];
				if (ch=='d') return (dd = d.getDate())<10 ? '0'+dd : dd;
			}
		);
	}
});

function isLeapYear(year) {
	return new Date(year, 1, 29).getDate()==29;
}

function daysInMonth(year,month) {
	return 32 - new Date(year, month, 32).getDate();
}

function daysInMonthByDate(date) {
	return 32 - new Date(date.getFullYear(), date.getMonth(), 32).getDate();
}

function getDay(date, firstWeekDay ) {
	var value = date.getDay() - firstWeekDay;
	if (value < 0) value = 7 + value;
	return value;
}

function getFirstWeek(year, mdifw, fdow) {
	var date = new Date(year,0,1);
	var firstday = getDay(date, fdow);
	
	var weeknumber = (7-firstday<mdifw) ? 0 : 1;
	
	return {date:date, firstDay:firstday, weekNumber:weeknumber, mdifw:mdifw, fdow:fdow};
}

function getLastWeekOfPrevYear(o) {
	var year = o.date.getFullYear()-1;
	var days = (isLeapYear(year) ? 366 : 365);
	var obj = getFirstWeek(year, o.mdifw, o.fdow);
	days = (days - 7 + o.firstDay);
	var weeks = Math.floor(days/7)+1;
	  
	return  weeks+obj.weekNumber;
}

function weekNumber(year, month, mdifw, fdow) {
	
	var o = getFirstWeek(year, mdifw, fdow);
	
	if (month==0) 
	{
		if (o.weekNumber==1) return 1;
		return getLastWeekOfPrevYear(o);
	}
	var	oneweek =  604800000;
	var d = new Date(year, month,1);
		d.setDate( 1+o.firstDay + (getDay(d,fdow)==0?1:0));
		
	weeknumber = o.weekNumber + Math.floor((d.getTime() - o.date.getTime()) / oneweek);
	
	return weeknumber;
}

Calendar = Class.create();
Object.extend(Calendar.prototype, {
    initialize: function(id,parameters) {

		// dayListTableId, weekNumberBarId, weekDayBarId - 3 tables ids',

		// dayListMarkup - day cell markup
		//		context: {day, date, weekNumber, weekDayNumber, isWeekend, isCurrentMonth,  elementId, component}
		// weekNumberMarkup - week number cell markup
		//		context: {weekNumber, elementId, component}
		// weekDayMarkup - week day cell markup
		//		context: {weekDayLabel, weekDayLabelShort, weekDayNumber, isWeekend, elementId, component}

		// headerMarkup
		// footerMarkup
		// headerOptionalMarkup - user defined header (optional)
		// footerOptionalMarkup - user defined footer (optional)
		
		// currentDate - date to show month (day not used) (mm/yyyy) 
		// selectedDate - selected date (mm/dd/yyyy)
		// weekDayLabels - collection of week day labels keyed by week day numbers
		// weekDayLabelsShort - collection of week day short labels keyed by week day numbers
		// minDaysInFirstWeek - locale-specific constant defining number of days in the first week
		// firstWeekDay - (0..6) locale-specific constant defining number of the first week day
		// showWeekDaysBar - show WeekDays Bar [default value is true]
		// showWeeksBar - show Weeks numbers bar [default value is true]
		
		// POPUP description
		// direction - [top-left, top-right, bottom-left, bottom-right, auto]
		// jointPoint - [top-left, top-right, bottom-left, bottom-right]
		// popup - true
		// id+PopupButton, id+InputDate,  
				
		// boundaryDatesMode - boundary dates onclick action:
		// 						"inactive" or undefined - no action (default)
		//						"scroll" - change current month
		//						"select" - change current month and select date
		
		
		this.id = id;
		this.params = parameters;
		if (!this.params.showWeekDaysBar) this.params.showWeekDaysBar = true;
		if (!this.params.showWeeksBar) this.params.showWeeksBar = true;
		if (!this.params.datePattern) thisparams.datePattern = "MMM d, y";
		
		// markups initialization
		if (!this.params.dayListMarkup) this.params.dayListMarkup = CalendarView.dayList;
		if (!this.params.weekNumberMarkup) this.params.weekNumberMarkup = CalendarView.weekNumber;
		if (!this.params.weekDayMarkup) this.params.weekDayMarkup = CalendarView.weekDay;
		if (!this.params.headerMarkup) this.params.headerMarkup = CalendarView.header;
		if (!this.params.footerMarkup) this.params.footerMarkup = CalendarView.footer;
		
		// popup offset
		this.popupOffset = {dx: (isNaN(this.params.horizontalOffset) ? 0 : parseInt(this.params.horizontalOffset,10)), dy: (isNaN(this.params.verticalOffset) ? 0 : parseInt(this.params.verticalOffset,10))};
		
		this.currentDate = this.params.currentDate ? this.params.currentDate : (this.params.selectedDate ? this.params.selectedDate : new Date());
		this.currentDate.setDate(1);
		this.selectedDate = this.params.selectedDate;
		
		if (typeof this.params.boundaryDatesMode=="string") this.params.boundaryDatesMode = this.params.boundaryDatesMode.toLowerCase();
				
		this.todayDate = new Date();
		
		this.selectedDateElement;
		
		this.firstWeekendDayNumber = 6-this.params.firstWeekDay;
		this.secondWeekendDayNumber = (this.params.firstWeekDay>0 ? 7-this.params.firstWeekDay : 0);
		
		this.calendarContext = new CalendarContext(this);
		
		this.DATE_ELEMENT_ID = this.params.dayListTableId+'Cell';
		this.WEEKNUMBER_ELEMENT_ID = this.params.weekNumberBarId+'Cell';
		this.WEEKDAY_ELEMENT_ID = this.params.weekDayBarId+'Cell';
		this.POPUP_ID = this.id+'Popup';
		this.POPUP_BUTTON_ID = this.id+'PopupButton';
		this.INPUT_DATE_ID = this.id+'InputDate';
		this.IFRAME_ID = this.id+'IFrame';
		
		//this.popupIntervalId=null;
		
		this.firstDateIndex = 0;
		
		this.daysData = {startDate:null, days:[]};
		this.days = [];
		this.todayCellId = null;
		this.todayCellColor = "";
		
		var obj=$(id);
		
		var htmlTextHeader = (!this.params.popup ? '<input id="'+this.INPUT_DATE_ID+'" name="'+this.INPUT_DATE_ID+'" type="hidden" style="display:none" value="'+this.getSelectedDateString(this.params.datePattern)+'"/>\n' : '') +
							 '<input id="'+this.id+'InputCurrentDate" name="'+this.id+'InputCurrentDate" type="hidden" style="display:none" value="'+this.getCurrentDate().format("MM/yyyy")+'"/>\n' +
							 '<table border="0" cellpadding="0" cellspacing="0" class="rich-calendar-exterior"><tbody>\n';
		var colspan = (this.params.showWeeksBar ? "8" : "7");
		var htmlHeaderOptional = (this.params.headerOptionalMarkup) ? '<tr><td class="rich-calendar-header-optional" colspan="'+colspan+'" id="'+this.id+'HeaderOptional"></td></tr>' : '';
		var htmlFooterOptional = (this.params.footerOptionalMarkup) ? '<tr><td class="rich-calendar-footer-optional" colspan="'+colspan+'" id="'+this.id+'FooterOptional"></td></tr>' : '';
		var htmlControlsHeader = '<tr><td class="rich-calendar-header" colspan="'+colspan+'" id="'+this.id+'Header"></td></tr>';
		var htmlControlsFooter = '<tr><td class="rich-calendar-footer" colspan="'+colspan+'" id="'+this.id+'Footer"></td></tr>';
		var htmlTextFooter = '</tbody></table>\n'
		var htmlTextIFrame = '';

		this.isVisible = true;
		if (this.params.popup==true)
		{
			// popup mode initialisation
			var e = $(this.id);
			if (e) 
			{
				e.style.display='none';
				e.style.position = 'absolute';
				this.isVisible = false;
				if (Richfaces.browser.isIE6)
				{
					new Insertion.Before(obj,'<iframe src="javascript:\'\'" frameborder="0" scrolling="no" id="' + this.IFRAME_ID + '"' +
					'style="display:none; position: absolute; width: 1px; height: 1px; background-color:white;">'+'</iframe>');
				}
			}
		}

		// days bar creation
		var styleClass;
		var bottomStyleClass;
		var htmlTextWeekDayBar='';
		var context;
		if (this.params.showWeekDaysBar)
		{ 
			var htmlTextWeekDayBar = '<tr id="'+this.params.weekDayBarId+'">';
			if (this.params.showWeeksBar) htmlTextWeekDayBar+='<td class="rich-calendar-days"><br/></td>';
			var weekDayCounter = this.params.firstWeekDay;
			for (var i=0;i<7;i++)
			{
				context = {weekDayLabel: this.params.weekDayLabels[weekDayCounter], weekDayLabelShort: this.params.weekDayLabelsShort[weekDayCounter], weekDayNumber:weekDayCounter, isWeekend:this.isWeekend(i), elementId:this.WEEKDAY_ELEMENT_ID+i, component:this}; 
				var weekDayHtml = this.evaluateMarkup(this.params.weekDayMarkup, context );
				if (weekDayCounter==6) weekDayCounter=0; else weekDayCounter++;

				styleClass = "rich-calendar-days";
				if (context.isWeekend)
				{
					styleClass += " rich-calendar-weekends";
				}
				if (i==6) styleClass += " rich-right-cell";
				htmlTextWeekDayBar+='<td class="'+styleClass+'" id="'+context.elementId+'">'+weekDayHtml+'</td>';
			}
			htmlTextWeekDayBar+='</tr>\n';
		}

		// week & weekNumber creation
		var htmlTextWeek='';
		var p=0;

		for (k=1;k<7;k++)
		{
			bottomStyleClass = (k==6 ? "rich-bottom-cell " : "");			
			htmlTextWeek+='<tr id="'+this.params.weekNumberBarId+k+'">';
			if (this.params.showWeeksBar)
			{
				context = {weekNumber: k, elementId:this.WEEKNUMBER_ELEMENT_ID+k, component:this}; 
				var weekNumberHtml = this.evaluateMarkup(this.params.weekNumberMarkup, context );
				htmlTextWeek+='<td class="rich-calendar-week '+bottomStyleClass+'" id="'+context.elementId+'">'+weekNumberHtml+'</td>';
			}
			
			// day cells creation 
			for (var i=0;i<7;i++)
			{
				styleClass = bottomStyleClass+"rich-cell-size rich-calendar-cell";
				if (i==this.firstWeekendDayNumber || i==this.secondWeekendDayNumber) styleClass+=" rich-calendar-holly";
				if (i==6) styleClass+=" rich-right-cell";
				
				htmlTextWeek+='<td class="'+styleClass+'" id="'+this.DATE_ELEMENT_ID+p+'"></td>';
				p++;
			}
			htmlTextWeek+='</tr>';
		}
		
		// set content
		obj.component = this;
		obj.richfacesComponent="richfaces:calendar";
		obj.innerHTML = htmlTextIFrame+htmlTextHeader+htmlHeaderOptional+htmlControlsHeader+htmlTextWeekDayBar+htmlTextWeek+htmlControlsFooter+htmlFooterOptional+htmlTextFooter;
		
		if(this.params.submitFunction)	this.submitFunction = this.params.submitFunction.bind(this);
		this.prepareEvents();
	},
	
	doCollapse: function() {
		if (!this.params.popup || !this.isVisible) return;
		
		/*this.stopTimer();
		this.stopPopupEvents($(this.id));
		this.stopPopupEvents($(this.POPUP_ID));*/
		
		var element = $(this.id);
		
		if (this.invokeEvent("collapse", element))
		{
			Event.stopObserving(window.document, "click", this.eventOnCollapse, false);
			
			if (this.eventOnCollapseFlag)
			{
				Event.stopObserving(window.document, "click", this.eventOnCollapse, false);
				this.eventOnCollapseFlag = false;
			}
			
			if (Richfaces.browser.isIE6) Element.hide(this.IFRAME_ID);
			Element.hide(element);
			this.isVisible = false;
		}
	},
	
	doExpand: function() {
		if (!this.params.popup || this.isVisible) return;
		
		var element = $(this.id);

		if (this.invokeEvent("expand", element))
		{
			var base = $(this.POPUP_ID)
			var baseInput = base.firstChild;
			var baseButton = baseInput.nextSibling;
			
			if (baseInput && baseInput.value!=undefined)
			{
				this.selectDate(baseInput.value);
			}
	
			var iframe = $(this.IFRAME_ID);
			
			/*this.setPopupEvents(e);
			this.setPopupEvents(base);*/
			
			//rect calculation
			
			var offsetBase = Position.cumulativeOffset(baseButton);
			
			if (this.params.showInput)
			{
				var offsetBase1 = Position.cumulativeOffset(baseInput);
			
				offsetBase = [offsetBase[0]<offsetBase1[0] ? offsetBase[0] : offsetBase1[0],
							  offsetBase[1]<offsetBase1[1] ? offsetBase[1] : offsetBase1[1]];
				var offsetDimInput = Richfaces.Calendar.getOffsetDimensions(baseInput);
			}
			
			var offsetDimBase = Richfaces.Calendar.getOffsetDimensions(base);
			var offsetDimButton = Richfaces.Calendar.getOffsetDimensions(baseButton);
			var o = {left: offsetBase[0],
					 top: offsetBase[1],
					 width: offsetDimBase.width,
					 height: (offsetDimInput && offsetDimInput.height>offsetDimButton.height ? offsetDimInput.height : offsetDimButton.height)};
					 
			Richfaces.Calendar.setElementPosition(element, o, this.params.jointPoint, this.params.direction, this.popupOffset);
	
			if (Richfaces.browser.isIE6)
			{
				iframe.style.left = element.style.left;
				iframe.style.top = element.style.top;
				var edim = Richfaces.Calendar.getOffsetDimensions(element);
				iframe.style.width = edim.width+'px';
				iframe.style.height = edim.height+'px';
				Element.show(iframe);
			}
			
			Element.show(element);
			
			this.isVisible = true;

			Event.observe(window.document, "click", this.eventOnCollapse, false);
		}
	},
	
	doSwitch: function() {
		this.isVisible ? this.doCollapse() : this.doExpand();
	},
	
	eventOnCollapse: function (e) {
		if (Event.element(e).id == this.POPUP_BUTTON_ID || (!this.params.enableManualInput && Event.element(e).id == this.INPUT_DATE_ID) ) return true;
		
		Position.prepare();
		if (Position.withinIncludingScrolloffsets($(this.id), Event.pointerX(e), Event.pointerY(e))) return true;
		this.doCollapse();
		
		return true;
	},
	
	getCurrentDate: function() {
		return this.currentDate;
	},	
	getSelectedDate: function() {
		if (!this.selectedDate) return null; else return this.selectedDate;
	},
	getSelectedDateString: function(pattern) {
		if (!this.selectedDate) return "";
		if (!pattern) pattern = this.params.datePattern;
		return this.selectedDate.format(pattern, this.params.monthLabels, this.params.monthLabelsShort);
	},

	getPrevYear: function() {
		var value = this.currentDate.getFullYear()-1;
		if (value<0) value = 0;
		return value;
	},
	getPrevMonth: function(asMonthLabel) {
		var value = this.currentDate.getMonth()-1;
		if (value < 0 ) value = 11;
		if (asMonthLabel)
		{
			return this.params.monthLabels[value];
		} else return value;
	},
	getCurrentYear: function() {
		return this.currentDate.getFullYear();
	},
	getCurrentMonth: function(asMonthLabel) {
		var value = this.currentDate.getMonth();
		if (asMonthLabel)
		{
			return this.params.monthLabels[value];
		} else return value;
	},
	getNextYear: function() {
		return this.currentDate.getFullYear()+1;
	},
	getNextMonth: function(asMonthLabel) {
		var value = this.currentDate.getMonth()+1;
		if (value > 11 ) value = 0;
		if (asMonthLabel)
		{
			return this.params.monthLabels[value];
		} else return value;
	},
	
	isWeekend: function(weekday) {
		return (weekday == this.firstWeekendDayNumber || weekday == this.secondWeekendDayNumber);
	},
	
	prepareEvents: function() {
		this.eventCellOnClick = this.eventCellOnClick.bindAsEventListener(this);
		this.eventCellOnMouseOver = this.eventCellOnMouseOver.bindAsEventListener(this);
		this.eventCellOnMouseOut = this.eventCellOnMouseOut.bindAsEventListener(this);
		this.eventOnCollapse = this.eventOnCollapse.bindAsEventListener(this);
		//this.eventOnMouseOver = this.eventOnMouseOver.bindAsEventListener(this);
		//this.eventOnMouseOut = this.eventOnMouseOut.bindAsEventListener(this);
	},
	
/*	setPopupEvents: function(obj) {
		Event.observe(obj, "mouseover", this.eventOnMouseOver, false);
		Event.observe(obj, "mouseout", this.eventOnMouseOut, false);
	},

	stopPopupEvents: function(obj) {
		Event.stopObserving(obj, "mouseover", this.eventOnMouseOver, false);
		Event.stopObserving(obj, "mouseout", this.eventOnMouseOut, false);
	},
	* 	
	stopTimer: function()
	{
		if (this.popupIntervalId!=null) 
		{
			clearTimeout(this.popupIntervalId);
			this.popupIntervalId=null;
		}		
	},
	
	eventOnMouseOver: function(e) {
		this.stopTimer();
	},
	
	eventOnMouseOut: function(e) {
		if (this.popupIntervalId==null) this.popupIntervalId = setTimeout('$("'+this.id+'").component.doCollapse()',400);
	},*/
	
	setCellEvents: function(obj) {
		Event.observe(obj, "click", this.eventCellOnClick, false);
		Event.observe(obj, "mouseover", this.eventCellOnMouseOver, false);
		Event.observe(obj, "mouseout", this.eventCellOnMouseOut, false);
	},
	stopCellEvents: function(obj) {
		Event.stopObserving(obj, "click", this.eventCellOnClick, false);
		Event.stopObserving(obj, "mouseover", this.eventCellOnMouseOver, false);
		Event.stopObserving(obj, "mouseout", this.eventCellOnMouseOut, false);
	},
	
	invokeEvent: function(eventName, element, event, date) {
		var eventFunction = this.params['on'+eventName];
		var result;

		if (eventFunction)
		{
			var eventObj;

			if (event)
			{
				eventObj = event;
			}
			else if( document.createEventObject ) 
			{
				eventObj = document.createEventObject();
			}
			else if( document.createEvent )
			{
				eventObj = document.createEvent('Events');
				eventObj.initEvent( eventName, true, false );
			}
			
			eventObj.rich = {component:this};
			eventObj.rich.date = date;

			try
			{
				result = eventFunction.call(element, eventObj);
			}
			catch (e) { LOG.warn("Exception: "+e.Message + "\n[on"+eventName + "]"); }

		}
		
		if (result!=false) result = true;
		
		return result;
	},
	
	eventCellOnClick: function (e) {
		var obj = Event.findElementByAttr(e, "TD", "id", this.DATE_ELEMENT_ID, true);
		if (obj)
		{
			var daydata = this.days[parseInt(obj.id.substr(this.DATE_ELEMENT_ID.length),10)];
			if (daydata._month==0)
			{
				var date=new Date(this.currentDate);
				date.setDate(daydata.day);
				
				if (this.selectDate(date,true))
				{
					this.doCollapse();
				}
				
			} else {
				if (this.params.boundaryDatesMode == "scroll") 
					if (daydata._month==-1) this.prevMonth(); else this.nextMonth();
				else if (this.params.boundaryDatesMode == "select") 
				{
					//var date = new Date(this.currentDate.getFullYear(), this.currentDate.getMonth()+daydata._month, daydata.day);
					if (this.selectDate(daydata.date))
					{
						this.doCollapse();
					}
				}
			}
		}
	},

	eventCellOnMouseOver: function (e) {
		var obj = Event.findElementByAttr(e, "TD", "id", this.DATE_ELEMENT_ID, true);
		if (obj)
		{
			var daydata = this.days[parseInt(obj.id.substr(this.DATE_ELEMENT_ID.length),10)];
			//var date = new Date(this.currentDate.getFullYear(), this.currentDate.getMonth()+daydata._month, daydata.day);
			if (this.invokeEvent("datemouseover", obj, e, daydata.date))
			{
				if (daydata._month==0) Element.addClassName(obj,'rich-calendar-hover');
			}
		}
	},
	
	eventCellOnMouseOut: function (e) {
		var obj = Event.findElementByAttr(e, "TD", "id", this.DATE_ELEMENT_ID, true);
		if (obj)
		{
			var daydata = this.days[parseInt(obj.id.substr(this.DATE_ELEMENT_ID.length),10)];
			//var date = new Date(this.currentDate.getFullYear(), this.currentDate.getMonth()+daydata._month, daydata.day);
			if (this.invokeEvent("datemouseout", obj, e, daydata.date))
			{
				if (daydata._month==0) Element.removeClassName(obj,'rich-calendar-hover');
			}
		}
	},

	load:function(daysData, isAjaxMode)	{
		//	startDate,
		//	days:array[]
		//	{
		//			data
		//			enabled boolean or function
		//			isEnabled function 
		//			text1: 'Meeting...',
		//			text2: 'Meeting...'
		//			tooltip 
		//			hasTooltip 
		//			dayStyleClass 
		//	}
		
		if (!$(this.id).component) return;
		
		if (daysData) {
			this.daysData = this.indexData(daysData, isAjaxMode);
		} else {
			this.daysData = null;
		}
		
		this.render();
	},
	
	indexData:function(daysData, isAjaxMode) {
		var dateYear = daysData.startDate.getFullYear();
		var dateMonth = daysData.startDate.getMonth();
		
		daysData.index = [];
		daysData.index[dateYear+'-'+dateMonth] = 0;
		if (isAjaxMode)
		{
			this.currentDate = daysData.startDate;
			this.currentDate.setDate(1);
			return daysData;
		}
		var idx = daysInMonthByDate(daysData.startDate)-daysData.startDate.getDate()+1;
		
		while (daysData.days[idx])
		{
			if (dateMonth==11) {dateYear++; dateMonth=0;} else dateMonth++;
			daysData.index[dateYear+'-'+dateMonth] = idx;
			idx+= (32 - new Date(dateYear, dateMonth, 32).getDate());
		}
		return daysData;
	},
	
	render:function() {
		this.todayDate = new Date();		
		
		var currentYear = this.getCurrentYear();
		var currentMonth = this.getCurrentMonth();
		
		var todayflag = (currentYear == this.todayDate.getFullYear() && currentMonth == this.todayDate.getMonth());
		var todaydate =  this.todayDate.getDate();
		
		var selectedflag = this.selectedDate && (currentYear == this.selectedDate.getFullYear() && currentMonth == this.selectedDate.getMonth())
		var selecteddate = this.selectedDate && this.selectedDate.getDate();

		var wd = getDay(this.currentDate, this.params.firstWeekDay);
		var currentMonthDays = daysInMonthByDate(this.currentDate);
		var previousMonthDays = daysInMonth(currentYear, currentMonth-1);
		
		var p=0;
		var month=-1;
		this.days = [];
		var dayCounter = previousMonthDays  - wd + 1;
		
		// previuos month days
		if (wd>0) while (dayCounter<=previousMonthDays)
		{
			this.days.push({day:dayCounter, isWeekend: this.isWeekend(p), _month:month}); dayCounter++; p++;
		}
			
		dayCounter = 1;
		month=0;
		
		this.firstDateIndex = p;

		// current month days
		if (this.daysData && this.daysData.index[currentYear+'-'+currentMonth]!=undefined)
		{
			var idx = this.daysData.index[currentYear+'-'+currentMonth];
			if (this.daysData.startDate.getFullYear()==currentYear && this.daysData.startDate.getMonth()==currentMonth)
			{
				var firstDay = firstDay=(this.daysData.days[idx].day ? this.daysData.days[idx].day : this.daysData.startDate.getDate());
				while (dayCounter<firstDay)
				{
					this.days.push({day:dayCounter, isWeekend:this.isWeekend(p%7), _month:month});
				
					dayCounter++;
					p++;
				}
			}
			
			var len = this.daysData.days.length;
			var obj;
			var flag;
			while (idx<len && dayCounter<=currentMonthDays)
			{
				flag = this.isWeekend(p%7);
				obj = this.daysData.days[idx];
				obj.day = dayCounter;
				obj.isWeekend = flag;
				obj._month = month;
				this.days.push(obj);
				idx++;
				dayCounter++;
				p++;
			}
		}
		while (p<42)
		{
			if (dayCounter>currentMonthDays) {dayCounter=1; month=1;}
			this.days.push({day:dayCounter, isWeekend: this.isWeekend(p%7), _month:month});
			dayCounter++;
			p++;
		}
		
		// render
		this.renderHeader();
		this.renderFooter();
		this.renderHeaderOptional();
		this.renderFooterOptional();
		
		//days render
		p=0;
		var element;
		var dataobj;
		var wn;
		if (this.params.showWeeksBar) wn = weekNumber(currentYear, currentMonth, this.params.minDaysInFirstWeek, this.params.firstWeekDay); /// fix it
		this.selectedDayElement=null;
		var weekflag=true;

		var e;
		
		var boundaryDatesModeFlag = (this.params.boundaryDatesMode == "scroll" || this.params.boundaryDatesMode == "select");
		
		if (this.highlightEffect) 
		{
			this.highlightEffect.cancel();
			this.highlightEffect=null;
		}
		if (this.todayCellId)
		{
			$(this.todayCellId).style['backgroundColor'] = '';
			this.todayCellId = null;
		}
		
		//var _d=new Date();
		
		if (this.selectedDateElement) {
			Element.classNames(this.selectedDateElement).remove("rich-calendar-select");
			this.selectedDateElement = null;
		}
		
		for (var k=1;k<7;k++)
		{
			//
			dataobj = this.days[p];
			
			var obj = $(this.params.weekNumberBarId+k);
			element = obj.firstChild;
			var weeknumber; 

			// week number update			
			if (this.params.showWeeksBar)
			{
				if (weekflag && currentMonth==11 &&
				   (k==5||k==6) &&
				   (dataobj._month==1 || (currentMonthDays-dataobj.day+1)<this.params.minDaysInFirstWeek) )
				{
					wn=1;
					weekflag=false;
				}
				weeknumber = wn;
			    element.innerHTML = this.evaluateMarkup(this.params.weekNumberMarkup, {weekNumber: wn++, elementId:element.id, component:this} );
			    if (k==1&&wn>52) wn=1;
			    element = element.nextSibling;
			}
			
			var weekdaycounter = this.params.firstWeekDay; 

			while (element)
			{
				// TODO rich-calendar-spec class not implemented
				// TODO fix start/stop event's calls
				this.stopCellEvents(element);
				
				dataobj.elementId=element.id;
				dataobj.date=new Date(currentYear, currentMonth+dataobj._month, dataobj.day);
				dataobj.weekNumber = weeknumber;
				dataobj.component = this;
				dataobj.isCurrentMonth = (dataobj._month==0);
				dataobj.weekDayNumber = weekdaycounter;
				if (weekdaycounter==6) weekdaycounter=0; else weekdaycounter++;
				element.innerHTML = this.evaluateMarkup(this.params.dayListMarkup, dataobj );
				
				// class styles
				e = Element.classNames(element);
				if (dataobj._month!=0) { e.add('rich-calendar-boundary-dates'); if (boundaryDatesModeFlag) e.add('rich-calendar-btn'); else e.remove('rich-calendar-btn');}
				else 
				{
					e.remove('rich-calendar-boundary-dates');
					e.add('rich-calendar-btn');
				}
				
				// TODO make some optimization with rich-calendar-today class
				if (todayflag && dataobj._month==0 && dataobj.day==todaydate) 
				{
					this.todayCellId = element.id;
					
					if (Richfaces.browser.isSafari && this.params.popup && !this.isVisible)
					{
						// Safari 2.0 fix 
						// if [display:none] Element.getStyle() function returns null;
						var els = $(this.id).style;
						var originalVisibility = els.visibility;
						var originalDisplay = els.display;
						els.visibility = 'hidden';
						els.display = '';
						this.todayCellColor = Element.getStyle(element, 'background-color').parseColor();
						els.display = originalDisplay;
						els.visibility = originalVisibility;
					} else 
					{					
						this.todayCellColor = Element.getStyle(element, 'background-color').parseColor();
					}
					e.add("rich-calendar-today");
				}
				else
				{
					e.remove("rich-calendar-today");
				}
				
				if (selectedflag && dataobj._month==0 && dataobj.day==selecteddate) {
					this.selectedDateElement = element;
					e.add("rich-calendar-select");
				}
				
				this.setCellEvents(element);
				p++;

				dataobj = this.days[p];
				element=element.nextSibling;
			}
		}
		//alert(new Date().getTime()-_d.getTime());
		
		// hack for IE 6.0 //fix 1072
		if (Richfaces.browser.isIE6)
		{
			var element = $(this.id);
			if (element)
			{
				element.style.width = "0px";
				element.style.height = "0px";
			}
		}
	},
	renderHeader: function()
	{
		this.renderMarkup(this.params.headerMarkup, this.id+"Header", this.calendarContext);
	},
	
	renderFooter: function()
	{
		this.renderMarkup(this.params.footerMarkup, this.id+"Footer", this.calendarContext);
	},

	renderHeaderOptional: function()
	{
		this.renderMarkup(this.params.headerOptionalMarkup, this.id+"HeaderOptional", this.calendarContext);
	},	

	renderFooterOptional: function()
	{
		this.renderMarkup(this.params.footerOptionalMarkup, this.id+"FooterOptional", this.calendarContext);
	},
	
	renderMarkup: function (markup, elementId, context)
	{
		if (!markup) return;

		var e = $(elementId);
		if (!e) return; 
	
		e.innerHTML = markup.invoke('getContent', context).join('');
	},
	
	evaluateMarkup: function(markup, context)
	{
		if (!markup) return "";
		return markup.invoke('getContent', context).join('');
	},
	
	onUpdate: function()
	{
		var formattedDate = this.getCurrentDate().format("MM/yyyy");
		$(this.id+'InputCurrentDate').value=formattedDate;
		
		if (this.submitFunction)
			this.submitFunction(formattedDate);
		else
			this.render();
	},
	
	nextMonth: function() {
		this.changeCurrentDate(0,1);
	},
	
	prevMonth: function() {
		this.changeCurrentDate(0,-1);
	},
	
	nextYear: function() {
		this.changeCurrentDate(1,0);
	},
	
	prevYear: function() {
		this.changeCurrentDate(-1,0);
	},
	
	changeCurrentDate: function(yearOffset, monthOffset) {
		var date = new Date(this.currentDate.getFullYear()+yearOffset, this.currentDate.getMonth()+monthOffset,1);
		if (this.invokeEvent("currentdateselect", $(this.id), null, date))
		{
			this.currentDate = date;
			this.onUpdate();
		}
	},
	
	today: function(noUpdate, noHighlight) {
		var now = new Date();
		var nowyear = now.getFullYear();
		var nowmonth = now.getMonth();
		var nowdate = now.getDate();
		var updateflag = false;

		if (nowdate!=this.todayDate.getDate()) {updateflag=true; this.todayDate = now;}
		
		if (nowyear != this.currentDate.getFullYear() || nowmonth != this.currentDate.getMonth() )
		{
			updateflag = true;
			this.currentDate = new Date(nowyear, nowmonth, 1);
		}
		
		if (updateflag)
		{ 
			if (noUpdate) this.render(); else this.onUpdate();
		}
		else
		{
			// highlight today
			if (this.isVisible && this.todayCellId && !noHighlight)
			{
				if (this.highlightEffect) 
				{
					this.highlightEffect.cancel();
					this.highlightEffect=null;
				}
				var e = $(this.todayCellId);
				e.style['backgroundColor'] = '';
				this.highlightEffect = new Effect.Highlight(e, {startcolor: this.todayCellColor, duration:0.3, transition: Effect.Transitions.sinoidal,
				afterFinish: this.onHighlightFinish});
			}
		}
	},
	
	onHighlightFinish: function (object)
	{
		object.element.style['backgroundColor'] = '';
	},
	
	selectDate: function(date, noUpdate, eventData) {
		if (!eventData)
		{
			eventData = {event: null, element: null};
		}
		
		var oldSelectedDate = this.selectedDate;
		var newSelectedDate;
		if (date)
		{
			if (typeof date=='string') date = Date.parseDate(date,this.params.datePattern, this.params.monthLabels, this.params.monthLabelsShort);
			newSelectedDate = date;
		}
		else
		{
			newSelectedDate = null;
		}
		
		// fire user event
		var flag = true;
		var isDateChanged = false;
		if ( (oldSelectedDate - newSelectedDate) && (oldSelectedDate!=null || newSelectedDate!=null) )
		{
			isDateChanged = true 	
			flag = this.invokeEvent("dateselect", eventData.element, eventData.event, date)
		}		     

		if (flag)
		{		   
			var field = $(this.INPUT_DATE_ID);
			this.selectedDate = newSelectedDate;
			if (this.selectedDate!=null)
			{
				field.value=this.getSelectedDateString(this.params.datePattern);
				
				var d = new Date(this.selectedDate);
				if (d.getMonth()==this.currentDate.getMonth() && d.getFullYear()==this.currentDate.getFullYear())
				{
					if (!oldSelectedDate || oldSelectedDate.getDate()!=d.getDate())
					{
						// find cell and change style class
						var e = $(this.DATE_ELEMENT_ID+(this.firstDateIndex + this.selectedDate.getDate()-1));
						if (this.selectedDateElement) Element.removeClassName(this.selectedDateElement, "rich-calendar-select");
						this.selectedDateElement = e;
						Element.addClassName(e, "rich-calendar-select");
	
						this.renderHeader();
						this.renderFooter();					
					}
				} else {
					// change currentDate and call this.onUpdate();
					d.setDate(1);
					this.currentDate = d;
					if (noUpdate) this.render(); else this.onUpdate();
				}
			}
			else
			{
				this.selectedDate = null;
				field.value = ""; 
				if (this.selectedDateElement)
				{
					Element.removeClassName(this.selectedDateElement, "rich-calendar-select");
					this.selectedDateElement = null;
					this.renderHeader();
					this.renderFooter();					
				}
				
				var date = new Date();
				if (this.currentDate.getMonth()==date.getMonth() && this.currentDate.getFullYear()==date.getFullYear())
				{
					this.renderHeader();
					this.renderFooter();					
				}
				this.today(noUpdate, true);
			}
			
			// call user event
			if (isDateChanged)
			{
				this.invokeEvent("dateselected", eventData.element, eventData.event, this.selectedDate);
			}
		}
		
		return flag;			
	},
	
	resetSelectedDate: function()
	{
		if (!this.selectedDate) return;
		if (this.invokeEvent("dateselect", null, null, null))
		{
			this.selectedDate = null;
			$(this.INPUT_DATE_ID).value = ""; 
			if (this.selectedDateElement)
			{
				Element.removeClassName(this.selectedDateElement, "rich-calendar-select");
				this.selectedDateElement = null;
			}
			this.renderHeader();
			this.renderFooter();
			this.doCollapse();
			this.invokeEvent("dateselected", null, null, null);
		}
	},
	
	showSelectedDate: function()
	{
		if (!this.selectedDate) return;
		if (this.currentDate.getMonth()!=this.selectedDate.getMonth() || this.currentDate.getFullYear()!=this.selectedDate.getFullYear())
		{
			this.currentDate = new Date(this.selectedDate);
			this.currentDate.setDate(1);
			this.onUpdate();
		}
	}
	
});

CalendarView = {};
CalendarView.getControl = function(text, functionName) {
	var attr = {
		onclick: (functionName ? "Richfaces.getComponent('calendar',this)."+functionName+"();" : "")+"return true;",
		className: "rich-calendar-btn"
	};
	
	return new E('div',attr,[new T(text)]);
};

CalendarView.getSelectedDateControl = function(text, functionName) {
	var attr = {
		onclick: "Richfaces.getComponent('calendar',this).showSelectedDate(); return true;",
		className: "rich-calendar-btn"
	};
	
	var a = [new T(text)];
	if (text)
	{
		a.push(new T(" "));
		a.push(new E('a', {href: '#', onclick: "Richfaces.getComponent('calendar',this).resetSelectedDate();return true;"}, [new T('(x)')]));
	}
	
	return new E('div',attr,a);
};

CalendarView.nextYearControl = CalendarView.getControl(">>", "nextYear");
CalendarView.previousYearControl = CalendarView.getControl("<<", "prevYear");
CalendarView.nextMonthControl = CalendarView.getControl(">", "nextMonth");
CalendarView.previousMonthControl = CalendarView.getControl("<", "prevMonth");
CalendarView.currentMonthControl = function (context) { return context.calendar.getCurrentDate().format("MMMM, yyyy", context.monthLabels, context.monthLabelsShort);}; 
CalendarView.todayControl = CalendarView.getControl("Today", "today");
CalendarView.selectedDateControl = function (context) { return CalendarView.getSelectedDateControl(context.calendar.getSelectedDateString(context.calendar.params.datePattern));};
//CalendarView.resetSelectedDateControl = function (context) { return (context.calendar.getSelectedDate() ? CalendarView.getControl("x", "resetSelectedDate") : "");};

CalendarView.header = [
	new E('table',{'border': '0', 'cellpadding': '0', 'cellspacing': '0', 'width': '100%'},
		[
			new E('tbody',{},
			[
				new E('tr',{},
				[
					new E('td',{'class': 'rich-calendar-tool'},
					[
						new ET(function (context) { return Richfaces.evalMacro("previousYearControl", context)})
					]),
					new E('td',{'class': 'rich-calendar-tool'},
					[
						new ET(function (context) { return Richfaces.evalMacro("previousMonthControl", context)})
					]),
					new E('td',{'class': 'rich-calendar-month'},
					[
						new ET(function (context) { return Richfaces.evalMacro("currentMonthControl", context)})
					]),
					new E('td',{'class': 'rich-calendar-tool'},
					[
						new ET(function (context) { return Richfaces.evalMacro("nextMonthControl", context)})
					]),
					new E('td',{'class': 'rich-calendar-tool'},
					[
						new ET(function (context) { return Richfaces.evalMacro("nextYearControl", context)})
					])
				])
			])
		]
	)];
	
CalendarView.footer = [
	new E('table',{'border': '0', 'cellpadding': '0', 'cellspacing': '0', 'width': '100%'},
		[
			new E('tbody',{},
			[
				new E('tr',{},
				[
					/*new E('td',{'class': 'rich-calendar-toolfooter'},
					[
						new ET(function (context) { return Richfaces.evalMacro("resetSelectedDateControl", context)})
					]),*/
					new E('td',{'class': 'rich-calendar-toolfooter', 'style': 'white-space:nowrap'},
					[
						new ET(function (context) { return Richfaces.evalMacro("selectedDateControl", context)})
					]),
					new E('td',{'class': 'rich-calendar-toolfooter', 'align': 'right'},
					[
						new ET(function (context) { return Richfaces.evalMacro("todayControl", context)})
					])
				])
			])
		]
	)];
	
CalendarView.dayList = [new ET(function (context) { return context.day})];
CalendarView.weekNumber = [new ET(function (context) { return context.weekNumber})];
CalendarView.weekDay = [new ET(function (context) { return context.weekDayLabelShort})];

CalendarContext = Class.create();
Object.extend(CalendarContext.prototype, {
    initialize: function(calendar) {
    	this.calendar=calendar;
		this.monthLabels=calendar.params.monthLabels;
		this.monthLabelsShort=calendar.params.monthLabelsShort;
		this.weekDayLabels=calendar.params.weekDayLabels;
		this.weekDayLabelsShort=calendar.params.weekDayLabelsShort;
    },

	nextYearControl: CalendarView.nextYearControl,
	previousYearControl: CalendarView.previousYearControl,
	nextMonthControl: CalendarView.nextMonthControl,
	previousMonthControl: CalendarView.previousMonthControl,
	currentMonthControl: CalendarView.currentMonthControl,
	todayControl: CalendarView.todayControl,
	selectedDateControl: CalendarView.selectedDateControl
	//resetSelectedDateControl: CalendarView.resetSelectedDateControl,
});