// constructor for IntervalCalendar
IntervalCalendar = function(id, containerId, config) {
	// The interval state, which counts the number of interval endpoints that have been selected (0 to 2).
	this._iState = 0;

	// custom properties
	if (config["iframe"] == undefined) { config["iframe"] = false; }
	if (config["MULTI_SELECT"] == undefined) { config["MULTI_SELECT"] = false; }
	if (config["pages"] == undefined) { config["pages"] = 1; }
	
	
	// call the constructor of the superclass
	IntervalCalendar.superclass.constructor.call(this, id, containerId, config);

	this.cfg.addProperty("disabledDates", {handler: this.configDisabledDays, value: []});
	this.cfg.addProperty("highlight1Dates", {value: []});
	this.cfg.addProperty("highlight2Dates", {value: []});
	this.cfg.addProperty("allowedNightsCount", {value: null});
	this.cfg.addProperty("disabledWeekDays", {handler: this.configDisabledDays, value: null});
	this.cfg.addProperty("blackoutDates", {handler: this.configDisabledDays, value: null});
	this.cfg.addProperty("unavailableDates", {handler: this.configDisabledDays, value: null});
	
	if (config) {
		this.cfg.applyConfig(config, true);
	}
	
	// custom properties:
	// start date
	this.startDate = null;
	this.startYear = 0;
	this.startMonth = 0;
	this.startDay = 0;
	
	// end date
	this.endDate = null;
	this.endYear = 0;
	this.endMonth = 0;
	this.endDay = 0;
	
	// number of nights
	this.nightsCount = 0;
	
	// event thrown when selection changes
	this.intervalChangedEvent = new YAHOO.util.CustomEvent('intervalchanged', this);
					
	// event handling
	this.beforeSelectEvent.subscribe(this.handleBeforeSelectEvent, this, true);
	this.selectEvent.subscribe(this.handleSelectEvent, this, true);
	this.beforeDeselectEvent.subscribe(this.handleBeforeDeselectEvent, this, true);
	this.deselectEvent.subscribe(this.handleDeselectEvent, this, true);
	this.renderEvent.subscribe(this.handleRenderEvent, this);
	
	this.configDisabledDays(null, null, null);
	
};

IntervalCalendar._DEFAULT_CONFIG = YAHOO.widget.CalendarGroup._DEFAULT_CONFIG;

// IntervalCalendar extends CalendarGroup
YAHOO.lang.extend(IntervalCalendar, YAHOO.widget.CalendarGroup);

IntervalCalendar.prototype.renderDisabledDate = function(workingDate, cell) {
	YAHOO.util.Dom.addClass(cell, this.Style.CSS_CELL_OOB);
	cell.innerHTML = workingDate.getDate();
	return YAHOO.widget.Calendar.STOP_RENDER;
};

IntervalCalendar.prototype.configDisabledDays = function(type, args, obj) {
	this._renderStack = [];
	this.renderStack = [];
	for (var p = 0; p < this.pages.length ; p++) {
		var page = this.pages[p];
		page._renderStack = [];
		page.renderStack = [];
	}
//	var disabledWeeksList = this.cfg.getProperty("disabledWeekDays");
//	if (disabledWeeksList != null && disabledWeeksList.length > 0) {
//		for (var i = 0; i < disabledWeeksList.length; i++) {
//			this.addWeekdayRenderer(disabledWeeksList[i], this.renderDisabledDate);
//		}
//	}
	
//	var disabledDatesList = this.cfg.getProperty("disabledDates"); 
//	if (disabledDatesList != null && disabledDatesList.length > 0) {
//		for (var i = 0; i < disabledDatesList.length; i++) {
//			this.addRenderer(disabledDatesList[i], this.renderDisabledDate);
//		}
//	}
	
//	var blackoutDatesList = this.cfg.getProperty("blackoutDates"); 
//	if (blackoutDatesList != null && blackoutDatesList.length > 0) {
//		for (var i = 0; i < blackoutDatesList.length; i++) {
//			this.addRenderer(blackoutDatesList[i], this.renderDisabledDate);
//		}
//	}
	
//	var unavailableDatesList = this.cfg.getProperty("unavailableDates"); 
//	if (unavailableDatesList != null && unavailableDatesList.length > 0) {
//		for (var i = 0; i < unavailableDatesList.length; i++) {
//			this.addRenderer(unavailableDatesList[i], this.renderDisabledDate);
//		}
//	}
	
	this.render();
};

IntervalCalendar.prototype._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);
};

IntervalCalendar.prototype._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.
IntervalCalendar.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).
IntervalCalendar.prototype.setInterval = function(d1, d2) {
	if (this.cfg.getProperty("MULTIPLE_SELECT")) {
		// 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);
		if (d1 == d2) {
			this._iState = 1;
		} else {
			this._iState = 2;
		}
	} else {
		this.cfg.setProperty('selected', this._dateString(d1), false);
	}
	this.setMonth(d1.getMonth());
	this.setYear(d1.getFullYear());
	this.render();
};

// Set nights count
IntervalCalendar.prototype.setNightsCount = function(nc) {
	if (this._iState == 1 || this._iState == 2) {
		var mayUpdate = this.isAllowedNightsCount(nc);
		if (mayUpdate) {
			var startDate = this.getSelectedDates()[0];
			var endDate = new Date();
			endDate.setTime(startDate.getTime() + (nc-1) * 86400000);
			this.setInterval(startDate, endDate);
		}
	}
};


