/**
 * @license
 * jQuery Tools 1.2.5 Tooltip - UI essentials
 *
 * NO COPYRIGHTS OR LICENSES. DO WHAT YOU LIKE.
 *
 * http://flowplayer.org/tools/tooltip/
 *
 * Since: November 2008
 * Date:    Wed Sep 22 06:02:10 2010 +0000
 */
(function($) {
	// static constructs
	$.tools = $.tools || {version: '1.2.5'};

	$.tools.tooltip = {

		conf: {

			// default effect variables
			effect: 'toggle',
			fadeOutSpeed: "fast",
			predelay: 0,
			delay: 30,
			opacity: 1,
			tip: 0,

			// 'top', 'bottom', 'right', 'left', 'center'
			position: ['top', 'center'],
			offset: [0, 0],
			relative: false,
			cancelDefault: true,

			// type to event mapping
			events: {
				def: 			"mouseenter,mouseleave",
				input: 		"focus,blur",
				widget:		"focus mouseenter,blur mouseleave",
				tooltip:		"mouseenter,mouseleave"
			},

			// 1.2
			layout: '<div/>',
			tipClass: 'tooltip'
		},

		addEffect: function(name, loadFn, hideFn) {
			effects[name] = [loadFn, hideFn];
		}
	};


	var effects = {
		toggle: [
			function(done) {
				var conf = this.getConf(), tip = this.getTip(), o = conf.opacity;
				if (o < 1) { tip.css({opacity: o}); }
				tip.show();
				done.call();
			},

			function(done) {
				this.getTip().hide();
				done.call();
			}
		],

		fade: [
			function(done) {
				var conf = this.getConf();
				this.getTip().fadeTo(conf.fadeInSpeed, conf.opacity, done);
			},
			function(done) {
				this.getTip().fadeOut(this.getConf().fadeOutSpeed, done);
			}
		]
	};


	/* calculate tip position relative to the trigger */
	function getPosition(trigger, tip, conf) {


		// get origin top/left position
		var top = conf.relative ? trigger.position().top : trigger.offset().top,
			 left = conf.relative ? trigger.position().left : trigger.offset().left,
			 pos = conf.position[0];

		top  -= tip.outerHeight() - conf.offset[0];
		left += trigger.outerWidth() + conf.offset[1];

		// iPad position fix
		if (/iPad/i.test(navigator.userAgent)) {
			top -= $(window).scrollTop();
		}

		// adjust Y
		var height = tip.outerHeight() + trigger.outerHeight();
		if (pos == 'center') 	{ top += height / 2; }
		if (pos == 'bottom') 	{ top += height; }


		// adjust X
		pos = conf.position[1];
		var width = tip.outerWidth() + trigger.outerWidth();
		if (pos == 'center') 	{ left -= width / 2; }
		if (pos == 'left')   	{ left -= width; }

		return {top: top, left: left};
	}



	function Tooltip(trigger, conf) {

		var self = this,
			 fire = trigger.add(self),
			 tip,
			 timer = 0,
			 pretimer = 0,
			 title = trigger.attr("title"),
			 tipAttr = trigger.attr("data-tooltip"),
			 effect = effects[conf.effect],
			 shown,

			 // get show/hide configuration
			 isInput = trigger.is(":input"),
			 isWidget = isInput && trigger.is(":checkbox, :radio, select, :button, :submit"),
			 type = trigger.attr("type"),
			 evt = conf.events[type] || conf.events[isInput ? (isWidget ? 'widget' : 'input') : 'def'];


		// check that configuration is sane
		if (!effect) { throw "Nonexistent effect \"" + conf.effect + "\""; }

		evt = evt.split(/,\s*/);
		if (evt.length != 2) { throw "Tooltip: bad events configuration for " + type; }


		// trigger --> show
		trigger.bind(evt[0], function(e) {

			clearTimeout(timer);
			if (conf.predelay) {
				pretimer = setTimeout(function() { self.show(e); }, conf.predelay);

			} else {
				self.show(e);
			}

		// trigger --> hide
		}).bind(evt[1], function(e)  {
			clearTimeout(pretimer);
			if (conf.delay)  {
				timer = setTimeout(function() { self.hide(e); }, conf.delay);

			} else {
				self.hide(e);
			}

		});


		// remove default title
		if (title && conf.cancelDefault) {
			trigger.removeAttr("title");
			trigger.data("title", title);
		}

		$.extend(self, {

			show: function(e) {

				// tip not initialized yet
				if (!tip) {

					// data-tooltip
					if (tipAttr) {
						tip = $(tipAttr);

					// single tip element for all
					} else if (conf.tip) {
						tip = $(conf.tip).eq(0);

					// autogenerated tooltip
					} else if (title) {
						tip = $(conf.layout).addClass(conf.tipClass).appendTo(document.body)
							.hide().append(title);

					// manual tooltip
					} else {
						tip = trigger.next();
						if (!tip.length) { tip = trigger.parent().next(); }
					}

					if (!tip.length) { throw "Cannot find tooltip for " + trigger;	}
				}

			 	if (self.isShown()) { return self; }

			 	// stop previous animation
			 	tip.stop(true, true);

				// get position
				var pos = getPosition(trigger, tip, conf);

				// restore title for single tooltip element
				if (conf.tip) {
					tip.html(trigger.data("title"));
				}

				// onBeforeShow
				e = e || $.Event();
				e.type = "onBeforeShow";
				fire.trigger(e, [pos]);
				if (e.isDefaultPrevented()) { return self; }


				// onBeforeShow may have altered the configuration
				pos = getPosition(trigger, tip, conf);

				// set position
				tip.css({position:'absolute', top: pos.top, left: pos.left});

				shown = true;

				// invoke effect
				effect[0].call(self, function() {
					e.type = "onShow";
					shown = 'full';
					fire.trigger(e);
				});


				// tooltip events
				var event = conf.events.tooltip.split(/,\s*/);

				if (!tip.data("__set")) {

					tip.bind(event[0], function() {
						clearTimeout(timer);
						clearTimeout(pretimer);
					});

					if (event[1] && !trigger.is("input:not(:checkbox, :radio), textarea")) {
						tip.bind(event[1], function(e) {

							// being moved to the trigger element
							if (e.relatedTarget != trigger[0]) {
								trigger.trigger(evt[1].split(" ")[0]);
							}
						});
					}

					tip.data("__set", true);
				}

				return self;
			},

			hide: function(e) {

				if (!tip || !self.isShown()) { return self; }

				// onBeforeHide
				e = e || $.Event();
				e.type = "onBeforeHide";
				fire.trigger(e);
				if (e.isDefaultPrevented()) { return; }

				shown = false;

				effects[conf.effect][1].call(self, function() {
					e.type = "onHide";
					fire.trigger(e);
				});

				return self;
			},

			isShown: function(fully) {
				return fully ? shown == 'full' : shown;
			},

			getConf: function() {
				return conf;
			},

			getTip: function() {
				return tip;
			},

			getTrigger: function() {
				return trigger;
			}

		});

		// callbacks
		$.each("onHide,onBeforeShow,onShow,onBeforeHide".split(","), function(i, name) {

			// configuration
			if ($.isFunction(conf[name])) {
				$(self).bind(name, conf[name]);
			}

			// API
			self[name] = function(fn) {
				if (fn) { $(self).bind(name, fn); }
				return self;
			};
		});

	}


	// jQuery plugin implementation
	$.fn.tooltip = function(conf) {

		// return existing instance
		var api = this.data("tooltip");
		if (api) { return api; }

		conf = $.extend(true, {}, $.tools.tooltip.conf, conf);

		// position can also be given as string
		if (typeof conf.position == 'string') {
			conf.position = conf.position.split(/,?\s/);
		}

		// install tooltip for each entry in jQuery object
		this.each(function() {
			api = new Tooltip($(this), conf);
			$(this).data("tooltip", api);
		});

		return conf.api ? api: this;
	};

}) (jQuery);




