/* --------------------------------------------------------------- */
// Displays the calendar widget
//
// var author = openJaw;
// var rip = author.updater();
// rip.name = Remi Palard;
// rip.email = remi.palard@gmail.com;
//
/* --------------------------------------------------------------- */


/* --------------------------------------------------------------- */
/* Init */
/* --------------------------------------------------------------- */
var target_widget;
var target_date;

var curId;
var compId;

var date_format 			= _jssDateFormat;
var short_date_Format		= _jssYYYYMMDD;
var current_day 			= new Date();
var today 						= new Date();
var armageddon 				= new Date();
var selected_day 			= new Date();
var _date 						= new Date();
var _calendars 				= new Array('adrcalendar_widget','adrcalendar_widget_2');
var _months 					= new Array('month_year_display_1','month_year_display_2');
var _days 						= new Array('calendarDays_1','calendarDays_2');
var _calendarWidth 		= 139;
var _calendarHeight 	= 135;
var _armStart 				= false;
var borderId;
var compareId;
var compareType;
var cantSelectBefore = new Date();


/* --------------------------------------------------------------- */
/* Tools */
/* --------------------------------------------------------------- */

function map(code,list) {
	var result = [];
	for (var i = 0; i < list.length; i++) {
		result.push( code(list[i]));
	}
	return result;
}

/* --------------------------------------------------------------- */

function grep(code,list) {
	var result = [];
	for (var i = 0; i < list.length; i++) {
		if (code(list[i])) {
			result.push( list[i]);
		}
	}
	return result;
}

/* --------------------------------------------------------------- */

function parent(widget) {
	if (widget.parentElement) { return widget.parentElement; }
	if (widget.parentNode) { return widget.parentNode; }
	if (widget.parent) { return widget.parent; }
	return;
}

function strftime(format,date) {
	var result = format;
	result = result.replace( /%Y/, date.getFullYear());
	// don't add 1 to cover the java date oddity becasue we are getting the name from an array beginning with 0
	result = result.replace( /%m/, month_names_short[date.getMonth()]);
	result = result.replace( /%d/, date.getDate());
	result = result.replace( /%D/, day_names[date.getDay()]);
	return result;
}

/* --------------------------------------------------------------- */

function strptime(format,text) {

	var result = new Date();

	// quote meta chars
	var s = '^' + format.replace( /([][.\*])/g, '\\$1') + '$';
	var re_format = new RegExp( s.replace(/%[Ymd]/g,'(\\d+)'));
	var match = text.match( re_format );

	if (match) {
		// Throw away the full string that appears for some weird reason
		match.shift();
		// we have a valid, matching date
		var date_parts = new Object();
		date_parts['Y'] = result.getFullYear();
		date_parts['m'] = result.getMonth();
		date_parts['d'] = result.getDate();

		order = format.match( /%[Ymd]/g );
		for (var i = 0; i < order.length; i++) {
			date_parts[ order[i].substr(1,1) ] = parseInt(match[i], 10);
		}

		if (date_parts['Y'] < 100) { date_parts += 2000; }
		result = new Date(date_parts.Y, date_parts.m-1, date_parts.d);
	}

	return result;
}

/* --------------------------------------------------------------- */

