calendar = {};
/**
 * obiekt na dane kalendarza, korzystaja z nich rozne moduly
 */
calendar.data = {
	'rents'				: {},
	'maxRentTime'		: 0, // w miesiacach
	'minRentTime'		: 0, // w sekundach
	'onChange'			: Prototype.emptyFunction,
	'getDayColor'		: Prototype.emptyFunction,
	'validateDataRange' : true,
	'startDate'			: new Date(), // obiekt typu date
	'today'				: new Date(), // obiekt typu date
	'currentSelection'	: {'from':new Date(), 'to':new Date()}, // obiekty typu date
	'lastShowedMonth'	: 0,
	'lastShowedYear'	: 0,
	'showedNum'			: 0,
	'hourlyMode'		: 0
};
/**
 * przechowuje wazniejsze dane kalendarza
 * 
 * obiekt opcji dla kalendarza zawiera:
 * - rents - tablica z obiektami z datami wynajec (do zaznaczenia czasow niedostepnosci)
 * - maxRentTime - na ile miesiecy pokazac kalendarzy
 * - minRentTime - minimalny okres jaki mozna zaznaczyc
 * - today - dzisiejsza data
 * - onChange - funkcja wywolywana po zmianie daty
 * - getDayColor - funkcja, ktora jako parametry przyjmuje rok, miesiac i dzien, a zwraca liczbe 1-8 (okresla kolor dnia)
 * 
 * @param {object} options - obiekt opcji dla kalendarza
 */
calendar.init = function(options)
{
	calendar.data = Object.extend(calendar.data, options);
	if(calendar.data.minRentTime < 86400){
		calendar.data.hourlyMode = 1;
	}
	
	calendar.availability.init();
	calendar.select.init();
	calendar.calendar.init();
}
/**
 * uaktualnienie pokazywanych dat, oraz wywolania funkcji callback
 */
calendar.update = function()
{
	if(calendar.data.validateDataRange){
		calendar.availability.validateRange();
	}
	calendar.select.update();
	calendar.calendar.update();
	calendar.data.onChange();
}
/**
 * nanosi nowe dane o dostepnosci na kalendarze
 * @param {array} rents
 */
calendar.newRentsData = function(rents)
{
	calendar.data.rents = rents;
	calendar.availability.init();
	calendar.calendar.markColors();
}
/**
 * zwraca poczatek aktulanego zaznaczenia
 * @return {Date}
 */
calendar.getFromDate = function()
{
	return calendar.data.currentSelection.from;
}
/**
 * zwraca koniec aktulanego zaznaczenia
 * @return {Date}
 */
calendar.getToDate = function()
{
	return calendar.data.currentSelection.to;
}

/**
 * modul zwiazany z polami select, pkazywanie ich, uaktualnianie, zczytywanie wartosci...
 */
calendar.select = {};
/**
 * pokazuje pola select\
 * @param {bool} rentForHours
 */
calendar.select.init = function()
{
	var data = calendar.select.getHtml();
	var templ = new Template(calendarLang.selects);
	$('rentTime').update(templ.evaluate(data));
	if(calendar.data.minRentTime>=86400){
		$('fromHour').hide();
		$('toHour').hide();
	}
	
	$('fromMonthYear').down().selected = 'selected';
	$('toMonthYear').down().selected = 'selected';
	$('fromMonthYear').observe('change', calendar.select.setDays.bindAsEventListener(calendar, 'from'));
	$('toMonthYear').observe('change', calendar.select.setDays.bindAsEventListener(calendar, 'to'));
	calendar.select.setDays(null, 'from');
	calendar.select.setDays(null, 'to');
	calendar.select.read(null);
	
	$('rentTime').getElements().each(function(el){
		el.observe('change', function(event){
			calendar.select.read();
			calendar.update();
		});
	});
}
/**
 * zwraca kod html selectow w jednym obiekcie z polami: hourOptions, dayOptions, monthYearOptions
 * @return {object}
 */
