		function kCalendar()
		{
			var options = arguments[0] || {};
			var self = this;
			this.elm = options.parent?options.parent:document.body;
			this.dateNow = new Date();
			this.month = options.month?options.month:this.dateNow.getMonth();
			this.day = options.date?options.date:this.dateNow.getDate();
			this.year = options.year?options.year:this.dateNow.getFullYear();
			this.weekStartDay = options.weekStartDay?options.weekStartDay:6;
			this.monthNameType = options.monthNameType?options.monthNameType:'Long';
			this.dayNameType = options.dayNameType?options.dayNameType:'VeryShort';
			this.data = options.data?options.data:{};
			this.price_data = options.price_data?options.price_data:{};
			this.price_display = options.price_display?options.price_display:{};
			this.length_display = options.length_display?options.length_display:null;
			this.price_input = options.price_input?options.price_input:null;
			this.date_input = options.date_input?options.date_input:null;
			this.length_input = options.length_input?options.length_input:null;
			this.sqlDate = options.sqlDate?options.sqlDate:"";
			this.showselected = options.showselected?options.showselected:false;
			this.length = options.length?options.length:7;
			this.dayElms = [];
			this.dayList = null;
			this.dateDisplay = null;
			this.lengthSelect = null;
			this.btnLast = null;
			this.btnNext = null;
			this.container = null;
			this.monthNames = {
				Long:['January','February','March','April','May','June','July','August','September','October','November','December'],
				Short:['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec']
			};
			this.dayNames = {
				Long:['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'],
				Short : ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'],
				VeryShort : ['Su','Mo','Tu','We','Th','Fr','Sa']
			};
			this.daysInThisMonth = function() {
				return this.daysInMonth(this.month, this.year);
			};
			this.daysInMonth = function(iMonth, iYear) {
				return 32 - new Date(iYear, iMonth, 32).getDate();
			};
			
			this.daysInLastMonth = function() {
				return this.daysInMonth(this.month-1<0?11:this.month-1, this.month-1<0?this.year-1:this.year);
			};
			this.firstDayOfThisMonth = function() {
				return this.firstDayOfMonth(this.month, this.year);
			};
			this.firstDayOfMonth = function(iMonth, iYear) {
				return new Date(iYear, iMonth, 1).getDay();
			};
			this.lastDayOfThisMonth = function() {
				return this.lastDayOfMonth(this.month, this.year);
			};
			this.lastDayOfMonth = function(iMonth, iYear) {
				return new Date(iYear,iMonth,this.daysInMonth(iMonth,iYear)).getDay();
			};
			

			
			this.addEventHandler = function(o,evtName,evtHandler) {
				typeof(attachEvent)=='undefined'?o.addEventListener(evtName,evtHandler,false):o.attachEvent('on'+evtName,evtHandler);
			};
			this.removeEventHandler = function(o,evtName,evtHandler) {
				typeof(attachEvent)=='undefined'?o.removeEventListener(evtName,evtHandler,false):o.detachEvent('on'+evtName,evtHandler);
			};
			this.hasClass = function(o,cStr) {
				return (typeof(o.className)!='undefined'?o.className.indexOf(cStr)+1:false);
			};

			this.addClass = function(o,cStr) {
				if (!o || !cStr) return false; // safety net
				if (self.hasClass(o,cStr)) return false;
				o.className = (o.className?o.className+' ':'')+cStr;
			};

			this.removeClass = function(o,cStr) {
				if (!o || !cStr) return false; // safety net
				if (!self.hasClass(o,cStr)) return false;
				o.className = o.className.replace(new RegExp('( '+cStr+')|('+cStr+')','g'),'');
			};
			this.init = function()
			{
				//this.year = 109;
				//alert(this.lastDayOfMonth(this.month,this.year));
				this.container = document.createElement('div');
				this.addClass(this.container, 'kc_calendar');
				this.elm.appendChild(this.container);

				this.btnNext = document.createElement('div');
				this.addClass(this.btnNext, 'kc_next');
				this.btnNext.innerHTML = "&gt;&gt;";
				this.btnNext.setAttribute("unselectable", "on");
				this.addEventHandler(this.btnNext,'mousedown',self.btnNextClick);
				this.container.appendChild(this.btnNext);

				this.dateDisplay = document.createElement('div');
				this.addClass(this.dateDisplay, 'kc_datedisplay');
				this.container.appendChild(this.dateDisplay);
				
				this.btnLast = document.createElement('div');
				this.addClass(this.btnLast, 'kc_last');
				this.btnLast.innerHTML = "&lt;&lt;";
				this.btnLast.setAttribute("unselectable", "on");
				this.addEventHandler(this.btnLast,'mousedown',self.btnLastClick);
				this.container.appendChild(this.btnLast);

				this.dayList = document.createElement('ul');
				this.addClass(this.dayList,'kc_list');
				this.container.appendChild(this.dayList);
				
				if(this.showselected&&this.sqlDate!="")
				{
					var o = this.sqlDate.match(/([0-9]*)\/([0-9]*)\/([0-9]*)/);
					this.year = o[1];
					this.month = o[2] -1;
					this.day = o[3];
				}
				//alert(o[2]);
				
				this.renderDays();
				this.setDateDisplay();

				if(this.length_display!=null)
				{
					
					this.lengthSelect = document.createElement('select');
					this.lengthSelect.id = 'kc_length_select';
					for(var f=1; f<3; f++)
					{
						var lengthOption = document.createElement('option');
						lengthOption.value = f * 7;
						lengthOption.innerHTML = f + (f==1?' week':' weeks');
						this.lengthSelect.appendChild(lengthOption);
					}
					this.lengthSelect.selectedIndex = (this.length/7)-1;
					this.length_display.appendChild(this.lengthSelect);
					this.addEventHandler(this.lengthSelect,'change',self.lengthChange);
				}
				if(this.length_input!=null) this.length_input.value = this.length;
				if(this.date_input!=null) this.date_input.value = this.sqlDate;
				//alert(this.daysInLastMonth());
			};
			this.readSqlDate = function(sqlDate)
			{
				var o = this.sqlDate.match(/([0-9]*)\/([0-9]*)\/([0-9]*)/);
				return{year:o[1],month:o[2]-1,date:o[3]};
			};
			this.getHolidayPrice = function()
			{
				  

				if(this.sqlDate==null||this.sqlDate=="") {
					this.price_display.innerHTML = "";
					return;
				}
				var sqlDate = this.readSqlDate(this.sqlDate);
				var thisdate = new Date(sqlDate.year, sqlDate.month, sqlDate.date);
				var tmpprice = 0;
				for(var f=0; f<this.length; f+=7)
				{
					var tmpdate = new Date(thisdate.getFullYear(), thisdate.getMonth(), thisdate.getDate()+f);
					try{tmpprice += this.price_data[tmpdate.getFullYear()][tmpdate.getMonth()+1][tmpdate.getDate()];}
					catch(ex){};
				}
				this.price_display.innerHTML = "&pound;" + tmpprice;
				if(this.price_input!=null) this.price_input.value = tmpprice;
			};
			this.renderDays = function()
			{
				var dateOffset = this.firstDayOfThisMonth()+7 - this.weekStartDay;
				dateOffset = dateOffset>6?dateOffset-7:dateOffset;
				var extraDays = this.weekStartDay + 7 - this.lastDayOfThisMonth();
				//alert(extraDays);
				extraDays = extraDays>7?extraDays-7:extraDays;
				for(var c=0; c<7; c++)
				{
					this.dayElms[c] = document.createElement("li");
					this.dayElms[c].innerHTML = this.dayNames[this.dayNameType][c+this.weekStartDay>6 ? c+this.weekStartDay-7 : c+this.weekStartDay];
					this.addClass(this.dayElms[c],'kc_header');
					this.dayList.appendChild(this.dayElms[c]);
					//alert(dayElms[c].innerHTML);
				}
				var daycount = 0;
				var lengthcount = 0;
				var weekbooked = false;
				var weekselected = false;
				var curprice = null;
				for(var f=0-dateOffset; f<this.daysInThisMonth() + extraDays -1; f++)
				{
					//var c = f+dateOffset;
					this.dayElms[c] = document.createElement("li");
					if(f<0||f>this.daysInThisMonth()-1) this.addClass(this.dayElms[c],'kc_not_in_month');
					var thisdate = f<this.daysInThisMonth()?f:f-this.daysInThisMonth();
					var thisdate = thisdate<0?this.daysInLastMonth()+thisdate + 1:thisdate + 1;
					var thismonth = self.month;
					var thisyear = self.year;
					if(f<0) {
						thismonth--;
						if(thismonth<0) {
							thismonth = 11;
							thisyear--;
						}
					}
					if(f>this.daysInThisMonth()-1) {
						thismonth++;
						if(thismonth>11) {
							thismonth = 0;
							thisyear++;
						}
					}
					//alert(thisyear + ", " + (thismonth+1) + ", " + thisdate);
					try {
						var thisdata = self.data[thisyear][thismonth+1][thisdate];
						if(thisdata) weekbooked = true;
					}
					catch(e){}
					var thisprice = null;
					try {
						thisprice = self.price_data[thisyear][thismonth+1][thisdate];
						if(thisprice!=null) curprice = thisprice;
					}
					catch (e){}
					//alert(curprice==null);
					if(self.sqlDate==thisyear + "/" + (thismonth + 1) + "/" + thisdate)
						weekselected = true;
					
					if(weekbooked) this.addClass(this.dayElms[c],'kc_booked');
					if(weekselected) this.addClass(this.dayElms[c],'kc_selected');
					this.dayElms[c].id = 'kc_date_' + c;
					this.dayElms[c].innerHTML = thisdate;
					if(curprice!=null) this.dayElms[c].setAttribute("title", "" + curprice);
					this.addEventHandler(this.dayElms[c],'mouseover',self.dateMouseover);
					this.addEventHandler(this.dayElms[c],'mouseout',self.dateMouseout);
					this.addEventHandler(this.dayElms[c],'mousedown', self.dateMousedown);
					this.addEventHandler(this.dayElms[c],'dblclick', self.dateDblClick);
					this.dayList.appendChild(this.dayElms[c]);
					c++;
					daycount++;
					if(daycount>6) {daycount = 0; weekbooked = false;}
					if(weekselected&&++lengthcount>=this.length) weekselected = false;
				}
				this.getHolidayPrice();

			};
			this.clearDays = function()
			{
				for(var f=0; f<this.dayElms.length; f++)
				{
					this.removeEventHandler(this.dayElms[f],'mouseover',self.dateMouseover);
					this.removeEventHandler(this.dayElms[f],'mouseout',self.dateMouseout);
					this.removeEventHandler(this.dayElms[f],'mousedown',self.dateMousedown);
					this.removeEventHandler(this.dayElms[f],'dblclick',self.dateDblClick);
				}
				this.dayList.innerHTML = '';
				this.dayElms.length = 0;
			};
			this.dateMouseover = function(e) {
				var elm = self.getTheDamnTarget(e);
				if(self.hasClass(elm, 'kc_booked')) return;
				var offset = 0;
				for(var f=0; f<self.dayElms.length; f++)
				{
					if(elm.id==self.dayElms[f].id) offset = f - (f%7);
					//self.removeClass(self.dayElms[f],'hover');
				}
				var dateselected = self.dayElms[offset].innerHTML;
				var monthselected = self.month;
				var yearselected = self.year;
				if(offset==7&&dateselected>20)
				{
					monthselected--;
					if(monthselected<0) {
						monthselected = 11;
						yearselected--;
					}
				}
				var thisdate = new Date(yearselected, monthselected, dateselected);
				var mydata = null;
				for(var f=0; f<self.length; f+=7)
				{
					var tmpdate = new Date(thisdate.getFullYear(), thisdate.getMonth(), thisdate.getDate()-0+f);
					try{
						mydata = self.data[tmpdate.getFullYear()][tmpdate.getMonth()+1][tmpdate.getDate()];
					}
					catch(ex)
					{
					}
				}
				if(mydata!=null) return;

				for(var f=offset; f<offset+self.length && f<self.dayElms.length; f++)
				{
					self.addClass(self.dayElms[f],'kc_hover');
				}
				//self.addClass(elm,'hover');
			};
			this.dateMouseout = function(e) {
				var elm = self.getTheDamnTarget(e);
				for(var f=0; f<self.dayElms.length; f++)
				{
					self.removeClass(self.dayElms[f],'kc_hover');
				}
				self.removeClass(elm,'kc_hover');
			};
			this.lengthChange = function(e) {
				var elm = self.getTheDamnTarget(e);
				self.length = parseInt(elm.value);
				if(self.length_input!=null) self.length_input.value = self.length;
				self.clearDays();
				//check if it's all cool
				var thisdate = new Date(self.sqlDate);
				var mydata = null;
				for(var f=0; f<self.length; f+=7)
				{
					var tmpdate = new Date(thisdate.getFullYear(), thisdate.getMonth(), thisdate.getDate()-0+f);
					try{ mydata = self.data[tmpdate.getFullYear()][tmpdate.getMonth()+1][tmpdate.getDate()];}
					catch(ex){}
				}
				if(mydata!=null) {
					self.sqlDate = null;
					if(self.date_input!=null) self.date_input.value = "";
					if(self.price_input!=null) self.price_input.value = "";
				}
				self.renderDays();
				self.setDateDisplay();
			};
			this.dateMousedown = function(e) {
				var elm = self.getTheDamnTarget(e);
				if(self.hasClass(elm, 'kc_booked')) return;
				var offset = 0;
				for(var f=0; f<self.dayElms.length; f++)
				{
					if(elm.id==self.dayElms[f].id) offset = f- (f%7);
					//self.removeClass(self.dayElms[f],'kc_selected');
				}
				var dateselected = self.dayElms[offset].innerHTML;
				var monthselected = self.month;
				var yearselected = self.year;
				if(offset==7&&dateselected>20)
				{
					monthselected--;
					if(monthselected<0) {
						monthselected = 11;
						yearselected--;
					}
				}
				var thisdate = new Date(yearselected, monthselected, dateselected);
				var mydata = null;
				for(var f=0; f<self.length; f+=7)
				{
					var tmpdate = new Date(thisdate.getFullYear(), thisdate.getMonth(), thisdate.getDate()-0+f);
					//alert(thisdate);
					try{
						mydata = self.data[tmpdate.getFullYear()][tmpdate.getMonth()+1][tmpdate.getDate()];
					}
					catch(ex)
					{
					}
				}
				if(mydata!=null) return;
				for(var f=0; f<self.dayElms.length; f++)
				{
					self.removeClass(self.dayElms[f],'kc_selected');
				}
				self.sqlDate = yearselected + "/" + (monthselected + 1) + "/" + dateselected;
				if(self.date_input!=null) self.date_input.value = self.sqlDate;
				self.getHolidayPrice();
				//alert(dateselected + " " + self.monthNames['Long'][monthselected] + " " + yearselected);
				for(var f=offset; f<offset+self.length&&f<self.dayElms.length; f++)
				{
					self.addClass(self.dayElms[f],'kc_selected');
				}
			};
			this.dateDblClick = function(e) {
				//window.location='http://www.derbyshirecountrycottages.co.uk/cottages_pages/show_cottages.aspx?week=' + self.sqlDate + '&length=' + self.length;
			};
			this.btnLastClick = function(e) {
				self.clearDays();
				self.month--;
				if(self.month<0) {
					self.month = 11;
					self.year--;
				}
				self.setDateDisplay();
				self.renderDays();
			};
			this.btnNextClick = function(e) {
				self.clearDays();
				self.month++;
				if(self.month>11) {
					self.month = 0;
					self.year++;
				}
				self.setDateDisplay();
				self.renderDays();
			};
			this.setDateDisplay = function() {
				this.dateDisplay.innerHTML = this.monthNames[this.monthNameType][this.month] + ' ' + this.year;

			};
			this.getTheDamnTarget = function(e) {
				return (e.target||e.srcElement||window.event.srcElement);
			};
			this.ask = function(question)
			{
				return "The answer to the question, " + question + " is confusing.";
			};
			this.init();
		}
