 (function($) {

	Calendar = function() {
		this._input = null;
		this._container = null;
		this._popControl = null;
		this._daySelector = null;
		this._monthSelector = null;
		this._yearSelector = null;
		this._selectedDate = null;
		
		this._settings = {
			dateFormat: '%d/%m/%Y',
			dayNames: ['Di', 'Lu', 'Ma', 'Me', 'Je', 'Ve', 'Sa'],
			monthNames: ['Janvier', 'F\u00e9vrier', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet', 'Ao\u00fbt', 'Septembre', 'Octobre', 'Novembre', 'D\u00e9cembre'],
			weekStart: 1,
			minDate: null,
			maxDate: null
		};
	};
	
	$.extend(Calendar.prototype, {
		_adjustDate: function(value, period) {
			var minDate = this._settings['minDate'];
			var maxDate = this._settings['maxDate'];
 			this._selectedDate = new Date(
				(this._selectedDate.getFullYear() + (period == 'year' ? value: 0)),
				(period == 'month' ? value : this._selectedDate.getMonth()),
				(period == 'day' ? value : this._selectedDate.getDate())
			);
			this._selectedDate = (minDate && this._selectedDate < minDate ? minDate : this._selectedDate);
			this._selectedDate = (maxDate && this._selectedDate > maxDate ? maxDate : this._selectedDate);
			this._updateCalendar(period != 'day');
		},
		
		_compareDates: function(date1, date2) {
			var a = d1.getFullYear() + '' + d1.getMonth() + '' + d1.getDate();
			var b = d2.getFullYear() + '' + d2.getMonth() + '' + d2.getDate();
			return (a < b ? -1 : (b < a ? 1 : 0));
		},
		
		_dateToString: function(theDate) {
			var s = this._settings['dateFormat'].replace(/%Y/g, theDate.getFullYear()
				).replace(/%y/g, theDate.getYear()
				).replace(/%m/g, this._zeroPad(theDate.getMonth()+1)
				).replace(/%n/g, theDate.getMonth()+1
				).replace(/%d/g, this._zeroPad(theDate.getDate())
				).replace(/%j/g, theDate.getDate());
			return s;
		},
		
		_getCalendar: function() {
			var contents = $('<div id="calendar-div"></div>');
			var weekStart = this._settings['weekStart'];
			
			// Selecteur de mois
			var monthNames = this._settings['monthNames'];
			this._monthSelector = $('<select id="month-selector"></select>');
			for (var i=0; i < monthNames.length; i++) {
				this._monthSelector.append($('<option value="' + i + '">' + monthNames[i] + '</option>'));
			}
			this._monthSelector.change(function(event) {
				calendar._adjustDate($(this).val(), 'month');
			});
			contents.append(this._monthSelector);
			
			// Calendrier
			var dayNames = this._settings['dayNames'];
			var tableRow = $('<tr></tr>');
			for (var i=0; i < dayNames.length; i++) {
				tableRow.append($('<th scope="col">' + dayNames[(i + weekStart) % 7] + '</th>'));
			}
			var tableHead = $('<thead></thead>').append(tableRow);
			this._daySelector = $('<tbody></tbody>');
			contents.append($('<table id="day-selector"></table>').append(tableHead).append(this._daySelector));
			
			// Selecteur d'annee
			var century = $('<a class="century" href="javascript:;" rel="100"></a>');
			this._handleMouseEvents(century);
			
			var decade = $('<a class="decade" href="javascript:;" rel="10"></a>');
			this._handleMouseEvents(decade);
			
			var year = $('<a class="year" href="javascript:;" rel="1"></a>');
			this._handleMouseEvents(year);
			
			this._yearSelector = $('<div id="year-selector"></div>');
			contents.append((this._yearSelector).append(century, decade, year));
			return contents;
		},
		
		_getNumber: function(s, i, m, n) {
			for (var j = n; j >= m; j--) {
				var n = s.substring(i,i+j);
				if (n.length < m) {
					return null;
				}
				if (this._isInteger(n)) {
					return n;
				}
			}
			return null;
		},
		
		_handleMouseEvents: function(elem) {
			elem.mousemove(function(event) {
				var target = event.target;
				var offset = $(event.target).offset();
				var y = (event.pageY || event.clientY) - offset.top;
				if (y < (target.offsetHeight / 2)) {
					if (this.className.indexOf('up') == -1) {
						$(this).removeClass('down').addClass('up');
					}
				} else {
					if (this.className.indexOf('down') == -1) {
						$(this).removeClass('up').addClass('down');
					}
				}
			}).mouseout(function() {
				$(this).removeClass('up').removeClass('down');
			}).click(function(event) {
				var offset = parseInt($(this).attr('rel'));
				calendar._adjustDate(($(this).is('.up') ? offset : -offset), 'year');
			});
		},
		
		_isInteger: function(s) {	
			var d='1234567890';
			for (var i = 0; i < s.length; i++) {
				if (d.indexOf(s.charAt(i)) == -1) {
					return false;
				}
			}
			return true;
		},
		
		_stringToDate: function(s) {
			var i = 0;
			var j = 0;
			var year;
			var month;
			var day;
			var dateFormat = this._settings['dateFormat'];
			while (i < dateFormat.length) {
				var c = dateFormat.charAt(i++);
				if (c == '%') {
					c = c + dateFormat.charAt(i++);
				}
				if (c == '%Y') {
					year = this._getNumber(s, j, 4, 4);
					j = j + 4;
				} else if (c == '%y') {
					year = this._getNumber(s, j, 1, 2);
					j = j + year.length;
				} else if (c == '%m') {
					month = this._getNumber(s, j, 2, 2);
					j = j + 2;
				} else if (c == '%n') {
					month = this._getNumber(s, j, 1, 2);
					j = j + month.length;
				} else if (c == '%d') {
					day = this._getNumber(s, j, 2, 2);
					j = j + 2;
				} else if (c == '%j') {
					day = this._getNumber(s, j, 1, 2);
					j = j + day.length;
				} else {
					j = j + 1;
				}
			}
			if (year <= 50) {
				year = "20" + year;
			} else if (year < 100) {
				year = "19" + year;
			}
			return new Date(year, month-1, day);
		},

		_updateCalendar: function(redrawDaySelector) {
			var theMonth = this._selectedDate.getMonth();
			var theYear = this._selectedDate.getFullYear();
			var theDate = new Date(theYear, theMonth, 1);
			var weekDay = theDate.getDay();
			
			theDate.setDate((this._settings['weekStart'] - weekDay - 7) % 7);
			this._monthSelector.val(theMonth);
			
			if (redrawDaySelector) {
				this._daySelector.empty();
				for (var theWeek = 0; theWeek < 6; theWeek++) {
					var weekRow = $('<tr></tr>');
					
					for (var theDay = 1; theDay <= 7; theDay++) {
						theDate.setDate(theDate.getDate() + 1);
						var d = theDate.getDate();
						if (theDate.getMonth() == theMonth) {
							var dayLink = $('<a href="javascript:;" rel="' + d + '">' + d + '</a>');
							dayLink.click(function(event) {
								calendar._adjustDate(parseInt($(this).attr('rel')), 'day');
								calendar._popControl.close(null);
							});
							var td = $('<td></td>').append(dayLink);
						} else {
							var td = $('<td>' + d + '</td>');
						}
						weekRow.append(td);
					}
					this._daySelector.append(weekRow);
				}
			}
			$('a', this._daySelector).removeClass('selected');
			$('a[@rel=' + this._selectedDate.getDate() + ']', this._daySelector).addClass('selected');
			
			theYear = '' + theYear;
			$('.century', this._yearSelector).empty().append(
				'<span class="digit-' + theYear.substr(0, 2) + '">' + theYear.substr(0, 2) + '</span>'
			);
			$('.decade', this._yearSelector).empty().append(
				'<span class="digit-' + theYear.substr(2, 1) + '">' + theYear.substr(2, 1) + '</span>'
			);
			$('.year', this._yearSelector).empty().append(
				'<span class="digit-' + theYear.substr(3, 1) + '">' + theYear.substr(3, 1) + '</span>'
			);
			var text = this._dateToString(this._selectedDate)
			$(this._input).val(text).attr('title', text);
		},
		
		_zeroPad: function(n) {
			var s = '0' + n;
			return s.substring(s.length - 2);
		},
		
		display: function(input, container, popControl) {
			this._input = input;
			this._container = container;
			this._popControl = popControl;
			
			var text = $(input).val();
			if (text != '') {
				var theDate = this._stringToDate(text);
				if (this._dateToString(theDate) == text) {
					this._selectedDate = theDate;
				} else {
					this._selectedDate = new Date();
				}
			} else {
				this._selectedDate = new Date();
			}
			$(this._container).append(calendar._getCalendar());
			this._updateCalendar(true);
		}
	});
	
	$.fn.calendar = function(settings) {
		$.extend(calendar._settings, settings);
		
		var imagesPath = $('script[type="text/javascript"][src$="js/edv.js"]').attr('src');
		imagesPath = imagesPath.substring(0, imagesPath.length - '/js/edv.js'.length);
		return this.each(function() {
			$(this).popControl({
				'buttonText': 'Modifier la date',
				'buttonImage': imagesPath + '/img/popcontrol-button.gif',
				'className': 'calendar-popup',
				'closeboxImage': imagesPath + '/img/popcontrol-closebox.gif',
				'setContent': function(input, container, popControl) { calendar.display(input, container, popControl); }
			});
		});
	};
	
	$(document).ready(function() {
		calendar = new Calendar(); // Singleton
	});
})(jQuery);