function isSearchDate(_date) {
	var response = true;

	// Year
	var year = getIntlYear(_date);
	if (year < 2000 || year > 2100) response = false;

	// Month
	var month = getIntlMonth(_date);
	if (month < 1 || month > 12)
		response = false;

	// Day
	var day = getIntlDay(_date);
	var monthLength = new Array(31,28,31,30,31,30,31,31,30,31,30,31);
	if (year/4 == parseInt(year/4)) monthLength[1] = 29;
	if (day > monthLength[month-1])
		response = false;

	/* Past date
	var now = new Date();
	var dateToCheck = new Date(year,(month-1),day);
	if (now.getTime() > dateToCheck.getTime())
		response = false;
	*/
	return response;
}
function getIntlYear(_date) {
	var ret;
	if (short_date_Format == "mmddyyyy"){
		ret = _date.substring(4,8);
	} else if (short_date_Format == "jjmmaaaa"){
		ret = _date.substring(4,8);
	} else {
		ret = _date.substring(0,4);
	}
	return noneNaNNumber(ret);
}
function getIntlMonth(_date) {
	var ret;
	if (short_date_Format == "mmddyyyy"){
		ret = _date.substring(0,2);
	} else if (short_date_Format == "jjmmaaaa"){
		ret = _date.substring(2,4);
	} else {
		ret = _date.substring(4,6);
	}
	return noneNaNNumber(ret);
}
function getIntlDay(_date) {
	var ret;
	if (short_date_Format == "mmddyyyy"){
		ret = _date.substring(2,4);
	} else if (short_date_Format == "jjmmaaaa"){
		ret = _date.substring(0,2);
	} else {
		ret = _date.substring(6,8);
	}
	return noneNaNNumber(ret);
}
function noneNaNNumber(i){
	if (isNaN(parseInt(i,10)))
		return 0;
	else
		return parseInt(i,10);
}


/* --------------------------------------------------------------- */

Date.prototype.setDMY = function(day,month,year) {
	// init
	this.setDate(1);	//Bug setMonth() february

	//Set date
	this.setYear(year);
	this.setMonth(month);
	this.setDate(day);
}
/* --------------------------------------------------------------- */

function add_days(date,delta) {

	// get the calendar date 24h before the current date:
	var result = new Date();
	result.setTime(date.getTime() + delta*(24 * 60 * 60 *1000) );
	if (result.getDate() == date.getDate()) {
	  // Ooops - date had more than 24 hours to it (DST!)
	  result.setTime( result.getTime() + (delta > 0 ? 1 : -1 ) *60 * 60 * 1000);
	}

	// Clamp the time to the original time:
	result.setHours( date.getHours());

	return result;
}

/* --------------------------------------------------------------- */

function day_before(date) { return add_days(date,-1); }
function day_after(date) { return add_days(date, 1); }
function first_of_month(date) { return new Date( date.getFullYear(), date.getMonth(), 1 ); }
function prev_month(date) { return day_before( first_of_month( date )); }
function next_month(date) { return add_days( first_of_month( date ),32 ); }
function prev_year(date) { var result = date; result.setYear( date.getFullYear() -1 ); return result; }
function next_year(date) { var result = date; result.setYear( date.getFullYear() +1 ); return result; }

/* --------------------------------------------------------------- */

function same_day(d1,d2) {
	return d1.getDate() == d2.getDate() && d1.getMonth() == d2.getMonth() && d1.getFullYear() == d2.getFullYear()
}

/* --------------------------------------------------------------- */

function isBefore(d1,d2) {
	if (d1.getFullYear() < d2.getFullYear()) { return true; }
	if ((d1.getFullYear() == d2.getFullYear() ) &&  (d1.getMonth() < d2.getMonth())) { return true; }
	if ((d1.getMonth() == d2.getMonth()) && (d1.getDate() < d2.getDate())) { return true; }
	return false;
}

/* --------------------------------------------------------------- */

function isAfter(d1,d2) {
	if (d1.getFullYear() > d2.getFullYear()) { return true; }
	if ((d1.getFullYear() == d2.getFullYear() ) &&  (d1.getMonth() > d2.getMonth())) { return true; }
	if ((d1.getMonth() == d2.getMonth()) && (d1.getDate() > d2.getDate())) { return true; }
	return false;
}


/* --------------------------------------------------------------- */
/* Update fct
/* --------------------------------------------------------------- */

function month_left_Check() {

	// check whether the left and right month arrows should be displayed for this month
   if ((current_day.getFullYear() == cantSelectBefore.getFullYear()) && (current_day.getMonth() <= cantSelectBefore.getMonth())) {
	  $("adrLeftArrow").style.display='none';
   } else {
	  $("adrLeftArrow").style.display='block';
   }
}

/* --------------------------------------------------------------- */

