/*  
 * The Zapatec DHTML Calendar
 *
 * Copyright (c) 2004 by Zapatec, Inc.
 * http://www.zapatec.com
 * 1700 MLK Way, Berkeley, California,
 * 94709, U.S.A.  
 * All rights reserved.
 *
 * Original version written by Mihai Bazon,
 * http://www.bazon.net/mishoo/calendar.epl
 *
 * This file defines helper functions for setting up the calendar.  They are
 * intended to help non-programmers get a working calendar on their site
 * quickly.  This script should not be seen as part of the calendar.  It just
 * shows you what one can do with the calendar, while in the same time
 * providing a quick and simple method for setting it up.  If you need
 * exhaustive customization of the calendar creation process feel free to
 * modify this code to suit your needs (this is recommended and much better
 * than modifying calendar.js itself).
 */

// $Id: calendar-setup.js,v 1.7 2005/04/08 22:14:38 dror Exp $

/**
 *  This function "patches" an input field (or other element) to use a calendar
 *  widget for date selection.
 *
 *  Note that you can use the Zapatec DHTML Calendar Wizard and generate the code
 *  and modify the results.
 *  The "params" is a single object that can have the following properties:
 *
 * \code
 *    prop. name   | description
 *  -------------------------------------------------------------------------------------------------
 *   inputField    | the ID of an input field to store the date
 *   displayArea   | the ID of a DIV or other element to show the date
 *   button        | ID of a button or other element that will trigger the calendar
 *   eventName     | event that will trigger the calendar, without the "on" prefix (default: "click")
 *   closeEventName| event that will close the calendar (i.e. one can use "focus" for eventName and "blur" for closeEventName)
 *   ifFormat      | date format that will be stored in the input field
 *   daFormat      | the date format that will be used to display the date in displayArea
 *   singleClick   | (true/false) wether the calendar is in single click mode or not (default: true)
 *   firstDay      | numeric: 0 to 6.  "0" means display Sunday first, "1" means display Monday first, etc.
 *   align         | alignment (default: "Br"); if you don't know what's this see the calendar documentation
 *   range         | array with 2 elements.  Default: [1900, 2999] -- the range of years available
 *   weekNumbers   | (true/false) if it's true (default) the calendar will display week numbers
 *   flat          | null or element ID; if not null the calendar will be a flat calendar having the parent with the given ID
 *   flatCallback  | function that receives a JS Date object and returns an URL to point the browser to (for flat calendar)
 *   disableFunc   | function that receives a JS Date object and should return true if that date has to be disabled in the calendar
 *   onSelect      | function that gets called when a date is selected.  You don't _have_ to supply this (the default is generally okay)
 *   onClose       | function that gets called when the calendar is closed.  [default]
 *   onUpdate      | function that gets called after the date is updated in the input field.  Receives a reference to the calendar.
 *   date          | the date that the calendar will be initially displayed to
 *   showsTime     | default: false; if true the calendar will include a time selector
 *   timeFormat    | the time format; can be "12" or "24", default is "12"
 *   timeInterval  | the step for changing minutes. Can be set to 1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30. When set you can only change minutes with "up" and "down" arrows. When null - arrows change time for 5 minutes and clicking on the minutes change it for 1 minute.
 *   electric      | if true (default) then given fields/date areas are updated for each move; otherwise they're updated only on close
 *   sortOrder	   | ("asc"(ending)/"desc"(ending)/"none"). If "asc" (default), order of the multiple dates (when multiple dates is on) will be sorted in ascending order. Otherwise, it will be sorted in descending order. "none" means no sorting is needed. 
 *   step          | configures the step of the years in drop-down boxes; default: 2
 *   position      | configures the calendar absolute position; default: null
 *   cache         | if "true" (but default: "false") it will reuse the same calendar object, where possible
 *   showOthers    | if "true" (but default: "false") it will show days from other months too
 *   saveDate      | if set (default unset) will save a cookie for this duration.
 * \endcode
 *
 *  None of them is required, they all have default values.  However, if you
 *  pass none of "inputField", "displayArea" or "button" you'll get a warning
 *  saying "nothing to setup".
 */