calendar.select.getHtml = function()
{
	var data = {};
	data.hourOptionsFrom = '';
	for(var i=0; i<24; i++){
		data.hourOptionsFrom += '<option value="'+i+'"'+( i==9 ? ' selected="selected"' : '' )+'>'+i+':00</option>';
	}
	data.hourOptionsTo = '';
	for(var i=0; i<24; i++){
		data.hourOptionsTo += '<option value="'+i+'"'+( i==9 ? ' selected="selected"' : '' )+'>'+i+':59</option>';
	}
	data.dayOptions = '';
	for(var i=1; i<32; i++){
		data.dayOptions += '<option value="'+i+'">'+i+'</option>';
	}
	data.monthYearOptions = '';
	var startMonth = calendar.data.startDate.getMonth();
	var startYear = calendar.data.startDate.getFullYear();
	var endMonth = startMonth + calendar.data.maxRentTime;
	var endYear = startYear + Math.floor(endMonth/11);
	endMonth = (endMonth%11);
	for(var month=startMonth, year=startYear; month<endMonth || year<endYear; ){
		data.monthYearOptions += '<option value="'+month+'.'+year+'">'+calendarLang.months[month]+' '+year+'</option>';
		month++;
		if(month>11){
        	year++;
        	month = 0;
        }
	}
	return data;
}
/**
 * ustawia odpowiednia ilosc dni dla miesiaca w select
 * @param {object} event
 * @param {string} fields
 */
calendar.select.setDays = function(event, fields)
{
	if(event){
		event.stop();
	}
	var tempDays = parseInt($F(fields+'Day')); 

	var monthYear = $(fields+'MonthYear').getValue().split('.');
	var daysNum = calendar.calendar.daysInMonth(monthYear[1], monthYear[0]);
	
	var dayOptions = '';
	if(monthYear[0]==calendar.data.today.getMonth() 
				&& monthYear[1]==calendar.data.today.getFullYear() 
				&& calendar.data.validateDataRange){
		var i = calendar.data.today.getDate();
	} else {
		var i = 1;
	}
	for(; i<=daysNum; i++){
		dayOptions += '<option value="'+i+'">'+i+'</option>';
	}
	$(fields+'Day').update(dayOptions);
	tempDays = (tempDays<i) ? i : tempDays;
	tempDays = (tempDays>daysNum) ? daysNum : tempDays;
	$(fields+'Day').value = tempDays;
}
/**
 * funkcja zczytuje dane z pol formularza i umieszcza je w danych obiektu
 */
calendar.select.read = function()
{
	calendar.data.currentSelection.from.setYear(parseInt($F('fromMonthYear').split('.')[1]));
	calendar.data.currentSelection.from.setMonth(parseInt($F('fromMonthYear').split('.')[0]));
	calendar.data.currentSelection.from.setDate(parseInt($F('fromDay')));
	if(calendar.data.minRentTime<86400){
		calendar.data.currentSelection.from.setHours(parseInt($F('fromHour')));
	} else {
		calendar.data.currentSelection.from.setHours(0);
	}
	calendar.data.currentSelection.from.setMinutes(0);
	calendar.data.currentSelection.from.setSeconds(0);
	
	calendar.data.currentSelection.to.setYear(parseInt($F('toMonthYear').split('.')[1]));
	calendar.data.currentSelection.to.setMonth(parseInt($F('toMonthYear').split('.')[0]));
	calendar.data.currentSelection.to.setDate(parseInt($F('toDay')));
	if(calendar.data.minRentTime<86400){
		calendar.data.currentSelection.to.setHours(parseInt($F('toHour')));
	} else {
		calendar.data.currentSelection.to.setHours(23);
	}
	calendar.data.currentSelection.to.setMinutes(59);
	calendar.data.currentSelection.to.setSeconds(59);
}
/**
 * funkcja uaktualnia pola formularza zgodnie z danymi w obiekcie
 */
