/*
 * This file is part of Nuts Framework.
 * Copyright (C) 2009 Nuts Develop Team.
 *
 * Nuts Framework is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License any later version.
 * 
 * Nuts Framework is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Nuts Framework. If not, see <http://www.gnu.org/licenses/>.
 */
(function($) {
	$.datetimepicker = $.datetimepicker || {};
	$.datetimepicker.defaults = {
		dateTimeFormat: 'yyyy-MM-dd HH:mm:ss',
		showOn: 'both', // 'focus' for popup on focus, 'button' for trigger button, or 'both' for either
		showAnim: 'fadeIn', // Name of jQuery animation for popup
		showOptions: {}, // Options for enhanced animations
		duration: 'fast', // Duration of display/closure
		defaultDateTime: null, // Used when field is blank: actual date or time string
		appendText: '', // Display text following the input box, e.g. showing the format
		buttonText: '...', // Text for trigger button
		buttonImage: '', // URL for trigger button image
		buttonImageOnly: false, // True if the image appears alone, false if it appears on a button
		inlineClass: 'ui-datetimepicker-i', // The name of the inline marker class
		globalClass: 'ui-datetimepicker-g', // The name of the global marker class
		triggerClass: 'ui-datetimepicker-trigger' // The name of the trigger marker class
	};

	var _uuid = new Date().getTime();
	var _showing = false;
	var _$dtp;
	var _$dtf;
	
	var _html = '<div class="ui-datetimepicker">'
		+ '<table border="0" cellspacing="0" cellpadding="0"><tr>'
		+ '<td class="ui-datetimepicker-tdp"><div class="ui-datetimepicker-dp"></div></td>'
		+ '<td class="ui-datetimepicker-ttp"><div class="ui-datetimepicker-tp"></div></td>'
		+ '</table></div>';

	function render($dtp, s) {
		getDatePicker($dtp).datepicker({
			dateFormat: s.dateTimeFormat,
			changeYear: s.changeYear,
			changeMonth: s.changeMonth, 
			onSelect: function(ds, ui) {
				setTimeout(function() {
					update($dtp)
				}, 10);
			}
		});
		getTimePicker($dtp).timepicker({
			timeFormat: s.dateTimeFormat,
			onSelect: function(ds, d) {
				setTimeout(function() {
					update($dtp)
				}, 10);
			}
		});
	}

	function unrender($dtp) {
		getDatePicker($dtp).datepicker("destroy");
		getTimePicker($dtp).timepicker("destroy");
	}
	
	function destroy($i) {
		var s = $i.data("datetimepicker");
		var $dtp = s.$dtp;
		
		if ($dtp == _$dtp) {
			if (s.trigger) {
				s.trigger.unbind('click');
				s.trigger.remove();
			}
			$i.unbind('focus', show);
		}
		else {
			unrender($dtp);
			$dtp.remove();
		}
		
		$i.data("datetimepicker", null);
	}

	function create(el, s) {
		s = $.extend({}, $.datetimepicker.defaults, s);

		var $i = $(el);
		
		if ($i.data("datetimepicker")) {
			return;
		}
		
		if (typeof(s.dateTimeFormat) == 'string') {
			s.dateTimeFormat = new DateFormat(s.dateTimeFormat);
		}

		var nodeName = el.nodeName.toLowerCase();
		var inline = (nodeName == 'div' || nodeName == 'span');

		if (inline) {
			var $dtp = $(_html).attr("id", "ui_dtp_" + (++_uuid))
						.addClass(s.inlineClass)
						.data('target', $i)
						.appendTo(el);

			s.$dtp = $dtp;
			$i.data("datetimepicker", s);

			render($dtp, s);
			
			parse.call(el);
		}
		else {
			if (!_$dtp) {
				if ($.browser.msie && parseInt($.browser.version,10) < 7) {
					_$dtf = $('<iframe id="ui_dtp_if_' + _uuid + '" class="ui-datetimepicker-f" src="javascript:false;" frameborder="0"></iframe>').appendTo('body');
				}
				_$dtp = $(_html).attr("id", "ui_dtp_" + _uuid).addClass(s.globalClass).appendTo('body');
			}

			s.$dtp = _$dtp;
			$i.data("datetimepicker", s);

			if (s.showOn == 'focus' || s.showOn == 'both') { // pop-up date picker when in the marked field
				$i.focus(show);
			}
			if (s.showOn == 'button' || s.showOn == 'both') { // pop-up date picker when button clicked
				if (!s.trigger) {
					s.trigger = $(s.buttonImageOnly ?
							$('<img/>').addClass(s.triggerClass)
								.attr({ src: s.buttonImage, alt: s.buttonText, title: s.buttonText }) :
							$('<button type="button"></button>').addClass(s.triggerClass)
								.html(s.buttonImage == '' ? s.buttonText : $('<img/>')
								.attr({ src: s.buttonImage, alt: s.buttonText, title: s.buttonText })));
				}
				$i.after(s.trigger);
				s.trigger.click(function(evt) {
					if (!_showing) {
						if (_$dtp) {
							var b1 = _$dtp.is(':visible');
							if (b1) {
								var b2 = _$dtp.data('target').get(0);
							}
						}
						if (_$dtp && _$dtp.is(':visible') && _$dtp.data('target').get(0) == el) {
							close.call(el, evt);
						}
						else {
							$i.focus();
							if (s.showOn == 'button') {
								show.call(el, evt);
							}
						}
					}
					return false;
				});
			}
		}
	}
	
	function update($dtp) {
		var $i = $dtp.data('target');
		var d = getDate($dtp);
		if (d && $i) {
			var s = $i.data("datetimepicker");
			var ds = s.dateTimeFormat.format(d);

			$i.val(ds).trigger('change');
			if (s.onSelect) {
				s.onSelect(ds, d);
			}
		}
	}

	function parse() {
		var $i = $(this);
		var s = $i.data("datetimepicker");
		var d = s.dateTimeFormat.parse($i.val() 
				|| (typeof(s.defaultDateTime) == 'string' ? s.defaultDateTime : '')
			)
			|| (typeof(s.defaultDateTime) == 'object' ? s.defaultDateTime : null) 
			|| new Date();

		setDate(s.$dtp, d);
		
		return s.dateTimeFormat.format(d);
	}

	function getDatePicker($dtp) {
		return $dtp.find(".ui-datetimepicker-dp");
	}
	
	function getTimePicker($dtp) {
		return $dtp.find(".ui-datetimepicker-tp");
	}
	
	function getPicker($i) {
		return $i.data("datetimepicker").$dtp;
	}
	
	function getDate($dtp) {
		var $i = $dtp.data('target');
		if ($i) {
			var s = $i.data("datetimepicker");
			var d = s.dateTimeFormat.parse($i.val() || (typeof(s.defaultDateTime) == 'string' ? s.defaultDateTime : ''))
						|| (typeof(s.defaultDateTime) == 'object' ? s.defaultDateTime : null) || new Date();

			var dd = getDatePicker($dtp).datepicker("getDate");
			if (dd) {
				d.setFullYear(dd.getFullYear());
				d.setMonth(dd.getMonth());
				d.setDate(dd.getDate());
			}
			
			var dt = getTimePicker($dtp).timepicker("getDate");
			if (dt) {
				d.setHours(dt.getHours());
				d.setMinutes(dt.getMinutes());
				d.setSeconds(dt.getSeconds());
			}

			return d;
		}
		return null;
	}
	
	function setDate($dtp, d) {
		var $i = $dtp.data('target');
		if ($i) {
			d = d || new Date();
			getDatePicker($dtp).datepicker("setDate", new Date(d.getTime()));
			getTimePicker($dtp).timepicker("setDate", d);
		}
		return d;
	}
	
	function postShow() {
		$(document).mouseup(mclose);
		_showing = false;
		if (_$dtf) {
			_$dtf.css({
				left: _$dtp.css('left'),
				top: _$dtp.css('top'),
				width: _$dtp.outerWidth(),
				height: _$dtp.outerHeight()
			});
		}
	}
	
	function postHide() {
		unrender(_$dtp);
		_showing = false;
		if (_$dtp) {
			_$dtp.css({ left: '-9999px', top: '-9999px' });
		}
	}
	
	function show(evt) {
		if (_showing) {
			return;
		}

		close();

		_showing = true;
			
		var $i = $(this);
		var s = $i.data("datetimepicker");

		render(_$dtp, s);

		var of = $i.offset();
		var top = of.top + $i.outerHeight();
		var left = of.left;

		_$dtp.data('target', $i).css({
			left: left,
			top: top
		});

		if ($.effects && $.effects[s.showAnim]) {
			_$dtp.show(s.showAnim, s.showOptions, s.duration, postShow);
		}
		else {
			_$dtp[s.showAnim || 'show']((s.showAnim ? s.duration : null), postShow);
		}

		parse.call(this);
		$i.keyup(parse);
	}

	function mclose(evt) {
		if ($(evt.target).closest('BODY').size() > 0) {
			close(evt);
		}
	}
	
	function close(evt) {
		if (_showing || _$dtp.is(':hidden') || !_$dtp.data('target')
				|| (evt && (_$dtp.data('target').get(0) == evt.target
						|| $(evt.target).closest('.ui-datetimepicker').attr('id') == _$dtp.attr('id')))) {
			return;
		}

		_showing = true;

		if (_$dtf) {
			_$dtf.css({ left: '-9999px', top: '-9999px' });
		}

		var $i = _$dtp.data('target');

		$(document).unbind('mouseup', mclose);
		$i.unbind('keyup', parse);

		if (evt) {
			var s = $i.data("datetimepicker");
			if ($.effects && $.effects[s.showAnim]) {
				_$dtp.hide(s.showAnim, s.showOptions, s.duration, postHide);
			}
			else {
				_$dtp[(s.showAnim == 'slideDown' ? 'slideUp' :
					(s.showAnim == 'fadeIn' ? 'fadeOut' : 'hide'))]((s.showAnim ? s.duration : null), postHide);
			}
		}
		else {
			postHide();
		}
	}

	$.fn.datetimepicker = function(s, v) {
		switch (s) {
		case 'destroy':
			return destroy(this);
		case 'getDatePicker':
			return getDatePicker(getPicker(this));
		case 'getTimePicker':
			return getTimePicker(getPicker(this));
		case 'getDate':
			return this.length ? getDate(getPicker(this)) : null;
		case 'setDate':
			return this.length ? setDate(getPicker(this), v) : v;
		default:
			return this.each(function() {
				create(this, s);
			});
		}
	};
})(jQuery);