Zapatec.Calendar.setup = function (params) {
	function param_default(pname, def) { if (typeof params[pname] == "undefined") { params[pname] = def; } };
	param_default("inputField",     null);
	param_default("displayArea",    null);
	param_default("button",         null);
	param_default("eventName",      "click");
	param_default("ifFormat",       "%Y/%m/%d");
	param_default("daFormat",       "%Y/%m/%d");
	param_default("singleClick",    true);
	param_default("disableFunc",    null);
	param_default("dateStatusFunc", params["disableFunc"]);	// takes precedence if both are defined
	param_default("dateText",       null);
	param_default("firstDay",       null);
	param_default("align",          "Br");
	param_default("range",          [1900, 2999]);
	param_default("weekNumbers",    true);
	param_default("flat",           null);
	param_default("flatCallback",   null);
	param_default("onSelect",       null);
	param_default("onClose",        null);
	param_default("onUpdate",       null);
	param_default("date",           null);
	param_default("showsTime",      false);
	param_default("sortOrder",      "asc");
	param_default("timeFormat",     "24");
	param_default("timeInterval",   null);
	param_default("electric",       true);
	param_default("step",           2);
	param_default("position",       null);
	param_default("cache",          false);
	param_default("showOthers",     false);
	param_default("multiple",       null);
	param_default("saveDate",       null);

	var tmp = ["inputField", "displayArea", "button"];
	for (var i in tmp) {
		if (typeof params[tmp[i]] == "string") {
			params[tmp[i]] = document.getElementById(params[tmp[i]]);
		}
	}
	if (!(params.flat || params.multiple || params.inputField || params.displayArea || params.button)) {
		alert("Calendar.setup:\n  Nothing to setup (no fields found).  Please check your code");
		return false;
	}
	if (((params.timeInterval) && ((params.timeInterval !== Math.floor(params.timeInterval)) || ((60 % params.timeInterval !== 0) && (params.timeInterval % 60 !== 0)))) || (params.timeInterval > 360)) {
		alert("timeInterval option can only have the following number of minutes:\n1, 2, 3, 4, 5, 6, 10, 15, 30,  60, 120, 180, 240, 300, 360 ");
		params.timeInterval = null;
	}
	if (params.saveDate) { //If saveDate is on We're saving the date in a cookie
		//fetch the cookie
		var cookieName = window.location.href + "--" + params.button.id;
		var newdate = Zapatec.Utils.getCookie(cookieName);
		if (newdate != null) { //if there's a cookie
			//set the value of the text field
			document.getElementById(params.inputField.id).value = newdate;
		}
	}

	function onSelect(cal) {
		var p = cal.params;
		var update = (cal.dateClicked || p.electric);
		if (update && p.flat) {
			if (typeof p.flatCallback == "function")
			{
			   if (!p.multiple) //User can call function submitFlatDates directly in Calendar object to handle the submission of multiple dates.
				p.flatCallback(cal);
			} else
				alert("No flatCallback given -- doing nothing.");
			return false;
		}
		if (update && p.inputField) {
			p.inputField.value = cal.date.print(p.ifFormat);
			if (typeof p.inputField.onchange == "function")
				p.inputField.onchange();
		}
		if (update && p.displayArea)
			p.displayArea.innerHTML = cal.date.print(p.daFormat);
		if (update && p.singleClick && cal.dateClicked)
			cal.callCloseHandler();
		if (update && typeof p.onUpdate == "function")
			p.onUpdate(cal);
		if (p.saveDate) { //save date in cookie
			//unique name of the cookie is the name of the button  + href 
			var cookieName = window.location.href + "--" + p.button.id;
			Zapatec.Utils.writeCookie(cookieName, p.inputField.value, null, '/', p.saveDate);
		}  
	};
	
	if (params.flat != null) {
		if (typeof params.flat == "string")
			params.flat = document.getElementById(params.flat);
		if (!params.flat) {
			alert("Calendar.setup:\n  Flat specified but can't find parent.");
			return false;
		}
		var cal = new Zapatec.Calendar(params.firstDay, params.date, params.onSelect || onSelect);
		cal.showsOtherMonths = params.showOthers;
		cal.showsTime = params.showsTime;
		cal.time24 = (params.timeFormat == "24");
		cal.timeInterval = params.timeInterval;
		cal.params = params;
		cal.weekNumbers = params.weekNumbers;
		cal.sortOrder = params.sortOrder.toLowerCase();
		cal.setRange(params.range[0], params.range[1]);
		cal.setDateStatusHandler(params.dateStatusFunc);
		cal.getDateText = params.dateText;
		if (params.ifFormat) {
			cal.setDateFormat(params.ifFormat);
		}
		
		if (params.inputField && params.inputField.type == "text" && typeof params.inputField.value == "string") {
			cal.parseDate(params.inputField.value);
		}

		if (params.multiple) {
		   cal.setMultipleDates(params.multiple);
		}
		cal.create(params.flat);
		cal.show();
		return cal;
	}

	var triggerEl = params.button || params.displayArea || params.inputField;
	triggerEl["on" + params.eventName] = function() {
		var dateEl = params.inputField || params.displayArea;
		var dateFmt = params.inputField ? params.ifFormat : params.daFormat;
		var mustCreate = false;
		var cal = window.calendar;
		if (!(cal && params.cache)) {
			window.calendar = cal = new Zapatec.Calendar(params.firstDay,
							     params.date,
							     params.onSelect || onSelect,
							     params.onClose || function(cal) {
								     if (params.cache)
									     cal.hide();
								     else
									     cal.destroy();
							     });
			cal.showsTime = params.showsTime;
			cal.time24 = (params.timeFormat == "24");
			cal.timeInterval = params.timeInterval;
			cal.weekNumbers = params.weekNumbers;
			cal.historyDateFormat = params.ifFormat || params.daFormat;
			mustCreate = true;
		} else {
			if (params.date)
				cal.setDate(params.date);
			cal.hide();
		}

		if (params.multiple) {
		   cal.setMultipleDates(params.multiple);
		}
		
		cal.showsOtherMonths = params.showOthers;
		cal.yearStep = params.step;
		cal.setRange(params.range[0], params.range[1]);
		cal.params = params;
		cal.setDateStatusHandler(params.dateStatusFunc);
		cal.getDateText = params.dateText;
		cal.setDateFormat(dateFmt);
		if (mustCreate)
			cal.create();
		if (dateEl) {
			var dateValue;
			//figure out if the it's in value or innerHTML
			if (dateEl.value) {
				dateValue = dateEl.value;
			} else {
				dateValue = dateEl.innerHTML;
			}
			if (dateValue != "") { //if there is a date to initialize from
				var parsedDate = Date.prototype.parseDate(dateEl.value || dateEl.innerHTML, dateFmt);
				//This check for when webmaster initializes the box with something like
				//"check in"
				if (parsedDate != null) { //if it's parsable
				cal.setDate(parsedDate);
				}
			}
		}
		if (!params.position)
			cal.showAtElement(params.button || params.displayArea || params.inputField, params.align);
		else
			cal.showAt(params.position[0], params.position[1]);
		return false;
	};

	if (params.closeEventName) {
		triggerEl["on" + params.closeEventName] = function() {
			if (window.calendar)
				window.calendar.callCloseHandler();
		};
	}

	return cal;
};
