/*
 * jQuery UI Timepicker 0.1.3
 *
 * Copyright 2010-2011, Francois Gelinas
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * http://fgelinas.com/code/timepicker
 *
 * Depends:
 *	jquery.ui.core.js
 *
 *
 * Change version 0.1.0 - moved the t-rex up here
 *

*/

(function ($, undefined) {

    $.extend($.ui, { timepicker: { version: "0.1.3"} });

    var PROP_NAME = 'timepicker';
    var tpuuid = new Date().getTime();

    /* Time picker manager.
    Use the singleton instance of this class, $.timepicker, to interact with the time picker.
    Settings for (groups of) time pickers are maintained in an instance object,
    allowing multiple different settings on the same page. */

    function Timepicker() {
        this.debug = true; // Change this to true to start debugging
        this._curInst = null; // The current instance in use
        this._isInline = false; // true if the instance is displayed inline
        this._disabledInputs = []; // List of time picker inputs that have been disabled
        this._timepickerShowing = false; // True if the popup picker is showing , false if not
        this._inDialog = false; // True if showing within a "dialog", false if not
        this._dialogClass = 'ui-timepicker-dialog'; // The name of the dialog marker class
        this._mainDivId = 'ui-timepicker-div'; // The ID of the main timepicker division
        this._inlineClass = 'ui-timepicker-inline'; // The name of the inline marker class
        this._currentClass = 'ui-timepicker-current'; // The name of the current hour / minutes marker class
        this._dayOverClass = 'ui-timepicker-days-cell-over'; // The name of the day hover marker class

        this.regional = []; // Available regional settings, indexed by language code
        this.regional[''] = { // Default regional settings
            hourText: 'Hour', // Display text for hours section
            minuteText: 'Minute', // Display text for minutes link
            amPmText: ['AM', 'PM'] // Display text for AM PM
        };
        this._defaults = { // Global defaults for all the time picker instances
            showOn: 'focus',    // 'focus' for popup on focus,
                                // 'button' for trigger button, or 'both' for either (not yet implemented)
            button: null,                   // 'button' element that will trigger the timepicker
            showAnim: 'fadeIn',             // Name of jQuery animation for popup
            showOptions: {},                // Options for enhanced animations
            appendText: '',                 // Display text following the input box, e.g. showing the format
            onSelect: null,                 // Define a callback function when a hour / minutes is selected
            onClose: null,                  // Define a callback function when the timepicker is closed
            timeSeparator: ':',             // The caracter to use to separate hours and minutes.
            showPeriod: false,              // Define whether or not to show AM/PM with selected time
            showPeriodLabels: true,         // Show the AM/PM labels on the left of the time picker
            showLeadingZero: true,          // Define whether or not to show a leading zero for hours < 10. [true/false]
            showMinutesLeadingZero: true,   // Define whether or not to show a leading zero for minutes < 10.
            altField: '',                   // Selector for an alternate field to store selected time into
            defaultTime: '',                // Used as default time when input field is empty or for inline timePicker

            //NEW: 2011-02-03
            onHourShow: null,			    // callback for enabling / disabling on selectable hours  ex : function(hour) { return true; }
            onMinuteShow: null,             // callback for enabling / disabling on time selection  ex : function(hour,minute) { return true; }
            // 2011-03-22 - v 0.0.9
            zIndex: null                    // specify zIndex
        };
        $.extend(this._defaults, this.regional['']);

        this.tpDiv = $('<div id="' + this._mainDivId + '" class="ui-timepicker ui-widget ui-helper-clearfix ui-corner-all " style="display: none"></div>');
    }

    $.extend(Timepicker.prototype, {
        /* Class name added to elements to indicate already configured with a time picker. */
        markerClassName: 'hasTimepicker',

        /* Debug logging (if enabled). */
        log: function () {
            if (this.debug)
                console.log.apply('', arguments);
        },

        // TODO rename to "widget" when switching to widget factory
        _widgetTimepicker: function () {
            return this.tpDiv;
        },

        /* Override the default settings for all instances of the time picker.
        @param  settings  object - the new settings to use as defaults (anonymous object)
        @return the manager object */
        setDefaults: function (settings) {
            extendRemove(this._defaults, settings || {});
            return this;
        },

        /* Attach the time picker to a jQuery selection.
        @param  target    element - the target input field or division or span
        @param  settings  object - the new settings to use for this time picker instance (anonymous) */
        _attachTimepicker: function (target, settings) {
            // check for settings on the control itself - in namespace 'time:'
            var inlineSettings = null;
            for (var attrName in this._defaults) {
                var attrValue = target.getAttribute('time:' + attrName);
                if (attrValue) {
                    inlineSettings = inlineSettings || {};
                    try {
                        inlineSettings[attrName] = eval(attrValue);
                    } catch (err) {
                        inlineSettings[attrName] = attrValue;
                    }
                }
            }
            var nodeName = target.nodeName.toLowerCase();
            var inline = (nodeName == 'div' || nodeName == 'span');

            if (!target.id) {
                this.uuid += 1;
                target.id = 'tp' + this.uuid;
            }
            var inst = this._newInst($(target), inline);
            inst.settings = $.extend({}, settings || {}, inlineSettings || {});
            if (nodeName == 'input') {
                this._connectTimepicker(target, inst);
            } else if (inline) {
                this._inlineTimepicker(target, inst);
            }
        },

        /* Create a new instance object. */
        _newInst: function (target, inline) {
            var id = target[0].id.replace(/([^A-Za-z0-9_-])/g, '\\\\$1'); // escape jQuery meta chars
            return { id: id, input: target, // associated target
                selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection
                drawMonth: 0, drawYear: 0, // month being drawn
                inline: inline, // is timepicker inline or not :
                tpDiv: (!inline ? this.tpDiv : // presentation div
                    $('<div class="' + this._inlineClass + ' ui-timepicker ui-widget  ui-helper-clearfix"></div>'))
            };
        },

        /* Attach the time picker to an input field. */
        _connectTimepicker: function (target, inst) {
            var input = $(target);
            inst.append = $([]);
            inst.trigger = $([]);
            if (input.hasClass(this.markerClassName)) { return; }
            this._attachments(input, inst);
            input.addClass(this.markerClassName).
                keydown(this._doKeyDown).
                keyup(this._doKeyUp).
                bind("setData.timepicker", function (event, key, value) {
                    inst.settings[key] = value;
                }).
                bind("getData.timepicker", function (event, key) {
                    return this._get(inst, key);
                });
            //this._autoSize(inst);
            $.data(target, PROP_NAME, inst);
        },

        /* Handle keystrokes. */
        _doKeyDown: function (event) {
            var inst = $.timepicker._getInst(event.target);
            var handled = true;
            inst._keyEvent = true;
            if ($.timepicker._timepickerShowing) {
                switch (event.keyCode) {
                    case 9: $.timepicker._hideTimepicker();
                        handled = false;
                        break; // hide on tab out
                    case 27: $.timepicker._hideTimepicker();
                        break; // hide on escape
                    default: handled = false;
                }
            }
            else if (event.keyCode == 36 && event.ctrlKey) { // display the time picker on ctrl+home
                $.timepicker._showTimepicker(this);
            }
            else {
                handled = false;
            }
            if (handled) {
                event.preventDefault();
                event.stopPropagation();
            }
        },

        /* Update selected time on keyUp */
        /* Added verion 0.0.5 */
        _doKeyUp: function (event) {
            var inst = $.timepicker._getInst(event.target);
            $.timepicker._setTimeFromField(inst);
            $.timepicker._updateTimepicker(inst);
        },

        /* Make attachments based on settings. */
        _attachments: function (input, inst) {
            var appendText = this._get(inst, 'appendText');
            var isRTL = this._get(inst, 'isRTL');
            if (inst.append) { inst.append.remove(); }
            if (appendText) {
                inst.append = $('<span class="' + this._appendClass + '">' + appendText + '</span>');
                input[isRTL ? 'before' : 'after'](inst.append);
            }
            input.unbind('focus', this._showTimepicker);
            if (inst.trigger) { inst.trigger.remove(); }
            var showOn = this._get(inst, 'showOn');
            if (showOn == 'focus' || showOn == 'both') { // pop-up time picker when in the marked field
                input.focus(this._showTimepicker);
            }
            if (showOn == 'button' || showOn == 'both') { // pop-up time picker when 'button' element is clicked
                var button = this._get(inst, 'button');
                $(button).click(function () {
                    if ($.timepicker._timepickerShowing && $.timepicker._lastInput == input[0]) { $.timepicker._hideTimepicker(); }
                    else { $.timepicker._showTimepicker(input[0]); }
                    return false;
                });

            }
        },


        /* Attach an inline time picker to a div. */
        _inlineTimepicker: function(target, inst) {
            var divSpan = $(target);
            if (divSpan.hasClass(this.markerClassName))
                return;
            divSpan.addClass(this.markerClassName).append(inst.tpDiv).
                bind("setData.timepicker", function(event, key, value){
                    inst.settings[key] = value;
                }).bind("getData.timepicker", function(event, key){
                    return this._get(inst, key);
                });
            $.data(target, PROP_NAME, inst);

            this._setTimeFromField(inst);
            this._updateTimepicker(inst);
            inst.tpDiv.show();
        },

        /* Pop-up the time picker for a given input field.
        @param  input  element - the input field attached to the time picker or
        event - if triggered by focus */
        _showTimepicker: function (input) {


            input = input.target || input;
            if (input.nodeName.toLowerCase() != 'input') { input = $('input', input.parentNode)[0]; } // find from button/image trigger
            if ($.timepicker._isDisabledTimepicker(input) || $.timepicker._lastInput == input) { return; } // already here

            // fix v 0.0.8 - close current timepicker before showing another one
            $.timepicker._hideTimepicker();

            var inst = $.timepicker._getInst(input);
            if ($.timepicker._curInst && $.timepicker._curInst != inst) {
                $.timepicker._curInst.tpDiv.stop(true, true);
            }
            var beforeShow = $.timepicker._get(inst, 'beforeShow');
            extendRemove(inst.settings, (beforeShow ? beforeShow.apply(input, [input, inst]) : {}));
            inst.lastVal = null;
            $.timepicker._lastInput = input;

            $.timepicker._setTimeFromField(inst);
            if ($.timepicker._inDialog) { input.value = ''; } // hide cursor
            if (!$.timepicker._pos) { // position below input
                $.timepicker._pos = $.timepicker._findPos(input);
                $.timepicker._pos[1] += input.offsetHeight; // add the height
            }
            var isFixed = false;
            $(input).parents().each(function () {
                isFixed |= $(this).css('position') == 'fixed';
                return !isFixed;
            });
            if (isFixed && $.browser.opera) { // correction for Opera when fixed and scrolled
                $.timepicker._pos[0] -= document.documentElement.scrollLeft;
                $.timepicker._pos[1] -= document.documentElement.scrollTop;
            }
            var offset = { left: $.timepicker._pos[0], top: $.timepicker._pos[1] };
            $.timepicker._pos = null;
            // determine sizing offscreen
            inst.tpDiv.css({ position: 'absolute', display: 'block', top: '-1000px' });
            $.timepicker._updateTimepicker(inst);

            // reset clicked state
            inst._hoursClicked = false;
            inst._minutesClicked = false;

            // fix width for dynamic number of time pickers
            // and adjust position before showing
            offset = $.timepicker._checkOffset(inst, offset, isFixed);
            inst.tpDiv.css({ position: ($.timepicker._inDialog && $.blockUI ?
			'static' : (isFixed ? 'fixed' : 'absolute')), display: 'none',
                left: offset.left + 'px', top: offset.top + 'px'
            });
            if (!inst.inline) {
                var showAnim = $.timepicker._get(inst, 'showAnim');
                var duration = $.timepicker._get(inst, 'duration');
                var zIndex = $.timepicker._get(inst, 'zIndex');
                var postProcess = function () {
                    $.timepicker._timepickerShowing = true;
                    var borders = $.timepicker._getBorders(inst.tpDiv);
                    inst.tpDiv.find('iframe.ui-timepicker-cover'). // IE6- only
					css({ left: -borders[0], top: -borders[1],
					    width: inst.tpDiv.outerWidth(), height: inst.tpDiv.outerHeight()
					});
                };

                // if not zIndex specified in options, use target zIndex + 1
                if ( ! zIndex) {
                    zIndex = $(input).zIndex() + 1;
                }
                inst.tpDiv.zIndex(zIndex);

                if ($.effects && $.effects[showAnim]) {
                    inst.tpDiv.show(showAnim, $.timepicker._get(inst, 'showOptions'), duration, postProcess);
                }
                else {
                    inst.tpDiv[showAnim || 'show']((showAnim ? duration : null), postProcess);
                }
                if (!showAnim || !duration) { postProcess(); }
                if (inst.input.is(':visible') && !inst.input.is(':disabled')) { inst.input.focus(); }
                $.timepicker._curInst = inst;
            }
        },

        /* Generate the time picker content. */
        _updateTimepicker: function (inst) {
            var self = this;
            var borders = $.timepicker._getBorders(inst.tpDiv);
 
            inst.tpDiv.empty().append(this._generateHTML(inst))
			.find('iframe.ui-timepicker-cover') // IE6- only
				.css({ left: -borders[0], top: -borders[1],
				    width: inst.tpDiv.outerWidth(), height: inst.tpDiv.outerHeight()
				})
			.end()
            // after the picker html is appended bind the click & double click events (faster in IE this way
            // then letting the browser interpret the inline events)
            // the binding for the minute cells also exists in _updateMinuteDisplay
            .find('.ui-timepicker-minute-cell')
                .bind("click", { fromDoubleClick:false }, $.proxy($.timepicker.selectMinutes, this))
                .bind("dblclick", { fromDoubleClick:true }, $.proxy($.timepicker.selectMinutes, this))
            .end()
            .find('.ui-timepicker-hour-cell')
                .bind("click", { fromDoubleClick:false }, $.proxy($.timepicker.selectHours, this))
                .bind("dblclick", { fromDoubleClick:true }, $.proxy($.timepicker.selectHours, this))
            .end()
			.find('.ui-timepicker td a')
				.bind('mouseout', function () {
				    $(this).removeClass('ui-state-hover');
				    if (this.className.indexOf('ui-timepicker-prev') != -1) $(this).removeClass('ui-timepicker-prev-hover');
				    if (this.className.indexOf('ui-timepicker-next') != -1) $(this).removeClass('ui-timepicker-next-hover');
				})
				.bind('mouseover', function () {
				    if (!self._isDisabledTimepicker(inst.inline ? inst.tpDiv.parent()[0] : inst.input[0])) {
				        $(this).parents('.ui-timepicker-calendar').find('a').removeClass('ui-state-hover');
				        $(this).addClass('ui-state-hover');
				        if (this.className.indexOf('ui-timepicker-prev') != -1) $(this).addClass('ui-timepicker-prev-hover');
				        if (this.className.indexOf('ui-timepicker-next') != -1) $(this).addClass('ui-timepicker-next-hover');
				    }
				})
			.end()
			.find('.' + this._dayOverClass + ' a')
				.trigger('mouseover')
			.end();
        },

        /* Generate the HTML for the current state of the date picker. */
        _generateHTML: function (inst) {
            var h, m, html = '';
            var showPeriod = (this._get(inst, 'showPeriod') == true);
            var showPeriodLabels = (this._get(inst, 'showPeriodLabels') == true);
            var showLeadingZero = (this._get(inst, 'showLeadingZero') == true);
            var amPmText = this._get(inst, 'amPmText');


            html = '<table class="ui-timepicker-table ui-widget-content ui-corner-all"><tr>' +
                   '<td class="ui-timepicker-hours">' +
                   '<div class="ui-timepicker-title ui-widget-header ui-helper-clearfix ui-corner-all">' +
                   this._get(inst, 'hourText') +
                   '</div>' +
                   '<table class="ui-timepicker">';

            // AM
            html += '<tr>';
                // + (showPeriodLabels ? '<th rowspan="2" class="periods">' + amPmText[0] + '</th>' : '');

            /*for (h = 0; h <= 5; h++) {
                html += this._generateHTMLHourCell(inst, h, showPeriod, showLeadingZero);
            }

            html += '</tr><tr>';
            for (h = 6; h <= 11; h++) {
                html += this._generateHTMLHourCell(inst, h, showPeriod, showLeadingZero);
            }      */

            // PM
            //html += '</tr><tr>';
                 //+ (showPeriodLabels ? '<th rowspan="2" class="periods">' + amPmText[1] + '</th>' : '');
            var hours_per_line = 4;
            var h_index = 0;
            for (h = 0; h <= 23; h++) {
                html += this._generateHTMLHourCell(inst, h, showPeriod, showLeadingZero);
                h_index++;
                if(h_index == hours_per_line && h < 23) {
                    html += '</tr><tr>';
                    h_index = 0;
                }
            }

            /*html += '</tr><tr>';
            for (h = 18; h <= 23; h++) {
                html += this._generateHTMLHourCell(inst, h, showPeriod, showLeadingZero);
            } */
            html += '</tr></table>' + // Close the hours cells table
                    '</td>' +         // Close the Hour td
                    '<td class="ui-timepicker-minutes">';

            html += this._generateHTMLMinutes(inst);

            html += '</td></tr></table>';

            return html;
        },

        /* Special function that update the minutes selection in currently visible timepicker
         * called on hour selection when onMinuteShow is defined  */
        _updateMinuteDisplay: function (inst) {
            var newHtml = this._generateHTMLMinutes(inst);
            inst.tpDiv.find('td.ui-timepicker-minutes').html(newHtml)
                // after the picker html is appended bind the click & double click events (faster in IE this way
                // then letting the browser interpret the inline events)
                // yes I know, duplicate code, sorry
                .find('.ui-timepicker-minute-cell')
                    .bind("click", { fromDoubleClick:false }, $.proxy($.timepicker.selectMinutes, this))
                    .bind("dblclick", { fromDoubleClick:true }, $.proxy($.timepicker.selectMinutes, this) );


        },

        /* Generate the minutes table */
        _generateHTMLMinutes: function (inst) {

            var m;
            var showMinutesLeadingZero = (this._get(inst, 'showMinutesLeadingZero') == true);
            var onMinuteShow = this._get(inst, 'onMinuteShow');
            // if currently selected minute is not enabled, we have a problem and need to select a new minute.
            if ( (onMinuteShow) ) {

                if (onMinuteShow.apply((inst.input ? inst.input[0] : null), [inst.hours , inst.minutes]) == false) {
                    // loop minutes and select first available
                    for (m = 0; m < 60; m ++) {
                        if (onMinuteShow.apply((inst.input ? inst.input[0] : null), [inst.hours, m])) {
                            inst.minutes = m;
                            break;
                        }
                    }
                }
            }

            var html = '' + // open minutes td
                       /* Add the minutes */
                       '<div class="ui-timepicker-title ui-widget-header ui-helper-clearfix ui-corner-all">' +
                       this._get(inst, 'minuteText') +
                       '</div>' +
                       '<table class="ui-timepicker">' +
                       '<tr>';

            var minutes_per_line = 10;
            var m_index = 0;
            for (m = 0; m <= 59; m++) {
                html += this._generateHTMLMinuteCell(inst, m, (m < 10) && showMinutesLeadingZero ? "0" + m.toString() : m.toString());
                m_index++;
                if(m_index == minutes_per_line && m < 59) {
                    html += '</tr><tr>';
                    m_index = 0;
                }
            }


            html += '</tr></table>';

            return html;
        },

        /* Generate the content of a "Hour" cell */
        _generateHTMLHourCell: function (inst, hour, showPeriod, showLeadingZero) {

            var displayHour = hour;
            if ((hour > 12) && showPeriod) {
                displayHour = hour - 12;
            }
            if ((displayHour == 0) && showPeriod) {
                displayHour = 12;
            }
            if ((displayHour < 10) && showLeadingZero) {
                displayHour = '0' + displayHour;
            }

            var html = "";
            var enabled = true;
            var onHourShow = this._get(inst, 'onHourShow');		//custom callback
            if (onHourShow) {
            	enabled = onHourShow.apply((inst.input ? inst.input[0] : null), [hour]);
            }

            if (enabled) {
            	html = '<td class="ui-timepicker-hour-cell" data-timepicker-instance-id="#' + inst.id.replace("\\\\","\\") + '" data-hour="' + hour.toString() + '">' +
                   '<a href="#timepick" class="ui-state-default ' +
                   (hour == inst.hours ? 'ui-state-active' : '') +
                   '">' +
                   displayHour.toString() +
                   '</a></td>';
            }
            else {
            	html =
            		'<td>' +
		                '<span class="ui-state-default ui-state-disabled ' +
		                (hour == inst.hours ? ' ui-state-active ' : ' ') +
		                '">' +
		                displayHour.toString() +
		                '</span>' +
		            '</td>';
            }
            return html;
        },

        /* Generate the content of a "Hour" cell */
        _generateHTMLMinuteCell: function (inst, minute, displayText) {
        	 var html = "";
             var enabled = true;
             var onMinuteShow = this._get(inst, 'onMinuteShow');		//custom callback
             if (onMinuteShow) {
            	 //NEW: 2011-02-03  we should give the hour as a parameter as well!
             	enabled = onMinuteShow.apply((inst.input ? inst.input[0] : null), [inst.hours,minute]);		//trigger callback
             }

             if (enabled) {
	            html = '<td class="ui-timepicker-minute-cell" data-timepicker-instance-id="#' + inst.id.replace("\\\\","\\") + '" data-minute="' + minute.toString() + '" >' +
	                   '<a href="#timepick" class="ui-state-default ' +
	                   (minute == inst.minutes ? 'ui-state-active' : '') +
	                   '" >' +
	                   displayText +
	                   '</a></td>';
             }
             else {

            	html = '<td>' +
	                 '<span class="ui-state-default ui-state-disabled" >' +
	                 	displayText +
	                 '</span>' +
                 '</td>';
             }
             return html;
        },

        /* Is the first field in a jQuery collection disabled as a timepicker?
        @param  target    element - the target input field or division or span
        @return boolean - true if disabled, false if enabled */
        _isDisabledTimepicker: function (target) {
            if (!target) { return false; }
            for (var i = 0; i < this._disabledInputs.length; i++) {
                if (this._disabledInputs[i] == target) { return true; }
            }
            return false;
        },

        /* Check positioning to remain on screen. */
        _checkOffset: function (inst, offset, isFixed) {
            var tpWidth = inst.tpDiv.outerWidth();
            var tpHeight = inst.tpDiv.outerHeight();
            var inputWidth = inst.input ? inst.input.outerWidth() : 0;
            var inputHeight = inst.input ? inst.input.outerHeight() : 0;
            var viewWidth = document.documentElement.clientWidth + $(document).scrollLeft();
            var viewHeight = document.documentElement.clientHeight + $(document).scrollTop();

            offset.left -= (this._get(inst, 'isRTL') ? (tpWidth - inputWidth) : 0);
            offset.left -= (isFixed && offset.left == inst.input.offset().left) ? $(document).scrollLeft() : 0;
            offset.top -= (isFixed && offset.top == (inst.input.offset().top + inputHeight)) ? $(document).scrollTop() : 0;

            // now check if datepicker is showing outside window viewport - move to a better place if so.
            offset.left -= Math.min(offset.left, (offset.left + tpWidth > viewWidth && viewWidth > tpWidth) ?
			Math.abs(offset.left + tpWidth - viewWidth) : 0);
            offset.top -= Math.min(offset.top, (offset.top + tpHeight > viewHeight && viewHeight > tpHeight) ?
			Math.abs(tpHeight + inputHeight) : 0);

            return offset;
        },

        /* Find an object's position on the screen. */
        _findPos: function (obj) {
            var inst = this._getInst(obj);
            var isRTL = this._get(inst, 'isRTL');
            while (obj && (obj.type == 'hidden' || obj.nodeType != 1)) {
                obj = obj[isRTL ? 'previousSibling' : 'nextSibling'];
            }
            var position = $(obj).offset();
            return [position.left, position.top];
        },

        /* Retrieve the size of left and top borders for an element.
        @param  elem  (jQuery object) the element of interest
        @return  (number[2]) the left and top borders */
        _getBorders: function (elem) {
            var convert = function (value) {
                return { thin: 1, medium: 2, thick: 3}[value] || value;
            };
            return [parseFloat(convert(elem.css('border-left-width'))),
			parseFloat(convert(elem.css('border-top-width')))];
        },


        /* Close time picker if clicked elsewhere. */
        _checkExternalClick: function (event) {
            if (!$.timepicker._curInst) { return; }
            var $target = $(event.target);
            if ($target[0].id != $.timepicker._mainDivId &&
				$target.parents('#' + $.timepicker._mainDivId).length == 0 &&
				!$target.hasClass($.timepicker.markerClassName) &&
				!$target.hasClass($.timepicker._triggerClass) &&
				$.timepicker._timepickerShowing && !($.timepicker._inDialog && $.blockUI))
                $.timepicker._hideTimepicker();
        },

        /* Hide the time picker from view.
        @param  input  element - the input field attached to the time picker */
        _hideTimepicker: function (input) {
            var inst = this._curInst;
            if (!inst || (input && inst != $.data(input, PROP_NAME))) { return; }
            if (this._timepickerShowing) {
                var showAnim = this._get(inst, 'showAnim');
                var duration = this._get(inst, 'duration');
                var postProcess = function () {
                    $.timepicker._tidyDialog(inst);
                    this._curInst = null;
                };
                if ($.effects && $.effects[showAnim]) {
                    inst.tpDiv.hide(showAnim, $.timepicker._get(inst, 'showOptions'), duration, postProcess);
                }
                else {
                    inst.tpDiv[(showAnim == 'slideDown' ? 'slideUp' :
					    (showAnim == 'fadeIn' ? 'fadeOut' : 'hide'))]((showAnim ? duration : null), postProcess);
                }
                if (!showAnim) { postProcess(); }
                var onClose = this._get(inst, 'onClose');
                if (onClose) {
                    onClose.apply(
                        (inst.input ? inst.input[0] : null),
					    [(inst.input ? inst.input.val() : ''), inst]);  // trigger custom callback
                }
                this._timepickerShowing = false;
                this._lastInput = null;
                if (this._inDialog) {
                    this._dialogInput.css({ position: 'absolute', left: '0', top: '-100px' });
                    if ($.blockUI) {
                        $.unblockUI();
                        $('body').append(this.tpDiv);
                    }
                }
                this._inDialog = false;
            }
        },

        /* Tidy up after a dialog display. */
        _tidyDialog: function (inst) {
            inst.tpDiv.removeClass(this._dialogClass).unbind('.ui-timepicker');
        },

        /* Retrieve the instance data for the target control.
        @param  target  element - the target input field or division or span
        @return  object - the associated instance data
        @throws  error if a jQuery problem getting data */
        _getInst: function (target) {
            try {
                return $.data(target, PROP_NAME);
            }
            catch (err) {
                throw 'Missing instance data for this timepicker';
            }
        },

        /* Get a setting value, defaulting if necessary. */
        _get: function (inst, name) {
            return inst.settings[name] !== undefined ?
			inst.settings[name] : this._defaults[name];
        },

        /* Parse existing time and initialise time picker. */
        _setTimeFromField: function (inst) {
            if (inst.input.val() == inst.lastVal) { return; }
            var defaultTime = this._get(inst, 'defaultTime');


            var timeToParse = this._getCurrentTimeRounded(inst);
            if (defaultTime != '') { timeToParse = defaultTime }
            if ((inst.inline == false) && (inst.input.val() != '')) { timeToParse = inst.input.val() }

            var timeVal = inst.lastVal = timeToParse;

            var time = this.parseTime(inst, timeVal);
            inst.hours = time.hours;
            inst.minutes = time.minutes;

            $.timepicker._updateTimepicker(inst);
        },
        /* Set the dates for a jQuery selection.
	    @param  target   element - the target input field or division or span
	    @param  date     Date - the new date */
	    _setTimeTimepicker: function(target, time) {
		    var inst = this._getInst(target);
		    if (inst) {
			    this._setTime(inst, time);
    			this._updateTimepicker(inst);
	    		this._updateAlternate(inst);
		    }
	    },

        /* Set the tm directly. */
        _setTime: function(inst, time, noChange) {
            var clear = !time;
            var origHours = inst.hours;
            var origMinutes = inst.minutes;
            var time = this.parseTime(inst, time);
            inst.hours = time.hours;
            inst.minutes = time.minutes;

            if ((origHours != inst.hours || origMinutes != inst.minuts) && !noChange) {
                inst.input.trigger('change');
            }
            this._updateTimepicker(inst);
            this._updateSelectedValue(inst);
        },

        /* Return the current time, ready to be parsed, rounded to the closest 5 minute */
        _getCurrentTimeRounded: function (inst) {
            var currentTime = new Date();
            var timeSeparator = this._get(inst, 'timeSeparator');
            // setting selected time , least priority first
            var currentMinutes = currentTime.getMinutes()
            // round to closest 5
            currentMinutes = Math.round( currentMinutes / 5 ) * 5;

            return currentTime.getHours().toString() + timeSeparator + currentMinutes.toString();
        },

        /*
        * Pase a time string into hours and minutes
        */
        parseTime: function (inst, timeVal) {
            var retVal = new Object();
            retVal.hours = -1;
            retVal.minutes = -1;

            var timeSeparator = this._get(inst, 'timeSeparator');
            var amPmText = this._get(inst, 'amPmText');
            var p = timeVal.indexOf(timeSeparator);
            if (p == -1) { return retVal; }

            retVal.hours = parseInt(timeVal.substr(0, p), 10);
            retVal.minutes = parseInt(timeVal.substr(p + 1), 10);

            var showPeriod = (this._get(inst, 'showPeriod') == true);
            var timeValUpper = timeVal.toUpperCase();
            if ((retVal.hours < 12) && (showPeriod) && (timeValUpper.indexOf(amPmText[1].toUpperCase()) != -1)) {
                retVal.hours += 12;
            }
            // fix for 12 AM
            if ((retVal.hours == 12) && (showPeriod) && (timeValUpper.indexOf(amPmText[0].toUpperCase()) != -1)) {
                retVal.hours = 0;
            }

            return retVal;
        },



        selectHours: function (event) {
            var $td = $(event.currentTarget);
            var id = $td.attr("data-timepicker-instance-id");
            var newHours = $td.attr("data-hour");
            var fromDoubleClick = event.data.fromDoubleClick;
            var target = $(id);
            var inst = this._getInst(target[0]);
            $td.parents('.ui-timepicker-hours:first').find('a').removeClass('ui-state-active');
            //inst.tpDiv.children('.ui-timepicker-hours a').removeClass('ui-state-active');
            $td.children('a').addClass('ui-state-active');

            inst.hours = newHours;
            this._updateSelectedValue(inst);

            inst._hoursClicked = true;
            if ((inst._minutesClicked) || (fromDoubleClick)) {
                $.timepicker._hideTimepicker();
                return false;
            }
            // added for onMinuteShow callback
            var onMinuteShow = this._get(inst, 'onMinuteShow');
            if (onMinuteShow) { this._updateMinuteDisplay(inst); }

            return false;
        },

        selectMinutes: function (event) {
            var $td = $(event.currentTarget);
            var id = $td.attr("data-timepicker-instance-id");
            var newMinutes = $td.attr("data-minute");
            var fromDoubleClick = event.data.fromDoubleClick;
            
//            console.log("selectMiutes",id, newMinutes, td, fromDoubleClick, this, id.data);
            var target = $(id);
            var inst = this._getInst(target[0]);
            $td.parents('.ui-timepicker-minutes:first').find('a').removeClass('ui-state-active');
            $td.children('a').addClass('ui-state-active');

            inst.minutes = newMinutes;
            this._updateSelectedValue(inst);

            inst._minutesClicked = true;
            if ((inst._hoursClicked) || (fromDoubleClick)) { $.timepicker._hideTimepicker(); }

            return false;
        },

        _updateSelectedValue: function (inst) {
            if ((inst.hours < 0) || (inst.hours > 23)) { inst.hours = 12; }
            if ((inst.minutes < 0) || (inst.minutes > 59)) { inst.minutes = 0; }

            var period = "";
            var showPeriod = (this._get(inst, 'showPeriod') == true);
            var showLeadingZero = (this._get(inst, 'showLeadingZero') == true);
            var amPmText = this._get(inst, 'amPmText');
            var selectedHours = inst.hours ? inst.hours : 0;
            var selectedMinutes = inst.minutes ? inst.minutes : 0;

            var displayHours = selectedHours;
            if ( ! displayHours) {
                displayHoyrs = 0;
            }


            if (showPeriod) {
                if (inst.hours == 0) {
                    displayHours = 12;
                }
                if (inst.hours < 12) {
                    period = amPmText[0];
                }
                else {
                    period = amPmText[1];
                    if (displayHours > 12) {
                        displayHours -= 12;
                    }
                }
            }

            var h = displayHours.toString();
            if (showLeadingZero && (displayHours < 10)) { h = '0' + h; }


            var m = selectedMinutes.toString();
            if (selectedMinutes < 10) { m = '0' + m; }

            var newTime = h + this._get(inst, 'timeSeparator') + m;
            if (period.length > 0) { newTime += " " + period; }

            if (inst.input) {
                inst.input.val(newTime);
                inst.input.trigger('change');
            }

            var onSelect = this._get(inst, 'onSelect');
            if (onSelect) { onSelect.apply((inst.input ? inst.input[0] : null), [newTime, inst]); } // trigger custom callback

            this._updateAlternate(inst, newTime);

            return newTime;
        },

        /* Update any alternate field to synchronise with the main field. */
        _updateAlternate: function(inst, newTime) {
            var altField = this._get(inst, 'altField');
            if (altField) { // update alternate field too
                $(altField).each(function() { $(this).val(newTime); });
            }
        }
    });



    /* Invoke the timepicker functionality.
    @param  options  string - a command, optionally followed by additional parameters or
    Object - settings for attaching new timepicker functionality
    @return  jQuery object */
    $.fn.timepicker = function (options) {

        /* Initialise the date picker. */
        if (!$.timepicker.initialized) {
            $(document).mousedown($.timepicker._checkExternalClick).
			find('body').append($.timepicker.tpDiv);
            $.timepicker.initialized = true;
        }

        var otherArgs = Array.prototype.slice.call(arguments, 1);
        if (typeof options == 'string' && (options == 'isDisabled' || options == 'getTime' || options == 'widget'))
            return $.timepicker['_' + options + 'Timepicker'].
			apply($.timepicker, [this[0]].concat(otherArgs));
        if (options == 'option' && arguments.length == 2 && typeof arguments[1] == 'string')
            return $.timepicker['_' + options + 'Timepicker'].
			apply($.timepicker, [this[0]].concat(otherArgs));
        return this.each(function () {
            typeof options == 'string' ?
			$.timepicker['_' + options + 'Timepicker'].
				apply($.timepicker, [this].concat(otherArgs)) :
			$.timepicker._attachTimepicker(this, options);
        });
    };

    /* jQuery extend now ignores nulls! */
    function extendRemove(target, props) {
        $.extend(target, props);
        for (var name in props)
            if (props[name] == null || props[name] == undefined)
                target[name] = props[name];
        return target;
    };

    $.timepicker = new Timepicker(); // singleton instance
    $.timepicker.initialized = false;
    $.timepicker.uuid = new Date().getTime();
    $.timepicker.version = "0.1.3";

    // Workaround for #4055
    // Add another global to avoid noConflict issues with inline event handlers
    window['TP_jQuery_' + tpuuid] = $;

})(jQuery);;
/*
 * Inline Form Validation Engine 2.1, jQuery plugin
 *
 * Copyright(c) 2010, Cedric Dugas
 * http://www.position-absolute.com
 *
 * 2.0 Rewrite by Olivier Refalo
 * http://www.crionics.com
 *
 * Form validation engine allowing custom regex rules to be added.
 * Licensed under the MIT License
 */
