/* 
03.11.2006 
TODO: 
 - time component 
*/
var Calendar = {

	init : function(cnf){
		
		/* mode - text/select box */
		this.mode = cnf.mode;
		
		/* absolute url */
		this.base_url = cnf.baseurl;		
		
		/* theme */
		this.theme_name = cnf.theme;
		
		/* is time input control required by default */
		this.time_comp = cnf.timecomponent;
		
		/* are year scrolling buttons required by default */
		this.year_scroll = cnf.yearscrool;
		
		/* if two digit year input dates after this year considered 20 century. */
		this.num_centyear = 30;
		
		/* day week starts from (normally 0-Su or 1-Mo) */
		this.num_weekstart = 1; 		
		
		/* date/time parsing regexp */
		this.re_num = /^\-?\d+$/;
		
		/* instances holder */
		this.calendars = [];
		
		/* container - div element */ 
		this.holder = null;	
		
		/* selected date */
		this.dt_selected = null;
		
		/* is calendar window opened */
		this.opened = false;
		
		/* import theme css file */
		this.importCss(this.getHead());
		
		/* setup language */
		this.lang = this.getLang();		
		
		/* add onclick event handler */
		this.addEvents();
		
	},

	updateOnChange : function(id){
		if(this.mode=='dropdown'){
			day = this.calendars[id].target.day.value.toString().zeroFill(2);
			month = this.calendars[id].target.month.value.toString().zeroFill(2);
			year = this.calendars[id].target.year.value;
			this.calendars[id].date = day + '/' + month + '/' + year;
			window.focus();
		}
	}, 
		
 	updateAfterEvent : function(){
		if(this.mode=='dropdown'){
			this.updateDropdowns(this.calendars[this.opened].date);
		} else {
			this.calendars[this.opened].target.fulldate.value = selected_date;
		}
	}, 
	
	updateDropdowns : function(date){
		date = date.split('/');
		try{
			_day = parseInt(date[0].toString().ltrim('0'));
			_month = parseInt(date[1].toString().ltrim('0'));
			_year = parseInt(date[2].toString().ltrim('0'));
			document.selectDropMenuByVal(this.calendars[this.opened].target.day, _day);		
			document.selectDropMenuByVal(this.calendars[this.opened].target.month, _month);		
			document.selectDropMenuByVal(this.calendars[this.opened].target.year, _year);
		}catch(e){}
	}, 

	setDatetime : function (n_datetime, b_close) {
		if(!this.opened) return;
		dt_datetime = this.prs_time( (document.cal ? document.cal.time.value : ''), new Date(n_datetime) );
		if (!dt_datetime) return;
		if (b_close) {
			selected_date = (document.cal ? this.gen_tsmp(dt_datetime) : this.gen_date(dt_datetime) );
			this.calendars[this.opened].date = selected_date;
			this.updateAfterEvent();
			this.hide();			
		} else {
			this.popup(this.opened, dt_datetime.valueOf());
		}
	}, 

	popup : function(id,str_datetime){
		/* create container div on first popup */
		if(this.holder==null)
			this.createHolder();
		if(this.opened) this.hide();
		if (str_datetime) {
			dt_current = this.prs_tsmp(str_datetime);
		} else {	
			dt_current = this.prs_tsmp(this.calendars[id].date);
			this.dt_selected = dt_current;
		}
		if(!dt_current) 
			return;
		pos = this.getPos(this.calendars[id].caller);
		cal = this.genHtml(dt_current);
		this.show(cal, pos);
		this.opened = id;
	},
	
	add : function(id, dt){
		if(this.mode=='dropdown'){
			target_controls = {	
				day : $('day_'+id),
				month : $('month_'+id),
			  year : $('year_'+id) 		
			};
		} else {
			target_controls = {	
				fulldate : $(id) 
			};
		}
		this.calendars[id] = {
			target : target_controls,
			caller : $('calendarCotnrol['+id+']'), 
			date : dt 
		};
	}, 

	date : function(id){
		return this.calendars[id].date;
	}, 

	getPos : function(n) {
		p = {absLeft : 0, absTop : 0};
		while (n) {
			p.absLeft += n.offsetLeft;
			p.absTop += n.offsetTop;
			n = n.offsetParent;
		}
		p.absLeft = parseInt(p.absLeft) + 20;
		p.absTop  = parseInt(p.absTop) + 5;
		w = {absWidth : 0, absHeight : 0};
		if( typeof( window.innerWidth ) == 'number' ) { 
			// Non-IE
			w.absWidth = window.innerWidth;
			w.absHeight = window.innerHeight;
		} else if( document.documentElement && ( document.documentElement.clientWidth || document.documentElement.clientHeight ) ) {
			//IE 6+ in 'standards compliant mode'
			w.absWidth = document.documentElement.clientWidth;
			w.absHeight = document.documentElement.clientHeight;
		} else if( document.body && ( document.body.clientWidth || document.body.clientHeight ) ) {
			//IE 4 compatible
			w.absWidth = document.body.clientWidth;
			w.absHeight = document.body.clientHeight;
		}
		if( w.absWidth < p.absLeft+200 ) 
			if( p.absLeft - 230 > 0 )
				p.absLeft -= 230;
		if( w.absHeight < p.absTop+160 ) 
			if( p.absTop - 160 > 0 )
				p.absTop -= 160;
		return p;
	},
	
	createHolder : function(){
		this.holder = document.createElement("div");
		this.holder.className = "calendarContainer";
		this.holder.setAttribute("class", "calendarContainer");
		this.holder.style.display = "none";
		this.holder.style.position = 'absolute';
		this.holder.style.zindex = 1000;
		this.holder.style.left = '0';
		this.holder.style.top = '0';
		this.holder.unselectable = "on";
		document.body.appendChild(this.holder);
	},

	getHead : function(){
		head = document.getElementsByTagName("head");
		return head[0];
	}, 

	importCss : function(head_obj){
		src = this.base_url+'themes/'+this.theme_name+'/calendar.css';
		element = document.createElement('link');
		element.setAttribute('href', src);
		element.setAttribute('rel', 'stylesheet');
		element.setAttribute('type', 'text/css');
		head_obj.appendChild(element);
	}, 

	error : function (str_message) {
		alert (str_message);
		return null;
	},
	
	show : function(html,pos){
		hideSelectElement();
		hideObjectElement();
		this.holder.innerHTML = html;
		this.holder.style.left = pos.absLeft + 'px';
		this.holder.style.top = pos.absTop + 'px';
		this.holder.style.display = "block"; 
	},
		
	hide : function(){
		showSelectElement();
		showObjectElement();
		if(!this.opened) return null;
		this.holder.innerHTML = "";
		this.holder.style.display = "none";
		this.opened = false;
	},
	
	addEvents : function (){
		if (document.body.addEventListener) {
			document.body.addEventListener ("click",this.captureEvent,false);
			document.body.addEventListener ("keyup",this.captureEvent,false);
		} else if (document.body.attachEvent) {
			document.body.attachEvent ("onclick",this.captureEvent);
			document.body.attachEvent ("onkeyup",this.captureEvent);
		} else {
			document.body.onclick = this.captureEvent;
			document.body.onkeyup = this.captureEvent;
		}
	}, 

	captureEvent : function (e){
		if (!e) e = window.event;
		t = e.target || e.srcElement;
		if( t==document.body && e.type.indexOf('click') > -1 )
			Calendar.hide();
		else if( ( e.type.indexOf('keyup') > -1 ) && (e.keyCode || e.which) == 27 ) { // escape 
			Calendar.hide();
		}	else {
			// alert(t);
			// alert(c);
		}
	}, 
	
	/////////////////////////////////////////////////////////////////////////////////
	/// HTML 
	/////////////////////////////////////////////////////////////////////////////////	
	
	genHtml : function (dt_current){
	
		if (this.year_scroll) {
			// get same date in the previous year
			dt_prev_year = new Date(dt_current);
			dt_prev_year.setFullYear(dt_prev_year.getFullYear() - 1);
			if (dt_prev_year.getDate() != dt_current.getDate())
				dt_prev_year.setDate(0);
			// get same date in the next year
			dt_next_year = new Date(dt_current);
			dt_next_year.setFullYear(dt_next_year.getFullYear() + 1);
			if (dt_next_year.getDate() != dt_current.getDate())
				dt_next_year.setDate(0);
		}
				
		// get same date in the previous month
		dt_prev_month = new Date(dt_current);
		dt_prev_month.setMonth(dt_prev_month.getMonth() - 1);
		if (dt_prev_month.getDate() != dt_current.getDate())
			dt_prev_month.setDate(0);
		
		// get same date in the next month
		dt_next_month = new Date(dt_current);
		dt_next_month.setMonth(dt_next_month.getMonth() + 1);
		if (dt_next_month.getDate() != dt_current.getDate())
			dt_next_month.setDate(0);
		
		// get first day to display in the grid for current month
		dt_firstday = new Date(dt_current);
		dt_firstday.setDate(1);
		dt_firstday.setDate(1 - (7 + dt_firstday.getDay() - this.num_weekstart) % 7);			

		html = '<table cellspacing="0" border="0" width="200"><tr><td class="calendarMain">';
		html += '<table cellspacing="0" cellpadding="2" width="100%" class="calendarHeader"><tr>';
		html += '<td align="left">'+this.lang.slelect_date+'</td>';
		html += '<td align="right"><a href="javascript:Calendar.hide()"><img src="'+this.base_url + 'themes/'+this.theme_name+'/close.gif" width="16" height="16" border="0" alt="'+this.lang.calendar_close+'"></a></td>';
		html += '</tr></table>';		

		// navigation 
		html += '<table cellspacing="1" cellpadding="2" width="100%" class="calendarNavigation"><tr>';
		if(this.year_scroll)
			html += '<td><a href="javascript:Calendar.setDatetime('+dt_prev_year.valueOf()+')"><img src="'+this.base_url + 'themes/'+this.theme_name+'/prev_year.gif" width="16" height="16" border="0" alt="'+this.lang.prev_year+'"></a></td>';
		html += '<td><a href="javascript:Calendar.setDatetime('+dt_prev_month.valueOf()+')"><img src="'+this.base_url + 'themes/'+this.theme_name+'/prev.gif" width="16" height="16" border="0" alt="'+this.lang.prev_month+'"></a></td>';		
		html += '<td align="center" width="100%" class="calendarCurmonth">'+this.lang.arr_months[dt_current.getMonth()]+' '+dt_current.getFullYear() + '</td>';	
		html += '<td><a href="javascript:Calendar.setDatetime('+dt_next_month.valueOf()+')"><img src="'+this.base_url + 'themes/'+this.theme_name+'/next.gif" width="16" height="16" border="0" alt="'+this.lang.next_month+'"></a></td>';
		if(this.year_scroll)
			html += '<td><a href="javascript:Calendar.setDatetime('+dt_next_year.valueOf()+')"><img src="'+this.base_url + 'themes/'+this.theme_name+'/next_year.gif" width="16" height="16" border="0" alt="'+this.lang.next_year+'"></a></td>';
		html += '</tr></table>';
		// end navigation 		

		html += '<table cellspacing="1" cellpadding="2" width="100%">';
		
		// print weekdays titles
		html += '<tr>';
		for (n=0; n<7; n++)
			html += '<td class="calendarWeekdays">'+this.lang.arr_weekdays[(this.num_weekstart+n)%7]+'</td>';
		html += '</tr>';
		
		// print calendar table
		dt_current_day = new Date(dt_firstday);		
		
		while (dt_current_day.getMonth() == dt_current.getMonth() || dt_current_day.getMonth() == dt_firstday.getMonth()) {
			// print row heder
			html += '<tr>';
			for (var n_current_wday=0; n_current_wday<7; n_current_wday++) {
				if (dt_current_day.getDate() == this.dt_selected.getDate() &&
					dt_current_day.getMonth() == this.dt_selected.getMonth() &&
					dt_current_day.getFullYear() == this.dt_selected.getFullYear())
					// print current date
					html += '<td class="calendarCurdate">';
				else if (dt_current_day.getDay() == 0 || dt_current_day.getDay() == 6)
					// weekend days
					html += '<td class="calendarWeekenddays">';
				else 
					// print working days of current month
					html += '<td class="calendarWorkingdays">';		
				if (dt_current_day.getMonth() == dt_current.getMonth())
					// print days of current month
					html += '<a href="javascript:Calendar.setDatetime('+dt_current_day.valueOf() +', true);">';
				else 
					// print days of other months
					html += '<a class="calendarOther" href="javascript:Calendar.setDatetime('+dt_current_day.valueOf() +', true);">';	
				html += dt_current_day.getDate()+'</a></td>';
				dt_current_day.setDate(dt_current_day.getDate()+1);
			}
			// print row footer
			html += '</tr>';
		}		
		
		html += '</table></td></tr></table>';
		
		return html;

	},  

	/////////////////////////////////////////////////////////////////////////////////
	/// TIME/DATE PARSING
	/////////////////////////////////////////////////////////////////////////////////
	
	gen_tsmp : function (dt_datetime) {
		return(this.gen_date(dt_datetime) + ' ' + this.gen_time(dt_datetime));
	},

	gen_date : function (dt_datetime) {
		return ( 
			(dt_datetime.getDate() < 10 ? '0' : '') 
			+ dt_datetime.getDate() + "/" + (dt_datetime.getMonth() < 9 ? '0' : '') 
			+ (dt_datetime.getMonth() + 1) + "/" + dt_datetime.getFullYear() 
		);
	},
	
	gen_time : function (dt_datetime) {
		return (
			(dt_datetime.getHours() < 10 ? '0' : '') + dt_datetime.getHours() + ":"
			+ (dt_datetime.getMinutes() < 10 ? '0' : '') + (dt_datetime.getMinutes()) + ":"
			+ (dt_datetime.getSeconds() < 10 ? '0' : '') + (dt_datetime.getSeconds())
		);
	}, 
	
	prs_tsmp : function (str_datetime) {
		if (!str_datetime) 
			return (new Date());
		if (this.re_num.exec(str_datetime))
			return new Date(str_datetime);
		arr_datetime = str_datetime.split(' ');
		return this.prs_time( arr_datetime[1], this.prs_date(arr_datetime[0]));
	},

	prs_date : function (str_date) {
	
		arr_date = str_date.split('/');
	
		if (arr_date.length != 3) return this.error ("Invalid date format: '" + str_date + "'.\nFormat accepted is dd/mm/yyyy.");
		if (!arr_date[0]) return this.error ("Invalid date format: '" + str_date + "'.\nNo day of month value can be found.");
		if (!this.re_num.exec(arr_date[0])) return this.error ("Invalid day of month value: '" + arr_date[0] + "'.\nAllowed values are unsigned integers.");
		if (!arr_date[1]) return this.error ("Invalid date format: '" + str_date + "'.\nNo month value can be found.");
		if (!this.re_num.exec(arr_date[1])) return this.error ("Invalid month value: '" + arr_date[1] + "'.\nAllowed values are unsigned integers.");
		if (!arr_date[2]) return this.error ("Invalid date format: '" + str_date + "'.\nNo year value can be found.");
		if (!this.re_num.exec(arr_date[2])) return this.error ("Invalid year value: '" + arr_date[2] + "'.\nAllowed values are unsigned integers.");
	
		dt_date = new Date();
		dt_date.setDate(1);
	
		if (arr_date[1] < 1 || arr_date[1] > 12) return this.error ("Invalid month value: '" + arr_date[1] + "'.\nAllowed range is 01-12.");
		dt_date.setMonth(arr_date[1]-1);
		 
		if (arr_date[2] < 100) arr_date[2] = Number(arr_date[2]) + (arr_date[2] < this.num_centyear ? 2000 : 1900);
		dt_date.setFullYear(arr_date[2]);
	
		dt_numdays = new Date(arr_date[2], arr_date[1], 0);
		dt_date.setDate(arr_date[0]);
		if (dt_date.getMonth() != (arr_date[1]-1)) return this.error ("Invalid day of month value: '" + arr_date[0] + "'.\nAllowed range is 01-"+dt_numdays.getDate()+".");
	
		return dt_date;
		
	}, 
	
	prs_time : function (str_time, dt_date) {
	
		if (!dt_date) return null;
		arr_time = String(str_time ? str_time : '').split(':');
	
		if (!arr_time[0]) dt_date.setHours(0);
		else if (this.re_num.exec(arr_time[0]))
			if (arr_time[0] < 24) dt_date.setHours(arr_time[0]);
			else return this.error ("Invalid hours value: '" + arr_time[0] + "'.\nAllowed range is 00-23.");
		else return this.error ("Invalid hours value: '" + arr_time[0] + "'.\nAllowed values are unsigned integers.");
		
		if (!arr_time[1]) dt_date.setMinutes(0);
		else if (this.re_num.exec(arr_time[1]))
			if (arr_time[1] < 60) dt_date.setMinutes(arr_time[1]);
			else return this.error ("Invalid minutes value: '" + arr_time[1] + "'.\nAllowed range is 00-59.");
		else return this.error ("Invalid minutes value: '" + arr_time[1] + "'.\nAllowed values are unsigned integers.");
	
		if (!arr_time[2]) dt_date.setSeconds(0);
		else if (this.re_num.exec(arr_time[2]))
			if (arr_time[2] < 60) dt_date.setSeconds(arr_time[2]);
			else return this.error ("Invalid seconds value: '" + arr_time[2] + "'.\nAllowed range is 00-59.");
		else return this.error ("Invalid seconds value: '" + arr_time[2] + "'.\nAllowed values are unsigned integers.");
	
		dt_date.setMilliseconds(0);
		return dt_date;
		
	},
	
	/////////////////////////////////////////////////////////////////////////////////
	/// LANGUAGE 
	/////////////////////////////////////////////////////////////////////////////////	
	
	getLang : function (){
		try{
			langPack = CalendarLanguagePack;
		} catch(e){
			langPack = {	
				arr_months : ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"], 
				arr_weekdays : ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"], 
				slelect_date : "Select date",
				calendar_close : "Close",
				next_month : "Next month",
				next_year : "Next year",
				prev_month : "Previous month",
				prev_year : "Previous year"				
			};		
		}
		return langPack;
	}
	
	
};

function hideSelectElement() {

	if (is_ie6()) {
		var selectElements = document.getElementsByTagName("select");
		for (var i = 0; i < selectElements.length; i++) {
			selectElements[i].style.visibility = "hidden";
		}
	}
}

function showSelectElement() {
	
	if (is_ie6()) {
		var selectElements = document.getElementsByTagName("select");
		for (var i = 0; i < selectElements.length; i++) {
			selectElements[i].style.visibility = "visible";
		}
	}
}

function hideObjectElement() {

	if (is_ie()) {
		var elements = document.getElementsByTagName("object");
		for (var i = 0; i < elements.length; i++) {
			elements[i].style.visibility = "hidden";
		}
	}
}

function showObjectElement() {

	if (is_ie()) {
		var elements = document.getElementsByTagName("object");
		for (var i = 0; i < elements.length; i++) {
			elements[i].style.visibility = "visible";
		}
	}
}

function is_ie6(){
    return ((window.XMLHttpRequest == undefined) && (ActiveXObject != undefined));
}

function is_ie() {
	
	if (window.ActiveXObject)
		return true;
		
	return false;
}