/**
 * @license
 * jQuery Tools 1.2.5 / Tooltip Dynamic Positioning
 *
 * NO COPYRIGHTS OR LICENSES. DO WHAT YOU LIKE.
 *
 * http://flowplayer.org/tools/tooltip/dynamic.html
 *
 * Since: July 2009
 * Date:    Wed Sep 22 06:02:10 2010 +0000
 */
(function($) {

    // version number
    var t = $.tools.tooltip;

    t.dynamic = {
        conf: {
            classNames: "top right bottom left"
        }
    };

    /*
     * See if element is on the viewport. Returns an boolean array specifying which
     * edges are hidden. Edges are in following order:
     *
     * [top, right, bottom, left]
     *
     * For example following return value means that top and right edges are hidden
     *
     * [true, true, false, false]
     *
     */
    function getCropping(el) {

        var w = $(window);
        var right = w.width() + w.scrollLeft();
        var bottom = w.height() + w.scrollTop();

        return [
            el.offset().top <= w.scrollTop(),                         // top
            right <= el.offset().left + el.width(),                // right
            bottom <= el.offset().top + el.height(),            // bottom
            w.scrollLeft() >= el.offset().left                     // left
        ];
    }

    /*
        Returns true if all edges of an element are on viewport. false if not

        @param crop the cropping array returned by getCropping function
     */
    function isVisible(crop) {
        var i = crop.length;
        while (i--) {
            if (crop[i]) { return false; }
        }
        return true;
    }

    // dynamic plugin
    $.fn.dynamic = function(conf) {

        if (typeof conf == 'number') { conf = {speed: conf}; }

        conf = $.extend({}, t.dynamic.conf, conf);

        var cls = conf.classNames.split(/\s/), orig;

        this.each(function() {

            var api = $(this).tooltip().onBeforeShow(function(e, pos) {

                // get nessessary variables
                var tip = this.getTip(), tipConf = this.getConf();

                /*
                    We store the original configuration and use it to restore back to the original state.
                */
                if (!orig) {
                    orig = [
                        tipConf.position[0],
                        tipConf.position[1],
                        tipConf.offset[0],
                        tipConf.offset[1],
                        $.extend({}, tipConf)
                    ];
                }

                /*
                    display tip in it's default position and by setting visibility to hidden.
                    this way we can check whether it will be on the viewport
                */
                $.extend(tipConf, orig[4]);
                tipConf.position = [orig[0], orig[1]];
                tipConf.offset = [orig[2], orig[3]];

                tip.css({
                    visibility: 'hidden',
                    position: 'absolute',
                    top: pos.top,
                    left: pos.left
                }).show();

                // now let's see for hidden edges
                var crop = getCropping(tip);

                // possibly alter the configuration
                if (!isVisible(crop)) {

                    // change the position and add class
                    if (crop[2]) { $.extend(tipConf, conf.top);        tipConf.position[0] = 'top';         tip.addClass(cls[0]); }
                    if (crop[3]) { $.extend(tipConf, conf.right);    tipConf.position[1] = 'right';     tip.addClass(cls[1]); }
                    if (crop[0]) { $.extend(tipConf, conf.bottom);     tipConf.position[0] = 'bottom';    tip.addClass(cls[2]); }
                    if (crop[1]) { $.extend(tipConf, conf.left);        tipConf.position[1] = 'left';     tip.addClass(cls[3]); }

                    // vertical offset
                    if (crop[0] || crop[2]) { tipConf.offset[0] *= -1; }

                    // horizontal offset
                    if (crop[1] || crop[3]) { tipConf.offset[1] *= -1; }
                }

                tip.css({visibility: 'visible'}).hide();

            });

            // restore positioning as soon as possible
            api.onBeforeShow(function() {
                var c = this.getConf(), tip = this.getTip();
                setTimeout(function() {
                    c.position = [orig[0], orig[1]];
                    c.offset = [orig[2], orig[3]];
                }, 0);
            });

            // remove custom class names and restore original effect
            api.onHide(function() {
                var tip = this.getTip();
                tip.removeClass(conf.classNames);
            });

            ret = api;

        });

        return conf.api ? ret : this;
    };

}) (jQuery);