(function($) {

    var methods = {

        /**
         * Kind of the constructor, called before any action
         * @param {Map} user options
         */
        init: function(options) {
            var form = this;
            if (!form.data('jqv') || form.data('jqv') == null ) {
                methods._saveOptions(form, options);

                // bind all formError elements to close on click
                $(".formError").live("click", function() {
                    $(this).fadeOut(150, function() {

                        // remove prompt once invisible
                        $(this).remove();
                    });
                });
            }
        },
        /**
         * Attachs jQuery.validationEngine to form.submit and field.blur events
         * Takes an optional params: a list of options
         * ie. jQuery("#formID1").validationEngine('attach', {promptPosition : "centerRight"});
         */
        attach: function(userOptions) {
            var form = this;
            var options;

            if(userOptions)
                options = methods._saveOptions(form, userOptions);
            else
                options = form.data('jqv');

            if (!options.binded) {
					if (options.bindMethod == "bind"){
                        // bind fields
                        form.find("[class*=validate]:not([type=checkbox])").bind(options.validationEventTrigger, methods._onFieldEvent);
                        form.find("[class*=validate][type=checkbox]").bind("click", methods._onFieldEvent);

                        // bind form.submit
                        form.bind("submit", methods._onSubmitEvent);
					} else if (options.bindMethod == "live") {
                        // bind fields with LIVE (for persistant state)
                        form.find("[class*=validate]:not([type=checkbox])").live(options.validationEventTrigger, methods._onFieldEvent);
                        form.find("[class*=validate][type=checkbox]").live("click", methods._onFieldEvent);

                        // bind form.submit
                        form.live("submit", methods._onSubmitEvent);
					}

                options.binded = true;
            }

        },
        /**
         * Unregisters any bindings that may point to jQuery.validaitonEngine
         */
        detach: function() {
            var form = this;
            var options = form.data('jqv');
            if (options.binded) {

                // unbind fields
                form.find("[class*=validate]").not("[type=checkbox]").unbind(options.validationEventTrigger, methods._onFieldEvent);
                form.find("[class*=validate][type=checkbox]").unbind("click", methods._onFieldEvent);
                // unbind form.submit
                form.unbind("submit", methods.onAjaxFormComplete);
                
               
                // unbind live fields (kill)
                form.find("[class*=validate]").not("[type=checkbox]").die(options.validationEventTrigger, methods._onFieldEvent);
                form.find("[class*=validate][type=checkbox]").die("click", methods._onFieldEvent);
                // unbind form.submit
                form.die("submit", methods.onAjaxFormComplete);
                
                form.removeData('jqv');
            }
        },
        /**
         * Validates the form fields, shows prompts accordingly.
         * Note: There is no ajax form validation with this method, only field ajax validation are evaluated
         *
         * @return true if the form validates, false if it fails
         */
        validate: function() {
            return methods._validateFields(this);
        },
        /**
         * Validates one field, shows prompt accordingly.
         * Note: There is no ajax form validation with this method, only field ajax validation are evaluated
         *
         * @return true if the form validates, false if it fails
         */
        validateField: function(el) {
            var options = $(this).data('jqv');
            return methods._validateField($(el), options);
        },
        /**
         * Validates the form fields, shows prompts accordingly.
         * Note: this methods performs fields and form ajax validations(if setup)
         *
         * @return true if the form validates, false if it fails, undefined if ajax is used for form validation
         */
        validateform: function() {
            return methods._onSubmitEvent.call(this);
        },
        /**
         * Displays a prompt on a element.
         * Note that the element needs an id!
         *
         * @param {String} promptText html text to display type
         * @param {String} type the type of bubble: 'pass' (green), 'load' (black) anything else (red)
         * @param {String} possible values topLeft, topRight, bottomLeft, centerRight, bottomRight
         */
        showPrompt: function(promptText, type, promptPosition, showArrow) {

            var form = this.closest('form');
            var options = form.data('jqv');
            // No option, take default one
			if(!options) options = methods._saveOptions(this, options);
            if(promptPosition)
                options.promptPosition=promptPosition;
            options.showArrow = showArrow==true;

            methods._showPrompt(this, promptText, type, false, options);
        },
        /**
         * Closes all error prompts on the page
         */
        hidePrompt: function() {
        		var promptClass =  "."+ methods._getClassName($(this).attr("id")) + "formError"
            $(promptClass).fadeTo("fast", 0.3, function() {
                $(this).remove();
            });
        },
        /**
         * Closes form error prompts, CAN be invidual
         */
        hide: function() {
        	if($(this).is("form")){
        		 var closingtag = "parentForm"+$(this).attr('id');
        	}else{
        		
        		var closingtag = $(this).attr('id') +"formError"
        	}
            $('.'+closingtag).fadeTo("fast", 0.3, function() {
                $(this).remove();
            });
        },
        /**
         * Closes all error prompts on the page
         */
        hideAll: function() {
            $('.formError').fadeTo("fast", 0.3, function() {
                $(this).remove();
            });
        },
        /**
         * Typically called when user exists a field using tab or a mouse click, triggers a field
         * validation
         */
        _onFieldEvent: function() {
            var field = $(this);
            var form = field.closest('form');
            var options = form.data('jqv');
            // validate the current field
            methods._validateField(field, options);
        },
        /**
         * Called when the form is submited, shows prompts accordingly
         *
         * @param {jqObject}
         *            form
         * @return false if form submission needs to be cancelled
         */
        _onSubmitEvent: function() {
            var form = $(this);
 			var options = form.data('jqv');
   
			// validate each field (- skip field ajax validation, no necessary since we will perform an ajax form validation)
            var r=methods._validateFields(form, true);
		
            if (r && options.ajaxFormValidation) {
                methods._validateFormWithAjax(form, options);
                return false;
            }

            if(options.onValidationComplete) {
                options.onValidationComplete(form, r);
                return false;
            }
            return r;
        },

        /**
         * Return true if the ajax field validations passed so far
         * @param {Object} options
         * @return true, is all ajax validation passed so far (remember ajax is async)
         */
        _checkAjaxStatus: function(options) {
            var status = true;
            $.each(options.ajaxValidCache, function(key, value) {
                if (!value) {
                    status = false;
                    // break the each
                    return false;
                }
            });
            return status;
        },
        /**
         * Validates form fields, shows prompts accordingly
         *
         * @param {jqObject}
         *            form
         * @param {skipAjaxFieldValidation}
         *            boolean - when set to true, ajax field validation is skipped, typically used when the submit button is clicked
         *
         * @return true if form is valid, false if not, undefined if ajax form validation is done
         */
        _validateFields: function(form, skipAjaxValidation) {
            var options = form.data('jqv');

            // this variable is set to true if an error is found
            var errorFound = false;
			
			// Trigger hook, start validation
			form.trigger("jqv.form.validating")
            // first, evaluate status of non ajax fields
            form.find('[class*=validate]').not(':hidden').each( function() {
                var field = $(this);
                errorFound |= methods._validateField(field, options, skipAjaxValidation);
            });
            // second, check to see if all ajax calls completed ok
            // errorFound |= !methods._checkAjaxStatus(options);
			
            // thrird, check status and scroll the container accordingly
			form.trigger("jqv.form.result", [errorFound])
			
            if (errorFound) {
				
                if (options.scroll) {

                    // get the position of the first error, there should be at least one, no need to check this
                    //var destination = form.find(".formError:not('.greenPopup'):first").offset().top;

                    // look for the visually top prompt
                    var destination = Number.MAX_VALUE;

                    var lst = $(".formError:not('.greenPopup')");
                    for (var i = 0; i < lst.length; i++) {
                        var d = $(lst[i]).offset().top;
                        if (d < destination)
                            destination = d;
                    }

                    if (!options.isOverflown)
                        $("html:not(:animated),body:not(:animated)").animate({
                            scrollTop: destination
                        }, 1100);
                    else {
                        var overflowDIV = $(options.overflownDIV);
                        var scrollContainerScroll = overflowDIV.scrollTop();
                        var scrollContainerPos = -parseInt(overflowDIV.offset().top);

                        destination += scrollContainerScroll + scrollContainerPos - 5;
                        var scrollContainer = $(options.overflownDIV + ":not(:animated)");

                        scrollContainer.animate({
                            scrollTop: destination
                        }, 1100);
                    }
                }
                return false;
            }
            return true;
        },
        /**
         * This method is called to perform an ajax form validation.
         * During this process all the (field, value) pairs are sent to the server which returns a list of invalid fields or true
         *
         * @param {jqObject} form
         * @param {Map} options
         */
        _validateFormWithAjax: function(form, options) {

            var data = form.serialize();
			var url = (options.ajaxFormValidationURL) ? options.ajaxFormValidationURL : form.attr("action");
            $.ajax({
                type: "GET",
                url: url,
                cache: false,
                dataType: "json",
                data: data,
                form: form,
                methods: methods,
                options: options,
                beforeSend: function() {
                    return options.onBeforeAjaxFormValidation(form, options);
                },
                error: function(data, transport) {
                    methods._ajaxError(data, transport);
                },
                success: function(json) {

                    if (json !== true) {

                        // getting to this case doesn't necessary means that the form is invalid
                        // the server may return green or closing prompt actions
                        // this flag helps figuring it out
                        var errorInForm=false;
                        for (var i = 0; i < json.length; i++) {
                            var value = json[i];
						
                            var errorFieldId = value[0];
                            var errorField = $($("#" + errorFieldId)[0]);
							
                            // make sure we found the element
                            if (errorField.length == 1) {
								
                                // promptText or selector
                                var msg = value[2];
								// if the field is valid
                                if (value[1] == true) {

                                    if (msg == ""  || !msg){
                                        // if for some reason, status==true and error="", just close the prompt
                                        methods._closePrompt(errorField);
                                    } else {
                                        // the field is valid, but we are displaying a green prompt
                                        if (options.allrules[msg]) {
                                            var txt = options.allrules[msg].alertTextOk;
                                            if (txt)
                                                msg = txt;
                                        }
                                        methods._showPrompt(errorField, msg, "pass", false, options, true);
                                    }

                                } else {
                                    // the field is invalid, show the red error prompt
                                    errorInForm|=true;
                                    if (options.allrules[msg]) {
                                        var txt = options.allrules[msg].alertText;
                                        if (txt)
                                            msg = txt;
                                    }
                                    methods._showPrompt(errorField, msg, "", false, options, true);
                                }
                            }
                        }
                        options.onAjaxFormComplete(!errorInForm, form, json, options);
                    } else
                        options.onAjaxFormComplete(true, form, "", options);
                }
            });

        },
        /**
         * Validates field, shows prompts accordingly
         *
         * @param {jqObject}
         *            field
         * @param {Array[String]}
         *            field's validation rules
         * @param {Map}
         *            user options
         * @return true if field is valid
         */
        _validateField: function(field, options, skipAjaxValidation) {
            if (!field.attr("id"))
                $.error("jQueryValidate: an ID attribute is required for this field: " + field.attr("name") + " class:" +
                field.attr("class"));

            var rulesParsing = field.attr('class');
            var getRules = /validate\[(.*)\]/.exec(rulesParsing);
            if (!getRules)
                return false;
            var str = getRules[1];
            var rules = str.split(/\[|,|\]/);

            // true if we ran the ajax validation, tells the logic to stop messing with prompts
            var isAjaxValidator = false;
            var fieldName = field.attr("name");
            var promptText = "";
			var required = false;
            options.isError = false;
            options.showArrow = true;
            optional = false;

            for (var i = 0; i < rules.length; i++) {

                var errorMsg = undefined;
                switch (rules[i]) {

                    case "optional":
                        optional = true;
                        break;
                    case "required":
                        required = true;
                        errorMsg = methods._required(field, rules, i, options);
                        break;
                    case "custom":
                        errorMsg = methods._customRegex(field, rules, i, options);
                        break;
                    case "ajax":
                        // ajax has its own prompts handling technique
						if(!skipAjaxValidation){
							methods._ajax(field, rules, i, options);
	                        isAjaxValidator = true;
						}
                        break;
                    case "minSize":
                        errorMsg = methods._minSize(field, rules, i, options);
                        break;
                    case "maxSize":
                        errorMsg = methods._maxSize(field, rules, i, options);
                        break;
                    case "min":
                        errorMsg = methods._min(field, rules, i, options);
                        break;
                    case "max":
                        errorMsg = methods._max(field, rules, i, options);
                        break;
                    case "past":
                        errorMsg = methods._past(field, rules, i, options);
                        break;
                    case "future":
                        errorMsg = methods._future(field, rules, i, options);
                        break;
                    case "maxCheckbox":
                        errorMsg = methods._maxCheckbox(field, rules, i, options);
                        field = $($("input[name='" + fieldName + "']"));
                        break;
                    case "minCheckbox":
                        errorMsg = methods._minCheckbox(field, rules, i, options);
                        field = $($("input[name='" + fieldName + "']"));
                        break;
                    case "equals":
                        errorMsg = methods._equals(field, rules, i, options);
                        break;
                    case "funcCall":
                        errorMsg = methods._funcCall(field, rules, i, options);
                        break;

                    default:
                    //$.error("jQueryValidator rule not found"+rules[i]);
                }
                if (errorMsg !== undefined) {
                    promptText += errorMsg + "<br/>";
                    options.isError = true;
					
                }

            }
            // If the rules required is not added, an empty field is not validated
            if(!required){
            	if(field.val() == "") options.isError = false;
            }
            // Hack for radio/checkbox group button, the validation go into the
            // first radio/checkbox of the group
            var fieldType = field.attr("type");

            if ((fieldType == "radio" || fieldType == "checkbox") && $("input[name='" + fieldName + "']").size() > 1) {
                field = $($("input[name='" + fieldName + "'][type!=hidden]:first"));
                options.showArrow = false;
            }

            if (options.isError){
				
                methods._showPrompt(field, promptText, "", false, options);
            }else{
				if (!isAjaxValidator) methods._closePrompt(field);
			}
			field.closest('form').trigger("jqv.field.error", [field, options.isError, promptText])
            return options.isError;
        },
        /**
         * Required validation
         *
         * @param {jqObject} field
         * @param {Array[String]} rules
         * @param {int} i rules index
         * @param {Map}
         *            user options
         * @return an error string if validation failed
         */
        _required: function(field, rules, i, options) {
            switch (field.attr("type")) {
                case "text":
                case "password":
                case "textarea":
                case "file":
                default:
                    if (!field.val())
                        return options.allrules[rules[i]].alertText;
                    break;
                case "radio":
                case "checkbox":
                    var name = field.attr("name");
                    if ($("input[name='" + name + "']:checked").size() == 0) {

                        if ($("input[name='" + name + "']").size() == 1)
                            return options.allrules[rules[i]].alertTextCheckboxe;
                        else
                            return options.allrules[rules[i]].alertTextCheckboxMultiple;
                    }
                    break;
                // required for <select>
                case "select-one":
                    // added by paul@kinetek.net for select boxes, Thank you
                    if (!field.val())
                        return options.allrules[rules[i]].alertText;
                    break;
                case "select-multiple":
                    // added by paul@kinetek.net for select boxes, Thank you
                    if (!field.find("option:selected").val())
                        return options.allrules[rules[i]].alertText;
                    break;
            }
        },
        /**
         * Validate Regex rules
         *
         * @param {jqObject} field
         * @param {Array[String]} rules
         * @param {int} i rules index
         * @param {Map}
         *            user options
         * @return an error string if validation failed
         */
        _customRegex: function(field, rules, i, options) {
            var customRule = rules[i + 1];
			var rule = options.allrules[customRule];
			if(!rule) {
				alert("jqv:custom rule not found "+customRule);
				return;
			}
			
			var ex=rule.regex;
			if(!ex) {
				alert("jqv:custom regex not found "+customRule);
				return;
			}
            var pattern = new RegExp(ex);

            if (!pattern.test(field.attr('value')))
                return options.allrules[customRule].alertText;
        },
        /**
         * Validate custom function outside of the engine scope
         *
         * @param {jqObject} field
         * @param {Array[String]} rules
         * @param {int} i rules index
         * @param {Map}
         *            user options
         * @return an error string if validation failed
         */
        _funcCall: function(field, rules, i, options) {
            var functionName = rules[i + 1];
            var fn = window[functionName];
            if (typeof(fn) == 'function')
                return fn(field, rules, i, options);

        },
        /**
         * Field match
         *
         * @param {jqObject} field
         * @param {Array[String]} rules
         * @param {int} i rules index
         * @param {Map}
         *            user options
         * @return an error string if validation failed
         */
        _equals: function(field, rules, i, options) {
            var equalsField = rules[i + 1];

            if (field.attr('value') != $("#" + equalsField).attr('value'))
                return options.allrules.equals.alertText;
        },
        /**
         * Check the maximum size (in characters)
         *
         * @param {jqObject} field
         * @param {Array[String]} rules
         * @param {int} i rules index
         * @param {Map}
         *            user options
         * @return an error string if validation failed
         */
        _maxSize: function(field, rules, i, options) {
            var max = rules[i + 1];
            var len = field.attr('value').length;

            if (len > max) {
                var rule = options.allrules.maxSize;
                return rule.alertText + max + rule.alertText2;
            }
        },
        /**
         * Check the minimum size (in characters)
         *
         * @param {jqObject} field
         * @param {Array[String]} rules
         * @param {int} i rules index
         * @param {Map}
         *            user options
         * @return an error string if validation failed
         */
        _minSize: function(field, rules, i, options) {
            var min = rules[i + 1];
            var len = field.attr('value').length;

            if (len < min) {
                var rule = options.allrules.minSize;
                return rule.alertText + min + rule.alertText2;
            }
        },
        /**
         * Check number minimum value
         *
         * @param {jqObject} field
         * @param {Array[String]} rules
         * @param {int} i rules index
         * @param {Map}
         *            user options
         * @return an error string if validation failed
         */
        _min: function(field, rules, i, options) {
            var min = parseFloat(rules[i + 1]);
            var len = parseFloat(field.attr('value'));

            if (len < min) {
                var rule = options.allrules.min;
                if (rule.alertText2) return rule.alertText + min + rule.alertText2;
                return rule.alertText + min;
            }
        },
        /**
         * Check number maximum value
         *
         * @param {jqObject} field
         * @param {Array[String]} rules
         * @param {int} i rules index
         * @param {Map}
         *            user options
         * @return an error string if validation failed
         */
        _max: function(field, rules, i, options) {
            var max = parseFloat(rules[i + 1]);
            var len = parseFloat(field.attr('value'));

            if (len >max ) {
                var rule = options.allrules.max;
                if (rule.alertText2) return rule.alertText + max + rule.alertText2;
                //orefalo: to review, also do the translations
                return rule.alertText + max;
            }
        },
        /**
         * Checks date is in the past
         *
         * @param {jqObject} field
         * @param {Array[String]} rules
         * @param {int} i rules index
         * @param {Map}
         *            user options
         * @return an error string if validation failed
         */
        _past: function(field, rules, i, options) {

            var p=rules[i + 1];
            var pdate = (p.toLowerCase() == "now")? new Date():methods._parseDate(p);
            var vdate = methods._parseDate(field.attr('value'));

            if (vdate < pdate ) {
                var rule = options.allrules.past;
                if (rule.alertText2) return rule.alertText + methods._dateToString(pdate) + rule.alertText2;
                return rule.alertText + methods._dateToString(pdate);
            }
        },
        /**
         * Checks date is in the future
         *
         * @param {jqObject} field
         * @param {Array[String]} rules
         * @param {int} i rules index
         * @param {Map}
         *            user options
         * @return an error string if validation failed
         */
        _future: function(field, rules, i, options) {

            var p=rules[i + 1];
            var pdate = (p.toLowerCase() == "now")? new Date():methods._parseDate(p);
            var vdate = methods._parseDate(field.attr('value'));

            if (vdate > pdate ) {
                var rule = options.allrules.future;
                if (rule.alertText2) return rule.alertText + methods._dateToString(pdate) + rule.alertText2;
                return rule.alertText + methods._dateToString(pdate);
            }
        },
        /**
         * Max number of checkbox selected
         *
         * @param {jqObject} field
         * @param {Array[String]} rules
         * @param {int} i rules index
         * @param {Map}
         *            user options
         * @return an error string if validation failed
         */
        _maxCheckbox: function(field, rules, i, options) {

            var nbCheck = rules[i + 1];
            var groupname = field.attr("name");
            var groupSize = $("input[name='" + groupname + "']:checked").size();
            if (groupSize > nbCheck) {
                options.showArrow = false;
                if (options.allrules.maxCheckbox.alertText2) return options.allrules.maxCheckbox.alertText + " " + nbCheck + " " + options.allrules.maxCheckbox.alertText2;
                return options.allrules.maxCheckbox.alertText;
            }
        },
        /**
         * Min number of checkbox selected
         *
         * @param {jqObject} field
         * @param {Array[String]} rules
         * @param {int} i rules index
         * @param {Map}
         *            user options
         * @return an error string if validation failed
         */
        _minCheckbox: function(field, rules, i, options) {

            var nbCheck = rules[i + 1];
            var groupname = field.attr("name");
            var groupSize = $("input[name='" + groupname + "']:checked").size();
            if (groupSize < nbCheck) {
                options.showArrow = false;
                return options.allrules.minCheckbox.alertText + " " + nbCheck + " " +
                options.allrules.minCheckbox.alertText2;
            }
        },
        /**
         * Ajax field validation
         *
         * @param {jqObject} field
         * @param {Array[String]} rules
         * @param {int} i rules index
         * @param {Map}
         *            user options
         * @return nothing! the ajax validator handles the prompts itself
         */
        _ajax: function(field, rules, i, options) {
			
			
            var errorSelector = rules[i + 1];
            var rule = options.allrules[errorSelector];
            var extraData = rule.extraData;
            var extraDataDynamic = rule.extraDataDynamic;

            if (!extraData)
                extraData = "";

            if (extraDataDynamic) {
              var tmpData = [];
              var domIds = String(extraDataDynamic).split(",");
              for (var i = 0; i < domIds.length; i++) {
                var id = domIds[i];
                if ($(id).length) {
                  var inputValue = field.closest("form").find(id).attr("value");
                  var keyValue = id.replace('#', '') + '=' + escape(inputValue);
                  tmpData.push(keyValue);
                }
              }
              extraDataDynamic = tmpData.join("&");
            } else {
              extraDataDynamic = "";              
            }
                                
            if (!options.isError) {
                $.ajax({
                    type: "GET",
                    url: rule.url,
                    cache: false,
                    dataType: "json",
                    data: "fieldId=" + field.attr("id") + "&fieldValue=" + field.attr("value") + "&extraData=" + extraData + "&" + extraDataDynamic,
                    field: field,
                    rule: rule,
                    methods: methods,
                    options: options,
                    beforeSend: function() {
                        // build the loading prompt
                        var loadingText = rule.alertTextLoad;
                        if (loadingText)
                            methods._showPrompt(field, loadingText, "load", true, options);
                    },
                    error: function(data, transport) {
                        methods._ajaxError(data, transport);
                    },
                    success: function(json) {
						
                        // asynchronously called on success, data is the json answer from the server
                        var errorFieldId = json[0];
                        var errorField = $($("#" + errorFieldId)[0]);
                        // make sure we found the element
                        if (errorField.length == 1) {
                            var status = json[1];
							// read the optional msg from the server
							var msg = json[2];
                            if (!status) {
                                // Houston we got a problem - display an red prompt
                                options.ajaxValidCache[errorFieldId] = false;
                                options.isError = true;

								// resolve the msg prompt
								if(msg) {
									if (options.allrules[msg]) {
                                    	var txt = options.allrules[msg].alertText;
                                    	if (txt)
                                    		msg = txt;
                                    }
								}
								else
                                    msg = rule.alertText;
                                
								methods._showPrompt(errorField, msg, "", true, options);
                            } else {
                                if (options.ajaxValidCache[errorFieldId] !== undefined)
                                    options.ajaxValidCache[errorFieldId] = true;

                                // resolves the msg prompt
								if(msg) {
									if (options.allrules[msg]) {
							           	var txt = options.allrules[msg].alertTextOk;
							           	if (txt)
							           		msg = txt;
							        }
								}
								else
							       	msg = rule.alertTextOk;                                

								// see if we should display a green prompt
                                if (msg)
                                    methods._showPrompt(errorField, msg, "pass", true, options);
                                else
                                    methods._closePrompt(errorField);
                            }
                        }
                    }
                });
            }
        },
        /**
         * Common method to handle ajax errors
         *
         * @param {Object} data
         * @param {Object} transport
         */
        _ajaxError: function(data, transport) {
            if(data.status == 0 && transport == null)
                alert("The page is not served from a server! ajax call failed");
            else if(typeof console != "undefined")
                console.log("Ajax error: " + data.status + " " + transport);
        },
        /**
         * date -> string
         *
         * @param {Object} date
         */
        _dateToString: function(date) {

            return date.getFullYear()+"-"+(date.getMonth()+1)+"-"+date.getDate();
        },
        /**
         * Parses an ISO date
         * @param {String} d
         */
        _parseDate: function(d) {

            var dateParts = d.split("-");
            if(dateParts==d)
                dateParts = d.split("/");
            return new Date(dateParts[0], (dateParts[1] - 1) ,dateParts[2]);
        },
        /**
         * Builds or updates a prompt with the given information
         *
         * @param {jqObject} field
         * @param {String} promptText html text to display type
         * @param {String} type the type of bubble: 'pass' (green), 'load' (black) anything else (red)
         * @param {boolean} ajaxed - use to mark fields than being validated with ajax
         * @param {Map} options user options
         */
        _showPrompt: function(field, promptText, type, ajaxed, options, ajaxform) {
            var prompt = methods._getPrompt(field);
			// The ajax submit errors are not see has an error in the form,
			// When the form errors are returned, the engine see 2 bubbles, but those are ebing closed by the engine at the same time
			// Because no error was found befor submitting
			if(ajaxform) prompt = false;
            if (prompt)
                methods._updatePrompt(field, prompt, promptText, type, ajaxed, options);
            else
                methods._buildPrompt(field, promptText, type, ajaxed, options);
        },
        /**
         * Builds and shades a prompt for the given field.
         *
         * @param {jqObject} field
         * @param {String} promptText html text to display type
         * @param {String} type the type of bubble: 'pass' (green), 'load' (black) anything else (red)
         * @param {boolean} ajaxed - use to mark fields than being validated with ajax
         * @param {Map} options user options
         */
        _buildPrompt: function(field, promptText, type, ajaxed, options) {

            // create the prompt
            var prompt = $('<div>');
            prompt.addClass(methods._getClassName(field.attr("id")) + "formError");
            // add a class name to identify the parent form of the prompt
            if(field.is(":input")) prompt.addClass("parentForm"+methods._getClassName(field.parents('form').attr("id")));
            prompt.addClass("formError");

            switch (type) {
                case "pass":
                    prompt.addClass("greenPopup");
                    break;
                case "load":
                    prompt.addClass("blackPopup");
            }
            if (ajaxed)
                prompt.addClass("ajaxed");

            // create the prompt content
            var promptContent = $('<div>').addClass("formErrorContent").html(promptText).appendTo(prompt);
            // create the css arrow pointing at the field
            // note that there is no triangle on max-checkbox and radio
            if (options.showArrow) {
                var arrow = $('<div>').addClass("formErrorArrow");

                switch (options.promptPosition) {
                    case "bottomLeft":
                    case "bottomRight":
                        prompt.find(".formErrorContent").before(arrow);
                        arrow.addClass("formErrorArrowBottom").html('<div class="line1"><!-- --></div><div class="line2"><!-- --></div><div class="line3"><!-- --></div><div class="line4"><!-- --></div><div class="line5"><!-- --></div><div class="line6"><!-- --></div><div class="line7"><!-- --></div><div class="line8"><!-- --></div><div class="line9"><!-- --></div><div class="line10"><!-- --></div>');
                        break;
                    case "topLeft":
                    case "topRight":
                        arrow.html('<div class="line10"><!-- --></div><div class="line9"><!-- --></div><div class="line8"><!-- --></div><div class="line7"><!-- --></div><div class="line6"><!-- --></div><div class="line5"><!-- --></div><div class="line4"><!-- --></div><div class="line3"><!-- --></div><div class="line2"><!-- --></div><div class="line1"><!-- --></div>');
                        prompt.append(arrow);
                        break;
                }
            }

            //Cedric: Needed if a container is in position:relative
            // insert prompt in the form or in the overflown container?
            if (options.isOverflown)
            	field.before(prompt);
            else
               $("body").append(prompt);

            var pos = methods._calculatePosition(field, prompt, options);
            prompt.css({
                "top": pos.callerTopPosition,
                "left": pos.callerleftPosition,
                "marginTop": pos.marginTopSize,
                "opacity": 0
            });

            return prompt.animate({
                "opacity": 0.87
            });

        },
        /**
         * Updates the prompt text field - the field for which the prompt
         * @param {jqObject} field
         * @param {String} promptText html text to display type
         * @param {String} type the type of bubble: 'pass' (green), 'load' (black) anything else (red)
         * @param {boolean} ajaxed - use to mark fields than being validated with ajax
         * @param {Map} options user options
         */
        _updatePrompt: function(field, prompt, promptText, type, ajaxed, options) {
			
            if (prompt) {
                if (type == "pass")
                    prompt.addClass("greenPopup");
                else
                    prompt.removeClass("greenPopup");

                if (type == "load")
                    prompt.addClass("blackPopup");
                else
                    prompt.removeClass("blackPopup");

                if (ajaxed)
                    prompt.addClass("ajaxed");
                else
                    prompt.removeClass("ajaxed");

                prompt.find(".formErrorContent").html(promptText);

                var pos = methods._calculatePosition(field, prompt, options);
                prompt.animate({
                    "top": pos.callerTopPosition,
                    "marginTop": pos.marginTopSize
                });
            }
        },
        /**
         * Closes the prompt associated with the given field
         *
         * @param {jqObject}
         *            field
         */
        _closePrompt: function(field) {

            var prompt = methods._getPrompt(field);
            if (prompt)
                prompt.fadeTo("fast", 0, function() {
                    prompt.remove();
                });
        },
        closePrompt: function(field) {
            return methods._closePrompt(field);
        },
        /**
         * Returns the error prompt matching the field if any
         *
         * @param {jqObject}
         *            field
         * @return undefined or the error prompt (jqObject)
         */
        _getPrompt: function(field) {

            var className = "." + methods._getClassName(field.attr("id")) + "formError";
            var match = $(className)[0];
            if (match)
                return $(match);
        },
        /**
         * Calculates prompt position
         *
         * @param {jqObject}
         *            field
         * @param {jqObject}
         *            the prompt
         * @param {Map}
         *            options
         * @return positions
         */
        _calculatePosition: function(field, promptElmt, options) {

            var promptTopPosition, promptleftPosition, marginTopSize;
            var fieldWidth = field.width();
            var promptHeight = promptElmt.height();

            var overflow = options.isOverflown;
            if (overflow) {
                // is the form contained in an overflown container?
                promptTopPosition = promptleftPosition = 0;
                // compensation for the arrow
                marginTopSize = -promptHeight;
            } else {
                var offset = field.offset();
                promptTopPosition = offset.top;
                promptleftPosition = offset.left;
                marginTopSize = 0;
            }

            switch (options.promptPosition) {

                default:
                case "topRight":
                    if (overflow)
                        // Is the form contained in an overflown container?
                        promptleftPosition += fieldWidth - 30;
                    else {
                        promptleftPosition += fieldWidth - 30;
                        promptTopPosition += -promptHeight;
                    }
                    break;
                case "topLeft":
                    promptTopPosition += -promptHeight - 10;
                    break;
                case "centerRight":
                    promptleftPosition += fieldWidth + 13;
                    break;
                case "bottomLeft":
                    promptTopPosition = promptTopPosition + field.height() + 15;
                    break;
                case "bottomRight":
                    promptleftPosition += fieldWidth - 30;
                    promptTopPosition += field.height() + 5;
            }

            return {
                "callerTopPosition": promptTopPosition + "px",
                "callerleftPosition": promptleftPosition + "px",
                "marginTopSize": marginTopSize + "px"
            };
        },
        /**
         * Saves the user options and variables in the form.data
         *
         * @param {jqObject}
         *            form - the form where the user option should be saved
         * @param {Map}
         *            options - the user options
         * @return the user options (extended from the defaults)
         */
        _saveOptions: function(form, options) {

            // is there a language localisation ?
            if ($.validationEngineLanguage)
                var allRules = $.validationEngineLanguage.allRules;
            else
                $.error("jQuery.validationEngine rules are not loaded, plz add localization files to the page");

            var userOptions = $.extend({

                // Name of the event triggering field validation
                validationEventTrigger: "blur",
                // Automatically scroll viewport to the first error
                scroll: true,
                // Opening box position, possible locations are: topLeft,
                // topRight, bottomLeft, centerRight, bottomRight
                promptPosition: "topRight",
                bindMethod:"bind",
				// internal, automatically set to true when it parse a _ajax rule
				inlineAjax: false,
                // if set to true, the form data is sent asynchronously via ajax to the form.action url (get)
                ajaxFormValidation: false,
                // Ajax form validation callback method: boolean onComplete(form, status, errors, options)
                // retuns false if the form.submit event needs to be canceled.
				ajaxFormValidationURL: false,
                // The url to send the submit ajax validation (default to action)
                onAjaxFormComplete: $.noop,
                // called right before the ajax call, may return false to cancel
                onBeforeAjaxFormValidation: $.noop,
                // Stops form from submitting and execute function assiciated with it
                onValidationComplete: false,

                // Used when the form is displayed within a scrolling DIV
                isOverflown: false,
                overflownDIV: "",

                // --- Internals DO NOT TOUCH or OVERLOAD ---
                // validation rules and i18
                allrules: allRules,
                // true when form and fields are binded
                binded: false,
                // set to true, when the prompt arrow needs to be displayed
                showArrow: true,
                // did one of the validation fail ? kept global to stop further ajax validations
                isError: false,
                // Caches field validation status, typically only bad status are created.
                // the array is used during ajax form validation to detect issues early and prevent an expensive submit
                ajaxValidCache: {}

            }, options);

            form.data('jqv', userOptions);
            return userOptions;
        },
        
        /**
         * Removes forbidden characters from class name
         * @param {String} className
         */
        _getClassName: function(className) {
        	return className.replace(":","_").replace(".","_");
        }
    };

    /**
     * Plugin entry point.
     * You may pass an action as a parameter or a list of options.
     * if none, the init and attach methods are being called.
     * Remember: if you pass options, the attached method is NOT called automatically
     *
     * @param {String}
     *            method (optional) action
     */
    $.fn.validationEngine = function(method) {

        var form = $(this);
		  if(!form[0]) return false;  // stop here if the form does not exist
		  
        if (typeof(method) == 'string' && method.charAt(0) != '_' && methods[method]) {

            // make sure init is called once
            if(method != "showPrompt" && method != "hidePrompt" && method != "hide" && method != "hideAll") 
            	methods.init.apply(form);
             
            return methods[method].apply(form, Array.prototype.slice.call(arguments, 1));
        } else if (typeof method == 'object' || !method) {
            // default constructor with or without arguments
			methods.init.apply(form, arguments);
            return methods.attach.apply(form);
        } else {
            $.error('Method ' + method + ' does not exist in jQuery.validationEngine');
        }
    };
})(jQuery);
;

