/*
 * DaiShu CMS 5 Date Picker
 *
 * Copyright (c) 2010 Scorpion Design, Inc.
 */
(function( $ ) {

$.widget( "cms.datepicker", $.ui.dialog, {
	options: {
		single: true,
		title: null,
		modal: false,
		//width: 238,
		width: 400,
		height: 'auto',
		open: function(e, data, widget) {
			widget._open.apply(widget, [e, data]);
		},
		buttons: {
			"Save" : function(e, widget) {
				widget._save.apply(widget, [e]);
				widget.close.apply(widget, [e]);
			},
			"Cancel" : function(e, widget) {
				widget._cancel.apply(widget, [e]);
			}
		},
		showdate: true,
		showtime: false,
		pattern: 'M/d/yyyy'
	},

	_html: '\
<div class="ui-datepicker">\
	<div class="ui-date">\
		<div class="ui-title">Year</div>\
		<div class="ui-years">\
			<div class="ui-list">&lt;<div class="ui-pop left"></div></div>\
			<div class="ui-year" _year="2010">2010</div>\
			<div class="ui-year" _year="2011">2011</div>\
			<div class="ui-year" _year="2012">2012</div>\
			<div class="ui-list">&gt;<div class="ui-pop right"></div></div>\
		</div>\
		<div class="ui-title">Month</div>\
		<div class="ui-months">\
			<div class="ui-month" _month="0">Jan</div>\
			<div class="ui-month" _month="1">Feb</div>\
			<div class="ui-month" _month="2">Mar</div>\
			<div class="ui-month" _month="3">Apr</div>\
			<div class="ui-month" _month="4">May</div>\
			<div class="ui-month" _month="5">Jun</div>\
			<div class="ui-month" _month="6">Jul</div>\
			<div class="ui-month" _month="7">Aug</div>\
			<div class="ui-month" _month="8">Sep</div>\
			<div class="ui-month" _month="9">Oct</div>\
			<div class="ui-month" _month="10">Nov</div>\
			<div class="ui-month" _month="11">Dec</div>\
		</div>\
		<div class="ui-title">Day</div>\
		<div class="ui-weeks">\
			<div class="ui-week">Sun</div>\
			<div class="ui-week">Mon</div>\
			<div class="ui-week">Tue</div>\
			<div class="ui-week">Wed</div>\
			<div class="ui-week">Thu</div>\
			<div class="ui-week">Fri</div>\
			<div class="ui-week">Sat</div>\
		</div>\
		<div class="ui-days"></div>\
		<div class="ui-title"><a href="javascript:void(0)" class="ui-today">Today</a></div>\
	</div>\
	<div class="ui-time">\
		<div class="ui-ampm">\
			<div class="ui-title">&nbsp;</div>\
			<div class="ui-plus" _plus="0">AM</div>\
			<div class="ui-plus" _plus="12">PM</div>\
		</div>\
		<div class="ui-minutes">\
			<div class="ui-title">Min</div>\
			<div class="ui-minute" _minute="0">:00</div>\
			<div class="ui-minute" _minute="5">:05</div>\
			<div class="ui-minute" _minute="10">:10</div>\
			<div class="ui-minute" _minute="15">:15</div>\
			<div class="ui-minute" _minute="20">:20</div>\
			<div class="ui-minute" _minute="25">:25</div>\
			<div class="ui-minute" _minute="30">:30</div>\
			<div class="ui-minute" _minute="35">:35</div>\
			<div class="ui-minute" _minute="40">:40</div>\
			<div class="ui-minute" _minute="45">:45</div>\
			<div class="ui-minute" _minute="50">:50</div>\
			<div class="ui-minute" _minute="55">:55</div>\
		</div>\
		<div class="ui-hours">\
			<div class="ui-title">Hour</div>\
			<div class="ui-hour" _hour="0">12</div>\
			<div class="ui-hour" _hour="1">1</div>\
			<div class="ui-hour" _hour="2">2</div>\
			<div class="ui-hour" _hour="3">3</div>\
			<div class="ui-hour" _hour="4">4</div>\
			<div class="ui-hour" _hour="5">5</div>\
			<div class="ui-hour" _hour="6">6</div>\
			<div class="ui-hour" _hour="7">7</div>\
			<div class="ui-hour" _hour="8">8</div>\
			<div class="ui-hour" _hour="9">9</div>\
			<div class="ui-hour" _hour="10">10</div>\
			<div class="ui-hour" _hour="11">11</div>\
		</div>\
	</div>\
	<div style="clear:both;"></div>\
</div>',

	activate: function( options ) {
		if ( !$.cms.datepicker.active ) {
			// If we don't have an active date picker, open it.
			return this._activate.apply( this, arguments );
		}  else if ( options && options.input && $.cms.datepicker.active === options.input[0] ) {
			// If the date picker is already focused on this element, do nothing.
			return false;
		} else {
			// Switch the context.
			$.extend( $.cms.datepicker.current.options, options );
			if ( $.cms.datepicker.current.isOpen() ) {
				$.cms.datepicker.current._start();
			} else {
				$.cms.datepicker.current._open();
			}
		}
	},

	deactivate: function() {
		var wz = $[this.namespace][this.widgetName];

		// If this is a single, get the instance.
		if ( wz._single ) {
			var instance = $.data( wz._single[0], this.widgetName );
			
			// Close it.
			if ( instance && instance.isOpen() ) {
				instance.close();
				return true;
			}
		}
	},

	// Wizard factory.
	_activate: function(options) {
		if ( options && options.showdate === false && options.showtime === false ) {
			return false;
		}

		var wz = $[this.namespace][this.widgetName];

		// See if we have a singleton, or previously created wizard.
		var el = wz._single;
		if ( !el ) {
			wz._single = el = $(this._html);
		}

		// See if there already is an instance associated with this element.
		var instance = $.data( el[0], this.widgetName );
		if ( instance ) {
			if ( instance.isOpen() ) {
				// If it's already open, do nothing.
				return;
			} else {
				// Re-set the options to their default values, with the exception of the measured sizeChildren element.
				var options = $.extend({}, wz.prototype.options, options);
				if ( instance.options.sizeChildren ) {
					options.sizeChildren = instance.options.sizeChildren;
				}
				instance.options = options;
			}
			// Open the wizard.
			instance.open();
		} else {
			// Create the wizard.
			instance = new wz( options, el[0] );
			$.data( el[0], this.widgetName, instance );
		}

		// Return the newly created wizard element.
		return el;
	},

	// Create the object.
	_create: function() {
		$.ui.dialog.prototype._create.apply( this, arguments );

		this.element.unselectable();

		// Shrink the titlebar.
		this.uiDialog.find('div.ui-dialog-titlebar')
			.children('span')
				.remove()
			.end()
			.css({height:18});

		// Set the styles.
		this.uiDialog.addClass('cms-datepicker');

		// Set up the child elements.
		this.elements = {
			date: this.element.children('div.ui-date'),
			time: this.element.children('div.ui-time'),
			years: this.element.find('div.ui-year'),
			months: this.element.find('div.ui-month'),
			days: this.element.find('div.ui-days'),
			hours: this.element.find('div.ui-hour'),
			minutes: this.element.find('div.ui-minute'),
			ampm: this.element.find('div.ui-plus'),
			pop: this.element.find('div.ui-pop')
		};
	},

	// Open the date picker.
	_open: function() {
		// Note the date picker is active.
		$.cms.datepicker.current = this;
		$.cms.datepicker.active = true;

		// Set the initial state.
		this._start();

		$(document).bind('mousedown', $.proxy(this._handleClick, this) );
	},

	// Set the initial state.
	_start: function() {
		// Make sure the mask and year popups are hidden.
		this.elements.pop.hide();
		this.element.removeClass('mask');
		this._mask = false;
		this._origvalue = undefined;

		// Show or hide the date/time portions.
		var width = 0;
		if ( this.options.showdate ) {
			this.elements.date.show();
			width = 238;
		} else {
			this.elements.date.hide();
		}
		if ( this.options.showtime ) {
			this.elements.time.show();
			if ( width > 0 ) {
				width = 400;
				this.elements.date.css({float:'left'});
				this.elements.time.css({float:'right'});
			} else {
				width = 165;
				this.elements.date.css({float:'none'});
				this.elements.time.css({float:'none'});
			}
		} else {
			this.elements.time.hide();
		}
		this.uiDialog.css({width:width});

		var date = this.options.date;
		if ( this.options.input && this.options.input.is('input:text,input:hidden') ) {
			// Note the active input.
			$.cms.datepicker.active = this.options.input[0];
			var text = this.options.input.is('input:text');

			if ( text ) {
				// Place the date picker.
				this.uiDialog.place({
					my: 'left top',
					at: 'left bottom',
					collision: 'fit flip',
					of: this.options.input,
					offset: { left:-1, top:2 },
					margin: {
						top:0,
						right:10,
						bottom:10,
						left:0
					}
				});
			}

			// Get the date and re-focus on the input element.
			this._origvalue = date = this.options.input.val();
			if ( text ) {
				this.options.input[0].focus();
			}
		}

		this._date = $.datetime.parse(date)||new Date();
		if ( this.options.showdate ) {
			this._updateYear();
		}
		if ( this.options.showtime ) {
			this._updateTime();
		}
	},

	// Clicked on the document.
	_handleClick: function(e) {
		var input = this.options.input && this.options.input.length && this.options.input[0], el;
		if ( e.target === input ) {
			// Clicked on the current textbox, we're okay.
			return;
		} else if ( $(e.target).closest('.cms-datepicker').length > 0 ) {
			var cls = (e.target.className||"").split(' ')[0];
			if ( this._mask ) {
				if ( cls === 'ui-pop' ) {
					return;
				}
				// Always reset the mask.
				this.elements.pop.hide();
				this.element.removeClass('mask');
				this._mask = false;
			}

			switch (cls) {
				case 'ui-year':
				case 'ui-year2':
					var year = parseInt(e.target.getAttribute('_year'));
					if ( year !== this._date.getFullYear() ) {
						var month = this._date.getMonth();
						this._date.setYear(year);
						if ( month !== this._date.getMonth() ) {
							this._setLastDay(year,month);
						}

						if ( cls === 'ui-year2' ) {
							this._updateYear();
						} else {
							this.elements.years.removeClass('selected');
							$(e.target).addClass('selected');
							this._updateMonth(true);
						}
						this._save();
					}
					break;
				case 'ui-month':
					var month = parseInt(e.target.getAttribute('_month'));
					if ( month !== this._date.getMonth() ) {
						this._date.setMonth(month);
						if ( month !== this._date.getMonth() ) {
							this._setLastDay(this._date.getFullYear(),month);
						}
						this._updateMonth();
						this._save();
					}
					break;
				case 'ui-day':
					var date = parseInt(e.target.getAttribute('_day'));
					if ( date !== this._date.getDate() ) {
						this._date.setDate(date);
						this.elements.days.children('.selected').removeClass('selected');
						this.elements.days.children("[_day='"+date+"']").addClass('selected');
						this._save();
					} else if ( !this.options.showtime ) {
						this._save();
					}
					if ( !this.options.showtime ) {
						this.close();
					}
					break;
				case 'ui-hour':
				case 'ui-plus':
					var hour = $.toInt( e.target.getAttribute('_hour') || this.elements.hours.filter('.selected').attr('_hour') ) +
								$.toInt( e.target.getAttribute('_plus') || this.elements.ampm.filter('.selected').attr('_plus') );
					if ( hour !== this._date.getHours() ) {
						this._date.setHours(hour);
						this._updateTime();
						this._save();
					}
					break;
				case 'ui-minute':
					var minute = parseInt(e.target.getAttribute('_minute'));
					if ( minute !== this._date.getMinutes() ) {
						this._date.setMinutes(minute);
						this._updateTime();
						this._save();
					}
					break;
				case 'ui-list':
					$(e.target).children('.ui-pop').show();
					this.element.addClass('mask');
					this._mask = true;
					break;
				case 'ui-today':
					this._date = new Date();
					this._updateYear();
					this._save();
					break;
			}
		} else {
			// Otherwise, close the date picker.
			this.close();
		}
	},

	// Set the date to the last day of the specified month.
	_setLastDay: function(year,month) {
		var hours,minutes;
		if ( this.options.showtime ) {
			// Get the time.
			hours = this._date.getHours();
			minutes = this._date.getMinutes();
			if ( hours >= 12 ) {
				plus = 12;
				hours -= 12;
			}
		}

		this._date = new Date( year, month+1, 0 );

		if ( this.options.showtime ) {
			// Update the time.
			this._date.setHours(hours);
			this._date.setMinutes(minutes);
		}
	},

	// Update the year panel.
	_updateYear: function() {
		var year = this._date.getFullYear();
		this.elements.years
				.removeClass('selected')
				.eq(0)
					.html(year-1).attr('_year',year-1)
				.end()
				.eq(1)
					.html(year).attr('_year',year).addClass('selected')
				.end()
				.eq(2)
					.html(year+1).attr('_year',year+1);

		var start = year-1,
			sb = [];
		while ( start-- >= 1900 ) {
			sb.push('<div class="ui-year2" _year="');
			sb.push(start);
			sb.push('">');
			sb.push(start);
			sb.push('</div>');
		}
		this.elements.pop.eq(0).html( sb.join("") );

		start = year+1;
		sb = [];
		while ( start++ <= 2040 ) {
			sb.push('<div class="ui-year2" _year="');
			sb.push(start);
			sb.push('">');
			sb.push(start);
			sb.push('</div>');
		}
		this.elements.pop.eq(1).html( sb.join("") );

		this._updateMonth(true);
	},

	// Update the month panel and the days of the month.
	_updateMonth: function(change) {
		var month = ""+this._date.getMonth(),
			selected = this.elements.months.filter('.selected');

		if ( selected.attr('_month') === month && !change ) {
			// If the current month is already selected, we're good.
			return;
		} else {
			// Select the correct month and note we have a change.
			selected.removeClass('selected');
			this.elements.months.filter("[_month='"+month+"']").addClass('selected');
		}

		// Update the days.
		this._updateDays();
	},

	// Select the correct day.
	_updateDays: function() {
		var day = ""+this._date.getDate(),
			sb = [],
			year = this._date.getFullYear(),
			month = this._date.getMonth(),
			date = this._date.getDate(),
			firstDay = new Date(year,month,1),
			lastDay = new Date(year,month+1,0),
			firstDayOfWeek = firstDay.getDay(),
			lastDayOfWeek = lastDay.getDay(),
			daysInMonth = lastDay.getDate(),
			current,
			day;

		if ( firstDayOfWeek === 0 ) {
			firstDayOfWeek = 7;
		}

		for ( var i=0; i<42; i++ ) {
			current = new Date(year,month,1-firstDayOfWeek+i);
			if ( current.getMonth() !== month ) {
				sb.push('<div class="disabled" _day="">&nbsp;</div>');
			} else {
				day = current.getDate();
				sb.push('<div class="ui-day');
				if ( date === day ) {
					sb.push(' selected');
				}
				sb.push('" _day="');
				sb.push(day);
				sb.push('">');
				sb.push(day);
				sb.push('</div>');
			}
		}
		this.elements.days.html( sb.join("") );
	},

	// Update the selected time.
	_updateTime: function() {
		var hours = this._date.getHours(),
			plus = 0,
			minutes = Math.floor(this._date.getMinutes()/5)*5,
			shours = this.elements.hours.filter('.selected'),
			sminutes = this.elements.minutes.filter('.selected'),
			splus = this.elements.ampm.filter('.selected');

		if ( hours >= 12 ) {
			plus = 12;
			hours -= 12;
		}

		if ( shours.attr('_hour') !== (""+hours) ) {
			shours.removeClass('selected');
			this.elements.hours.filter("[_hour='"+hours+"']").addClass('selected');
		}

		if ( sminutes.attr('_minute') !== (""+minutes) ) {
			sminutes.removeClass('selected');
			this.elements.minutes.filter("[_minute='"+minutes+"']").addClass('selected');
		}

		if ( splus.attr('_plus') !== (""+hours) ) {
			splus.removeClass('selected');
			this.elements.ampm.filter("[_plus='"+plus+"']").addClass('selected');
		}

		if ( minutes !== this._date.getMinutes() || this._date.getSeconds() !== 0 ) {
			this._date.setMinutes(minutes);
			this._date.setSeconds(0);
			this._date.setMilliseconds(0);
		}
	},

	// Save any changes made in the wizard.
	_save: function(e) {
		// Get the date.
		var date = $.datetime.format( this._date, this.options.pattern );

		// Save the date.
		if ( this.options.input && this.options.input.is('input:text,input:hidden') ) {
			this.options.input.blur().val(date);
		}
	},

	_cancel: function() {
		// Re-set the original value.
		if ( this._origvalue !== undefined ) {
			this.options.input.val( this._origvalue||"" );
		}

		// Re-focus on the original element.
		if ( this.options.input && this.options.input.is(':text:visible') ) {
			this.options.input[0].focus();
		}

		// Close the date picker.
		$.ui.dialog.prototype._cancel.apply( this, arguments );
	},

	// Close the wizard.
	close: function() {
		// if we've updated the value, fire the change at the very end.
		if ( this._origvalue !== undefined && this._origvalue !== this.options.input.val() ) {
			this.options.input.trigger('change');
		}

		if ( $.browser.msie ) {
			// MSIE, like the colossal shithead it is, fires the focus element on a delay.  Therefore, we have to
			// clear the active date picker on a timeout, so the picker doesn't keep popping up.
			setTimeout(function(){
				if ( $.cms.datepicker.active &&
					 $.cms.datepicker.current &&
					 $.cms.datepicker.current.options &&
					 $.cms.datepicker.current.options.input &&
					 $.cms.datepicker.active === $.cms.datepicker.current.options.input[0] ) {
					$.cms.datepicker.active = null;
				}
			},1);
		} else {
			$.cms.datepicker.active = null;
		}

		$(document).unbind('mousedown', this._handleClick);

		return $.ui.dialog.prototype.close.apply( this, arguments );
	}

});

})( jQuery );