function month_right_Check() {

	// check whether the left and right month arrows should be displayed for this month
	//if ((current_day.getFullYear() == armageddon.getFullYear()) && (current_day.getMonth() >= (armageddon.getMonth()-1)) && (_armStart == true)) {
	//  $("rightArrow").style.display='none';
	//} else {
	//   $("rightArrow").style.display='block';
	//}
}

/* --------------------------------------------------------------- */


function year_left_click(widget) {
	adr_display_month( prev_year( current_day ));
}

/* --------------------------------------------------------------- */

function adr_month_left_click(widget) {
	for(i=0; i<_calendars.length; i++) {
		tmpDay = current_day;
		for(j=1; j<_calendars.length-i; j++) {
			tmpDay = prev_month( current_day );
		}
		adr_display_month( tmpDay ,_months[i],_days[i]);
	}
	current_day = prev_month( current_day );
	month_left_Check();
	month_right_Check();
}

/* --------------------------------------------------------------- */

function adr_month_right_click(widget) {
	tmpDay = current_day;
	for(i=0; i<_calendars.length; i++) {
		tmpDay = next_month( tmpDay );
		adr_display_month( tmpDay ,_months[i],_days[i]);
	}
	current_day = next_month( current_day );
	month_left_Check();
	month_right_Check();
}

/* --------------------------------------------------------------- */

function adr_calendar_cells(_cells) {
	var div = $(_cells);
	return grep( function(i){ return i.className == 'cell'}, div.getElementsByTagName('span'));
}



function adr_close_widget() {
	$("calendar").hide();
    if(navigator.appVersion.match(/MSIE 6/)) {
    	var iframe = $("calendar_iframe");
		if(iframe) {
			iframe.hide();
		}
    }

    document.body.onclick = null;
    Event.stopObserving(document.body, "keydown", Calendar.notifyKeyPress);

	borderId.removeClassName("activated");
}

/* --------------------------------------------------------------- */
function checkDate() {
	var el = $(curId);
	if (isSearchDate(el.value)) {
		var year = getIntlYear(el.value);
		var month = getIntlMonth(el.value);
		var day = getIntlDay(el.value);

		var toFormat = new Date(year,month-1,day);
		el.value = strftime(date_format,toFormat);
		month = month<10?'0'+month:month;
		day = day<10?'0'+day:day;
		$(curId + 'Date').value = year + '-' + month + '-' + day;
		
		if (curId != '' && $(compId + 'Date').value != ''){
			if ((compareType == 'before' && $(compId + 'Date').value > $(curId + 'Date').value) ||
				(compareType == 'after' && $(compId + 'Date').value < $(curId + 'Date').value)){
				$(compId + 'Date').value = "";
				$(compId).value = "";
			}
		}

	}
}

/**
 * Call-back function called when the user clicks somewhere. The calendar should be closed if the click happened outside
 * of the calendar.
 */
function widget_onblur(event) {
    event = event || window.event;
    var source = Event.element(event);
	recoverBackup(target_widget);
	adr_close_widget();
	checkDate();
}


function proceed(event, year, month, day) {
	Event.stop(event);
	var selected = new Date(year,month,day);
	var s = selected != '' ? strftime(date_format,selected) : '';

	if (day.toString().length < 2) day2 = '0' + day;
	else day2 = day;
	month2 = month +1
	if (month2.toString().length < 2) month2 = '0' + month2;

	/* Apply dates */
	target_date.value = year + '-' + month2 + '-' + day2;
	target_widget.value = s;


	// Common Fields
	saveCommonFields(target_date.id, target_date.value);
	saveCommonFields(target_widget.id, target_widget.value);


	if (compareId != '' && $(compareId + 'Date').value != ''){
		if ((compareType == 'after' && $(compareId + 'Date').value < target_date.value) ||
			(compareType == 'before' && $(compareId + 'Date').value > target_date.value)){
			//$(compareId + 'Date').value = target_date.value;
			$(compareId + 'Date').value = "";
			//$(compareId).value = target_widget.value;
			$(compareId).value = "";
		}
	}
	var field = target_widget;
	adr_close_widget();
	moveFocus(target_widget.id);

    updateFormMessage(field.name);
}

