
/********************************************************
* Calendar for FMS                                      *
* Version:  0.1                                         *
* Author:   Yarullin A.R., azatyar@gmail.com            *
* Homepage: http://fms.net.ru/                          *
* Copyright 2008, Fms.net.ru                            *
*                                                       *
* Example:                                              *
* // param idContainer Element id: 'calendar'           *
* // param typeWeek Begin day: 0-sanday, 1-monday       *
* var calendarObj = new Calendar('calendar', 0);        *
* calendarObj.selectDays = ['2008.08.08'];              *
* calendarObj.linkDays = [{'2008.08.08':'/news.html'}]; *
* calendarObj.MakeMatrix();                             *
* calendarObj.ShowMatrix();                             *
********************************************************/

function Calendar(idContainer, typeWeek){
	this.container = new String();
	this.currentDate = 0;				// ткуцщая дата
	this.currentDay = 0;				// текущий день
	this.currentMonth = 0;				// текущий месяц
	this.currentYear = 0;				// текущий год
	this.pastMonth = 0;					// прошлый месяц
	this.monthDaysCount = new Array();	// количество дней в месяцах
	this.monthLink = new String();		// ссылка на месяц вида: /news/date/%s.html
	this.leapYear = new Boolean(false);	// високосный год
	this.selectDays = new Array();		// выделить дни
	this.linkDays = new Array();		// дни со ссылками
	this.nameDays = new Array();		// имена дней
	this.nameMonths = new Array();		// имена месяцев
	this.typeWeek = new Number(0);		// начало недели: 0-воскресенье, 1-понедельник
	this.matrix = new Array();
	this.result = new String();
	this.showed = new Boolean(false);
	this.days = {
		number: new Number(0),
		day: new Number(0),
		link: new String(),
		select: new Boolean(false),
		disable: new Boolean(false),
		current: new Boolean(false)
	};
	this.Init = function(){
		var d = new Date();
		this.currentDate = d.getDate();
		this.currentDay = d.getDay() - this.typeWeek;
		if(this.currentDay < 0)
			this.currentDay = 6;
		else if(this.currentDay > 6)
			this.currentDay = 0;
		this.currentMonth = d.getMonth();
		this.currentYear = d.getFullYear();
		this.monthDaysCount = [30, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
		this.leapYear = false;
		if(this.currentYear % 4 == 0){
			this.leapYear = true;
			this.monthDaysCount[1] = 29;
		}
		this.pastMonth = (this.currentMonth - 1 >= 0) ? (this.currentMonth - 1) : 11;
		this.nameDays = ['S','M','T','W','Th','F','Sa'];
		this.nameMonths = ['January','February','March','April','May','June','July','August','September','October','November','December'];
		this.monthLink = '/news/date/%s.html';
	};
	this.SetContainer = function(o){
		this.container = o;
	};
	this.InnerHTML = function(str){
		document.getElementById(this.container).innerHTML = str;
	};
	this.AppendChild = function(o){
		document.getElementById(this.container).appendChild(o);
	};
	this.ReplaceChild = function(o){
		var c = document.getElementById(this.container);
		c.innerHTML = '';
		c.appendChild(o);
	};
	this.BackMonth = function(){
		this.ChangeMonth(-1);
	};
	this.NextMonth = function(){
		this.ChangeMonth(1);
	};
	this.ChangeMonth = function(shift){
		var d = new Date();
		d.setMonth(this.currentMonth + shift);
		this.currentMonth = d.getMonth();
		this.currentDate = d.getDate();
		this.currentDay = d.getDay() - this.typeWeek;
		if(this.currentDay < 0)
			this.currentDay = 6;
		else if(this.currentDay > 6)
			this.currentDay = 0;
		if(this.currentMonth == 0 && shift < 0)
			this.currentYear -= 1;
		else if(this.currentMonth == 1 && shift > 0)
			this.currentYear += 1;
		this.pastMonth = (this.currentMonth - 1 >= 0) ? (this.currentMonth - 1) : 11;
		this.MakeMatrix();
		this.ShowMatrix();
	};
	this.MakeMatrix = function(){
		var disable = true;
		var countNumber = 0;
		var tempDate = new Date();
		tempDate.setMonth(this.currentMonth);
		tempDate.setDate(1);
		var temp = tempDate.getDay() - this.typeWeek;
		if(temp < 0)
			temp = 6;
		else if(temp > 6)
			temp = 0;
		var countDay = this.monthDaysCount[this.pastMonth] - temp + 1;
		if(countDay > this.monthDaysCount[this.pastMonth]){
			countDay = 1;
			disable = false;
		}
		tempDate = new Date();
		var matrix = new Array();
		
		for(var i = 0; i < 6; i++){
			if(i == 5 && disable){
				break;
			}
			matrix.push(new Array());
			for(var j = 0; j < 7; j++){
				var d = clone(this.days);
				d.number = countNumber;
				d.day = countDay;
				d.select = false;
				d.current = false;
				d.link = '';
				if(!disable && d.day == this.currentDate && tempDate.getMonth() == this.currentMonth && tempDate.getFullYear() == this.currentYear)
					d.current = true;
				if(!disable){
					for(var x = 0; x < this.selectDays.length; x++)
						if(this.selectDays[x] == this.currentYear+'.'+((this.currentMonth+1) < 10 ? '0'+(this.currentMonth+1) : (this.currentMonth+1))+'.'+(d.day < 10 ? '0'+d.day : d.day))
							d.select = true;
					for(var x = 0; x < this.linkDays.length; x++){
						var dTemp = this.currentYear+'.'+((this.currentMonth+1) < 10 ? '0'+(this.currentMonth+1) : (this.currentMonth+1))+'.'+(d.day < 10 ? '0'+d.day : d.day);
						if(this.linkDays[x][dTemp] != null)
							d.link = this.linkDays[x][dTemp];
					}
				}
				d.disable = disable;
				if(disable && d.day == this.monthDaysCount[this.pastMonth]){
					countDay = 0;
					disable = false;
				}
				else if(!disable && d.day == this.monthDaysCount[this.currentMonth]){
					countDay = 0;
					disable = true;
				}
				matrix[i][j] = d;
				countNumber++;
				countDay++;
			}
		}
		this.matrix = matrix;
	};
	this.ShowMatrix = function(){
		var IE = (window.navigator.appName == 'Microsoft Internet Explorer') ? true : false;
		var result = new String();
		var matrix = this.matrix;
		var table = document.createElement('table');
		if(!IE) table.setAttribute('class','calendar');
		else table.setAttribute('className','calendar'); // Fox for IE
		// head. Months
		var tHead = document.createElement('thead');
		var row = document.createElement('tr');
		// navigation and month name
		var cell = document.createElement('th');
		cell.innerHTML = '<a href="javascript:void(0);" onclick="' + this.container + '.BackMonth();">&laquo;</a>';
		row.appendChild(cell);
		var cell = document.createElement('th');
		if(!IE) cell.setAttribute('colspan', '5');
		else cell.setAttribute('colSpan', '5'); // Fix for IE
		if(this.monthLink == '')
			cell.innerHTML = this.nameMonths[this.currentMonth] + ' ' + this.currentYear;
		else
			cell.innerHTML = '<a href="' + 
				this.monthLink.replace('%s', this.currentYear.toString().charAt(2) + 
				this.currentYear.toString().charAt(3) + '.' + 
				((this.currentMonth + 1) < 10 ? ('0' + (this.currentMonth + 1)) : (this.currentMonth + 1))) + 
				'">' + this.nameMonths[this.currentMonth] + '</a> ' +
				'<a href="' + 
				this.monthLink.replace('%s', this.currentYear.toString().charAt(2) + 
				this.currentYear.toString().charAt(3)) + 
				'">' + this.currentYear + '</a>';
		row.appendChild(cell);
		var cell = document.createElement('th');
		cell.innerHTML = '<a href="javascript:void(0);" onclick="' + this.container + '.NextMonth();">&raquo;</a>';
		row.appendChild(cell);
		// head. Days
		tHead.appendChild(row);
		var row = document.createElement('tr');
		for(var i = 0; i < 7; i++){
			var cell = document.createElement('td');
			var w = ((i + typeWeek) < 0) ? (7 - i + typeWeek) : ((i + typeWeek) >= 7 ? (i + typeWeek - 7) : (i + typeWeek));
			cell.innerHTML = this.nameDays[w];
			row.appendChild(cell);
		}
		tHead.appendChild(row);
		table.appendChild(tHead);
		
		var tBody = document.createElement('tbody');
		for(var i = 0; i < matrix.length; i++){
			var row = document.createElement('tr');
			for(var j = 0; j < matrix[i].length; j++){
				var cell = document.createElement('td');
				if(matrix[i][j].select){
					if(!IE) cell.setAttribute('class', 'select');
					else cell.setAttribute('className', 'select'); // Fix for IE
				}
				if(matrix[i][j].current){
					if(!IE) cell.setAttribute('class', 'current');
					else cell.setAttribute('className', 'current'); // Fix for IE
				}
				if(matrix[i][j].disable){
					if(!IE) cell.setAttribute('class', 'disable');
					else cell.setAttribute('className', 'disable'); // Fix for IE
				}
				cell.innerHTML = matrix[i][j].day;
				if(matrix[i][j].link != ''){
					cell.innerHTML = '<a href="' + matrix[i][j].link + '">' + matrix[i][j].day + '</a>';
				}
				row.appendChild(cell);
			}
			tBody.appendChild(row);
		}
		table.appendChild(tBody);
		if(this.showed)
			this.ReplaceChild(table);
		else
			this.AppendChild(table);
		this.showed = true;
	};
	this.SetWeek = function(type){
		this.typeWeek = type;
	};
	this.Init();
	if(idContainer != null){
		this.SetContainer(idContainer);
	}
	if(typeWeek != null)
		this.SetWeek(typeWeek);
}

function clone(o){
	if(!o || 'object' !== typeof o){
		return o;
	}
	var c = 'function' === typeof o.pop ? [] : {};
	var p, v;
	for(p in o){
		if(o.hasOwnProperty(p)){
			v = o[p];
			if(v && 'object' === typeof v){
				c[p] = clone(v);
			}
			else{
				c[p] = v;
			}
		}
	}
	return c;
}
