// Title: Tigra Calendar PRO
// Description: Tigra Calendar PRO is flexible JavaScript Calendar offering
//	high reliability and wide browsers support.
// URL: http://www.softcomplex.com/products/tigra_calendar_pro/
// Version: 1.1 (on page mode)
// Date: 09/15/2002 (mm/dd/yyyy)
// Technical Support: support@softcomplex.com (specify product title and order ID)
// Notes: This Script is shareware. Please visit url above for registration details.

// user configuration block:
// months as they appear in the selection list
var ARR_MONTHS = ["January", "February", "March", "April", "May", "June",
		"July", "August", "September", "October", "November", "December"];
// week day titles as they appear on the calendar
var ARR_WEEKDAYS = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
// day week starts from (normally 0-Su or 1-Mo)
var NUM_WEEKSTART = 0;
// when visitor tries to select date out of the range
var LOG_SHOWERROR = true; // show error message
var LOG_SETLIMIT  = true; // set closest allowed date
// in year selection box how many years to list relative to current year
var NUM_YEARSBEFORE = 4;
var NUM_YEARSAFTER  = 4;

var calendars = [];
var today = new Date();

function calendar (str_date, str_form_name, str_ctrl_name, str_min_date, str_max_date, rel_id) {
	this.get_html  = cal_get_html;
	this.get_body  = cal_get_body;
	this.set_year  = cal_set_year;
	this.set_month = cal_set_month;
	this.set_day   = cal_set_day;
	this.validate  = cal_validate;
	this.UA=U_A=new _UserAgent();
	this.rel_id = rel_id; // id of related calendar
	this.weekbuffer = 0; // flag if weekbuffer is to be added to arrival date to auto calc departure date
	
	this.update = (document.body && document.body.innerHTML ? cal_css_update : cal_rel_update);
	
	this.id = calendars.length;
	calendars[this.id] = this;
		
	var re_url = new RegExp('cal' + this.id + '_val=(\\d+)');
	var dt_params = (str_date ? cal_parse_date(str_date) : cal_date_only());
	this.dt_current = (re_url.exec(String(window.location))
		? new Date(new Number(RegExp.$1)) : dt_params);
	
	if (!str_form_name)
		return alert('Form name is required parameter of draw method.');
	if (!document.forms[str_form_name])
		return alert ("Form with name '" + this.form_name + "' can't be found in the document.");
	this.form_name = str_form_name;
	this.control_name = (str_ctrl_name ? str_ctrl_name : 'datetime_' + this.id);
	
	var re_num = /^-?\d+$/;
	if (str_min_date != null)
		this.min_date = (re_num.exec(str_min_date)
			? new Date (dt_params.valueOf() - new Number(str_min_date * 864e5))
			: cal_parse_date(str_min_date)
		);
	if (str_max_date != null)
		this.max_date = (re_num.exec(str_max_date)
			? new Date (dt_params.valueOf() + new Number(str_max_date * 864e5))
			: cal_parse_date(str_max_date)
		);
	LOG_SHOWERROR = false;	
	this.dt_current = this.validate(this.dt_current);
	LOG_SHOWERROR = true;	
	document.write (this.get_html(this.dt_current));
	this.control_obj = document.forms[str_form_name].elements[this.control_name];
	this.mon_ctrl    = document.forms[this.form_name].elements['dt_mon_'  + this.id];
	this.year_ctrl   = document.forms[this.form_name].elements['dt_year_' + this.id];
}

function cal_css_update (dt_datetime) {
	this.dt_current = dt_datetime;
	this.control_obj.value = cal_generate_date(dt_datetime);
	
	var obj_container = (document.all ?
		document.all['cal_body_' + this.id] :
		document.getElementById('cal_body_' + this.id)
	);
	obj_container.innerHTML =  this.get_body(dt_datetime);
	this.mon_ctrl.selectedIndex = dt_datetime.getMonth(); 
	this.year_ctrl.selectedIndex =dt_datetime.getFullYear() - Number(this.year_ctrl.options[1].text) + 1;
	this.control_obj.value = cal_generate_date(dt_datetime);
}