/* --------------------------------------------------------------- */

function adr_display_month(month,_monthTarget,_dayTarget) {

	var first = first_of_month( month );
	var month_year_display = $(_monthTarget);
	var curr = first;

	month_year_display.innerHTML = month_names[month.getMonth()] + " " + month.getFullYear();

	while ((curr.getDay()+1) != 1) curr = day_before(curr);
	var cells = adr_calendar_cells(_dayTarget);

	for (var offset = 0; offset < cells.length; offset++) {

		var link = true;
		var span_class = 'calendarDay';

		// Today (not used)
		if (same_day(curr,today)) { span_class = 'today' }

		// Selected Day
		if (same_day(curr,selected_day)) {
			span_class = 'currentSelection';
		}

		// Can't select a day before cantSelectBefore
		if (isBefore(curr,cantSelectBefore)) {
			link = false;
			if(curr.getMonth() == cantSelectBefore.getMonth() && curr.getYear() == cantSelectBefore.getYear()) {
				span_class = 'forbiddenDay';
			} else {
				link = true;
			}
		}

		// Can't select a day after armageddon...
		//if ( (_armStart == true) && (curr.getTime() > armageddon.getTime()) ) {
		//	span_class = 'forbiddenDay';
		//	link = false;
		//}

		// Can't select a day after 355...
		if (curr > add_days(new Date(),355)) {
			span_class = 'forbiddenDay';
			link = false;
		}



		// Month before
		if (curr.getMonth() != month.getMonth()) {
			span_class = 'otherMonth';
			link = false;
		}

   		// Display link
		if (link) {
			cells[offset].innerHTML = '<div class="'+span_class+'" onclick="proceed(event, '+curr.getFullYear()+','+(curr.getMonth())+','+curr.getDate() +')">' + curr.getDate() + '</div>';
		}
		else {
			cells[offset].innerHTML = '<div class="'+span_class+'">' + curr.getDate() + '</div>';
		}

		curr = day_after( curr );
	}
	//update shortcuts when getting the left one
	if(_monthTarget == _months[0]){
		updateShortcuts(month);
	}
 }
/* --------------------------------------------------------------- */

function updateShortcuts(month) {
	// Update the shortcuts at the bottom of the calendar.
	var shortcuts = $("calendar").down("div.shortcuts");
	var label = shortcuts.down("label");

	// IE fix: attach this element elsewhere in order to avoid it to be destroyed when updating the "div.shortcuts" element HTML.
	$("calendar").appendChild(label);

	var fragment = "";
	var date = Date.parse(month.toISO()) || Date.today();
	date.setDate(1); // set day (time zone bug?)
	var display = [date, date.shift(+1, Date.Month)];
    date = Date.today();
    date.setDate(1); // set day (time zone bug?)
    var spread = 13;
    var scope = [date, date.shift(spread, Date.Month)];
    var index = 0;
    while(date < scope[1]) {
        if(index > 0) {
            if(!((spread - index) % 5)) {
                fragment += "<br/>";
            }
            else {
                fragment += " | ";
            }
        }

        /*!date.isWithin(display) bug with timezone*/
        if(((date.getMonth() != display[0].getMonth()) || (date.getYear() != display[0].getYear()))
        	&& ((date.getMonth() != display[1].getMonth()) || (date.getYear() != display[1].getYear()))) {
        	fragment += '<a href="javascript:Calendar.jumpTo(\'' + date.toISO() + '\');">' + month_names_short[date.getMonth()] + ' ' + date.getFullYear()+ '</a>';
        }
        else {
        	fragment += month_names_short[date.getMonth()] + " " + date.getFullYear();
        }

        date = date.shift(+1, Date.Month);
        index++;
    }

    shortcuts.update(fragment);
    shortcuts.insert({top: label});
}



