var Calendar = Class.create();
// Static Methods:
Object.extend(Calendar, {
	allCalendars: $H(),

	get: function(id){
		return this.allCalendars.get(id);
	},

	add: function(calendar){
		this.allCalendars.set(calendar.id, calendar);
	},

	remove: function(calendar){
		if(calendar != null){
			calendar.destroy();
			this.allCalendars.unset(calendar.id);
		}
	},

	removeAll: function(){
		this.allCalendars.values().each(this.remove.bind(this));
	},

	bindToField: function(field){
		field = $(field);
		var img = field.next("img.calendarImage");
		//Para garantir que a imagem é do campo mesmo, faz o caminho inverso:
		if(img != null && img.previous("input[type=text]") === field){
			img.title = Bundle.getMessage("txt.date.click.here.to.choose");
			Event.observe(img, "click", function(event){
				new Calendar({
					removeWhenHide: true,
					clonePositionFrom: img.identify(),
					setDate: function(timeMilis){
						field.value = Date.format_DDMMYYYY(new Date(timeMilis));
					},
					setFormattedDate: function(formattedDate){
						field.value = formattedDate;
					}
				}).show(Date.parse_DDMMYYYY(field.value));
	
				Event.stop(event);
				return false;
			}.bindAsEventListener(this));
		}
	},

	hideOthers: function(exceptCalendar){
		this.allCalendars.values().each(function(cal){
			if(cal != exceptCalendar && cal.options.hideOnChoose){
				cal.hide();
			}
		});
	}
});
Event.observe(window, "unload", Calendar.removeAll.bind(Calendar));