function cal_rel_update (dt_datetime) {
	var arr_location = String(window.location).split('?');
	var arr_params = String(arr_location[1]).split('&');
	var num_found = -1;
	for (var i = 0; i < arr_params.length; i++)
		if((arr_params[i].split('='))[0] == 'cal' + this.id + '_val') {
			num_found = i;
			break;
		}
	arr_params[(num_found == -1 ? (arr_location[1] ? arr_params.length : 0) : num_found)]= 'cal' + this.id + '_val=' + dt_datetime.valueOf();
	this.control_obj.value = cal_generate_date(dt_datetime);
	window.location = arr_location[0] + '?' + arr_params.join('&');
}

function cal_set_day (num_datetime) {
	// add one hour to overcome the bug when a date span includes the date
	// inwhich the calendar switches from daylight savings to standard time
	var dt_newdate = new Date(num_datetime + 60*60*1000);
	this.weekbuffer += 1;
	this.update(this.validate(dt_newdate));
}

function cal_set_month () {

	var dt_newdate = new Date(this.dt_current);
	var num_month = this.mon_ctrl.options[this.mon_ctrl.selectedIndex].value;
		
	dt_newdate.setMonth(num_month);
	if (num_month != dt_newdate.getMonth())
		dt_newdate.setDate(0);
	
	dt_newdate = this.validate(dt_newdate);
	if (dt_newdate == this.dt_current)
		this.mon_ctrl.selectedIndex = this.dt_current.getMonth();
	else {
		// update the related calendar on month change
		if (this.rel_id != null) {
			var newdate = dt_newdate;
			if (this.weekbuffer < 1)
				// create a new date by adding a buffer week
				var newdate = new Date(dt_newdate.getTime() + 7*24*60*60*1000);
			calendars[this.rel_id].update(newdate);
		}
		this.update(dt_newdate);
	}
}

function cal_set_year () {
	var dt_newdate = new Date(this.dt_current);
	var str_year = this.year_ctrl.options[this.year_ctrl.selectedIndex].text;
	var str_scroll = this.year_ctrl.options[this.year_ctrl.selectedIndex].value;
	
	var num_year;
	
	if (str_scroll&& str_scroll!='_') {
		num_year = (str_scroll == '+'? (this.dt_current.getFullYear() + NUM_YEARSAFTER): (this.dt_current.getFullYear() -  NUM_YEARSAFTER));
	}
	else num_year = new Number(str_year);
	dt_newdate.setFullYear(num_year);
	var num_month = this.mon_ctrl.options[this.mon_ctrl.selectedIndex].value;
	if (num_month != dt_newdate.getMonth()) 	dt_newdate.setDate(0);
	var flag = this.validate(dt_newdate, true);
	dt_newdate = this.validate(dt_newdate);
	if (dt_newdate.valueOf() == this.dt_current.valueOf()) {
		this.year_ctrl.selectedIndex =this.dt_current.getFullYear() - Number(this.year_ctrl.options[1].text) + 1;
		return;
	}

	if (str_scroll && str_scroll!='_') {
		if(!flag) num_year = dt_newdate.getFullYear();
		this.year_ctrl.length = 0;
		this.year_ctrl.options[0] = new Option('<< ' + (num_year - NUM_YEARSBEFORE), '-');
		for (var i = 1; i < NUM_YEARSBEFORE + NUM_YEARSAFTER; i++) {
			this.year_ctrl.options[i] = new Option(num_year + i - NUM_YEARSBEFORE,'_');
			this.year_ctrl.options[i].selected = !(i-NUM_YEARSBEFORE);
		}
		this.year_ctrl.options[NUM_YEARSBEFORE + NUM_YEARSAFTER] = new Option((num_year + NUM_YEARSAFTER) + ' >>', '+');
	}
	
	// update the related calendar on year change
	if (this.rel_id != null) {
		var newdate = dt_newdate;
		if (this.weekbuffer < 1)
			// create a new date by adding a buffer week
			var newdate = new Date(dt_newdate.getTime() + 7*24*60*60*1000);
		calendars[this.rel_id].update(newdate);
	}
		
	this.update(dt_newdate);
}