function adrCalendar(dateFieldId, linkedDateId, _type) {
	var pos;
	curId = dateFieldId;
	compId = linkedDateId;

	/* Re init today (just in case...) */
	today = new Date();

	var widget = $(dateFieldId);
	var linked_date = "";
	target_date = $(dateFieldId + 'Date');
	target_date.activate();
	pos = findPos(widget);
	
	compareId = '';

	document.body.onclick = function(event) {
	    event = event || window.event;
	    var source = Event.element(event);
		var calendar = $("calendar");
		if((source != target_widget) && (source != calendar) && !source.descendantOf(calendar)) {
	    	widget_onblur(event);
	    }
	};

	// If we do not delay the key listener affectation it could catch any event that is being caught by a listener that
	// lead here, inducing a bad calendar behavior. Indeed, here, at this stage, such an event would not yet be propaga-
	// -ted to the "body" element.
	(function() { Event.observe(document.body, "keydown", Calendar.notifyKeyPress); }).delay(0.005);

	if($(linkedDateId)) {
		compareId = linkedDateId;
		compareType = _type;

		/* Can't select after the departing date */
		//if (_type == 'after') {
		//	linked_date = $(linkedDateId + 'Date').value;
		//
		//	if (linked_date != '') {
		//		sDate = linked_date.split('-');
		//		armageddon.setDMY(sDate[2], sDate[1]-1, sDate[0]);
		//		_armStart = true;
		//	}
		//}

		/* Can't select before the leaving date */
		if(_type == 'before') {
			linked_date = $(linkedDateId + 'Date').value;

			if(linked_date != '') {
				sDate = linked_date.split('-');

				today.setDMY(sDate[2], sDate[1]-1, parseInt(sDate[0]));
				_armStart = false;
			}
		}
	}

	// YYYY-MM-DD = 10
	if(target_date.value.length == 10) {
		sDate = target_date.value.split('-');
		current_day.setDMY(sDate[2], sDate[1]-1, sDate[0]);
	}
	else {
		current_day.setDMY(today.getDate(), today.getMonth(), today.getFullYear());
	}

	// find lower edge of edit widget:

	pos.top = pos.top - _calendarHeight;

	// Fix the selected day once
	selected_day = current_day;
	// find/create calendar widget
	for(i=0; i < _calendars.length; i++) {
		// Construction date - Set the calendar to the first of month
		_date.setDMY(1,current_day.getMonth() + i,current_day.getFullYear());

		// If departure date and return date are in the same month
		// We don't display the second calendar
		//if ( (_armStart == true) && (_date.getTime() > armageddon.getTime()) ) return;

		var adrcalendar_widget = $(_calendars[i]);

		// Now connect the current edit to the div:
		target_widget = widget;
		adr_display_month(_date,_months[i],_days[i]);
		month_left_Check();
		month_right_Check();
	}

	updateShortcuts(today);

    // Show the calendar around the targeted field.
	var calendar = $("calendar");
    var position = widget.positionedOffset();
    position[0] = position[0] - 3 + "px";
    position[1] = position[1] - calendar.getHeight() - 5 + "px";
    calendar.style.top = position[1];
    calendar.style.left = position[0];
    if(navigator.appVersion.match(/MSIE 6/)) {
    	var iframe = $("calendar_iframe");
    	iframe.setStyle({
    		left: position[0],
    		top: position[1]
    	});
    	iframe.show();
    }
    calendar.show();

	if (borderId) borderId.removeClassName("activated");
	
    var border = borderId = $(dateFieldId + 'Border');
    border.addClassName("activated");
}

Calendar = {
    jumpTo: function(date) {
        date = (date instanceof Date) ? date : Date.parse(date);
        _calendars.each(function(calendar, index) {
            adr_display_month(date.shift(index, Date.Month), _months[index], _days[index]);
        });
        current_day = date;
        month_left_Check();
        month_right_Check();
    },

    notifyKeyPress: function(event) {
        var field = null;
        switch(event.keyCode) {
            case Event.KEY_RETURN:
            case Event.KEY_TAB:
                widget_onblur(event);
                if(!event.shiftKey) {
                	moveFocus(target_widget.id);
                }
                Event.stop(event);
                break;
            case Event.KEY_ESC:
                widget_onblur(event);
                return;
        }
    }
};
