/**
* iCalendarGroup is an extension of the CalendarGroup designed specifically
* for the selection of an interval of dates.
* <p>
* Requires CalendarGroup version 2.5.1+
* </p>
* 
* @namespace YAHOO.whardy.widget
* @module icalendargroup
* @title iCalendarGroup
* @requires yahoo, dom, event, calendar
* @author John Peloquin, W. Hardy Interactive <john@whardy.com>
* @version 0.1
*/
YAHOO.namespace('whardy.widget');

/**
* iCalendarGroup is an extension of the CalendarGroup designed specifically
* for the selection of an interval of dates, as opposed to a single date or
* an arbitrary collection of dates.
* <p>
* <b>Note:</b> when using iCalendarGroup, dates should not be selected or
* deselected using the 'selected' configuration property or any of the
* CalendarGroup select/deselect methods. Doing so will corrupt the internal
* state of the control. Instead, use the provided methods setInterval and
* resetInterval.
* </p>
* <p>
* Similarly, when handling select/deselect/etc. events, do not use the
* dates passed in the arguments to attempt to keep track of the currently
* selected interval. Instead, use getInterval.
* </p>
* 
* @namespace YAHOO.whardy.widget
* @class iCalendarGroup
* @extends YAHOO.widget.CalendarGroup
* @constructor
* @param {String | HTMLElement} ctr The id of, or reference to, an HTML DIV element which will contain the control.
* @param {Object} cfg optional The initial configuration options for the control.
*/
YAHOO.whardy.widget.iCalendarGroup = function(ctr, cfg) {
	/**
	* The interval state, which counts the number of interval endpoints that have
	* been selected (0 to 2).
	* 
	* @type Number
	*/
	this._iState = 0;
	
	if(YAHOO.lang.isUndefined(cfg)) {
		var cfg = {};
	}
	
	// Must be a multi-select CalendarGroup
	cfg.multi_select = true;
	
	// Call parent constructor
	YAHOO.whardy.widget.iCalendarGroup.superclass.constructor.call(this, ctr, cfg);
	
	// Subscribe internal event handlers
	this.beforeSelectEvent.subscribe(this._iOnBeforeSelect, this, true);
	this.selectEvent.subscribe(this._iOnSelect, this, true);
	this.beforeDeselectEvent.subscribe(this._iOnBeforeDeselect, this, true);
	this.deselectEvent.subscribe(this._iOnDeselect, this, true);

}; YAHOO.lang.extend(YAHOO.whardy.widget.iCalendarGroup, YAHOO.widget.CalendarGroup);

/**
* Default configuration parameters.
* 
* @property YAHOO.whardy.widget.iCalendarGroup._DEFAULT_CONFIG
* @final
* @static
* @private
* @type Object
*/
YAHOO.whardy.widget.iCalendarGroup._DEFAULT_CONFIG = YAHOO.widget.CalendarGroup._DEFAULT_CONFIG;

/**
* 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.
*/
YAHOO.whardy.widget.iCalendarGroup.prototype._dateString = function(d) {
	var a = new Array();
	a[this.cfg.getProperty(YAHOO.whardy.widget.iCalendarGroup._DEFAULT_CONFIG.MDY_MONTH_POSITION.key)-1] = (d.getMonth() + 1);
	a[this.cfg.getProperty(YAHOO.whardy.widget.iCalendarGroup._DEFAULT_CONFIG.MDY_DAY_POSITION.key)-1] = d.getDate();
	a[this.cfg.getProperty(YAHOO.whardy.widget.iCalendarGroup._DEFAULT_CONFIG.MDY_YEAR_POSITION.key)-1] = d.getFullYear();
	var s = this.cfg.getProperty(YAHOO.whardy.widget.iCalendarGroup._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.
*/
YAHOO.whardy.widget.iCalendarGroup.prototype._dateIntervalString = function(l, u) {
	var s = this.cfg.getProperty(YAHOO.whardy.widget.iCalendarGroup._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.
*/
YAHOO.whardy.widget.iCalendarGroup.prototype.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.
*/
YAHOO.whardy.widget.iCalendarGroup.prototype.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
*/
YAHOO.whardy.widget.iCalendarGroup.prototype.resetInterval = function() {
	// Update configuration
	this.cfg.setProperty('selected', [], false);
	this._iState = 0;
}

/**
* Handles beforeSelect event.
* 
* @method _iOnBeforeSelect
* @private
*/
YAHOO.whardy.widget.iCalendarGroup.prototype._iOnBeforeSelect = 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 _iOnSelect
* @private
*/
YAHOO.whardy.widget.iCalendarGroup.prototype._iOnSelect = 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 _iOnBeforeDeselect
* @private
*/
YAHOO.whardy.widget.iCalendarGroup.prototype._iOnBeforeDeselect = 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 _iOnDeselect) */
		return false;
	}
}

/**
* Handles deselectEvent event.
* 
* @method _iOnDeselect
* @private
*/
YAHOO.whardy.widget.iCalendarGroup.prototype._iOnDeselect = 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
		// NOTE: shouldn't this be an array of arrays? doesn't seem to be...
		var d = a[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;
	}
}