function cal_get_html (dt_datetime) {
	var signal = this.UA.ns71?'onclick':'onchange';
	// print calendar header
		
	var i, str_buffer = new String (
		'<table cellspacing="0" class="calOuterTable" border="0"><tr>' +
		'<td><input type="hidden" name="' + this.control_name + '" value="' + cal_generate_date(this.dt_current) + '">' + 
		'<table cellspacing="0" class="calSelectTable"><tr><td>' +
		'<select name="dt_mon_' + this.id + '" class="calMonCtrl" onchange="return calendars[' + this.id + '].set_month();">');
	for (i = 0; i < 12; i++)
			str_buffer += '<option value="' + i + '"' + (i == dt_datetime.getMonth() ? ' selected' : '') + '>' + ARR_MONTHS[i] + "</option>\n";
	str_buffer += '</select></td>' +
		'<td align="right"><select name="dt_year_' + this.id + '" class="calYearCtrl" '+signal+'="return calendars[' + this.id + '].set_year();">' +
		'<option value="-">&lt;&lt; ' + (dt_datetime.getFullYear() - NUM_YEARSBEFORE) + "</option>\n";
		
	for (i = 1 - NUM_YEARSBEFORE; i < NUM_YEARSAFTER; i++) {
				str_buffer += '<option value="_" ' + (i == 0 ? ' selected' : '') + '>' + (dt_datetime.getFullYear() + i )+ "</option>\n";
			}
	str_buffer += '<option value="+">' + (dt_datetime.getFullYear() + NUM_YEARSAFTER) +  " &gt;&gt;</option>\n" +
		'</select></td></tr></table></td></tr>' +
		'<tr><td><div id="cal_body_' + this.id + '">' + this.get_body(dt_datetime) +'</div>'
		+ '</td>'
		+ '</tr></table>';
	return (str_buffer);
}

function cal_get_body (dt_datetime) {

	// get same date in the previous year
	var dt_prev_year = new Date(dt_datetime);
	dt_prev_year.setFullYear(dt_prev_year.getFullYear() - 1);
	if (dt_prev_year.getDate() != dt_datetime.getDate())
		dt_prev_year.setDate(0);
	
	// get same date in the next year
	var dt_next_year = new Date(dt_datetime);
	dt_next_year.setFullYear(dt_next_year.getFullYear() + 1);
	if (dt_next_year.getDate() != dt_datetime.getDate())
		dt_next_year.setDate(0);
	
	// get first day to display in the grid for current month
	var dt_firstday = new Date(dt_datetime);
	dt_firstday.setDate(1);
	dt_firstday.setDate(1 - (7 + dt_firstday.getDay() - NUM_WEEKSTART) % 7);
	
	// print calendar body
	var str_buffer = new String (
	'<table cellspacing="1" cellpadding="2" class="calDaysTable" width="100%">');

	// print weekdays titles
	str_buffer += '<tr>';
	for (var n = 0; n < 7; n++)
		str_buffer += '<td class="calWTitle">' + ARR_WEEKDAYS[(NUM_WEEKSTART + n) % 7] + '</td>';
	// print calendar table
	str_buffer += "</tr>\n";

	var dt_current_day = new Date(dt_firstday);
	while (dt_current_day.getMonth() == dt_datetime.getMonth() ||
		dt_current_day.getMonth() == dt_firstday.getMonth()) {
		// print row heder
		str_buffer += '<tr>';
		for (var n_current_wday = 0; n_current_wday < 7; n_current_wday++) {

				// --- set background style ---
				if (dt_current_day.getDate() == dt_datetime.getDate() &&
					dt_current_day.getMonth() == dt_datetime.getMonth())
					// print current date
					str_buffer += '<td class="calDayCurrent" align="center" valign="middle">';
				else if (dt_current_day.getDay() == 0 || dt_current_day.getDay() == 6)
					// weekend days
					str_buffer += '<td class="calDayWeekend" align="center" valign="middle">';
				else
					// print working days of current month
					str_buffer += '<td class="calDayWorking" align="center" valign="middle">';

				// --- set foreground style ---
				// forbidden dates
				if (!this.validate(dt_current_day, true))
					str_buffer += '<span class="calForbDate">'
						+ dt_current_day.getDate() + '</span></td>';
				// dates of current month
				else if (dt_current_day.getMonth() == dt_datetime.getMonth()) {
					
					// determine if we have a related calendar
					if (this.rel_id == null) {
						str_buffer += '<a href="javascript:calendars[' + this.id +
							'].set_day(' + dt_current_day.valueOf() + ');" class="calThisMonth">'
							+ dt_current_day.getDate() + '</a></td>';
					}
					else {
						if (this.weekbuffer < 1) 
								str_buffer += '<a href="javascript:calendars[' + this.id +
									'].set_day(' + dt_current_day.valueOf() + ');calendars[' + this.rel_id +
									'].set_day(' + eval(dt_current_day.valueOf()+(1000*60*60*24*7)) + ');" class="calThisMonth">'
									+ dt_current_day.getDate() + '</a></td>';
						else
							str_buffer += '<a href="javascript:calendars[' + this.id +
								'].set_day(' + dt_current_day.valueOf() + ');" class="calThisMonth">'
								+ dt_current_day.getDate() + '</a></td>';

					}
				}
				// dates of other months
				else 
					if (this.weekbuffer < 1)
								str_buffer += '<a href="javascript:calendars[' + this.id +
									'].set_day(' + dt_current_day.valueOf() + ');calendars[' + this.rel_id +
									'].set_day(' + eval(dt_current_day.valueOf()+(1000*60*60*24*7)) + ');" class="calThisMonth">'
									+ dt_current_day.getDate() + '</a></td>';
					else
						str_buffer += '<a href="javascript:calendars[' + this.id +
							'].set_day(' + dt_current_day.valueOf() + ');" class="calOtherMonth">'
							+ dt_current_day.getDate() + '</a></td>';
						
				dt_current_day.setDate(dt_current_day.getDate() + 1);
		}
		// print row footer
		str_buffer += "</tr>\n";
	}
	// print calendar footer

	str_buffer +=
		'</table>';
								
	return (str_buffer);
}

