
// Calendar class
var Calendar = function(o){

	// Init params.
	
	this.isOpen = false;
	
	this.instance = null;
	this.startDate = null;
	this.container = null;
	this.openOnStart = null;
	this.range = {start:null,end:null,cbFunction:function(){}};
	this.limit = {start:null,end:null};
	this.start = null;
	this.end = null;
	this.showSelectedDate = null;
	this.showWeekNumber = null;
	this.showCloseButton = null;
	
	this.strYear = null;
	this.strMonth = null;
	this.strDay = null;
	
	
	if (o ) {
		if (o.range) {
	
			this.startRange = o.range.start;
			this.endRange = o.range.end;
	
		}
		
	
		if (o.instance)
			this.instance = o.instance;
			
		if (o.startDate)
			this.startDate = o.startDate;
			
		if (o.container)
			this.container = o.container;
			
		if (o.openOnStart)
			this.openOnStart = o.openOnStart;
		
		if (o.limit)
			this.limit = o.limit;
		
		if (o.showCloseButton)
			this.showCloseButton = o.showCloseButton;
		
		if (o.range) 
			this.range = o.range;
		
		if (o.start)
			this.start = o.start;
			
		if (o.end)
			this.end = o.end;
			
		if (o.showWeekNumber)
			this.showWeekNumber = o.showWeekNumber;
			
		if (o.showSelectedDate)
			this.showSelectedDate = o.showSelectedDate;
		
	}
	
	this.date = new Date();
	
	
	this.month = ['Januari','Februari','Mars','April','Maj','Juni','Juli','Augusti','September','Oktober','November','December'];
	this.day = ['Måndag','Tisdag','Onsdag','Torsdag','Fredag','Lördag','Söndag'];
	
	this.currDate = new Date();
	
	this.selectedDate = new Date();
	
	this.renderDate = new Date();
	
	this.checkRequestedDate = function(year,month,day) {
	
		
		var dReq = new Date();
		dReq.setFullYear(year);
		dReq.setMonth(month);
		dReq.setDate(day);
		dReq.setHours(23);
		dReq.setMinutes(59);
		
		var dStart = new Date();
		var startDate = this.dateStrToObject(this.limit.start);
		
		dStart.setFullYear(startDate.year);
		dStart.setMonth(startDate.month);
		dStart.setDate(startDate.day);
		
		var dEnd = new Date();
		var endDate = this.dateStrToObject(this.limit.end);
		
		dEnd.setFullYear(endDate.year);
		dEnd.setMonth(endDate.month);
		dEnd.setDate(endDate.day);
		dReq.setHours(00);
		dReq.setMinutes(01);
		
		
		var startOk = (dStart<dReq);
		var endOk = (dEnd>dReq);
		var allOk = (startOk&&endOk);
		
		if (this.instance == 'cal2' && day == 10) {
		
			//console.log(dEnd +"  >  "+dReq +" =  "+(dEnd>dReq));
		
		}
		
		return allOk;
			
	
	}
	
	this.dateObj = function() {
	
		return {curr:this.curr,selected:this.selected};
	
	}
	
	this.getRealDay = function(d) {
		
		d=d.getDay();
		
		
		if (d==0) {
			
			d=6;
		}
		else {
		
			d = d-1;
		}
		return d;
	
	}
	
	this.setDay = function(d) {
		
		//console.log("Setting day to",d);
		
		
		if (!this.checkRequestedDate(this.selectedDate.getFullYear(),this.selectedDate.getMonth(),d)) {
			return;
		}
		
		this.selectedDate.setDate( d);
		
		this.renderDate.setMonth( this.selectedDate.getMonth() );
		
		this.renderDate.setDate( 1 );
		
		var startRangeStr = this.selectedDate.getFullYear() + "-" + (this.selectedDate.getMonth()+1) + "-" + this.selectedDate.getDate();
		
		this.setRange(startRangeStr,startRangeStr,'day');
		
		
	
	}
	
	this.goDay = function(dir) {
	
		if (!this.checkRequestedDate(this.selectedDate.getFullYear(),this.selectedDate.getMonth(),this.selectedDate.getDate()+dir)) {
			return;
		}
	
		this.selectedDate.setDate( this.selectedDate.getDate()+dir );
		
		this.renderDate.setMonth( this.selectedDate.getMonth() );
		
		this.renderDate.setDate( 1 );
		
	
	}
	
	this.setMonth = function(m,set) {
		
		
		
		//if (!this.checkRequestedDate(this.selectedDate.getFullYear(),m,this.selectedDate.getDate())) {
		//	return;
		//}
		
		//console.log("Setting month to",m);
		
		this.selectedDate.setMonth( m );
		
		this.renderDate.setMonth( this.selectedDate.getMonth() );
		
		
		if (set) {
		
					
			var startRangeStr = this.selectedDate.getFullYear() + "-" + (this.selectedDate.getMonth()+1) + "-" + 1;
			
			var d = new Date();
			d.setFullYear(this.selectedDate.getFullYear());
			d.setMonth(this.selectedDate.getMonth()+1);
			d.setDate(0);
			
			var endDate = this.dateStrToObject(this.limit.end);

			
			var endRangeStr = this.selectedDate.getFullYear() + "-" + (this.selectedDate.getMonth()+1) + "-" + d.getDate();
			
			if (!this.checkRequestedDate(this.selectedDate.getFullYear(),this.selectedDate.getMonth(),1)  ) {
				
				
				return;
			}
			this.setRange(startRangeStr,endRangeStr,'month');
		
		}
		//this.renderDate.setDate( 1 );
	
	}
	
	
	this.goMonth = function(dir) {
		
		//if (!this.checkRequestedDate(this.selectedDate.getFullYear(),this.selectedDate.getMonth()+dir,this.selectedDate.getDate())) {
		//	return;
		//}
		
		//console.log("Setting month to",this.selectedDate.getMonth()+dir);
		
		this.selectedDate.setMonth( this.selectedDate.getMonth()+dir);
		
		this.renderDate.setMonth( this.selectedDate.getMonth());
		
		//this.renderDate.setDate( 1 );
	
	}
	
	this.setYear = function(y) {
		
		
		if (!this.checkRequestedDate(y,this.selectedDate.getMonth(),this.selectedDate.getDate())) {
			return;
		}
		
		//console.log("Setting year to",y);
		
		this.selectedDate.setFullYear( y );
		
		this.renderDate.setFullYear( this.selectedDate.getFullYear() );
	
	}
	
	this.goYear = function(dir,set) {
		
		if (!this.checkRequestedDate(this.selectedDate.getFullYear()+dir,this.selectedDate.getMonth(),this.selectedDate.getDate())) {
			
							
			if ( (dir>0 &&this.checkRequestedDate(this.selectedDate.getFullYear()+dir,1,1)) || (dir<0 &&this.checkRequestedDate(this.selectedDate.getFullYear()+dir,12,31)) ) {
				
			}
			else {
				
				return;
			}
		}
		
		//console.log("Setting year to",this.selectedDate.getFullYear()+dir);
		
		this.selectedDate.setFullYear( this.selectedDate.getFullYear()+dir );
		
		this.renderDate.setFullYear( this.selectedDate.getFullYear() );
	
	}
	
	this.setDate = function(date){
		//console.log("Setdate",date);
		date = this.dateStrToObject(date);
		
		this.setDay(date.day);
		
		this.setMonth(date.month);
		this.setYear(date.year);
		
		
		//this.selectedDate.setDate( date );
		
		//this.renderDate.setDate( this.selectedDate.getDate() );
	
	
	}
	
	this.getDays = function(o) {

		
		f = 32 - new Date(o.getFullYear(), o.getMonth(), 32).getDate();
		return f;
	
	}
	
	this.dateStrToObject = function(dstr) {
	
		var d = dstr.split('-');
		
		return {'year':d[0],'month':parseFloat(d[1])-1,'day':d[2]};
	
	}
	
	this.getData = function(i) {
		g = {
				selected: {
					year:		this.selectedDate.getFullYear(),
					month:		this.selectedDate.getMonth(),
					date:		this.selectedDate.getDate(),
					day:		this.getRealDay(this.selectedDate),
					days:		this.getDays(this.selectedDate)
				},
				current: {
					year:		this.currDate.getFullYear(),
					month:		this.currDate.getMonth(),
					date:		this.currDate.getDate(),
					day:		this.getRealDay(this.currDate),
					days:		this.getDays(this.currDate)
				},
				firstDay:	this.getRealDay(this.renderDate)
				
				
		};
	
		return g;
	
	}
	
	this.setRange = function(start,end,type) {
	
		if (!this.range.start && type != 'year' && type != 'month')
			start = null;
	
		if (!this.range.end && type != 'year' && type != 'month'  )
			end = null;
		
		
		if (start) {
			s = this.dateStrToObject(start);
			
			
			this.selectedDate.setFullYear(s.year);
			this.selectedDate.setMonth(s.month);
			this.selectedDate.setDate(s.day);
			
			
		
		}
		
		if (end) {
				s = this.dateStrToObject(end);
				this.selectedDate.setFullYear(s.year);
				this.selectedDate.setMonth(s.month);
				this.selectedDate.setDate(s.day);
			}
		
		var data = this.getData('range');
		
		this.strYear = data.selected.year;
		this.strMonth = this.month[data.selected.month]; 
		this.strDay = this.day[data.selected.day];
		this.strDate = data.selected.date;
		
		this.strWeek = this.getWeekNumber(data.selected.date,true);
		
		if (type == 'day' )
			if (start != end)
				type = 'custom';
		
		this.type = type;
		
		if (start) {
			var req = this.dateStrToObject(start);
			var limit = this.dateStrToObject(this.limit.start);
			isInRange = this.checkRequestedDate(req.year,req.month,req.day);
			
			// Date isn't in range. Set to closest valid date. (unless years differ)
			
			if (!isInRange) {
				
				
				// If requested year is lower than year limit, return
				if (req.year < limit.year) {
					return;
				}
				
				// If requested month is lower than month limit, set start to start limit.
				if (req.month < limit.month) {
					start = this.limit.start;
				}
				// If requested month is equal to limit month, but requested day is lower than limit day. Set start to start limit.
				else if (req.month == limit.month && req.day < limit.day) {
					start = this.limit.start;
				}
				
				
				
				
			
			}
			//console.log('start',g);
		}

		if (end) {
			var req = this.dateStrToObject(end);
			var limit = this.dateStrToObject(this.limit.end);
			isInRange = this.checkRequestedDate(req.year,req.month,req.day);
			
			// Date isn't in range. Set to closest valid date. (unless years differ)
			
			if (!isInRange) {
				
				
				// If requested year is greater than year limit, return
				if (req.year > limit.year) {
					return;
				}
				
				// If requested month is greater than month limit, set start to start limit.
				if (req.month > limit.month) {
					end = this.limit.end;
				}
				// If requested month is equal to limit month, but requested day is greater than limit day. Set end to end limit.
				else if (req.month == limit.month && req.day > limit.day) {
					end = this.limit.end;
				}
				
				
				
				
			
			}
		}
		
		this.range.cbFunction(start,end,type);
	
	}
	
	this.setCustRange = function(start,end) {
	
		this.setRange(start,end,'custom');
	
	}
	
	this.getWeekNumber = function(day,log){
		//lets calc weeknumber the cruel and hard way :D
		//Find JulianDay
		
		year = (this.selectedDate.getFullYear());
		month = (this.selectedDate.getMonth());
		//day = (this.selectedDate.getDate());
		
		
		month += 1; //use 1-12
		var a = Math.floor((14-(month))/12);
		var y = year+4800-a;
		var m = (month)+(12*a)-3;
		var jd = day + Math.floor(((153*m)+2)/5) + 
					 (365*y) + Math.floor(y/4) - Math.floor(y/100) + 
					 Math.floor(y/400) - 32045;      // (gregorian calendar)
		//var jd = (day+1)+Math.Round(((153*m)+2)/5)+(365+y) + 
		//                 Math.round(y/4)-32083;    // (julian calendar)
		
		//now calc weeknumber according to JD
		var d4 = (jd+31741-(jd%7))%146097%36524%1461;
		var L = Math.floor(d4/1460);
		var d1 = ((d4-L)%365)+L;
		NumberOfWeek = Math.floor(d1/7) + 1;
		
		
		return NumberOfWeek;         
	}	
	
	this.render = function(render) {
		
		this.goDay(0);
		
		container = this.container;
		
		if (render) {
			this.isOpen = true;
			Element.show(container);
		}
		else {
			this.isOpen = false;
			Element.hide(container);
			return;	
		}
		
		var data = this.getData('render');
		
		var currMonth = this.month[data.selected.month];
		var currYear = '<span style="cursor:pointer" onclick="eval(\''+this.instance+'\').setRange(\''+data.selected.year+'-01-01\',\''+data.selected.year+'-12-31\',\'year\')">'+data.selected.year+'</span>';

		if (!this.range.canSet)
			currYear = '<span>'+data.selected.year+'</span>';
	
		var totalDays = data.selected.days;
		var firstDay = data.firstDay;
		

		// Render
		
		var str = "";
		// Containing div Start
		str += '<div class="CalendarContainer">';
		
		
		var monthStr = '';
		monthStr+='<table cellpadding=0 cellspacing=0 align="center" style="font-size:12px;"><tr>';
		monthStr+='<td>';
		monthStr+= '<div class="Buttons" onclick="eval(\''+this.instance+'\').setMonth('+(data.selected.month-1)+');eval(\''+this.instance+'\').render(true)">-</div>';
		monthStr+='</td>';
		monthStr+='<td>';
		if (this.range.canSet)
			monthStr+= '<div style="width:75px;text-align:center;" class="Buttons" onclick="eval(\''+this.instance+'\').setMonth('+(data.selected.month)+',true);eval(\''+this.instance+'\').render(true)">'+this.month[data.selected.month]+'</div>';
		else
			monthStr+='<div style="width:75px;text-align:center;">'+this.month[data.selected.month]+'</div>';
		monthStr+='</td>';
		monthStr+='<td>';
		monthStr+= '<div class="Buttons" onclick="eval(\''+this.instance+'\').setMonth('+(data.selected.month+1)+');eval(\''+this.instance+'\').render(true)">+</div>';
		monthStr+='</td>';
		monthStr+='<td>';
		if (this.range.canSet)
			monthStr+= '<div class="Buttons" onclick="eval(\''+this.instance+'\').setRange(\''+data.selected.year+'-01-01\',\''+data.selected.year+'-12-31\',\'year\')">'+data.selected.year+'</div>';
		else
			monthStr+= '<div style="margin-left:10px">'+data.selected.year+'</div>';
		monthStr+='</td>';
		monthStr+='</tr></table>';
		
		prevYear = '';
		currYear = '';
		nextYear = '';
		
		str += '<div style="text-align:center;width:200px;height:20px;"> '+monthStr+'</div>';
		
		var firstDayHasBeenSet = false;
		var lastDayHasBeenSet = false;
		
		var dayCount=1;
		
		
		
		for (var row = 1;row<=6;row++) {
			
			var rowHasValidDays = false;
			
			str += '<div style="overflow:hidden;position:relative;">';
			
				if (row == 1){
					
					str += '<div style="overflow:hidden;">';
					
					for (var k=0;k<this.day.length;k++){
					
						str+='<div class="WeekName">'+this.day[k].substring(0,3) +'</div>';
					}
					
					// Close button.
					if (this.showCloseButton)
						str+='<div class="CloseButton" onclick="eval(\''+this.instance+'\').close()">x</div>';
					
					str += '</div>';
					
					
				
				}
				
				
				var week = this.getWeekNumber(dayCount);
				
				var firstWeekDay = null;
				var lastWeekDay = null;
				
				for (var col = 1;col<=7;col++ ) {
					
					
					if (col == 1) {
					
					str+='<div style="clear:both"><!-- --></div>';
					
					}
					
					if (dayCount > totalDays && !lastDayHasBeenSet) {
						
						lastDayHasBeenSet = true;
					
					}
					
					if (col > firstDay && !firstDayHasBeenSet) {
						
						firstDayHasBeenSet = true;
					
					}
					
					
					if (!firstDayHasBeenSet || lastDayHasBeenSet) {
				
						str += '<div class="WeekDayOutOfRange">&nbsp;</div>';
					
					}
					
					
					
					if (firstDayHasBeenSet && !lastDayHasBeenSet) {
								
								 
								
						var dateWithinRange = this.checkRequestedDate(this.selectedDate.getFullYear(),this.selectedDate.getMonth(),dayCount);
						
						
						rowHasValidDays = true;
						
						var clickNess = 'onclick="eval(\''+this.instance+'\').setDay('+dayCount+');eval(\''+this.instance+'\').render(true);"';
						
						if (dateWithinRange) {
							
							
							this.lastDayOfMonth = dayCount;
							
							if (!firstWeekDay)
								firstWeekDay = dayCount;
							
							lastWeekDay = dayCount;
							
							if (dayCount == data.selected.date && this.showSelectedDate) {
								
								str += '<div class="WeekDaySelected" '+clickNess+'>' + dayCount+'</div>';
							}
							else {
								
								if (dayCount == data.current.date && data.current.month == data.selected.month && data.current.year == data.selected.year) {
									
									str += '<div class="WeekDayActive" '+clickNess+'>'+dayCount+'</div>';
								}
								else
									str += '<div class="WeekDay" '+clickNess+'>' + dayCount+'</div>';
									
									
								
							}
						
						}
						else {
							
							if (dayCount == data.selected.date)
								str += '<div class="WeekDaySelected" '+clickNess+'>' + dayCount+'</div>';
							else
								str += '<div class="WeekDayInActive" >'+dayCount+'</div>';
							
						}
								
						if (col == 7 && !lastWeekDay) {
							lastWeekDay = dayCount;
						}
						
						dayCount++;
						
					}
					
					
					
					
				}
			
			
			//console.log(firstWeekDay,lastWeekDay);
			
			var wnRangeStart = this.selectedDate.getFullYear() + "-" + (this.selectedDate.getMonth()+1) + "-" + firstWeekDay;
			
			var wnRangeEnd = this.selectedDate.getFullYear() + "-" + (this.selectedDate.getMonth()+1) + "-" + lastWeekDay;
			
			// Add week number
			if (rowHasValidDays && this.showWeekNumber) {
				if (firstWeekDay != null && lastWeekDay != null)
					str += '<div class="WeekNumber" onclick="eval(\''+this.instance+'\').setRange(\''+wnRangeStart+'\',\''+wnRangeEnd+'\',\'week\');">'+week+'</div>';
				else
					str += '<div class="WeekNumberInactive" >'+week+'</div>';
					
			}	
				
				str += '</div>';	
		}
		
		
		// Containing div End
		str+='</div>';
		document.getElementById(container).innerHTML = str;
		
	}
	
	this.lastDayOfMonth = 0;
	
	this.toggle = function() {
	
		if (this.isOpen)
			this.render(false);
		else
			this.render(true);
	
	}
	
	this.open = function(){
		
		
		this.render(true);
		
	}
	
	this.close = function(){
		
		
		this.render(false);
		
	}
	
	
	if (this.startDate) {
	
		this.setDate(this.startDate);
		

	}

	if (this.openOnStart) {
		
		
		this.render(true);

	}
	
	this.setDay(this.selectedDate.getDate());
	
	this.render(true);


};