(function($){
    $.fn.validationEngineLanguage = function(){
    };
    $.validationEngineLanguage = {
        newLang: function(){
            $.validationEngineLanguage.allRules = {
                "required": { // Add your regex rules here, you can take telephone as an example
                    "regex": "none",
                    "alertText": flightright.text.required,
                    "alertTextCheckboxMultiple": flightright.text.select,
                    "alertTextCheckboxe": flightright.text.required
                },
                "min": {
                    "regex": "none",
                    "alertText": flightright.text.min
                },
                "max": {
                    "regex": "none",
                    "alertText": flightright.text.max
                }


            };
            
        }
    };
    $.validationEngineLanguage.newLang();
})(jQuery);


    
;
/*<--- --------------------------------------------------------------------------------------- ----
	
	Blog Entry:
	Binding Events To Non-DOM Objects With jQuery
	
	Author:
	Ben Nadel / Kinky Solutions
	
	Link:
	http://www.bennadel.com/index.cfm?event=blog.view&id=1520
	
	Date Posted:
	Mar 6, 2009 at 9:45 AM
	
---- --------------------------------------------------------------------------------------- ---> */


 
	// Our plugin will be defined within an immediately
	// executed method.
	(
		function( $ ){
			// Default to the current location.
			var strLocation = window.location.href;
			var strHash = window.location.hash;
			var strPrevLocation = "";
			var strPrevHash = "";

			// This is how often we will be checkint for
			// changes on the location.
			var intIntervalTime = 10;

			// This method removes the pound from the hash.
			var fnCleanHash = function( strHash ){
				return(
					strHash.substring( 1, strHash.length )
					);
			}

			// This will be the method that we use to check
			// changes in the window location.
			var fnCheckLocation = function(){
				// Check to see if the location has changed.
				if (strLocation != window.location.href){

					// Store the new and previous locations.
					strPrevLocation = strLocation;
					strPrevHash = strHash;
					strLocation = window.location.href;
					strHash = window.location.hash;

                    if(formSubmitted || strHash.indexOf('overlay') != -1 || strPrevHash.indexOf('overlay') != -1) {
                        formSubmitted = false;
                        return false;
                    }
					// The location has changed. Trigger a
					// change event on the location object,
					// passing in the current and previous
					// location values.
					$( window.location ).trigger(
						"change",
						{
							currentHref: strLocation,
							currentHash: fnCleanHash( strHash ),
							previousHref: strPrevLocation,
							previousHash: fnCleanHash( strPrevHash )
						}
						);

				}
			}

			// Set an interval to check the location changes.
			setInterval( fnCheckLocation, intIntervalTime );
		}
	)( jQuery );