function cal_date_only (dt_datetime) {
	if (!dt_datetime)
		dt_datetime = new Date();
	dt_datetime.setHours(0);
	dt_datetime.setMinutes(0);
	dt_datetime.setSeconds(0);
	dt_datetime.setMilliseconds(0);
	return dt_datetime;
}

function cal_validate (dt_datetime, b_silent) {
	if (this.max_date && dt_datetime > this.max_date) {
		if (b_silent) return false;
		if (LOG_SHOWERROR) alert ('Sorry, dates after ' + cal_generate_date(this.max_date) + ' are not allowed.');
		return (LOG_SETLIMIT ? this.max_date : this.dt_current); 
	}
	if (this.min_date && dt_datetime < this.min_date) {
		if (b_silent) return false;
		if (LOG_SHOWERROR) alert ('Sorry, dates before ' + cal_generate_date(this.min_date) + ' are not allowed.');
		return (LOG_SETLIMIT ? this.min_date : this.dt_current); 
	}
	// more validation can be added here
	return dt_datetime;
}

function _UserAgent() {
	
	var b = navigator.appName;
	var v = this.version = navigator.appVersion;
	var ua=this.uas = navigator.userAgent.toLowerCase();
	this.v = parseInt(v);
	this.mozilla=false;
	this.ns = (b == "Netscape");
	this.ie = (b == "Microsoft Internet Explorer");
	this.opera = ua.indexOf("opera")>0;
	if(ua.indexOf("netscape") < 0 && ua.indexOf("msie") < 0  && ua.indexOf("opera") < 0 && this.v >= 5) {
		this.mozilla = true;
		this.ns = false;
	}
	if (this.ns) {
		if(ua.indexOf('netscape/7.1') > 0) this.ns71 = true; 
		else {
			this.v = parseInt(v);
			this.ns4 = (this.v==4);
			this.ns6 = (this.v>=5);
			this.ns71 = false; 
		}
		
	}
	else if (this.ie) {
		this.ie4 = this.ie5 = this.ie55 = this.ie6 = false;
		if (v.indexOf('MSIE 4') > 0) {this.ie4 = true; this.v = 4;}
		else if (v.indexOf('MSIE 5') > 0) {this.ie5 = true; this.v = 5;}
		else if (v.indexOf('MSIE 5.5') > 0) {this.ie55 = true; this.v = 5.5;}
		else if (v.indexOf('MSIE 6') > 0) {this.ie6 = true; this.v = 6;}
	}
	else if (this.opera || this.mozilla) {
		this.v = parseInt(v);
	}
	this.win32 = ua.indexOf("win")>-1;
	this.mac = ua.indexOf("mac")>-1;
	this.other = (!this.win32 && !this.mac);
	
}

