(function() {
    function IntervalCalendar(container, cfg) {
	/**
	* The interval state, which counts the number of interval endpoints that have
	* been selected (0 to 2).
	* 
	* @private
	* @type Number
	*/
	this._iState = 0;

	// Must be a multi-select CalendarGroup
	cfg = cfg || {};
	cfg.multi_select = true;

	// Call parent constructor
	IntervalCalendar.superclass.constructor.call(this, container, cfg);

	// Subscribe internal event handlers
	this.beforeSelectEvent.subscribe(this._intervalOnBeforeSelect, this, true);
	this.selectEvent.subscribe(this._intervalOnSelect, this, true);
	this.beforeDeselectEvent.subscribe(this._intervalOnBeforeDeselect, this, true);
	this.deselectEvent.subscribe(this._intervalOnDeselect, this, true);
    }

    /**
    * Default configuration parameters.
    * 
    * @property IntervalCalendar._DEFAULT_CONFIG
    * @final
    * @static
    * @private
    * @type Object
    */
    IntervalCalendar._DEFAULT_CONFIG = YAHOO.widget.CalendarGroup._DEFAULT_CONFIG;

    YAHOO.lang.extend(IntervalCalendar, YAHOO.widget.CalendarGroup, {

	/**
	* Returns a string representation of a date which takes into account
	* relevant localization settings and is suitable for use with
	* YAHOO.widget.CalendarGroup and YAHOO.widget.Calendar methods.
	* 
	* @method _dateString
	* @private
	* @param {Date} d The JavaScript Date object of which to obtain a string representation.
	* @return {String} The string representation of the JavaScript Date object.
	*/
	_dateString : function(d) {
	    var a = [];
	    a[this.cfg.getProperty(IntervalCalendar._DEFAULT_CONFIG.MDY_MONTH_POSITION.key)-1] = (d.getMonth() + 1);
	    a[this.cfg.getProperty(IntervalCalendar._DEFAULT_CONFIG.MDY_DAY_POSITION.key)-1] = d.getDate();
	    a[this.cfg.getProperty(IntervalCalendar._DEFAULT_CONFIG.MDY_YEAR_POSITION.key)-1] = d.getFullYear();
	    var s = this.cfg.getProperty(IntervalCalendar._DEFAULT_CONFIG.DATE_FIELD_DELIMITER.key);
	    return a.join(s);
	},

	/**
	* Given a lower and upper date, returns a string representing the interval
	* of dates between and including them, which takes into account relevant
	* localization settings and is suitable for use with
	* YAHOO.widget.CalendarGroup and YAHOO.widget.Calendar methods.
	* <p>
	* <b>Note:</b> No internal checking is done to ensure that the lower date
	* is in fact less than or equal to the upper date.
	* </p>
	* 
	* @method _dateIntervalString
	* @private
	* @param {Date} l The lower date of the interval, as a JavaScript Date object.
	* @param {Date} u The upper date of the interval, as a JavaScript Date object.
	* @return {String} The string representing the interval of dates between and
	*                   including the lower and upper dates.
	*/
	_dateIntervalString : function(l, u) {
	    var s = this.cfg.getProperty(IntervalCalendar._DEFAULT_CONFIG.DATE_RANGE_DELIMITER.key);
	    return (this._dateString(l)
	            + s + this._dateString(u));
	},

	/**
	* Returns the lower and upper dates of the currently selected interval, if an
	* interval is selected.
	* 
	* @method getInterval
	* @return {Array} An empty array if no interval is selected; otherwise an array
	*                 consisting of two JavaScript Date objects, the first being the
	*                 lower date of the interval and the second being the upper date.
	*/
	getInterval : function() {
	    // Get selected dates
	    var dates = this.getSelectedDates();
	    if(dates.length > 0) {
	        // Return lower and upper date in array
	        var l = dates[0];
	        var u = dates[dates.length - 1];
	        return [l, u];
	    }
	    else {
	        // No dates selected, return empty array
	        return [];
	    }
	},

	/**
	* Sets the currently selected interval by specifying the lower and upper
	* dates of the interval (in either order).
	* <p>
	* <b>Note:</b> The render method must be called after setting the interval
	* for any changes to be seen.
	* </p>
	* 
	* @method setInterval
	* @param {Date} d1 A JavaScript Date object.
	* @param {Date} d2 A JavaScript Date object.
	*/
	setInterval : function(d1, d2) {
	    // Determine lower and upper dates
	    var b = (d1 <= d2);
	    var l = b ? d1 : d2;
	    var u = b ? d2 : d1;
	    // Update configuration
	    this.cfg.setProperty('selected', this._dateIntervalString(l, u), false);
	    this._iState = 2;
	},

	/**
	* Resets the currently selected interval.
	* <p>
	* <b>Note:</b> The render method must be called after resetting the interval
	* for any changes to be seen.
	* </p>
	* 
	* @method resetInterval
	*/
	resetInterval : function() {
	    // Update configuration
	    this.cfg.setProperty('selected', [], false);
	    this._iState = 0;
	},

	/**
	* Handles beforeSelect event.
	* 
	* @method _intervalOnBeforeSelect
	* @private
	*/
	_intervalOnBeforeSelect : function(t,a,o) {
	    // Update interval state
	    this._iState = (this._iState + 1) % 3;
	    if(this._iState == 0) {
	        // If starting over with upcoming selection, first deselect all
	        this.deselectAll();
	        this._iState++;
	    }
	},

	/**
	* Handles selectEvent event.
	* 
	* @method _intervalOnSelect
	* @private
	*/
	_intervalOnSelect : function(t,a,o) {
	    // Get selected dates
	    var dates = this.getSelectedDates();
	    if(dates.length > 1) {
	        /* If more than one date is selected, ensure that the entire interval
	            between and including them is selected */
	        var l = dates[0];
	        var u = dates[dates.length - 1];
	        this.cfg.setProperty('selected', this._dateIntervalString(l, u), false);
	    }
	    // Render changes
	    this.render();
	},

	/**
	* Handles beforeDeselect event.
	* 
	* @method _intervalOnBeforeDeselect
	* @private
	*/
	_intervalOnBeforeDeselect : function(t,a,o) {
	    if(this._iState != 0) {
	        /* If part of an interval is already selected, then swallow up
	            this event because it is superfluous (see _intervalOnDeselect) */
	        return false;
	    }
	},

	/**
	* Handles deselectEvent event.
	*
	* @method _intervalOnDeselect
	* @private
	*/
	_intervalOnDeselect : function(t,a,o) {
	    if(this._iState != 0) {
	        // If part of an interval is already selected, then first deselect all
	        this._iState = 0;
	        this.deselectAll();

	        // Get individual date deselected and page containing it
	        var d = a[0][0];
	        var date = YAHOO.widget.DateMath.getDate(d[0], d[1] - 1, d[2]);
	        var page = this.getCalendarPage(date);
	        if(page) {
	            // Now (re)select the individual date
	            page.beforeSelectEvent.fire();
	            this.cfg.setProperty('selected', this._dateString(date), false);
	            page.selectEvent.fire([d]);
	        }
	        // Swallow up since we called deselectAll above
	        return false;
	    }
	}
    });

    YAHOO.namespace("example.calendar");
    YAHOO.example.calendar.IntervalCalendar = IntervalCalendar;
})();


