/**
 * jCalendar 0.5
 * Some code based on jQuery Date Picker (http://kelvinluck.com/assets/jquery/datePicker/)
 * Copyright (c) 2007 Theodore Serbinski (http://tedserbinski.com)
 * Dual licensed under the MIT (MIT-LICENSE.txt)
 * and GPL (GPL-LICENSE.txt) licenses.
 * 
 * jCalendar 0.6
 * Code modify by David Prados Luna. 
 * Original code by Theodore Serbinski.
 * Whats new in this version:
 * 	- Modularized all application.
 *  - Added options as public object.
 *  - Select date from a <select> elemento is configurable.
 */
jQuery(function($){
	jQuery.jcalendar = {
		options: {
			range: {},
			days: ['S', 'M', 'Tu', 'W', 'Th', 'F', 'S'],
			months: ['January', 'Febuary', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
			navLinks: {
				p:'Prev', 
				n:'Next', 
				c:'Close', 
				b:'Choose date',
				t: 'Today'
			},
			dateSeparator: "/",
			jumpDate: true,
			create: function(){},
			complete: function(){}
		},
		show: function(a, day, month, year) {
			this._firstDate = this._startDate;
			this._lastDate = this._endDate;
			this._firstDayOfWeek = this._firstDayOfWeek;
	
			// pass in the selected form date if one was set
			var selected;
			if (year.val() > 0 && month.val() > 0 && day.val() > 0) {
			  selected = new Date(year.val(), month.val(), day.val());
			}
			else {
			  selected = null;
			}
			this._drawCalendar(selected, a, day, month, year);
		},
		changeMonth: function(d, e, day, month, year) {
			this._drawCalendar(d, e, day, month, year);
		},
		/**
		* Function: setLanguageStrings
		*
		* Allows you to localise the calendar by passing in relevant text for the english strings in the plugin.
		*
		* Arguments:
		* days		-	Array, e.g. ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']
		* months	-	Array, e.g. ['January', 'Febuary', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
		* navLinks	-	Object, e.g. {p:'Prev', n:'Next', c:'Close', b:'Choose date'}
		**/
		setLanguageStrings: function(aDays, aMonths, aNavLinks) {
			days = aDays;
			months = aMonths;
			navLinks = aNavLinks;
		},
		/**
		* Function: setDateWindow
		*
		* Used internally to set the start and end dates for a given date select
		*
		* Arguments:
		* i			-	The id of the INPUT element this date window is for
		* w			-	The date window - an object containing startDate and endDate properties
		*				e.g. {startDate:'24-11-1981', endDate:'25-12-2012}
		**/
		setDateWindow: function(i, w, year) {
			if (w == undefined) w = this.options.range;
			if (w.startDate == undefined) {
				// set the minimum browseable date equal to January of the min year in the select box
				// don't get the first option because that is an empty year
	
				// note we can't do this: year.find('option:eq(1)').val()
				// it doesn't work in 1.0 since find() is destructive
				// so we copy the object to a new var
				this._startDate = new Date($(year).find('option:eq(1)').val(), 0, 1);
			}
			else {
				dateParts = w.startDate.split('-');
				this._startDate = new Date(dateParts[2], Number(dateParts[1])-1, Number(dateParts[0]));
			}
			if (w.endDate == undefined) {
			  // set the maximum browseable date equal to December of the max year in the select box
	
			  // note we can't do this: year.find('option:last').val()
				// it doesn't work in 1.0 since find() is destructive
				// so we copy the object to a new var
				this._endDate = new Date($(year).find('option:last').val(), 11, 1);
			}
			else {
				dateParts = w.endDate.split('-');
				this._endDate = new Date(dateParts[2], Number(dateParts[1])-1, Number(dateParts[0]));
			}
			this._firstDayOfWeek = w.firstDayOfWeek == undefined ? 0 : w.firstDayOfWeek;
		},
		_firstDayOfWeek: 0,
		_firstDate: null,
		_lastDate:  null,
		_selectedDate: null,
		actualMonthDays: 30,
		_drawCalendar: function(dateIn, a, day, month, year) {
			var options = this.options;
			var months = options.months;
			var days = options.days;
			var navLinks = options.navLinks;
			var _firstDayOfWeek = this._firstDayOfWeek;
			var _firstDate = this._firstDate;
			var _lastDate = this._lastDate;
			var _selectedDate = this._selectedDate;
			
			/*
			var _drawCalendar = function(dateIn, a, day, month, year) {*/
			  var today = new Date();
			  var d;
				if (dateIn == undefined) {
					// start from this month.
					d = new Date(today.getFullYear(), today.getMonth(), 1);
					year.val(today.getFullYear());
					month.val(today.getMonth()+1);
					day.val(today.getDate());
				}
				else {
					// start from the passed in date
					d = dateIn;
					d.setDate(1);
				}
				
				// check that date is within allowed limits
				if ((d.getMonth() < _firstDate.getMonth() && d.getFullYear() == _firstDate.getFullYear()) || d.getFullYear() < _firstDate.getFullYear()) {
					d = new Date(_firstDate.getFullYear(), _firstDate.getMonth(), 1);
				}
				else if ((d.getMonth() > _lastDate.getMonth() && d.getFullYear() == _lastDate.getFullYear()) || d.getFullYear() > _lastDate.getFullYear()) {
					d = new Date(_lastDate.getFullYear(), _lastDate.getMonth(), 1);
				}
				
				var firstMonth = true;
				var firstDate = _firstDate.getDate();
					
				// create prev and next links
				if (!(d.getMonth() == _firstDate.getMonth() && d.getFullYear() == _firstDate.getFullYear())) {
					// not in first display month so show a previous link
					firstMonth = false;
					var lastMonth = d.getMonth() == 0 ? new Date(d.getFullYear()-1, 11, 1) : new Date(d.getFullYear(), d.getMonth()-1, 1);
					var prevLink = jQuery('<a href="#prev" class="prevMonthNav" title="'+ navLinks.p +'">'+ navLinks.p +'</a>').click(function() {
						jQuery.jcalendar.changeMonth(lastMonth, this, day, month, year);
						return false;
					});
				}
		
				var finalMonth = true;
				var lastDate = _lastDate.getDate();
		
				if (!(d.getMonth() == _lastDate.getMonth() && d.getFullYear() == _lastDate.getFullYear())) {
					// in the last month - no next link
					finalMonth = false;
					var nextMonth = new Date(d.getFullYear(), d.getMonth()+1, 1);
					var nextLink = jQuery('<a href="#next" class="nextMonthNav" title="'+ navLinks.n +'">'+ navLinks.n +'</a>').click(function() {
						jQuery.jcalendar.changeMonth(nextMonth, this, day, month, year);
						return false;
					});
				}
				
				navLinks.t = months[d.getMonth()] + " <span>"+d.getFullYear()+"</span>";
				
				var todayLink = jQuery('<a href="#today" class="calendarTodayNav">'+ navLinks.t +'</a>').click(function() {
					day.val(today.getDate());
					jQuery.jcalendar.changeMonth(today, this, day, month, year);
					return false;
				});
		
		    // update the year and month select boxes
		  	year.val(d.getFullYear());
		  	month.val(d.getMonth()+1);
		
				var headRow = jQuery("<tr></tr>");
				for (var i=1; i<=_firstDayOfWeek+7; i++) { //dpl
					var weekday = i%7;
					var wordday = days[weekday];
					headRow.append('<th scope="col" abbr="'+ wordday +'" title="'+ wordday +'" class="'+ (weekday == 0 || weekday == 6 ? 'weekend' : 'weekday') +'">'+ wordday +'</th>');
				}
				headRow = jQuery("<thead></thead>").append(headRow);
		
				var tBody = jQuery("<tbody></tbody>");
				var lastDay = (new Date(d.getFullYear(), d.getMonth()+1, 0)).getDate();
				var curDay = _firstDayOfWeek+1 - d.getDay(); //dpl
				if (curDay > 0) curDay -= 7;
		
				var todayDate = today.getDate();
				var thisMonth = d.getMonth() == today.getMonth() && d.getFullYear() == today.getFullYear();
		
		    // render calendar
				do {
		 		  var thisRow = jQuery("<tr></tr>");
		  		for (var i=1; i<=7; i++) { //dpl
		  			var weekday = (_firstDayOfWeek + i) % 7;
		  			var atts = {'class':(weekday == 0 || weekday == 6 ? 'weekend ' : 'weekday ')};
		
		  			if (curDay < 0 || curDay >= lastDay) {
		  				dayStr = '';
		  			}
		  			else if (firstMonth && curDay < firstDate-1) {
		  				dayStr = curDay+1;
		  				atts['class'] += 'inactive';
		  			}
		  			else if (finalMonth && curDay > lastDate-1) {
		  				dayStr = curDay+1;
		  				atts['class'] += 'inactive';
		  			}
		  			else {
		  				d.setDate(curDay+1);
						d.setMonth(month.val()-1);
						date = d.getDate() + this.options.dateSeparator + months[d.getMonth()] + this.options.dateSeparator + d.getFullYear();
		  				// attach a click handler to every day to select it if clicked
		  				// we use the rel attribute to keep track of the day that is being clicked
		  				dayStr = jQuery('<a href="#'+date.replace(/\s/g,"-")+'" datetime="'+ date +'">'+ (curDay+1) +'</a>').bind("click", function(e) {
				            if (_selectedDate) {
				               _selectedDate.removeClass('selected');
				            }
				      			_selectedDate = jQuery(this);
				      			_selectedDate.addClass('selected');
								
				            day.val(_selectedDate.text());
				  			//return false -> Eliminado por que a este elemento se le asigna otro evento posterior y el return false no lo har�a disparar.  
		  				});
		
		  				// highlight the current selected day
		  				if (day.val() == d.getDate()) {
		  				  _selectedDate = dayStr;
		  				  _selectedDate.addClass('selected');
		  				}
		  			}
		
		  			if (thisMonth && curDay+1 == todayDate) {
		  				atts['class'] += 'today';
		  			}
		  			thisRow.append(jQuery("<td></td>").attr(atts).append(dayStr));
		  			curDay++;
		      }
		
					tBody.append(thisRow);
				} while (curDay < lastDay);
				
				this.actualMonthDays = curDay;
				var currentdate = d;
				if($(".jcalendar-jumpDate").length) {
					currentdate.setDate($("select.jcalendar-jumpDay").val());
					/*currentdate.setMonth($("select.jcalendar-jumpMonth").val());
					currentdate.setFullYear($("select.jcalendar-jumpYear").val());*/
				}
				
				jQuery('div.jcalendar').html('<div class="jcalendarNav"></div><table></table>');
				jQuery('div.jcalendar > div.jcalendarNav').append(prevLink, todayLink, nextLink);
				jQuery('div.jcalendar table').append(headRow, tBody);
				
				var jumpDateWrapper = this.makeJumpDate(currentdate);
				if (this.options.jumpDate) {
					jQuery('div.jcalendar').prepend(jumpDateWrapper);
					// Volvemos a asignarle por que la primera vez le pasamos inputs con un valor.
					// Con el evento click del d�a cambiaba dicho input y no el select.
					day = jumpDateWrapper.find("select.jcalendar-jumpDay").val(day.val());
					month = jumpDateWrapper.find("select.jcalendar-jumpMonth").val(month.val());
					year = jumpDateWrapper.find("select.jcalendar-jumpYear").val(year.val());
				}
				
			//};
			setTimeout(function(){
				this.options.complete.apply(jQuery('div.jcalendar'), arguments);
			}.bind(this),100);
		},
		makeJumpDate: function(currdate){
			var jumpDateWrapper = $(".jcalendar-jumpDate"), 
				day = $("select.jcalendar-jumpDay"), 
				month = $("select.jcalendar-jumpMonth"), 
				year = $("select.jcalendar-jumpYear"),
				actualMonthDays = this.actualMonthDays,
				monthNames = this.options.months;
			
			jumpDateWrapper = jumpDateWrapper.length ? jumpDateWrapper : $("<div class='jcalendar-jumpDate'>");
			day = day.length ? day : $("<select class='jcalendar-jumpDay'>");
			month = month.length ? month : $("<select class='jcalendar-jumpMonth'>");
			year = year.length ? year : $("<select class='jcalendar-jumpYear'>");
			
			if(!day.children().length)
				day.append(function(){ var i=0, result = document.createDocumentFragment(); while(i++<actualMonthDays){ result.appendChild($("<option>", { value: i, text: i })[0]); } return result; })
				   .children().filter(function(){ return this.value == currdate.getDate(); }).attr("selected", "selected");
			if(!month.children().length)
				month.append(function(){ var i=-1, result = document.createDocumentFragment(); while(i++<11){ result.appendChild($("<option>", { value: i+1, text: monthNames[i] })[0]); } return result; })
					 .children().filter(function(){ return this.value-1 == currdate.getMonth(); }).attr("selected", "selected");
			if(!year.children().length)
				year.append(function(){ var i=new Date().getFullYear()-3, result = document.createDocumentFragment(); while(i++<2012){ result.appendChild($("<option>", { value: i, text: i })[0]); } return result; })
					.children().filter(function(){ return this.value == currdate.getFullYear(); }).attr("selected", "selected");
			
			jumpDateWrapper.append(day, month, year);
				
			day.change(function(){
				if (this.value > 0) {
					d = new Date(year.val(), month.val() - 1, this.value);
					jQuery.jcalendar.changeMonth(d, this.options.range, day, month, year);
				}
			});
			
			month.bind("change", function(){
				if (this.value > 0) {
					d = new Date(year.val(), this.value - 1, day.val());
					jQuery.jcalendar.changeMonth(d, this.options.range, day, month, year);
				}
			});
			year.change(function(){
				if (this.value > 0) {
					d = new Date(this.value, month.val() - 1, day.val());
					jQuery.jcalendar.changeMonth(d, this.options.range, day, month, year);
				}
			});
			
			return jumpDateWrapper;
		},
		setOptions: function(options){
			for(var member in options){
				if(this.options[member])
					this.options[member] = options[member]
			}
		}
	}
	jQuery.fn.jcalendar = function(options) {
		jQuery.jcalendar.setOptions(options);
		var options = options || {},
			a = options.range || {};
		return this.map(function(){
			var calendarWrapper = jQuery('<div class="jcalendar"></div>');
			
			var day = $(this).find('select.jcalendar-select-day');
			var month = $(this).find('select.jcalendar-select-month');
			var year = $(this).find('select.jcalendar-select-year');
			
			$(this).before(calendarWrapper);
			
			jQuery.jcalendar.setDateWindow(this, a, $("<input value='"+new Date().getFullYear()+"'/>"));
			jQuery.jcalendar.show(this, $("<input value='"+new Date().getDate()+"'/>"), $("<input value='"+new Date().getMonth()+"'/>"), $("<input value='"+new Date().getFullYear()+"'/>"));
			return calendarWrapper[0];
		});
	};
});