/** CLOCK ********************************************************************/
(function($)
{
    var selectors = {
        clock: '#clock',
        selectHour: '#clock select[name="clock_hour"]',
        selectMinute: '#clock select[name="clock_minute"]',
        selectAmPm: '#clock select[name="clock_ampm"]',
        hour12: '#clock select[name="clock_hour"] option[value="12"]',
        minute0: '#clock select[name="clock_minute"] option[value="00"]',
        ampmPm: '#clock select[name="clock_ampm"] option[value="pm"]',
        apply: '#clock-apply'
    };

    var defaults = {
    };

    var initialized = false;
    var icon_tag = '<div class="clock-icon"></div>';
    var input = null;

    // Plugin definition
    $.fn.clock = function(opts)
    {
        var options = $.extend({}, defaults, opts);

        initializeClock();

        this.each(function()
        {
            this.options = options;

            // Add the clock icon
            $(icon_tag)
            .insertAfter(this)
            .click(showClock)
            .data({
                buddy: this
            });
        });
    };



    /**
    * Initialize the clock plugin
    */
    function initializeClock()
    {
        if( initialized )
        {
            return;
        }

        initialized = true;

        var html =
            '<div id="clock">' +
            '<div id="clock-time-fields">' +
            '<select name="clock_hour">';

        for( var i = 1; i <= 12; i++ )
        {
            html += '<option value="' + i + '">' + pad(i) + '</option>';
        }

        html +=
            '</select>' +
            ' : ' +
            '<select name="clock_minute">' +
            '<option value="00">00</option>' +
            '<option value="15">15</option>' +
            '<option value="30">30</option>' +
            '<option value="45">45</option>' +
            '<option value=""></option>';

        for( var i = 1; i < 60; i++ )
        {
            html += '<option value="' + pad(i) + '">' + pad(i) + '</option>';
        }

        html +=
            '</select> ' +
            '<select name="clock_ampm">' +
            '<option value="am">am</option>' +
            '<option value="pm">pm</option>' +
            '</select>' +
            '<span id="clock-apply"></span>' +
            '</div>' +
            '</div>';

        $('body')
        .append(html);

        // Time changed or applied
        $([selectors.selectHour, selectors.selectMinute, selectors.selectAmPm].join(','))
        .change(updateInput);

        $(selectors.apply)
        .click(function()
        {
            updateInput();
            hideClock();
        })
    }


    /**
    * Update the input field with the new time
    */
    function updateInput()
    {
        var current = $(input).val();
        var hour = $(selectors.selectHour).val();
        var minute = $(selectors.selectMinute).val();
        var ampm = $(selectors.selectAmPm).val();

        if( minute == '' )
        {
            minute = '00';
        }

        var time = hour + ':' + minute + ampm;

        if( !current.match(/(\d+):(\d+)([ap]m)/i) )
        {
            $(input).val(time);
        }
        else
        {
            $(input).val(current.replace(/(\d+):(\d+)([ap]m)/, time));
        }
    }


    /**
    * Set the clock to a default value
    */
    function setNow()
    {
        var selecteds = [
            selectors.hour12,
            selectors.minute0,
            selectors.ampmPm
        ];

        $(selecteds.join(','))
        .attr('selected', 'selected');
    }


    /**
    * Show the clock
    */
    function showClock()
    {
        // Don't redisplay
        if( $(this).data('buddy') == input )
        {
            return;
        }

        input = $(this).data('buddy');

        var current = $(input).val();
        var matches = null;
        var selected = null;

        if( (matches = current.match(/(\d+):(\d+)([ap]m)/i)) != null )
        {
            var selecteds = [
                selectors.selectHour + ' option[value=' + matches[1] + ']',
                selectors.selectMinute + ' option[value=' + matches[2] + ']',
                selectors.selectAmPm + ' option[value=' + matches[3] + ']'
            ];

            $(selecteds.join(','))
            .attr('selected', 'selected');
        }
        else
        {
            setNow();
        }

        // Position the clock
        var offset = $(this).offset();

        $(selectors.clock)
        .css({
            top: offset.top - 7 + 'px',
            left: offset.left + 'px'
        })
        .show();

        // Events that hide the clock
        $(document)
        .mousedown(mouseDown)
        .keydown(keyDown);
    }



    /**
    * Handle document mousedown
    */
    function mouseDown(e)
    {
        if( !$(e.target).is(selectors.clock) && $(e.target).parents(selectors.clock).length == 0 )
        {
            hideClock();
        }
    }


    /**
    * Handle document keydown
    */
    function keyDown(e)
    {
        if( e.keyCode == 27 /* escape */ )
        {
            hideClock();
        }

        else if( e.keyCode == 9 /* tab */ )
        {
            $(input)
            .focus();

            hideClock();
        }
    }


    /**
    * Hide the clock
    */
    function hideClock()
    {
        input = null;
        $(document).unbind('mousedown', mouseDown).unbind('keydown', keyDown);
        $(selectors.clock).hide();
    }


    /**
    * Zero pad numbers less than 10
    */
    function pad(number)
    {
        return (number < 10 ? '0' : '') + number;
    }
})(jQuery);