$(function () {
    if (!intervalSelect) {
	    return;
    }

    $('#interval1').attr('width', '45%');
    $('#interval2').attr('width', '55%');
    
    var inTxt = YAHOO.util.Dom.get("pickup_date_plain"),
	outTxt = YAHOO.util.Dom.get("return_date_plain"),
	inField = YAHOO.util.Dom.get("pickup_date"),
	outField = YAHOO.util.Dom.get("return_date"),
	inDate, outDate, interval;

    var placeholder = 'bitte ausw&auml;hlen';

    if ($('#pickup_date').val() == '') {
    	$('#pickup_date_plain').html(placeholder);
    } else {
    	$('#pickup_date_plain').html($('#pickup_date').val());
    }
    if ($('#return_date').val() == '') {
    	$('#return_date_plain').html(placeholder);
    } else {
    	$('#return_date_plain').html($('#return_date').val());
    }

    $('#pickup_date, #return_date, .date_picker').hide();

    var cal = new YAHOO.example.calendar.IntervalCalendar("cal1Container", {pages:2});

    cal.cfg.setProperty("DATE_FIELD_DELIMITER", ".");
    cal.cfg.setProperty("MDY_DAY_POSITION", 1);
    cal.cfg.setProperty("MDY_MONTH_POSITION", 2);
    cal.cfg.setProperty("MDY_YEAR_POSITION", 3);
    cal.cfg.setProperty("MD_DAY_POSITION", 1);
    cal.cfg.setProperty("MD_MONTH_POSITION", 2);
    if (culture == 'en') {
        cal.cfg.setProperty("MONTHS_SHORT",   ["Jan", "Feb", "Mar", "Apr", "Mai", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dez"]);
        cal.cfg.setProperty("MONTHS_LONG",    ["January", "February", "March", "April", "Mai", "June", "July", "August", "September", "October", "November", "Dezember"]);
        cal.cfg.setProperty("WEEKDAYS_1CHAR", ["S", "M", "T", "W", "T", "F", "S"]);
        cal.cfg.setProperty("WEEKDAYS_SHORT", ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"]);
        cal.cfg.setProperty("WEEKDAYS_MEDIUM",["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]);
        cal.cfg.setProperty("WEEKDAYS_LONG",  ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]);
    } else {
        cal.cfg.setProperty("MONTHS_SHORT",   ["Jan", "Feb", "M\u00E4r", "Apr", "Mai", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dez"]);
        cal.cfg.setProperty("MONTHS_LONG",    ["Januar", "Februar", "M\u00E4rz", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"]);
        cal.cfg.setProperty("WEEKDAYS_1CHAR", ["S", "M", "D", "M", "D", "F", "S"]);
        cal.cfg.setProperty("WEEKDAYS_SHORT", ["So", "Mo", "Di", "Mi", "Do", "Fr", "Sa"]);
        cal.cfg.setProperty("WEEKDAYS_MEDIUM",["Son", "Mon", "Die", "Mit", "Don", "Fre", "Sam"]);
        cal.cfg.setProperty("WEEKDAYS_LONG",  ["Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag"]);
    }


    cal.cfg.setProperty("HIDE_BLANK_WEEKS", true);
    var curtime = new Date().getTime();
    cal.cfg.setProperty("MINDATE", formatDate(new Date(curtime + 86400000)));
    cal.cfg.setProperty("MAXDATE", formatDate(new Date(curtime + 330 * 86400000)));

    if ($('#pickup_date').val() != '' && $('#return_date').val() != '') {
	cal.setInterval(makeDate($('#pickup_date').val()), makeDate($('#return_date').val()));
	cal.cfg.setProperty("PAGEDATE", $('#pickup_date').val().substr(3));
    } else {
	cal.cfg.setProperty("PAGEDATE", formatDate(new Date(curtime + 86400000)).substr(3));
    }

    $('#cal1Container').CreateBubblePopup({ innerHtml: (culture == 'en' ? 'Please click on your desired pick-up date!' : 'Bitte klicken Sie den Anmiettag an!'), themeName: 'orange', innerHtmlStyle: { padding: '7px' } });
    setTimeout(function() {
	if ($('#cal1Container').HasBubblePopup()) {
		$('#cal1Container').ShowBubblePopup();
	}
    },6500);
    $("#pickup_date_wrapper, #return_date_wrapper").click(function() {
        $('#cal1Container').css('background-color', '#AACCE3');
	if ($('#cal1Container').HasBubblePopup()) {
		$('#cal1Container').ShowBubblePopup();
	}
    });

    cal.selectEvent.subscribe(function() {
	interval = this.getInterval();

	if (interval.length == 2) {
	    inDate = interval[0];
	    inTxt.innerHTML = formatDate(inDate);
	    inField.value = formatDate(inDate);

	    if (interval[0].getTime() != interval[1].getTime()) {
	        outDate = interval[1];
	        outTxt.innerHTML = formatDate(outDate);
		outField.value = formatDate(outDate);
		$('#cal1Container').RemoveBubblePopup();
		$('#cal1Container').CreateBubblePopup({ innerHtml: (culture == 'en' ? 'Change the selected period? Please click on your desired pick-up date first!' : 'Zeitraum ändern? Bitte klicken Sie zunächst den Anmiettag an!'), themeName: 'orange', innerHtmlStyle: { padding: '7px' }, openingDelay: 1000 });
	    } else {
	        outTxt.innerHTML = placeholder;
		outField.value = '';
		$('#cal1Container').RemoveBubblePopup();
		$('#cal1Container').CreateBubblePopup({ innerHtml: (culture == 'en' ? 'Thanks! Please click on the desired drop-off date now!' : 'Danke! Klicken Sie nun bitte den Rückgabetag an!'), mouseOut: 'show', themeName: 'orange', innerHtmlStyle: { padding: '7px' } }).ShowBubblePopup();
	    }
	}
    }, cal, true);

    cal.render();
});

function formatDate(d) {
	return zeroPad(d.getDate(), 2) + "." + zeroPad(d.getMonth() + 1, 2) + "." + d.getFullYear()
}

function makeDate(d) {
	return new Date(d.substr(6,4), d.substr(3,2) - 1, d.substr(0,2));
}

function zeroPad(num,count)
{
	var numZeropad = num + '';
	while(numZeropad.length < count) {
		numZeropad = "0" + numZeropad;
	}
	return numZeropad;
}