Object.extend(Calendar.prototype, {

	id: null,
	container: null,

	// global variables
	s_userAgent: window.navigator.userAgent.toLowerCase(),
	re_webkit: /WebKit\/(\d+)/i,
	b_mac: null,
	b_ie5: null,
	b_ie6: null,
	b_ieFix: null,
	b_ieMac: null,
	b_safari: null,

	initialize: function(options, appendToDivId) {
		this.b_mac = this.s_userAgent.indexOf('mac') != -1;
		this.b_ie5 = this.s_userAgent.indexOf('msie 5') != -1;
		this.b_ie6 = this.s_userAgent.indexOf('msie 6') != -1 && this.s_userAgent.indexOf('opera') == -1;
		this.b_ieFix = this.b_ie5 || this.b_ie6;
		this.b_ieMac = this.b_mac && this.b_ie5;
		this.b_safari = this.b_mac && this.re_webkit.exec(this.s_userAgent) && Number(RegExp.$1) < 500;
		this.id = "calendar_"+(new Date().getTime())+"_"+Math.random();

		this.setOptions(options);

		this.container = new Element("div", {id:this.id});
		this.container.className = "calendar";
		this.container.hide(); // Cria a div escondida, depois mostra.
		($(appendToDivId) || $(document.body)).appendChild(this.container);

		if(this.options.hideOnChoose){
			Event.observe($(document.body), "click", function(){
				var div = this.container;
				if(div != null && div.visible()){
					this.hide();
				}
				return true;
			}.bind(this));
			this.container.setStyle("background-color: #A6C06D");
		}

		Calendar.add(this);
	},

	setOptions: function(options){
		this.options = Object.extend({
			setDate: Prototype.emptyFunction,
			setFormattedDate: Prototype.emptyFunction,
			hideOnChoose: true,
			removeWhenHide: false,
			returnFormattedDate: true,
			months: [ "Janeiro", "Fevereiro", "Março", "Abril", "Maio", "Junho", "Julho", "Agosto", "Setembro", "Outubro", "Novembro", "Dezembro" ],
			weekdays: [ "Dom", "Seg", "Ter", "Qua", "Qui", "Sex", "Sab" ],
			yearscroll: false, // show year scroller
			weekstart: 0, // first day of week: 0-Su or 1-Mo
			centyear: 70, // 2 digit years less than 'centyear' are in 20xx, otherwise in 19xx.
			imgpath: "/scripts/calendar/image/" // directory with calendar images
		}, options||{});

		// Corrige imgpath:
		if(!this.options.imgpath.startsWith(window.contextPath)){
			this.options.imgpath = window.contextPath + this.options.imgpath;
		}
	},

	show: function(date) {
		// generate HTML and show calendar
		this.render(date);
		this.container.show();
		this.clonePosition();

		Calendar.hideOthers(this);
	},

	clonePosition: function(){
		if(this.options.clonePositionFrom != null){
			var position = function(){
				var elem = $(this.options.clonePositionFrom);
				var dimensions = elem.getDimensions();
				this.container.setStyle({position: "absolute"});
				this.container.clonePosition(elem, {
					setWidth: false, setHeight: false,
					offsetTop: dimensions.height
				});
			}.bind(this);
			try{ position(); }catch(e){/*IE Bug*/ position(); }
		}
	},

	render: function(d_date) {
		var d_today = this.resetTime(new Date());

		// figure out date to display
		if (!d_date) // selected by default
			d_date = d_today;
		else if (typeof(d_date) == 'number') // get from number
			d_date = this.resetTime(new Date(d_date));

		if (!d_date) return false;
		var d_selected = d_date;

		// first date to display
		var d_firstday = new Date(d_date);
		d_firstday.setDate(1);
		d_firstday.setDate(1 - (7 + d_firstday.getUTCDay() - this.options.weekstart) % 7);

		var a_class;				
		var s_html = '<table class="mtr" cellspacing="0" cellpadding="0"><tbody><tr class="wd">';		
		// print weekdays titles
		for (var i = 0; i < 7; i++){
			var klass = "";
			if(i == 0){klass = "prim";}
			if(i == 6){klass = "ult";}
			s_html += '<th class='+klass+'>' + this.options.weekdays[(this.options.weekstart + i) % 7] + '</th>';
		}
		s_html += '</tr>' ;

		// print calendar table
		var n_date, n_month, d_current = new Date(d_firstday);
		while (d_current.getUTCMonth() == d_date.getUTCMonth() ||
			   d_current.getUTCMonth() == d_firstday.getUTCMonth()) {

			// print row header
			s_html +='<tr>';
			for (var n_wday = 0; n_wday < 7; n_wday++) {
				a_class = [];
				n_date  = d_current.getUTCDate();
				n_month = d_current.getUTCMonth();
				var formattedCurrent = [];
				formattedCurrent[0] = d_current.getUTCDate().toString(); //DIA
				formattedCurrent[1] = (d_current.getUTCMonth() + 1).toString(); //MES
				formattedCurrent[2] = d_current.getUTCFullYear().toString(); //ANO
				formattedCurrent[0] = (formattedCurrent[0].length < 2) ? "0"+formattedCurrent[0] : formattedCurrent[0];
				formattedCurrent[1] = (formattedCurrent[1].length < 2) ? "0"+formattedCurrent[1] : formattedCurrent[1];
				var formattedCurrentDate = formattedCurrent[0] +"/"+ formattedCurrent[1] +"/"+ formattedCurrent[2];
	
				// other month
				if (d_current.getUTCMonth() != d_date.getUTCMonth())
					a_class[a_class.length] = 'othermonth';
				
				// weekend
				if (d_current.getUTCDay() == 0 || d_current.getUTCDay() == 6)
					a_class[a_class.length] = 'weekend';

				// today
				if (formattedCurrentDate == Date.format_DDMMYYYY(d_today))
					a_class[a_class.length] = 'today';
				
				// selected
				if (formattedCurrentDate == Date.format_DDMMYYYY(d_selected))
					a_class[a_class.length] = 'selected';

				if(this.options.returnFormattedDate){
					s_html += '<td onclick="Calendar.get(\''+this.id+'\').chooseFormattedDate(\'' + formattedCurrentDate + '\')"' + (a_class.length ? ' class="' + a_class.join(' ') + '">' : '>') + n_date + '</td>';
				}else{
					s_html += '<td onclick="Calendar.get(\''+this.id+'\').chooseDate(' + d_current.valueOf() + ')"' + (a_class.length ? ' class="' + a_class.join(' ') + '">' : '>') + n_date + '</td>';
				}
	
				d_current.setUTCDate(++n_date);
			}
			// print row footer
			s_html +='</tr>';
		}
		s_html +='</tbody></table>';

		s_html += '<table class="ctrl" cellspacing="0" cellpadding="0"><tbody><tr>';
		s_html += (this.options.yearscroll ? '<td' + this.linkMonthYear(d_date, -1, 'y') + ' class="naveg" title="Ano Anterior">&lsaquo;</td>' : '');
		s_html += '<td' + this.linkMonthYear(d_date, -1) + ' class="naveg" title="Mês Anterior">&laquo;</td><th>';
		s_html += this.options.months[d_date.getUTCMonth()] + ' ' + d_date.getUTCFullYear();
		s_html += '</th><td' + this.linkMonthYear(d_date, 1) + ' class="naveg" title="Próximo Mês">&raquo;</td>';
		s_html += (this.options.yearscroll ? '<td' + this.linkMonthYear(d_date, 1, 'y') + ' class="naveg" title="Próximo Ano">&rsaquo;</td></td>' : '');
		s_html += '</tr></tbody></table>';

		// update HTML
		this.container.innerHTML = s_html;

		return true;
	},
	setSelectedDate: function(n_date){
		this.render.bind(this, n_date).defer();
	},

	chooseDate: function(n_date) {
		this.options.setDate(n_date);
		if(this.options.hideOnChoose){
			this.hide();
		}else{
			this.setSelectedDate(n_date);
		}
	},
	
	chooseFormattedDate: function(formattedDate){
		this.options.setFormattedDate(formattedDate);
		if(this.options.hideOnChoose){
			this.hide();
		}else{
			this.setSelectedDate(n_date);
		}
	},

	hide: function(){
		var div = this.container;
		div.hide();
		if(this.options.removeWhenHide){
			Calendar.remove(this);
		}
	},

	destroy: function(){
		var div = this.container;
		if(div.visible()){
			div.hide();
		}

		if(Prototype.Browser.IE){
			//IE Bug: Problemas com remoção de divs.
			div.innerHTML = "";
		}else{
			div.remove();
		}

		// Quebra a relação Objeto->DOM:
		this.container = null;
		this.options.clonePositionFrom = null;
	},

	linkMonthYear: function(d_date, d_diff, s_units) {
		var s_units = (s_units == 'y' ? 'FullYear' : 'Month');
		var d_result = new Date(d_date);
		d_result['set' + s_units](d_date['get' + s_units]() + d_diff);
		if (d_result.getDate() != d_date.getDate())
			d_result.setDate(0);
		return ' onclick="Event.stop(event); Calendar.get(\''+this.id+'\').render(' + d_result.valueOf() + ');"';
	},

	resetTime: function(d_date, copy) {
		if(copy) d_date = new Date(d_date.getTime());
		d_date.setHours(0);
		d_date.setMinutes(0);
		d_date.setSeconds(0);
		d_date.setMilliseconds(0);
		return d_date;
	}
});