calendar.select.update = function()
{
	$('fromMonthYear').value = calendar.data.currentSelection.from.getMonth()+'.'
								+calendar.data.currentSelection.from.getFullYear();
	calendar.select.setDays(null, 'from');
	$('fromDay').value = calendar.data.currentSelection.from.getDate();
	$('fromHour').value = calendar.data.currentSelection.from.getHours();
	
	$('toMonthYear').value = calendar.data.currentSelection.to.getMonth()+'.'
								+calendar.data.currentSelection.to.getFullYear();
	calendar.select.setDays(null, 'to');
	$('toDay').value = calendar.data.currentSelection.to.getDate();
	$('toHour').value = calendar.data.currentSelection.to.getHours();
}


/**
 * modul odpowiedzialny za tworzenie kalendarza 
 */ 
calendar.calendar = {};
/**
 * metoda wyolywana po zaladowaniu danych o dostepnosci oferty oraz cennikow z serwera
 */
calendar.calendar.init = function()
{
	if(calendar.data.startDate.getMonth()==0){
		calendar.data.lastShowedMonth = 11;
		calendar.data.lastShowedYear = calendar.data.startDate.getFullYear()-1;
	} else {
		calendar.data.lastShowedMonth = calendar.data.startDate.getMonth()-1;
		calendar.data.lastShowedYear = calendar.data.startDate.getFullYear();
	}
	var showNum = (calendar.data.maxRentTime>4 ? 4 : calendar.data.maxRentTime);
	calendar.calendar.showNextCalendars(showNum);
	if(calendar.data.maxRentTime<=4){
		$('showMoreCalendars').hide();
	} else {
		$('showMoreCalendars').observe('click', function(event){
			event.stop();
			if(calendar.data.maxRentTime > calendar.data.showedNum+4){
				var showNum = 4;
			} else {
				var showNum = calendar.data.maxRentTime - calendar.data.showedNum;
				$('showMoreCalendars').hide();
			}
			calendar.calendar.showNextCalendars(showNum);
		});
	}
}
/**
 * pokazuje wskazana ilosc kolejnych kalendarzy
 */
calendar.calendar.showNextCalendars = function(showNum)
{
	for(var i=0; i<showNum; i++){
		calendar.data.lastShowedMonth++;
		if(calendar.data.lastShowedMonth>11){
			calendar.data.lastShowedMonth = 0;
			calendar.data.lastShowedYear++;
		}
		$('calendars').insert(calendar.calendar.createMonthCalendar(calendar.data.lastShowedYear, 
																		calendar.data.lastShowedMonth));
	}
	calendar.data.showedNum += showNum;
	calendar.calendar.markColors();
	calendar.calendar.update();
	
	$$('#calendars td.active').each(function(td){
		td.onclick = calendar.calendar.tdClick.bindAsEventListener(calendar, td.id);
	});
}
/**
 * tworzy i zwraca kod html kalendarzyka na podany miesiac
 * @param {int} year
 * @param {int} month
 * @return {string}
 */
calendar.calendar.createMonthCalendar = function(year, month)
{
	month = calendar.calendar.calculateMonthData(year, month);
	var calendarString = '';
	var day = 1;
	var id='';
	for(var i=0; i<6; i++){
		calendarString += '<tr>';
		var start = (i==0 ? month.firstDay : 0 );
		for(var j=0; j<7; j++){
			if(start<=j && day<=month.daysInMonth){
				id = ' id="'+day+'.'+month.month+'.'+month.year+'"';
				calendarString += (j==6) ? '<td'+id+' class="sunday">' : '<td'+id+'>';
				calendarString += day+'</td>';
				day++;
			} else {
				calendarString += '<td class="empty">&nbsp;</td>';
			}
		}
		calendarString += '</tr>';
	}
	var tmpl = new Template(calendarLang.table);
	month.tbody = calendarString;
	month.monthName = calendarLang.months[month.month];
	return tmpl.evaluate(month);
}
/**
 * oblicza i zwraca dane o podanym miesiacu 
 * (month, year, daysInMonth, weeksInMonth, firstDay)
 * @param {int} year
 * @param {int} mont
 * @return {object}
 */