/** CALENDAR *****************************************************************/
(function($)
{
    var selectors = {
        calendar: '#calendar',
        navNext: '#calendar-nav .next',
        navPrev: '#calendar-nav .prev',
        selectMonth: '#calendar select[name="calendar_month"]',
        selectYear: '#calendar select[name="calendar_year"]',
        selectHour: '#calendar select[name="calendar_hour"]',
        selectMinute: '#calendar select[name="calendar_minute"]',
        selectAmPm: '#calendar select[name="calendar_ampm"]',
        divTime: '#calendar-time',
        divTimeFields: '#calendar-time-fields',
        day: '#calendar tbody td',
        dayNumber: 'div div',
        hour12: '#calendar select[name="calendar_hour"] option[value="12"]',
        minute0: '#calendar select[name="calendar_minute"] option[value="00"]',
        ampmPm: '#calendar select[name="calendar_ampm"] option[value="pm"]'
    };

    var defaults = {
        time: true
    };

    var initialized = false;
    var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
    var days = ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'];
    var one_minute = 60 * 1000;
    var one_hour = one_minute * 60;
    var one_day = one_hour * 24;
    var one_week = one_day * 7;
    var icon_tag = '<div class="calendar-icon"></div>';
    var input = null;

    // Plugin definition
    $.fn.calendar = function(opts)
    {
        var options = $.extend({}, defaults, opts);

        initializeCalendar();

        this.each(function()
        {
            this.options = options;

            // Add the calendar icon
            $(icon_tag)
            .insertAfter(this)
            .click(showCalendar)
            .data({
                buddy: this
            });
        });
    };



    /**
    * Initialize the calendar plugin
    */
    function initializeCalendar()
    {
        if( initialized )
        {
            return;
        }

        initialized = true;

        var now = new Date();
        var year = now.getFullYear();

        var html =
            '<div id="calendar">' +
            '<div id="calendar-nav">' +
            '<span class="prev inline-block" month="-1">&lt;</span>' +
            '<select name="calendar_month">';

        for( var i = 0; i < months.length; i++ )
        {
            html += '<option value="' + pad(i + 1) + '">' + months[i] + '</option>';
        }

        html +=
            '</select> ' +
            '<select name="calendar_year">';

        for( var i = 1990; i < year + 25; i++ )
        {
            html += '<option value="' + i + '">' + i + '</option>';
        }

        html +=
            '</select>' +
            '<span class="next inline-block" month="1">&gt;</span>' +
            '</div>' +
            '<div id="calendar-month">' +
            '<table cellpadding="0" cellspacing="1">' +
            '<thead>' +
            '<tr>';

        for( var i = 0; i < days.length; i++ )
        {
            html += '<td><div>' + days[i] + '</div></td>';
        }

        html +=
            '</tr>' +
            '</thead>' +
            '<tbody>' +
            '<tr>';

        for( var i = 1; i <= 42; i++ )
        {
            html += '<td><div><div>' + i + '</div></div></td>';

            if( i % 7 == 0 )
            {
                html += '</tr><tr>';
            }
        }

        html +=
            '</tbody>' +
            '</table>' +
            '</div>' +
            '<div id="calendar-time">' +
            '<div id="calendar-time-fields">' +
            '<select name="calendar_hour">';

        for( var i = 1; i <= 12; i++ )
        {
            html += '<option value="' + i + '">' + pad(i) + '</option>';
        }

        html +=
            '</select>' +
            ' : ' +
            '<select name="calendar_minute">' +
            '<option value="00">00</option>' +
            '<option value="15">15</option>' +
            '<option value="30">30</option>' +
            '<option value="45">45</option>' +
            '<option value="00"></option>';

        for( var i = 0; i < 60; i++ )
        {
            html += '<option value="' + pad(i) + '">' + pad(i) + '</option>';
        }

        html +=
            '</select> ' +
            '<select name="calendar_ampm">' +
            '<option value="am">am</option>' +
            '<option value="pm">pm</option>' +
            '</select>' +
            '</div>' +
            '</div>' +
            '</div>';

        $('body')
        .append(html);

        // Next/previous month
        $([selectors.navPrev, selectors.navNext].join(','))
        .click(function()
        {
            jumpMonth($(this).attr('month'));
        });

        // Month or year changed
        $([selectors.selectMonth, selectors.selectYear].join(','))
        .change(updateCalendar);

        // Date clicked
        $(selectors.day)
        .click(function()
        {
            var hour = $(selectors.selectHour).val();
            var minute = $(selectors.selectMinute).val();
            var ampm = $(selectors.selectAmPm).val();
            var time = hour + ':' + minute + ampm;
            var datetime = $(this).attr('date') + (input.options.time ? ' ' + time : '');

            if( input )
            {
                $(input).val(datetime);
            }

            hideCalendar();
        });

        // Time changed
        $([selectors.selectHour, selectors.selectMinute, selectors.selectAmPm].join(','))
        .change(function()
        {
            var current = $(input).val();
            var hour = $(selectors.selectHour).val();
            var minute = $(selectors.selectMinute).val();
            var ampm = $(selectors.selectAmPm).val();
            var time = hour + ':' + minute + ampm;

            $(input).val(current.replace(/(\d+):(\d+)([ap]m)/, time));
        });

        setToday();
        updateCalendar();
    }


    /**
    * Update the calendar with a new month and/or year
    */
    function updateCalendar()
    {
        var selected_month = parseInt($(selectors.selectMonth).val());
        var selected_year = $(selectors.selectYear).val();
        var start_date = new Date(selected_year, selected_month - 1, 1, 12);
        var days_in_month = new Date(start_date.getFullYear(), start_date.getMonth(), 0).getDate();

        var day_of_week = start_date.getDay();
        if( day_of_week == 0 )
        {
            day_of_week = 7;
        }
        start_date.setTime(start_date.getTime() - (day_of_week * one_day));

        var current_date = new Date();
        var i = 0;

        $(selectors.day)
        .removeClass()
        .each(function()
        {
            current_date.setTime(start_date.getTime() + (i++ * one_day));

            var month = pad(current_date.getMonth() + 1);
            var date = pad(current_date.getDate());
            var full_date = month + '/' + date + '/' + current_date.getFullYear();

            $(this)
            .attr('date', full_date)
            .addClass(month != selected_month ? 'other-month' : '');

            $(selectors.dayNumber, this)
            .text(date);
        });

        var today = new Date();
        var full_date = pad(today.getMonth() + 1) + '/' + pad(today.getDate()) + '/' + today.getFullYear();

        $(selectors.day + '[date="' + full_date + '"]')
        .removeClass()
        .addClass('today');

        var current = $(input).val();
        if( current && (matches = current.match(/(\d{1,2})\/(\d{1,2})\/(\d{4})/)) != null )
        {
            $(selectors.day + '[date="' + pad(matches[1]) + '/' + pad(matches[2]) + '/' + matches[3] + '"]')
            .removeClass()
            .addClass('selected');
        }
    }


    /**
    * Set the calendar to the current month and year
    */
    function setToday()
    {
        var today = new Date();
        var month = pad(today.getMonth() + 1);

        var selecteds = [
            selectors.selectYear + ' option[value=' + today.getFullYear() + ']',
            selectors.selectMonth + ' option[value=' + month + ']',
            selectors.hour12,
            selectors.minute0,
            selectors.ampmPm
        ];

        $(selecteds.join(','))
        .attr('selected', 'selected');
    }


    /**
    * Show the calendar
    */
    function showCalendar()
    {
        // Don't redisplay
        if( $(this).data('buddy') == input )
        {
            return;
        }

        input = $(this).data('buddy');

        var current = $(input).val();
        var matches = null;
        var selected = null;

        if( (matches = current.match(/((\d{1,2})\/(\d{1,2})\/(\d{4}))(\s+(\d+):(\d+)([ap]m))?/)) != null )
        {
            var selecteds = [
                selectors.selectYear + ' option[value=' + matches[4] + ']',
                selectors.selectMonth + ' option[value=' + pad(matches[2]) + ']'
            ];

            if( matches[5] != undefined )
            {
                selecteds.push(
                    selectors.selectHour + ' option[value=' + matches[6] + ']',
                    selectors.selectMinute + ' option[value=' + matches[7] + ']',
                    selectors.selectAmPm + ' option[value=' + matches[8] + ']'
                );
            }

            $(selecteds.join(','))
            .attr('selected', 'selected');
        }
        else
        {
            setToday();
        }

        updateCalendar();


        // Show/hide time selection
        if( input.options.time )
        {
            $(selectors.divTimeFields)
            .show();
        }
        else
        {
            $(selectors.divTimeFields)
            .hide();
        }

        // Position the calender
        var offset = $(input).offset();
        var height = $(input).outerHeight();
        var calHeight = $(selectors.calendar).outerHeight();
        var calOffsetTop = offset.top + height;
        var windowHeight = $(window).height();
        var positionCss = {
            top: calOffsetTop + 'px',
            left: offset.left + 'px'
        };

        // Under input field is the default, but
        // may need to be on top to prevent getting
        // chopped off at the bottom of the browser window
        if( calHeight + calOffsetTop > windowHeight )
        {
            positionCss = {
                top: offset.top - calHeight + 'px',
                left: offset.left + 'px'
            };
        }

        $(selectors.calendar)
        .css(positionCss)
        .show();


        // Events that hide the calendar
        $(document)
        .mousedown(mouseDown)
        .keydown(keyDown);
    }


	/**
    * Handle document mousedown
    */
	function mouseDown(e)
	{
		if( $(e.target).parents(selectors.calendar).length == 0 )
		{
			hideCalendar();
		}
	}


    /**
    * Handle document keydown
    */
	function keyDown(e)
	{
		if( e.keyCode == 27 /* escape */ )
		{
			hideCalendar();
		}

		else if( e.keyCode == 9 /* tab */ )
		{
			$(input)
			.focus();

			hideCalendar();
		}
	}


    /**
    * Hide the calendar
    */
    function hideCalendar()
    {
        input = null;
        $(document).unbind('mousedown', mouseDown).unbind('keydown', keyDown);
        $(selectors.calendar).hide();
    }


    /**
    * Jump forward or back one month
    */
    function jumpMonth(amount)
    {
        var selected_month = parseInt($(selectors.selectMonth).val()) - 1;
        var selected_year = parseInt($(selectors.selectYear).val());
        var now = new Date(selected_year, selected_month + parseInt(amount), 1, 12);

        var selecteds = [
            selectors.selectYear + ' option[value=' + now.getFullYear() + ']',
            selectors.selectMonth + ' option[value=' + pad(now.getMonth() + 1) + ']'
        ]

        $(selecteds.join(','))
        .attr('selected', 'selected')

        updateCalendar();
    }


    /**
    * Zero pad numbers less than 10
    */
    function pad(number)
    {
        number = parseInt(number);
        return (number < 10 ? '0' : '') + number;
    }

})(jQuery);



$(function()
{
    $('div.validation.ttip')
    .append('<span></span>')
    .tooltip({
        offset: [-5, 0]
    })
    .dynamic();

	$('input.date').calendar({time: false});
    $('input.datetime').calendar();
    $('input.time').clock();
});


