
function rangepicker (instancename, first_day_of_week, months_before, months_after) {
	var dstart;
	var dend;
	var dshow;
	var showstart;
	var showend;
	var select_active=0;
	
	//init row of weekdays according to 1st day of week
	var days = ['D','L','M','M','J','V','S'];
		var txtweekdays = '';
	for (var wkd=0; wkd<7; wkd++) {
		txtweekdays += '<th>' + days[(wkd+first_day_of_week)%7] + '</th>';
	}			
	
	this.to_year = document.getElementById(instancename + '_to_year');
	this.to_month = document.getElementById(instancename + '_to_month');
	this.to_day = document.getElementById(instancename + '_to_day');

	this.from_year = document.getElementById(instancename + '_from_year');
	this.from_month = document.getElementById(instancename + '_from_month');
	this.from_day = document.getElementById(instancename + '_from_day');


	//init calendar from field values or set to today's date
	this.init_cal = function () {
		//get values from form fields or set to this date
		if (this.to_year.value && this.to_month.value && this.to_day.value) {

			dend = new Date(this.to_year.value, parseInt(this.to_month.value,10)-1, this.to_day.value);
		} else {
			dend = new Date();
		}
		dshow = new Date(dend.getFullYear(),dend.getMonth(),dend.getDate()) ;

		//get values from form fields or set to end date
		if (this.from_year.value && 	this.from_month.value && this.from_day.value) {
			dstart = new Date(this.from_year.value, parseInt(this.from_month.value,10)-1, this.from_day.value);
		} else {
			dstart = new Date(dend.getFullYear(),dend.getMonth(),dend.getDate()) ;
		}
		this.show_cal();
	}

	//return date object from date string, given as 'YYYY,mm,dd'
	function split_date(str_date) {
		var dateary = str_date.split(',');
		return new Date(dateary[0],dateary[1],dateary[2]);
	}

	// monday first day of week
	function dayofweek(d) {
		return (d.getDay()+6) % 7; //ISO-week
		return d.getDay();
	}

	//set start and/or end dates in range on onclick events
	this.set_range = function (date_start, date_end) {
		if (!date_end) {
			if (select_active==0) {
				dstart = split_date(date_start);
				dend = split_date(date_start);
				select_active = 1;
			} else {
				dtmp = split_date(date_start);
				if (dtmp>=dstart) {
					dend = dtmp;
				} else {
					dend = dstart;
					dstart = dtmp;
				}
				select_active = 0;

				//set new show month only if full selection is not visible in current view
				if (dstart<showstart) {
					dshow = new Date(dend.getFullYear(),dend.getMonth(),1) ;
				}
			}
		} else {
			select_active = 0;
			dstart = split_date(date_start);
			dend = split_date(date_end);
			//set new show month only if full selection is not visible in current view
			if (dstart<showstart) {
				dshow = new Date(dend.getFullYear(),dend.getMonth(),1) ;
			}
		}
		this.show_cal();

		//set the date values in the form fields
		this.to_year.value = dend.getFullYear();
		this.to_month.value = dend.getMonth()+1;
		this.to_day.value = dend.getDate();

		this.from_year.value = dstart.getFullYear();
		this.from_month.value = dstart.getMonth()+1;
		this.from_day.value = dstart.getDate();
		
		majDates() ;
	}
	
	if (first_day_of_week==1) {
		//get week number (european). Credits to Ferry van Schaik (ferryvs@teq.nl)
		this.getweek = function (year,month,day) {
			var when = new Date(year,month,day);
			var newYear = new Date(year,0,1);
			var modDay = newYear.getDay();
			if (modDay == 0) modDay=6; else modDay--;

			var daynum = ((Date.UTC(year,when.getMonth(),when.getDate(),0,0,0) - Date.UTC(year,0,1,0,0,0)) /1000/60/60/24) + 1;

			if (modDay < 4 ) {
				var weeknum = Math.floor((daynum+modDay-1)/7)+1;
			} else {
				var weeknum = Math.floor((daynum+modDay-1)/7);
				if (weeknum == 0) {
					year--;
					var prevNewYear = new Date(year,0,1);
					var prevmodDay = prevNewYear.getDay();
					if (prevmodDay == 0) prevmodDay = 6; else prevmodDay--;
					if (prevmodDay < 4) weeknum = 53; else weeknum = 52;
				}
			}

			return + weeknum;
		}
	} else {
		this.getweek = function (year,month,day) {
		    var when = new Date(year,month,day);
		    var newYear = new Date(year,0,1);
		    var offset = 7 + 1 - newYear.getDay();
		    if (offset == 8) offset = 1;
		    var daynum = ((Date.UTC(year,when.getMonth(),when.getDate(),0,0,0) - Date.UTC(year,0,1,0,0,0)) /1000/60/60/24) + 1;
		    var weeknum = Math.floor((daynum-offset+7)/7);
		    if (weeknum == 0) {
			year--;
			var prevNewYear = new Date(year,0,1);
			var prevOffset = 7 + 1 - prevNewYear.getDay();
			if (prevOffset == 2 || prevOffset == 8) weeknum = 53; else weeknum = 52;
		    }
		    return weeknum;
		}
	}

	//change displayed month
	this.show_month = function (month) {
		dshow.setMonth(month, 1);
		this.show_cal();
	}
	
	this.show_year = function (year) {
		dshow.setFullYear(year, 1);
		this.show_cal();
	}
	//go to start of range
	this.to_dstart = function() {
		dshow.setFullYear(dstart.getFullYear(),dstart.getMonth(),1);
		this.show_cal();
	}
	//go to end of range
	this.to_dend = function() {
		dshow.setFullYear(dend.getFullYear(),dend.getMonth(),1);
		this.show_cal();
	}

	//show calendar(s)
	this.show_cal = function () {

		//show year, select full year
		var tmpT1 = dshow.getFullYear() +',0,1';
		var tmpT2 = (dshow.getFullYear()+1) +',0,0';
		
		var htxt = "" ;
		
		htxt += '<table><tr><th colspan="2"><a href="#" onclick="'+instancename+'.show_year('+(dshow.getFullYear()-1)+
		');return false;">&lt;</a></th><th colspan="4"><a href="#" onclick="'+
			instancename+'.set_range(\''+tmpT1+'\',\''+tmpT2+'\');return false;'+
			'">' + (dshow.getFullYear()) + '</a></th><th colspan="2"><a href="#" onclick="'+instancename+'.show_year('+(dshow.getFullYear()+1)+
			');return false;">&gt;</a></th></tr>'
			
		showstart = new Date(dshow.getFullYear(), dshow.getMonth()-months_before, 1);
		showstart.setDate(1-dayofweek(showstart));
		showend = new Date(dshow.getFullYear(), dshow.getMonth()+months_after+1, 1);
		showend.setDate(7-dayofweek(showend));

		//show three months at a time
		for (var dm=-months_before; dm<=months_after; dm++) {

			tmpT1 = dshow.getFullYear() +',' + (dshow.getMonth()+dm)+ ',1';
			tmpT2 = dshow.getFullYear() +',' + (dshow.getMonth()+1+dm) + ',0';


			//setup calendar grid, whole month selector
			var d1 = new Date(dshow.getFullYear(), dshow.getMonth()+dm, 1);
			
			var this_month = d1.getMonth();

			switch (this_month)
			{
				case 0: moisSt = "Janvier" ; break;
				case 1: moisSt = "F&#233;vrier" ; break;
				case 2: moisSt = "Mars" ; break;
				case 3: moisSt = "Avril" ; break;
				case 4: moisSt = "Mai" ; break;
				case 5: moisSt = "Juin" ; break;
				case 6: moisSt = "Juillet" ; break;
				case 7: moisSt = "Ao&#251;t" ; break;
				case 8: moisSt = "Septembre" ; break;
				case 9: moisSt = "Octobre" ; break;
				case 10: moisSt = "Novembre" ; break;
				case 11: moisSt = "D&#233;cembre" ; break;
			}
			
			htxt += '<tr><th colspan="2"><a href="#" onclick="'+instancename+'.show_month('+(dshow.getMonth()-1)+
			');return false;">&lt;</a></th><th colspan="4"><a href="#" onclick="'+
				instancename+'.set_range(\''+tmpT1+'\',\''+tmpT2+'\');return false;'+
				'">'+moisSt+'</a></th><th colspan="2"><a href="#"  onclick="'+instancename+'.show_month('+(dshow.getMonth()+1)+');return false;">&gt;</a></th></tr>';
				
	
			htxt += '<tr><th></th>' + txtweekdays + '</tr>';
		
			d1.setDate(1-dayofweek(d1));

			var weekno = this.getweek(d1.getFullYear(),d1.getMonth(), d1.getDate());

			//link to selected range
			if (dm==-months_before && dstart<d1) {
				if (dend<d1) {
					htxt += '<tr><th></th><td colspan="7" class="sel1"><a href="#" onclick="'+instancename+'.to_dend();return false;">&lt</a></td></tr>';
				} else {
					htxt += '<tr><th></th><td colspan="7" class="sel1"><a href="#" onclick="'+instancename+'.to_dstart();return false;">&lt</a></td></tr>';
				}
			}
			//show weeks - till first week in new month
			for (var w=0; (w<2 || d1.getMonth()==this_month);w++) {

				if (weekno>52) {
					weekno = 1;

				}
				//week selector
				htxt += '<tr><th><a href="#" onclick="'+
					instancename+'.set_range(\''+(d1.getFullYear()+','+d1.getMonth()+','+d1.getDate())+'\',\''+(d1.getFullYear()+','+d1.getMonth()+','+(6+d1.getDate()))+'\');return false;'+
					'">'+weekno+'</a></th>';

				//show weekdays
				for (var d=0; d<7; d++) {
					var tdstyle = ((d1>=dstart) && (d1<=dend))?
						((select_active==1)?
							'sel2':
							'sel1')
						:'';
					var astyle = (d1.getMonth()==this_month)?'':'a_sm';

					htxt += '<td class="'+tdstyle+'"><a class="'+astyle+'"href="#" onclick="'+
						instancename+'.set_range(\''+(d1.getFullYear()+','+d1.getMonth()+','+d1.getDate())+'\',\'\');return false;'+
						'">' + (d1.getDate()) + '</a></b></td>';
					d1.setDate(d1.getDate()+1);
				}
				htxt += '</tr>';
				weekno++;
			}
			//link to selected range
			if (dm==months_after && dend>d1) {
				if (dstart>d1) {
					htxt += '<tr><th></th><td colspan="7" class="sel1"><a href="#" onclick="'+instancename+'.to_dstart();return false;">&gt</a></td></tr>';
				} else {
					htxt += '<tr><th></th><td colspan="7" class="sel1"><a href="#" onclick="'+instancename+'.to_dend();return false;">&gt</a></td></tr>';
				}
			}

			htxt += '</table>';
		}

	
		//display in div
		document.getElementById(instancename + '_div').innerHTML = htxt;
	}
	this.init_cal();
}