;
/**
 * JS für den Entschädigungsrechner
 */
var formSubmitted = false;

(function ($) {
    $(function() {
        //document ready work
        var ccform = $('.cc-form');
        var currentstep = '';
        if(!ccform.length) {
            return;
        }

        initForm();
        // Bind a change handler to the window location.
        $( window.location ).bind(
            "change",
            function( objEvent, objData ){
              if($('body').hasClass('page-compensation')) {
                  formSubmitted = true;
                  document.location.hash = objData.previousHash;
                  alert('Bitte benutzen Sie die Navigation im Formular.')
              }

            }
            );

        if(typeof document.location.hash.split('#')[1] != 'undefined' && document.location.hash.split('#')[1].indexOf('form') > -1) {
          currentstep = document.location.hash.split('#')[1];
          navigateForm(ccform, {cc_next: currentstep, cc_validate: 'form-js-navigation'}, 'navigate');
        }

        if($('input[name=auto_submit]', ccform).val() == 'yes') {
            $('.cc-submit', ccform).click();
        }

    });

    function initForm() {
        //bind form-events
        var ccform = $('.cc-form');
        $('input[readonly=readonly], select[readonly=readonly]', ccform).addClass('readonly');
        var date = new Date();
        $('#flight_date, #alternative_flight_date, #flight_planned_arrival_date, #flight_real_arrival_date, #flight_cancellation_date, #flight_alternative_transport_date, #flight_real_departure_date').attr('autocomplete', 'off').datepicker({
            dateFormat: 'dd.mm.yy',
            maxDate: date,
            minDate: new Date(date.getFullYear() - 10 ,0 ,1)
        }).live('blur', function() {
             if(new RegExp('^([0-9]{1,22})\.([0-9]{1,2})\.([0-9]{4})$').test($(this).val())) {
                var splitDate = $(this).val().split('.');
                 if(splitDate[0].length < 2) {
                     splitDate[0] = '0' + splitDate[0];
                 }
                 if(splitDate[1].length < 2) {
                     splitDate[1] = '0' + splitDate[1];
                 }
                 $(this).val(splitDate[0] + '.' + splitDate[1] + '.' + splitDate[2]);
             }
            });
        $("#flight_cancellation_date").datepicker("option", "maxDate", $("#flight_cancellation_date").attr('rel'));

        $('#flight_time, #alternative_flight_time, #flight_planned_arrival_time, #flight_real_arrival_time, #flight_real_departure_time').attr('autocomplete', 'off').timepicker({
            hourText: flightright.text.hourText,
            minuteText: flightright.text.minuteText,
            showPeriodLabels: false,
            showLeadingZero: true,
            defaultTime: 'leer'
        }).live('blur', function() {
             if(new RegExp('^([0-9]{1,2}):([0-9]{1,2})$').test($(this).val())) {
                var splitTime = $(this).val().split(':');
                 if(splitTime[0].length < 2) {
                     splitTime[0] = '0' + splitTime[0];
                 }
                 if(splitTime[1].length < 2) {
                     splitTime[1] = '0' + splitTime[1];
                 }
                 $(this).val(splitTime[0] + ':' + splitTime[1]);
             }
            });

        fr_autocomplete('flight_from', 'airport');
        fr_autocomplete('flight_to', 'airport');
        fr_autocomplete('flight_booked_airline', 'airline');
        fr_autocomplete('flight_airline', 'airline');
        fr_autocomplete('alternative_flight_airline', 'airline');

        formLogic();

        $('input, select', ccform).live('focus', function() {ccform.validationEngine('hide');});
        $('input[type=text]', ccform).attr('maxlength', '255');

        $('.cc-submit', ccform).die('click').live('click', function() {
            var formdata = {};

            var disabled = $('input[disabled=disabled], select[disabled=disabled]', ccform);
            disabled.removeAttr('disabled');
            $.each(ccform.serializeArray(),function(){
                formdata[this.name]=this.value;
            });
            disabled.attr('disabled', 'disabled');
            ccform.validationEngine('hide');
            if(ccform.validationEngine('validate') === true) {
                formdata['cc_direction'] = 'forw';
                navigateForm(ccform, formdata, 'navigate');
            }
            return false;
        });
        $('.cc-back', ccform).die('click').live('click', function() {
            navigateForm(ccform, {cc_next: $('input[name=cc_back]', ccform).val(), cc_validate: 'form-js-navigation', cc_direction: 'back', cc_form: $('input[name=cc_form]', ccform).val()}, 'navigate');
            return false;
        });

        $('.edit-flight-link', ccform).die('click').live('click', function() {
            navigateForm(ccform, {cc_next: $(this).attr('rel'), cc_validate: 'form-js-navigation', cc_direction: 'back'}, 'navigate');
            return false;
        });

        $('.no-white-space').live('blur', function(){
            $(this).val($(this).val().replace(' ', ''));
        });

        $('#flight_leg').die('change').live('change', function() {
            if($(this).attr('rel') != $(this).val()) {
               navigateForm(ccform, {'leg': $(this).val(), 'cc_next' : 'form-start-big'}, 'change-leg');
            }
        });

        $('#flight_booked_airline').live('keyup change blur', copy_airline);
        $('#flight_airline').live('keyup', function() {
            $('#flight_booked_airline').die('keyup change blur', copy_airline);
        });

        $('#flight_booked_nr').live('keyup change blur', copy_flight_number);
        $('#flight_nr').live('keyup', function() {
            $('#flight_booked_nr').die('keyup change blur', copy_flight_number);
        });

        //Airline und Flugnummer sychronisieren
        $('#form-oag #flight_airline_id, #form-start-big #flight_booked_airline_id, #form-start-big #flight_airline_id, #form-alternative-transport-detail #alternative_flight_airline_id').die('IATA_CHANGED', sync_airline_to_flight_number).live('IATA_CHANGED', sync_airline_to_flight_number);
        $('#form-oag #flight_nr, #form-start-big #flight_booked_nr, #form-start-big #flight_nr, #form-alternative-transport-detail #alternative_flight_nr').die('keyup', sync_flight_number_to_airline).live('keyup', sync_flight_number_to_airline);

    }

    function copy_airline() {
        //Airline beim Tippen kopieren
        $('#flight_airline').val($('#flight_booked_airline').val());
        $('#flight_airline_id').val($('#flight_booked_airline_id').val());
    }

    function copy_flight_number() {
        //wenn es sich um die selbe Airline handelt, dann beim Tippen die Flugnummer kopieren
        if($('#flight_airline_id').val() == $('#flight_booked_airline_id').val()) {
            $('#flight_nr').val($('#flight_booked_nr').val());
        }
    }

    function sync_airline_to_flight_number(event) {
        if($(this).val()) {
           var flight_nr_field = $(event.currentTarget).attr('id').replace('_airline_id', '_nr');
           $('#' + flight_nr_field).val($(this).val());
           if($(event.currentTarget).attr('id') == 'flight_booked_airline_id') {
                $('#flight_nr').val($(this).val());
           }
        }
    }

    function sync_flight_number_to_airline(event) {
        var iata = $(event.currentTarget).val().substr(0,2).toUpperCase();
        var airline_field = $(event.currentTarget).attr('id').replace('_nr', '_airline');
        var airline_id_field = $(event.currentTarget).attr('id').replace('_nr', '_airline_id');
        if(iata.length == 2 && $('#' + airline_id_field).val() != iata) {
            $.ajax({
                url: flightright.autocomplete + '/airline',
                dataType: 'json',
                type: 'GET',
                data: {'term' : iata},
                success: function(data) {
                    $.each(data, function(i, e) {
                        if(e.iata == iata) {
                            $('#' + airline_id_field).val(e.iata);
                            $('#' + airline_field).val(e.name);
                            if($(event.currentTarget).attr('id') == 'flight_booked_nr') {
                                $('#flight_airline_id').val(e.iata);
                                $('#flight_airline').val(e.name);
                            }
                        }
                    });
                }
            });
        }
    }

    /* Ein-/Ausblenden von Zusatzformularen/-infos und setzen von cc_next */
    function formLogic() {

        var ccform = $('.cc-form');

        switch(ccform.attr('id')) {
            case 'form-start-multipart':
                $('input[name=flight_multipart]', ccform).die('change click').live('change click', function() {
                    if($(this).val() == 'yes') {
                        $('#flight_multipart_airline_box', ccform).slideDown();
                    } else {
                        $('#flight_multipart_airline_box', ccform).slideUp();
                    }
                });
                $('input[name=flight_multipart_airline]', ccform).die('change click').live('change click', function() {
                    if($(this).val() == 'yes') {
                        $('#flight_multipart_airline_box .form-hint', ccform).slideUp();
                    } else {
                        $('#flight_multipart_airline_box .form-hint', ccform).slideDown();
                    }
                });
                break;
            break;
            case 'form-start-big':
                $('#flight_cancelled:not(.readonly)', ccform).die('change click').live('change click', function() {
                    $('#flight_delayed_detail_box', ccform).hide();
                    $('#flight_nottransported_detail_box', ccform).hide();
                    $('input[name=cc_next]', ccform).val($(this).attr('rel'));
                });
                $('#flight_delayed:not(.readonly)', ccform).die('change click').live('change click', function() {
                    $('#flight_delayed_detail_box', ccform).slideDown();
                    $('#flight_nottransported_detail_box', ccform).slideUp();
                    $('input[name=cc_next]', ccform).val($(this).attr('rel'));
                });
                $('#flight_nottransported:not(.readonly)', ccform).die('change click').live('change click', function() {
                    $('#flight_nottransported_detail_box', ccform).slideDown();
                    $('#flight_delayed_detail_box', ccform).slideUp();
                    $('input[name=cc_next]', ccform).val($(this).attr('rel'));

                });
                break;

            case 'form-alternative-transport':
                $('input[name=flight_alternative]', ccform).die('change click').live('change click', function() {
                    if($(this).val() == 'yes') {
                        $('input[name=cc_next]', ccform).val($('#flight_alternative_yes', ccform).attr('rel'));
                    }
                    if($(this).val() == 'no') {
                        $('input[name=cc_next]', ccform).val($('#flight_alternative_no', ccform).attr('rel'));
                    }
                });
                break;
            case 'form-alternative-transport-flight':
                if($('#flight_planned_arrival_date', ccform).val() == '') {
                    $('#flight_planned_arrival_date', ccform).val($('#flight_planned_arrival_date', ccform).attr('alt'));
                }
                if($('#flight_real_departure_date', ccform).val() == '') {
                    $('#flight_real_departure_date', ccform).val($('#flight_real_departure_date', ccform).attr('alt'));
                }
                if($('#flight_real_arrival_date', ccform).val() == '') {
                    $('#flight_real_arrival_date', ccform).val($('#flight_real_arrival_date', ccform).attr('alt'));
                }
                break;

            case 'form-delay-reasons':
                $('select[name=flight_delay_reason_main]', ccform).die('change').live('change', function() {
                    $('.flight_delay_reason_sub', ccform).hide().attr('name', 'temp');
                    $('#flight_delay_reason_sub_' + $(this).val(), ccform).show().attr('name', 'flight_delay_reason_sub');
                });
                break;

            case 'form-next-part':
                $('input[name=flight_next_part]', ccform).die('change click').live('change click', function() {
                    if($(this).val() == 'yes') {
                        $('input[name=cc_next]', ccform).val($('#flight_next_part_yes', ccform).attr('rel'));
                    }
                    if($(this).val() == 'no') {
                        $('input[name=cc_next]', ccform).val($('#flight_next_part_no', ccform).attr('rel'));
                    }
                });
                break;

            case 'form-calc-compensation':
                $('select[name=flight_passengers_amount]', ccform).die('change').live('change', function() {
                    if($(this).val() > 1) {
                        $('input[name=cc_next]', ccform).val($('option:selected', this).attr('rel'));
                    } else {
                        $('input[name=cc_next]', ccform).val($('option:selected', this).attr('rel'));
                    }
                });
                break;

            case 'form-received-compensation':
                $('input[name=flight_received_compensation]', ccform).die('change click').live('change click', function() {
                    if($(this).val() == 'yes') {
                        $('#flight_received_compensation_box', ccform).slideDown();
                    } else {
                        $('#flight_received_compensation_box', ccform).slideUp();
                    }
                });
                $('input[name=flight_received_compensation_money_sum]', ccform).die('change').live('change', function() {
                   if($(this).val() != '') {
                       $('input[name=flight_received_compensation_money]', ccform).attr('checked', 'checked')
                   }
                });
                $('input[name=flight_received_compensation_voucher_sum]', ccform).die('change').live('change', function() {
                   if($(this).val() != '') {
                       $('input[name=flight_received_compensation_voucher]', ccform).attr('checked', 'checked')
                   }
                });
                $('input[name=flight_received_compensation_ask]', ccform).die('change click').live('change click', function() {
                    if($(this).val() == 'yes') {
                        $('#flight_received_compensation_ask_box', ccform).slideDown();
                    } else {
                        $('#flight_received_compensation_ask_box', ccform).slideUp();
                    }
                });
                break;

            case 'form-costs':
                $('input[name=flight_costs]', ccform).die('change click').live('change click', function() {
                    if($(this).val() == 'yes') {
                        $('#flight_costs_box', ccform).slideDown();
                        $('.flight_costs_checkbox .input-checkbox:checked', ccform).parents('.flight_costs_checkbox').next('.flight_costs_text').find('.flight_costs_data').show();
                    } else {
                        $('#flight_costs_box', ccform).slideUp();
                    }
                });
                $('.flight_costs_checkbox .input-checkbox', ccform).die('change click').live('change click', function() {
                    if($(this).attr('checked') == 'checked' || $(this).attr('checked') == true) {
                        $(this).parents('.flight_costs_checkbox').next('.flight_costs_text').find('.flight_costs_data').slideDown();
                    } else {
                        $(this).parents('.flight_costs_checkbox').next('.flight_costs_text').find('.flight_costs_data').slideUp();
                    }
                });
                break;

            case 'form-alternative-transport-detail':
                $('select[name=flight_alternative_means_of_transport]', ccform).die('change').live('change', function() {
                    if($(this).val() == 'plane') {
                        $('#alternative_transport_info', ccform).slideUp();
                        $('#alternative_flight_info', ccform).slideDown();
                    } else if($(this).val() == 'train' || $(this).val() == 'bus') {
                        $('#alternative_flight_info', ccform).slideUp();
                        $('#alternative_transport_info', ccform).slideDown();
                    } else {
                        $('#alternative_flight_info', ccform).slideUp();
                        $('#alternative_transport_info', ccform).slideUp();
                    }
                });
                break;
            case 'form-reimbursement':
                $('input[name=flight_reimbursement]', ccform).die('change click').live('change click', function() {
                    if($(this).val() == 'yes') {
                        $('#flight_ticket_price_box', ccform).slideDown();
                    } else {
                        $('#flight_ticket_price_box', ccform).slideUp();
                    }
                });
                break;
            case 'form-finish':
                //conversion FLIGHT-601
                if(typeof(_vis_opt_top_initialize) == "function") {
                   // Code for Custom Goal: Formular fertig
                    _vis_opt_register_conversion(1,2);
                    _vis_opt_pause(500);
                   }
                break;
        }

        var readonly = $('input.readonly, select.readonly');
        readonly.removeClass('readonly');
        $('input[type=radio]:checked', ccform).trigger('click');
        $('select', ccform).trigger('change');
        readonly.addClass('readonly').live('click change', function() {return false;});
        readonly.die('click', switchReadonly).live('click', switchReadonly);

        $('form#form-message a.cc_edit_oag').live('click', switchReadonly);
        ccform.attr('autocomplete', 'false');

    }

    function navigateForm(ccform, formdata, action) {
        if(!ccform.hasClass('inProgress')) {
            ccform.addClass('inProgress');
            ccform.animate({opacity: 0.2}, 200, 'linear', function() {
                $.ajax({
                        url: flightright.action,
                        dataType: 'json',
                        type: 'POST',
                        data: {'data' : formdata, 'action' : action},
                        success: function(data) {
                            $('form').validationEngine('hideAll');
                            if(data.errors.length) {
                                $.each(data.errors, function(i, el) {
                                   $('#' + el.field + ', #' + el.field + '_yes, #' + el.field + '_no').validationEngine('showPrompt', el.error, 'error');
                                });
                            } else if (data.message && data.message.title) {
                                var buttons = new Array();
                                buttons.push({
                                    text : flightright.text.manual_input,
                                    click : function() {
                                        formSubmitted = true;
                                        var loc = document.location.href;
                                        if(ccform.attr('id') != 'form-alternative-transport-detail') {
                                            document.location.href = flightright.calc + '#form-start-big';
                                            if(loc.indexOf(flightright.calc) > 0) {
                                                document.location.reload();
                                            }
                                        } else {
                                            document.location.reload();
                                        }
                                    }});
                                buttons.push({
                                    text: flightright.text.cancel,
                                    click: function() {
                                        $(this).dialog( "close");
                                        $("#dialog:ui-dialog").dialog("destroy");
                                        ccform.css({opacity: 1});
                                        ccform.removeClass('inProgress');
                                    }
                                });
                                showDialog(
                                    data.message.title,
                                    data.message.text,
                                    buttons
                                 );
                            } else if($('#block-flightright-start-form #form-start').length > 0 || $('#block-flightright-start-form #form-oag').length > 0) {
                                formSubmitted = true;
                                document.location.href = flightright.calc + '#form-start-big';
                                return;
                            } else if(data.session > 0 || formdata['cc_next'] == 'form-start' || formdata['cc_next'] == 'form-start-big' || formdata['cc_next'] == 'form-finish') {
                                formSubmitted = true;
                                if(data.stop != 'form-stop') {
                                    document.location.hash='#' + formdata['cc_next'];
                                }
                                ccform.replaceWith(data.html);
                                $('.cc-form').show('fast');
                                initForm();
                                $('#flight_data_block').html('');
                                $.each(data.status, function(index, value) {
                                    $('#flight_data_block').append('<li>' + value + '</li>');
                                });
                                if(typeof(_vis_opt_GA_track) == "function") { _vis_opt_GA_track(); }
                                _gaq.push(['_trackPageview', $('.cc-form input[name=cc_pos]').val() + '_' + $('.cc-form').attr('id').replace('form-', '') + (typeof(formdata['cc_direction']) != 'undefined' ? ('_' + formdata['cc_direction']) : '')]);
                            } else {
                                formSubmitted = true;
                                document.location.href = flightright.calc;
                            }

                            if(!data.errors.length) {
                                $.each(data['cc-form'], function(item_name, item_value) {
                                    if(item_value.value == '' && item_value.oag_empty_hint == true) {
                                        $('#' + item_name + ', #' + item_name + '_yes, #' + item_name + '_no, .cc-form input[name=' + item_name + ']:first').validationEngine('showPrompt', flightright.text.oag_no_data, 'pass');
                                    }
                                });
                            }

                            ccform.css({opacity: 1});
                            $('html,body').animate({scrollTop: 150}, 1000);
                            ccform.removeClass('inProgress');
                        }
                    });
            });
        }
    }

    function fr_autocomplete(id, type) {
        var ac_minlength = 2;
        try {
            $('#' + id).attr('autocomplete', 'off').autocomplete({
                minLength: ac_minlength,
                source: flightright.autocomplete + '/' + type,
                focus: function( event, ui ) {
                    $('#' + id).val( ui.item.name );
                    return false;
                },
                select: function( event, ui ) {
                    $('#' + id).val( ui.item.name );
                    $('#' + id + '_id').val( ui.item.iata ).trigger('IATA_CHANGED');


                    return false;
                },
                search: function( event, ui ) {
                    $('#' + id + '_id').val('').trigger('IATA_CHANGED');
                },
                close: function( event, ui ) {
                    if($('#' + id).val().length > ac_minlength && $('#' + id + '_id').val() == '') {
                        var ac_data = $('#autocomplete-' + id + ' li:first').data('item.autocomplete');
                        $('#' + id + '_id').val(ac_data.iata).trigger('IATA_CHANGED');
                        $('#' + id).val(ac_data.name);
                    }
                }

            })
            .data( "autocomplete" )
            ._renderItem = function( ul, item ) {
                ul.attr('id', 'autocomplete-' + id);
                return $( "<li></li>" )
                    .data( "item.autocomplete", item )
                    .append( "<a>" + item.name + "</a>" )

                    .appendTo( ul );
            };
        } catch(e) {}

    }

    function showDialog(title, text, buttonlist) {
            $("#dialog:ui-dialog").dialog("destroy");
            if(!$("#dialog-confirm").length) {
                $('body').append('<div id="dialog-confirm">	<p><span class="ui-icon ui-icon-alert" style="float:left; margin:0 7px 20px 0;"></span><span class="dialog-text"></span></p></div>');
            }
            var dialogContainer = $("#dialog-confirm");
            dialogContainer.attr('title', title);
            $('.dialog-text', dialogContainer).html(text);
            dialogContainer.dialog({
                resizable: false,
                autoOpen: false,
                height:140,
                modal: true,
                buttons: buttonlist
            });

            dialogContainer.dialog('open');
    }

    function switchReadonly(event) {
        var buttons = new Array();
        buttons.push({
            text : flightright.text.yes,
            click : function() {
            $('input.readonly, select.readonly').removeAttr('readonly').removeClass('readonly');
            $(this).dialog("close");
            $("#dialog:ui-dialog").dialog("destroy");
            $('.cc-form').append('<input type="hidden" name="oag_readonly" value="off" />');
            if($(event.currentTarget).hasClass('cc_edit_oag')) {
                navigateForm($('.cc-form'), {cc_next: $('.cc-form input[name=cc_back]').val(), cc_validate: 'form-js-navigation', cc_direction: 'back', cc_form: $('.cc-form input[name=cc_form]').val(), oag_readonly: $('.cc-form input[name=oag_readonly]').val()}, 'navigate');
            } else {
                $(event.currentTarget).trigger(event.type);
            }
        }});
        buttons.push({
            text: flightright.text.no,
            click: function() {$(this).dialog("close"); $( "#dialog:ui-dialog" ).dialog("destroy");}
        });

        showDialog(
            flightright.text.hint,
            flightright.text.oag_disabled_dialog,
            buttons
        );
        return false;
    }

})(jQuery);


;
﻿/* German initialisation for the jQuery UI date picker plugin. */
/* Written by Milian Wolff (mail@milianw.de). */
jQuery(function($){
	$.datepicker.regional['de'] = {
		closeText: 'schließen',
		prevText: '&#x3c;zurück',
		nextText: 'Vor&#x3e;',
		currentText: 'heute',
		monthNames: ['Januar','Februar','März','April','Mai','Juni',
		'Juli','August','September','Oktober','November','Dezember'],
		monthNamesShort: ['Jan','Feb','Mär','Apr','Mai','Jun',
		'Jul','Aug','Sep','Okt','Nov','Dez'],
		dayNames: ['Sonntag','Montag','Dienstag','Mittwoch','Donnerstag','Freitag','Samstag'],
		dayNamesShort: ['So','Mo','Di','Mi','Do','Fr','Sa'],
		dayNamesMin: ['So','Mo','Di','Mi','Do','Fr','Sa'],
		weekHeader: 'Wo',
		dateFormat: 'dd.mm.yy',
		firstDay: 1,
		isRTL: false,
		showMonthAfterYear: false,
		yearSuffix: ''};
	$.datepicker.setDefaults($.datepicker.regional['de']);
});
;