calendar.calendar.calculateMonthData = function(year, month)
{
	var date = new Date();
	date.setDate(1);
	date.setMonth(month);
	date.setYear(year);
	var result = {};
	result.month = month;
	result.year = year;
	result.daysInMonth = calendar.calendar.daysInMonth(year,month);
	result.firstDay = (date.getDay()+6)%7;
	result.weeksInMonth = Math.ceil((result.daysInMonth+result.firstDay)/7);
	return result;
}
/**
 * zwraca ilosc dni w podanym miesiacu, w pelni zgodne z kalendarzem gregorianskim
 * @param {int} year
 * @param {int} mont
 * @return {int}
 */
calendar.calendar.daysInMonth = function(year, month)
{
	var days = new Array(31,28,31,30,31,30,31,31,30,31,30,31);
	if(month==1){
		if( ( year%4==0 && year%100!=0 ) || year%400==0 ){
			return 29;
		} else {
			return 28;
		}
	} else {
		return days[month];
	}
}
/**
 * uaktualnia wyswietlanie zaznaczonego obszaru na kalendzarzu
 */
calendar.calendar.update = function()
{
	$$('#calendars td.chosen').each(function(el){
		el.removeClassName('chosen');
	});
	var fromYear = calendar.data.currentSelection.from.getFullYear();
	var fromMonth = calendar.data.currentSelection.from.getMonth();
	var fromDay = calendar.data.currentSelection.from.getDate();
	var toYear = calendar.data.currentSelection.to.getFullYear();
	var toMonth = calendar.data.currentSelection.to.getMonth();
	var toDay = calendar.data.currentSelection.to.getDate();
	var id;
	
	var year=fromYear, month=fromMonth, day=fromDay;
	var i = year*10000 + month*100 + day;
	var maxI = toYear*10000 + toMonth*100 + toDay;
	
	while(i <= maxI){
		id = day+'.'+month+'.'+year;
		if($(id)){
			$(id).addClassName('chosen');
		}
		day++;
		id = day+'.'+month+'.'+year;
		if(!$(id)){ // sprawdzenie, czy miesiac ma tyle dni ;>
			day=1;
			month++;
			if(month>11){
				month=0;
				year++;
			}
		}
		i = year*10000 + month*100 + day;
	}
}
/**
 * koloruje kalendarze (zaznacza ceny, dni niedostepne itd)
 */
calendar.calendar.markColors = function()
{
	$$('#calendars td').each(function(td){
		if(!td.hasClassName('empty')){
			var day = td.id.split('.')[0];
			var month = td.id.split('.')[1];
			var year = td.id.split('.')[2];
			if(calendar.availability.isAvailable(year, month, day)){
				td.className = '';
				var priceLevel = calendar.data.getDayColor(year, month, day) || 1;
				td.addClassName('priceLevel'+priceLevel);
				td.addClassName('active');
			} else {
				td.className = '';
				td.addClassName('unavailable');
				if(!calendar.data.validateDataRange){
					td.addClassName('active');
				}
			}
		}
	});
	var todayKey = calendar.data.today.getDate()+'.'+calendar.data.today.getMonth()+'.'+calendar.data.today.getFullYear();
	$(todayKey).addClassName('today');
}
/**
 * obsluga akcji klikniecia na dzien
 * @param {object} event
 */