// Resets the currently selected interval.
IntervalCalendar.prototype.resetInterval = function() {
	// Update configuration
	this.cfg.setProperty('selected', [], false);
	this._iState = 0;
};

// handler for beforeSelect event.
IntervalCalendar.prototype.handleBeforeSelectEvent = function(type, args, obj) {
	// Update interval state
	if (this.cfg.getProperty("MULTIPLE_SELECT")) {
		this._iState = (this._iState + 1) % 3;
		if (this._iState == 0) {
			// If starting over with upcoming selection, first deselect all
			this.deselectAll();
			this._iState++;
		}
	}
};

// handler for select event. Do not allow more than 2 selected dates.
IntervalCalendar.prototype.handleSelectEvent = function(type, args, obj) {
	// Get selected dates
	var dates = this.getSelectedDates();
	if (this._iState == 2) {
		var l = dates[0];
		var nc = 1;
		if (dates.length > 1) {
			var u = dates[dates.length - 1];
			nc = Math.round((u.getTime() - l.getTime())/86400000) + 1;
		}
		var mayUpdate = this.isAllowedNightsCount(nc);
		if (!mayUpdate) {
			this._iState = 1;
			this.cfg.setProperty('selected', this._dateString(l), false);
			this.render();
			return;
		}
	}
	if (dates.length > 1) {
		var l = dates[0];
		var u = dates[dates.length - 1];
		this.cfg.setProperty('selected', this._dateIntervalString(l, u), false);
	}
	// Render changes
	this.render();
};

// handler for beforeDeselect event.
IntervalCalendar.prototype.handleBeforeDeselectEvent = function(type, args, obj) {
	if (this._iState != 0) {
		return false;
	}
}

// when a date is deselected, update the start / end dates
IntervalCalendar.prototype.handleDeselectEvent = function(type, args, obj) {
	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 = args[0];
    	var date = new Date();
    	YAHOO.widget.DateMath.clearTime(date);
    	date.setFullYear(d[0]);
    	date.setMonth(d[1] - 1);
    	date.setDate(d[2]);
    	
		this.setInterval(date, date);
    	
    	// Swallow up since we called deselectAll above
    	return false;
	}
};

IntervalCalendar.prototype.handleRenderEvent = function(type, args, obj) {
	var highlight1DatesList = obj.cfg.getProperty("highlight1Dates"); 
	if (highlight1DatesList != null && highlight1DatesList.length > 0) {
		var highlight1Hash = new Object();
		for (var i = 0; i < highlight1DatesList.length; i++) {
			highlight1Hash[highlight1DatesList[i]] = true;
		}
	
		for (var p = 0; p < obj.pages.length ; p++) {
			var page = obj.pages[p];
			for (var i = 0; i < page.cellDates.length; i++) {
				if (highlight1Hash[page.cellDates[i]]) {
					YAHOO.util.Dom.addClass(page.cells[i], "highlight1");
				}
			}
		}
	}
	
	var highlight2DatesList = obj.cfg.getProperty("highlight2Dates"); 
	if (highlight2DatesList != null && highlight2DatesList.length > 0) {
		var highlight2Hash = new Object();
		for (var i = 0; i < highlight2DatesList.length; i++) {
			highlight2Hash[highlight2DatesList[i]] = true;
		}
	
		for (var p = 0; p < obj.pages.length ; p++) {
			var page = obj.pages[p];
			for (var i = 0; i < page.cellDates.length; i++) {
				if (highlight2Hash[page.cellDates[i]]) {
					YAHOO.util.Dom.addClass(page.cells[i], "highlight2");
				}
			}
		}
	}
	
	obj._updateInterval();
	
};

IntervalCalendar.prototype.isAllowedNightsCount = function(nc) {
	var isAllowed = false;
	if (this.cfg.getProperty("allowedNightsCount") == null) {
		return true;
	} else {
		var allowedValues = this.cfg.getProperty("allowedNightsCount");
		if (allowedValues.length == 1 && allowedValues[0] == nc) {
			return true;
		}
		if (allowedValues.length == 2 && allowedValues[0] <= nc && allowedValues[1] >= nc) {
			return true;
		}
	}
	return false;
}

// update start and end date
IntervalCalendar.prototype._updateInterval = function() {
	var selDates = this.getSelectedDates();
	if (selDates == null || selDates.length == 0) {
		this.startDate = null;
		this.startYear = 0;
		this.startMonth = 0;
		this.startDay = 0;
		this.endDate = null;
		this.endYear = 0;
		this.endMonth = 0;
		this.endDay = 0;
		this.nightsCount = 0;
	} else {
		this.startDate = selDates[0];
		this.endDate = selDates[selDates.length - 1];
		this.startYear = this.startDate.getFullYear();
		this.startMonth = this.startDate.getMonth() + 1;
		this.startDay = this.startDate.getDate();
		this.endYear = this.endDate.getFullYear();
		this.endMonth = this.endDate.getMonth() + 1;
		this.endDay = this.endDate.getDate();
		this.nightsCount = Math.round((this.endDate.getTime() - this.startDate.getTime())/86400000) + 1;
		
	}
	
	this.intervalChangedEvent.fire();
};
