/**
 * DatePicker.js
 * ============= 
 * Start and End date packer using the YUI Calendar classes
 * This class creates two Calendar objects and links each of them with an input text field
 * The DatePicker is constructed with a JSON array (options) which are described below:
 * 
 * 	minDate:			The Date string of the minimum date (default is today) format is MM/DD/YYYY
 *	maxDate:			The Date string of the maximum date (default is today+2yrs) format is MM/DD/YYYY
 * 	startDate:			The start date (string) to be set in the Calendar - format is WoW style YYYYMMDD 
 *	endDate:			The end date (string) to be set in the Calendar - format is WoW style YYYYMMDD
 * 	startCalendarDiv:	The DOM id of the start calendar DIV
 * 	endCalendarDiv:		The DOM id of the end calendar DIV
 * 	startCalendarImg:	The DOM id of the Image icon used with the start calendar
 * 	endCalendarImg:		The DOM id of the Image icon used with the end calendar
 *  startDateFieldId:	The DOM id of the start date inout text field
 * 	endDateFieldId:		The DOM id of the end date input text field 
 * 	startCalendarTitle:	The text associated with the start Calendar
 *  endCalendarTitle:	The text associated with the end Calendar
 *   
 */
YAHOO.namespace("wow");
YAHOO.wow.DatePicker = function() {

	//Handy YUI Shortcuts
	var Event = YAHOO.util.Event;
	var Dom = YAHOO.util.Dom;

	//The mininmum and maximum dates 
	var minDate;
	var maxDate;
	
	//The (optional) start and end dates and their associated strings
	var startDate; 
	var endDate;
	
	//The startDate and endDate input text fields
	var startDateField;
	var endDateField;

	//The startDate and endDate YUI Calendar objects
	var calStart;
	var calEnd;

	//The ids of the div holders for the calendard
	var startCalendarDiv = "startCalendarId";
	var endCalendarDiv = "endCalendarId";

	//The ids of the div holders for the calendar images
	var startCalendarImg = "calendarImg1";
	var endCalendarImg = "calendarImg2";
	
	//The DOM id values for start and end date input text fields
	var startDateFieldId = "display_start_date";
	var endDateFieldId = "display_end_date";
	
	//The titles of the calendar popups
	var startCalendarTitle = "Start Date";
	var	endCalendarTitle = "End Date";

	/**
	 * Create the Calendar objects, fields and selected dates using 
	 * the supplied options.
	 */
	var createCalendars = function(options) {
	
		//Set all the necessary default values
		setDefaults();    	        
		
    	//Have we been supplied with a list of options? If so use 'em
    	if (options) parseOptions(options);
    	
    	//Get the associated input text-fields for start and end dates
    	startDateField = Dom.get(startDateFieldId);
    	endDateField = Dom.get(endDateFieldId);
    	
    	//Construct the startDate Calendar
		calStart = new YAHOO.widget.Calendar("startCalendar",
			startCalendarDiv, 
			{ title:startCalendarTitle, mindate:minDate, maxdate:maxDate, close:true });
		calStart.dateField = startDateField;
		calStart.wowDateString = "";
		calStart.render();

		//Construct the endDate Calendar
		calEnd = new YAHOO.widget.Calendar("endCalendar", 
			endCalendarDiv, 
			{ title:endCalendarTitle, mindate:minDate, maxdate:maxDate, close:true });
		calEnd.dateField = endDateField;
		calEnd.wowDateString = "";
		calEnd.render();
			
		// Add back references to each other calendar
		calEnd.minCal = calStart;
		calStart.maxCal = calEnd;

		//Check if valid start and end dates have been supplied                                                            
		if (isValidDate(startDate)) updateCalendarFields(calStart, startDate);
		if (isValidDate(endDate)) updateCalendarFields(calEnd, endDate);

		calStart.selectEvent.subscribe(calSelect, calStart, true);
		calEnd.selectEvent.subscribe(calSelect, calEnd, true);
		
		// Wire up the startDate Calendar select 'click' listeners
		Event.addListener(startCalendarImg, "click", calStart.show, calStart, true);
		Event.addListener(endCalendarImg, "click", calEnd.show, calEnd, true);

		Event.addListener(startDateFieldId, "focus", calStart.show, calStart, true);		
		Event.addListener(endDateFieldId, "focus", calEnd.show, calEnd, true);	
	};

	/**
	 * Sets all the default values for mandatory fields such as minDate, maxDate etc
	 */
	 var setDefaults = function() {
	 	
		//Initialise the default min and max Date values
		minDate = new Date(); //today is the default
		maxDate = new Date();
		maxDate.setDate(maxDate.getDate()+730); //two years ahead of today is the deafult
	 };
	 
	/**
	 * Handles the select event from a Calendar widget
	 * Here we update the check the dates and update calendars accordingly
	 */
	var calSelect = function(e, args, calendar) {
		
		// Extract the date. Note 1st selection contains the date we are interested in
		var date = calendar.getSelectedDates()[0]; 
		
		//Must check that the supplied date is valid
		if (!isValidDate(date)) return false;
		
		// Get the maxCal and set its min date to the calendars current 'date'
		if (calendar.maxCal) {
			calendar.maxCal.cfg.setProperty("mindate", date);
						
			//If this new date is greater than the max cals current date we also need to shift the pageDate
			if (!calendar.maxCal.getSelectedDates()[0] || (date.getTime() > calendar.maxCal.getSelectedDates()[0].getTime())) {
				calendar.maxCal.cfg.setProperty("pageDate", date);
			}
			
			//Always render to ensure changes are visible
			calendar.maxCal.render();			
		}

		// Get the minCal and set its maxDate to the calendars current date
		if (calendar.minCal) {
			calendar.minCal.cfg.setProperty("maxdate", date);
			calendar.minCal.render();
		}		

		//Update the display date of the current calendar
		updateCalendarFields(calendar, date);
		calendar.render();
		
		//Hide the Calendar
		calendar.hide();
	};
	
	/**
	 * Parse the options and set the start and end selection dates
	 */
	 var parseOptions = function(options) {
	 	
	 	//Set the id of the calendar DIVs
	 	if (options.startCalendarDiv) { startCalendarDiv = options.startCalendarDiv; }
	 	if (options.endCalendarDiv) { endCalendarDiv = options.endCalendarDiv; }
	 	
	 	//Set the ids of the calendar Images
	 	if (options.startCalendarImg) { startCalendarImg = options.startCalendarImg; }
	 	if (options.endCalendarImg) { endCalendarImg = options.endCalendarImg; }

	 	//Set the minDate and maxDate if they have been supplied
	 	if (options.minDate) { minDate = new Date(options.minDate); }
	 	if (options.maxDate) { maxDate = new Date(options.maxDate); }

		//Set the startDate and endDate object values by munging any incoming date string	
	 	if (options.startDate) { startDate = mungeWowDateString(options.startDate); }
	 	if (options.endDate) { endDate = mungeWowDateString(options.endDate); }

		//Set the start and end Date field id values	 	
	 	if (options.startDateFieldId) { startDateFieldId = options.startDateFieldId; } 
	 	if (options.endDateFieldId) { endDateFieldId = options.endDateFieldId; }	 	
	 	
		//Set the titles of the calendar pop-ups
	 	if (options.startCalendarTitle) { startCalendarTitle = options.startCalendarTitle; }
	 	if (options.endCalendarTitle) { endCalendarTitle = options.endCalendarTitle; }	
	 };
	 
	/**
	 * Updates the calendar input text fields and wow Date string only
	 * Does not call Calendar.select which would result in infinite loop
	 */
	var updateCalendarFields = function(cal, date) {
		
		//Check we have a valid date and the wowDateStrings are not empty
		if (!isValidDate(date))return false;
		
		var year = date.getFullYear();
		var month = date.getMonth() + 1;
		var day = date.getDate();
		
		if (month < 10) month = "0" + month;
			
		// Update the associated date Text field with the calendar's selected value
		cal.dateField.value = day + "/" + month + "/" + year;
		cal.wowDateString = year + "" + month + "" + day;			
		
		return true;
	};
	
	/**
	 * Updates the Calendar's selected date from the value currently 
	 * contained in its dateField text box (dateField.value)
	 * This requires a bit of munging as the dateField is in format dd/mm/yyyy
	 * and the standard JS Date() function requires a string in format mm/dd/yyyy
	 */
	var updateCalendar = function(cal) {
		
		var dateStr = getDateStringFromCalField(cal);
		
		//If the dateField.value is empty, clear wowDateString field and continue
		if (dateStr == "") {
			cal.wowDateString = "";
			cal.hide();
			return;
		}
		
		//Construct a new date
		var newDate = new Date(dateStr);

		//If it is not a valid date, we reset to current calendar date
		if (!isValidDate(newDate)) {
			updateCalendarFields(cal, cal.getSelectedDates()[0]);
			cal.hide();
			return;	
		}
		
		//If the new date is less than the current min date we reject it
		if (cal.minCal && (newDate.getTime() < cal.minCal.getSelectedDates()[0].getTime()) ) {
			updateCalendarFields(cal, cal.getSelectedDates()[0]);
			cal.hide();
			return;
		}

		//Similarily, if the new date is greater than the maximum permitted date, we reject it
		if (newDate.getTime() > maxDate.getTime()) {
			updateCalendarFields(cal, cal.getSelectedDates()[0]);
			cal.hide();
			return;
		}
		
		cal.select(newDate);		
		cal.cfg.setProperty("pagedate", newDate);
		cal.render();
	};
	
	/**
	 * Check that the supplied Date is valid
	 */
	var isValidDate = function(date) {
		
		//Need to check supplied Date is valid
		if (date) {
			var year = date.getFullYear();
			var month = date.getMonth() + 1;
			var day = date.getDate();
			
			//If we have a duffer then use the oldDate
			if (year && month && day) return true;
		}
		
		return false;
	};
	
	/**
	 * Takes a wow formatted date (i.e. YYYYMMDD) and returns a new Date object from it
	 */
	var mungeWowDateString = function(dateString) {
		
		if (dateString) {
			var year = dateString.substring(0,4);
			var month = dateString.substring(4,6);
			var day = dateString.substring(6,dateString.length);

			return new Date(month + "/" + day + "/" + year);
		}
	};
	
	/**
	 * Retrives the contents of the calendar's input text field
	 * and returns it as a valid 'dd/mm/yyyy' formatted String
	 * Note it will preserve and empty String
	 */
	var getDateStringFromCalField = function(cal) {

		//Preserve an empty string
		var fieldValue = cal.dateField.value;
		if (!fieldValue || fieldValue.length == 0) return "";

		//Otherwise split on the '/' character
		var fields = fieldValue.split("/");
		var dateStr = fields[1] + "/" + fields[0] + "/" + fields[2]; 
		return dateStr;
	}
	
	/**
     * Public functions for our DatePicker.js
     */
    return {

		// Initialise our SearchForm
        init: function(args) {
        	createCalendars(args);
        	
        	//Return a reference to our good self
        	return this;
        },
        
        //Returns the wow-style date strings (as an array startDate=dateStr[0] endDate=dateStr[1]
        getDateStrings: function() {

			//Return the startCal and endCal date strings (in wow style)        	
        	return [calStart.wowDateString, calEnd.wowDateString];
        },
        
        //Returns the actual Date() objects
        getDates: function() {
        	
        	//Returns the currently selected dates of our start and end calendars
        	return [calStart.getSelectedDates()[0], calEnd.getSelectedDates()[0]];
        },
        
        //Updates the Calendars with the current values in the input field useful if submitting forms)
        updateCalendars: function() {
        	
        	//Simply call update on each calendar
        	updateCalendar(calStart);
        	updateCalendar(calEnd);	
        }
    };
}();