﻿(function($) {
	$.fn.monthYear = function(options) {
		var pickers = [];
		
		this.each(function() { pickers.push( new $.monthYearSelector( $(this), options ) ) });
		
		return pickers;
	}
	
	$.monthYearSelector = function(input, options) {
		var $this = this;
		
		this.pickerInput = input;
		this.settings = $.extend($.monthYearSelector.defaults, options);
		this.hideDelayTimer = null;
		this.beingShown = false;
		this.shown = false;
		this.closing = false;
		this.currentMonth = 1;
		this.currentYear = this.settings.year;

		this.pickerInput.keypress( this.inputKeyPress )
		
		this.createCalendarPopup();
		this.createCalendarTrigger();
	}

	$.extend($.monthYearSelector, {
		defaults: {
			cssPrefix: 'monthYear-',
			icon: { height: 15, width: 16 },
			fullMonths: false,
			time: 250,
			hideDelay: 2000,
			year: (new Date()).getFullYear()
		},
		prototype: {
			showDatePicker: function() {
				if( $.__OPENED_CALENDAR && $.__OPENED_CALENDAR != this ) { $.__OPENED_CALENDAR.hideDatePicker(); }
				// if we are showing now, don't hide it if its on delay
				if (this.hideDelayTimer) clearTimeout(this.hideDelayTimer);
				if( this.closing || this.beingShown || this.shown) return;
				
				var $this = this;

				// don't trigger the animation again if we're being shown, or already visible
				this.beingShown = true;
				
				// IE6 doesn't support overlaying on top of select boxes
				$(document.body).addClass('fixSelect');
				
				// TODO: This is wrong, breaks if it the calendar widget isn't shown onload
				var topCalendar = this.pickerInput.position().top + this.pickerInput.outerHeight() - this.popup.outerHeight();
				var leftCalendar = this.pickerInput.position().left + $(this.pickerInput).outerWidth() + 5;
				
				// reset position of popup box
				this.popup
					.css({top: topCalendar, left: leftCalendar})
					.show()
					.animate({opacity: 1}, this.settings.time, 'swing', function() {
						// once the animation is complete, set the tracker variables
						$this.beingShown = false;
						$this.shown = true;
						$.__OPENED_CALENDAR = $this;
					});
			},
			// this can get fired from the clicking on the icon while its showing
			hideDatePicker: function() {
				// reset the timer if we get fired again - avoids double animations
				if (this.hideDelayTimer) clearTimeout(this.hideDelayTimer);
				
				var $this = this;
				
				this.closing = true;
				
				$(document.body).removeClass('fixSelect');
				
				this.popup.animate({opacity: 0}, this.settings.time, 'swing', function() {
					// once the animate is complete, set the tracker variables
					$this.shown = false;
					$this.beingShown = false;
					$this.closing = false;
					// hide the popup entirely after the effect (opacity alone doesn't do the job)
					$this.popup.hide();
					$.__OPENED_CALENDAR = null;
				});
			},
			// this will get fired from a mouseout, to give time to the user to allow for picking the date
			hideDatePickerDelay: function() { 
				// reset the timer if we get fired again - avoids double animations
				if (this.hideDelayTimer) clearTimeout(this.hideDelayTimer);
				
				var $this = this;

				// store the timer so that it can be cleared in the mouseover if required
				this.hideDelayTimer = setTimeout(function() {
					$this.hideDatePicker();
				}, this.settings.hideDelay);
			},
			startIncrementDecrement: function(delta, time) {
				$this = this;
				
				$('.' + this.settings.cssPrefix + 'currentYear', this.popup).html( this.currentYear += delta );
				
				if (time > 75)
					time = time - 25;
					
				this.timeout = setTimeout( function() { $this.startIncrementDecrement(delta, time) }, time);
			},
			stopIncrementDecrement: function() {
				clearTimeout(this.timeout);
			},
			inputKeyPress: function(e) {
				// TODO: Major Refactor
				var inputEle = e.target || e.srcElement;
				var $inputEle = $(inputEle);
				
				// delete rules
				if( e.which == 8 ) {
					if( $inputEle.val().length == 3 ) {
						if( inputEle.__MONTH_ADD_ZERO ) { 
							$inputEle.val("");
							inputEle.__MONTH_ADD_ZERO = false;
							e.preventDefault();
						} else {
							$inputEle.val( $inputEle.val().substring(0,2) );
						}
					}
					return;
				} else if( e.which == 9 ) { return; }
				
				if( $inputEle.val().length == 0 ) {
					switch( e.which ) {
						case "0".charCodeAt(0): 
						case "1".charCodeAt(0): 
							return;
							break;
						case "2".charCodeAt(0): 
						case "3".charCodeAt(0): 
						case "4".charCodeAt(0): 
						case "5".charCodeAt(0): 
						case "6".charCodeAt(0): 
						case "7".charCodeAt(0): 
						case "8".charCodeAt(0): 
						case "9".charCodeAt(0): 
							$inputEle.val("0" + String.fromCharCode( e.which ) + "/" );
							inputEle.__MONTH_ADD_ZERO = true;
							
							e.preventDefault();
							break;
						default:
							e.preventDefault();
							return;
							break;
					}
				} else if( $inputEle.val().length == 1 ) {
					switch( e.which ) {
						case "/".charCodeAt(0):
						case "-".charCodeAt(0):
						case ".".charCodeAt(0):
						case "\\".charCodeAt(0):
							if( $inputEle.val() != "0" ) {
								$inputEle.val("0" + $inputEle.val() + "/");
								inputEle.__MONTH_ADD_ZERO = true;
							}
							e.preventDefault();
							return;
						case "0".charCodeAt(0): 
							if( $inputEle.val() == "0" ) { 
								e.preventDefault(); 	
								return;
							} 
						case "1".charCodeAt(0): 					
						case "2".charCodeAt(0): 	
							$inputEle.val( $inputEle.val() + String.fromCharCode( e.which ) + "/" );
							e.preventDefault();
							return;
							break;
							case "3".charCodeAt(0):
							case "4".charCodeAt(0):
							case "5".charCodeAt(0):
							case "6".charCodeAt(0):
							case "7".charCodeAt(0):
							case "8".charCodeAt(0):
							case "9".charCodeAt(0):
								if( $inputEle.val() != "1" ) {
									$inputEle.val( $inputEle.val() + String.fromCharCode( e.which ) + "/" );
								}
								
								e.preventDefault();
								return;
							break;
						default:
							e.preventDefault();
							return;
							break;
					}
				} else if( $inputEle.val().length == 2 ) {
					$inputEle.val($inputEle.val() + "/");					
					if( e.which < "0".charCodeAt(0) || e.which > "9".charCodeAt(0) ){
						e.preventDefault();
						return;
					}
				} else if( $inputEle.val().length > 2 ) {
					if( e.which < "0".charCodeAt(0) || e.which > "9".charCodeAt(0) ){
						e.preventDefault();
						return;
					} 
				}
				
				var oldValue = $inputEle.val();
				
				setTimeout( function() {
					if( $inputEle.val().length >= 3 ) {
						if( $inputEle.val().substring(2,3) != "/" ) {
							$inputEle.val( oldValue );
						}
						if( $inputEle.val().length >= 8 ) {
							$inputEle.val( oldValue );
						}
					}
				}, 10);
			},
			repositionTrigger: function() {
				return this.calendarTrigger.css('position', 'absolute')
					.css('top', this.pickerInput.position().top + Math.floor( ( this.pickerInput.outerHeight() - this.settings.icon.height) / 2) )
					.css('left', this.pickerInput.position().left + this.pickerInput.innerWidth() - this.settings.icon.width );
			},
			createCalendarTrigger: function() {
				var $this = this;

				this.pickerInput.css('padding-right', parseInt(this.pickerInput.css('padding-right')) + this.settings.icon.width);				
				
				return this.calendarTrigger = $('<a></a>')
					.addClass(this.settings.cssPrefix + 'calendarIcon')
					.click(function() { $this.shown ? $this.hideDatePicker() : $this.showDatePicker() } )
					.mouseout(function() { $this.hideDatePickerDelay(); })
					.css('position', 'absolute')
					.voidLink()
					.insertAfter(this.pickerInput)
					.css('top', this.pickerInput.position().top + Math.floor( ( this.pickerInput.outerHeight() - this.settings.icon.height) / 2) )
					.css('left', this.pickerInput.position().left + this.pickerInput.innerWidth() - this.settings.icon.width );

			},
			createCalendarPopup: function() {
				var $this = this;
				
				var months = ( this.settings.fullMonths ) 
					? ["January","February","March","April","May","June","July","August","September","October","November","December"]
					: ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]
				
				var yearEle = $('<div></div>')
					.addClass(this.settings.cssPrefix + 'year')
					.addClass('clearfix')
					.append(
						$('<a></a>')
							.html('&laquo;')
							.voidLink()
							.addClass(this.settings.cssPrefix + 'yearIncrement')
							.addClass(this.settings.cssPrefix + 'yearIncrementDown')
							.mousedown(function(e) { $this.startIncrementDecrement(-1, 340); })
							.mouseup(function(e) { $this.stopIncrementDecrement(-1); this.blur(); })
							.mouseout(function(e) { $this.stopIncrementDecrement(-1); }),
						$('<span></span>')
							.html(this.currentYear)
							.addClass(this.settings.cssPrefix + 'currentYear'),
						$('<a></a>')
							.html('&raquo;')
							.voidLink()
							.addClass(this.settings.cssPrefix + 'yearIncrement')
							.addClass(this.settings.cssPrefix + 'yearIncrementUp')
							.mousedown(function(e) { $this.startIncrementDecrement(1, 340); })
							.mouseup(function(e) { $this.stopIncrementDecrement(1); this.blur(); })
							.mouseout(function(e) { $this.stopIncrementDecrement(1); })
					);
								
				var monthEles = $('<div></div>')
					.addClass(this.settings.cssPrefix + 'allMonths')
				
				$.each( months, function(monthIndex) {
					var value = monthIndex + 1;
					if( monthIndex < 10 ) { value = "0" + value; }
					monthEles.append(
						$('<a></a>')
							.addClass($this.settings.cssPrefix + 'month')
							.text(this.toString())
							.voidLink()
							.data('value', value)
							.click(function(e) {
								$this.pickerInput.val( $(this).data('value') + "/" + $this.currentYear);
								$this.hideDatePicker();
							})
					);
				});
								
				return this.popup = $('<div></div>')
					.addClass(this.settings.cssPrefix + 'control')
					.css('opacity', 0)
					.insertAfter(this.pickerInput)
					.mouseover(function(){$this.showDatePicker();})
					.mouseout(function(){$this.hideDatePickerDelay();})
					.append(
						$('<div></div>')
						.addClass(this.settings.cssPrefix + 'container')
						.addClass('clearfix')
						.append( yearEle, monthEles )
					);
			}
		}
	});
})(jQuery);