calendar.calendar.tdClick = function(event, id)
{
	var day = parseInt(id.split('.')[0]);
	var month = parseInt(id.split('.')[1]);
	var year = parseInt(id.split('.')[2]);
	
	if(calendar.calendar.firstClick.day){
		var firstClickHash = calendar.calendar.firstClick.day + calendar.calendar.firstClick.month*100 + 
								calendar.calendar.firstClick.year*10000;
		var currentHash = day + month*100 + year*10000;
		if(currentHash > firstClickHash){
			calendar.data.currentSelection.to.setDate(13); // kazdy miesiac ma ten dzien, bez tego czasami bledy byly
			calendar.data.currentSelection.to.setYear(year);
			calendar.data.currentSelection.to.setMonth(month);
			calendar.data.currentSelection.to.setDate(day);
		} else {
			calendar.data.currentSelection.from.setDate(13);
			calendar.data.currentSelection.from.setYear(year);
			calendar.data.currentSelection.from.setMonth(month);
			calendar.data.currentSelection.from.setDate(day);
		}
		calendar.calendar.firstClick = {};
		
	} else {
		calendar.calendar.firstClick.day = day;
		calendar.calendar.firstClick.month = month;
		calendar.calendar.firstClick.year = year;
		calendar.data.currentSelection.to.setDate(13); // kazdy miesiac ma ten dzien, bez tego czasami bledy byly
		calendar.data.currentSelection.to.setYear(year);
		calendar.data.currentSelection.to.setMonth(month);
		calendar.data.currentSelection.to.setDate(day);
		calendar.data.currentSelection.from.setDate(13);
		calendar.data.currentSelection.from.setYear(year);
		calendar.data.currentSelection.from.setMonth(month);
		calendar.data.currentSelection.from.setDate(day);
	}
	calendar.update();
}
calendar.calendar.firstClick = {};


/**
 * modul odpowiedzialny za dostepnosc oferty
 */
calendar.availability = {};
/**
 * inicjalizacja modulu dostepnosci (utworzeie mapy dostepnosci)
 */
calendar.availability.init = function()
{
	calendar.availability.map = {};
	for(var i=0; i<calendar.data.rents.length; i++){
		var tempTime = new Date();
		var endTime = new Date();
		tempTime.setTime(calendar.data.rents[i].unixTimeFrom*1000);
		endTime.setTime(calendar.data.rents[i].unixTimeTo*1000);
		for(; tempTime.getTime()<endTime.getTime(); tempTime.setTime(tempTime.getTime()+86400000)){
			var key = tempTime.getFullYear()+'.'+tempTime.getMonth()+'.'+tempTime.getDate();
			calendar.availability.map[key] = 'all';
		}
	}
}
/**
 * sprawdza, czy podany dzien jest wolny
 * dni przeszle pokazywane sa, jako niedostepne
 * @param {int} year
 * @param {int} month
 * @param {int} day
 * @param {bool}
 */
calendar.availability.isAvailable = function(year, month, day)
{
	var today = calendar.data.today;
	if( calendar.data.validateDataRange && ( year<today.getFullYear() || ( year==today.getFullYear() && month<today.getMonth() ) 
			|| ( year==today.getFullYear() && month==today.getMonth() && day<today.getDate() ) ) ){
		return false;
	} else {
		var key = year+'.'+month+'.'+day;
		return !calendar.availability.map[key];
	}
}
/**
 * sprawdza, czy zakres zapisany w calendar.data jest dostepny w calosci
 * jesli nie, wyswietla komunikat i zmniejsza zakres
 */
calendar.availability.validateRange = function()
{
	var tempTime = new Date();
	var endTime = new Date();
	tempTime.setTime(calendar.data.currentSelection.from.getTime());
	endTime.setTime(calendar.data.currentSelection.to.getTime());
	for(; tempTime.getTime()<endTime.getTime(); tempTime.setTime(tempTime.getTime()+86400000)){
		if(!calendar.availability.isAvailable(tempTime.getFullYear(), tempTime.getMonth(), tempTime.getDate())){
			calendar.data.currentSelection.to.setTime(tempTime.getTime()-86400000+3599000);
			break;
		}
	}	
	
}

