function Calendar(o) {

	//container, city, first_year, last_year, language, home, img_path, start_year, start_month, name
	var container = o.container;
	var language  = o.language;
	var first_year = o.first_year;
	var last_year  = o.last_year;
	var home = o.home;
	var city = o.city;
	var img_path = o.img_path;
	var start_year = o.start_year;
	var start_month = o.start_month;
	var active_day = o.active_day;
	var name = o.name;
	

	if (container == null) {
		alert('Error: first parameter must be id or HTML element');
		return;
	}
	
	if (container.constructor == String) {
		if (document.getElementById(container) == null) {
			alert('Error: element with id "' + container + '" does not exist');
			return;
		}
		this.container = document.getElementById(container);
	}
	else {
		if (container.nodeType == null || container.nodeType != 1) {
			alert('Error: container must be id or HTML element');
			return;
		}
	}
	
	if (language == null) {
		this.language = 'ru';
	}
	else if (language != 'ru' && language != 'en') {
		this.language = 'ru';
	} else {
		this.language = language;
	}
	
	//alert('this.language = ' + this.language);
	
	
	if (this.language == 'ru') {
		this.Days = ['','','','','','',''];
		this.Months = ['','','','','','','','','','','',''];
	}
	else if (this.language == 'en') {
		this.Days = ['Mn','Tu','We','Th','Fr','Sa','Su'];
		this.Months=['January','February','March','April','May','June','July','August','September','October','November','December'];
	}
	else {
		this.Days = ['','','','','','',''];
		this.Months = ['','','','','','','','','','','',''];
	}

	var min_year = 0;
	var max_year = 9999;
	
	if (first_year && (first_year + '').match(/^\d{4}$/)) {	
		if (first_year < min_year || first_year > max_year) {
			alert('Error: year must be between ' + min_year + ' and ' + max_year);
			return;
		}
		this.first_year = first_year;
	}
	else {
		this.first_year = min_year;
	}

	
	if (last_year && (last_year + '').match(/^\d{4}$/)) {
		if (last_year < min_year || last_year > max_year) {
			alert('Error: year must be between ' + min_year + ' and ' + max_year);
			return;
		}
	
		if (last_year < this.first_year) {
			alert('Error: Last year must be greater first year, first_year = ' + this.first_year + ', last_year = ' + last_year);
			return;
		}
		this.last_year = last_year;		
	} else {
		this.last_year = max_year;
	}
	
	if (home == null) {
		this.home = '/';
	} else {
		this.home = home;
	}
	
	this.city = city;

	if (img_path != null) {
		this.img_path = img_path;
	}
	else {
		this.img_path = '/images/';
	}


	var obj_name = name != null ? name : 'Calendar_' + (new Date).getTime();

	var today = new Date();

	if (start_year != null) {
		start_year += 0;
		if (start_year < this.first_year || start_year > this.last_year) {
			alert('Error: start_year must be beetwen this.first_year and this.last_year, start_year = ' + start_year + ', first_year = ' + this.first_year + ', last_year = ' + this.last_year);
			return;
		}
	} else {
		start_year = today.getFullYear();
	}

	this.start_year = start_year;

	//alert('start_month = ' + start_month);
	if (start_month != null) {
		start_month += 0;
		if (start_month < 1 || start_month > 12) {
			alert('Error: start_month must be between 1 and 12');
			return;
		}
		start_month--;
	}
	else {
		start_month = today.getMonth();
	}

	this.start_month = start_month;

	if (active_day == null) {
		active_day = today.getDate();	
	}
	else if (active_day == 0) {
		active_day = 0	
	}
	else if (active_day >= 1 && active_day <= 31) {
		var date = new Date(start_year, start_month, active_day);
		var month = date.getMonth();
		if (month != start_month) {
			alert('Error: Date ' + start_year + '/' + start_month + '/' + active_day + ' does not exist');
			return;
		}
	} else {
		alert('Error: wrong parameter active_date, active_day = ' + active_day);
		return;
	}
	
	this.active_day = active_day;

	window[obj_name] = this;
	
	Calendar.cal_prn(start_year, start_month, obj_name);
}

Calendar.cal_prn = function (y, m, obj_name, day_) {
	//console.trace(1);
	var obj = window[obj_name];
	var img_path = obj.img_path;
	var Days  = obj.Days;
	var city  = obj.city;
	var max_year = obj.last_year;
	var min_year = obj.first_year;
	var home = obj.home;
	//console.log('max_year = ' + max_year);
  
	IN=0; //,      (  -  innerHTML,  -  outerHTML)
	firefox=/firefox/i;
	//if(firefox.exec(navigator.userAgent)) {IN=1}else{IN=0};

	var s=new String;
	var d=new Date;

	//alert('obj.active_day = ' + obj.active_day);
	var day = obj.active_day;
	//alert(day);
	if (day == null) {
		day = d.getDate();
	}
	/*if (day_ == null) {
 		day = d.getDate();
	} else {
		day = day_ + 0;
	}*/


	var month=new Array();
	var cur_month = obj.start_month;
	var cur_year  = obj.start_year; 
	//alert(obj.start_month);

	m = m?m:(m==0?m:d.getMonth());

	/*alert('day = ' + day);
	alert('m = ' + m + '\ncur_month = ' + cur_month);
	alert('y = ' + y + '\ncur_year = ' + cur_year);*/

	month = Calendar.generate_month(y,m);

	s+=IN?' ':'<table class="cal" ID="calendar" border="0" cellspacing="1" width="100%" height="100">';
	s+='<thead class="cal">';
	for(column=0;column<Days.length;column++)//  
	   { s+='<th style="padding:2 2 0 2;border-right:white 1px solid" width="10">'+Days[column]+'</th>'; }
	// 
	s+='<th style="text-align:left;color:black; padding:2 0 2 4;font-size:8pt;font-weight:bold;font-family:Serif" width=100%>'+y+'</th>';
	s+='</thead>';

	s+='<tbody>';
	
	//console.log(month);
	
	for (line = 0; line < month.length; line++) {

		var adl = ((day >= month[line][0]) && (day <= month[line][0] + 6) && m == parseInt(cur_month, 10) && y==parseInt(cur_year, 10)) ? 1 : 0;
        
		if(y > cur_year) adl = 0;
		s+='<tr class="'+(adl?'active_day_line':'other_day_line')+'">';
		var lin=new Array();
		lin=month[line];
		if(line==0)//   
		{ 
			for (column=0;column<(7-lin.length);column++) { 
				s+='<td class="other_day" style="color:#eeeeee;">'+( 0?( Calendar.count_days(y,m-1)+1-(7-lin.length)+column ):'&nbsp;' )+'</td>'; 
			} 
		}
		
		if(adl) {
			for(column=0;column<lin.length;column++) {
				var ada = month[line][column]; // 
				s+='<td class="'+( ( ada==day )?'active_day':'other_day' )+' ">'+'<a  style="color:'+( (column>4)?'white':'black' )+'" href="' + home +(city?city+'/':'')+y+'/'+(m<9?'0':'')+(m+1)+'/'+(ada<10?'0':'')+ada+'/';
				s+='">';
				s+=(ada<10?'0':'')+ada+'</a>'+'</td>';
			}
		}
		else {
			for(column=0;column<lin.length;column++) {
				var ada = month[line][column]; // 
				s+='<td class="other_day">'+'<a href="' + home +(city?city+'/':'')+y+'/'+(m<9?'0':'')+(m+1)+'/'+(ada<10?'0':'')+ada+'/';
				s+='">';
				s+=(ada<10?'0':'')+ada+'</a>'+'</td>';
			}	
		}
			//   
		mid = ( ( month.length % 2 ) ? ( Math.floor(month.length/2) ) : ( Math.floor(month.length/2)-1 ) ) - 1;
		if (month.length == 4) {
			mid++;
		}
		var tmp_y = m == 11 ? y + 1 : y;
		//console.log('tmp_y = ' + tmp_y);

		if (line==0)     // 
		{
			if (y == min_year && m == 0 ) {
				s+='<td class="other_month" style="padding:1 0 1 0" > &nbsp; </td>'; 
			} 
			/*else if (y >= min_year && y <= max_year) {
				s+='<td class="other_month" style="padding:1 0 1 0" onClick="' + Calendar.btn_up(y,m, obj_name)+'">'+( Calendar.btn_up(y,m, obj_name)?'<img onClick="' + Calendar.btn_up(y,m,obj_name) + '" border=0 ALT="" src="img/arrow_up.gif">':'&nbsp;' )+'</td>'; 
			} */
			else {
				s+='<td class="other_month" style="padding:1 0 1 0" onClick="' + Calendar.btn_up(y,m, obj_name)+'">'+( Calendar.btn_up(y,m, obj_name)?'<img border=0 ALT="" src="' + img_path + '/arrow_up.gif">':'&nbsp;' )+'</td>'; 
			}
		}
		else if(line==month.length-1) {
			//  
			for(column=0;column<7-lin.length;column++)
				s+='<td class="other_day">&nbsp;</td>';

			// 
			if (tmp_y <= max_year)
				s+='<td class="other_month" style="padding:1 0 1 0" onClick="' + Calendar.btn_down(y,m, obj_name)+'">'+'<img border=0 ALT="" src="' + img_path + '/arrow_down.gif">'+'</td>';
			else
				s+='<td class="other_month" style="padding:1 0 1 0"> &nbsp; </td>';
		}
		else if ( line==mid ) //  ( )
		{ 
			s += '<td class="active_month">'
			s += '<a href="' + home +(city?city+'/':'')+y+'/'+(m  + 1 < 10 ? '0' : '') + (m + 1) + '/';
			s += '">';
			s += Calendar.month_name(m, obj_name);
			s += '</a>';
			s += '</td>'; 
		}
		else if(line < mid)    //   
		{
			s+='<td class="other_month">';
			
			if (Calendar.btn_up(y,m, obj_name)) {
				if (y == min_year && m > 1  ) {
					s+='<a href="' + home +(city?city+'/':'')+y+'/'+(m<10&&m!=0?'0':'')+(m<1?12+m:m)+'/">';
				} 
				else if (y > min_year && y <= max_year) {
					s+='<a href="' + home +(city?city+'/':'')+tmp_y+'/'+(m<10&&m!=0?'0':'')+(m<1?12+m:m)+'/">';
				}
			
				s+=Calendar.month_name((m-1), obj_name)
				if (y == min_year && m > 1  ) {
					s+='</a>'; 
				} else if (y > min_year) {
					s+='</a>';
				}
			} else {
				s+='&nbsp;'
			}
			
			s+='</td>'; 
		}
		else if( line > mid )   //   
		{ 
			s+='<td class="other_month">';
			if (tmp_y <= max_year) {
				var month_ = Math.abs(m - mid + line) % 12;
				
				
				var year = y;
				if (month_ <= 1 && m >= 9) {
					year++;
				}
				
				s += '<a href="' + home +(city ? city + '/' : '') + year + '/' + (Math.abs(m - mid + line + 1) < 10 || Math.abs(m - mid + line + 1) - 12 > 0 ? '0' : '') + (Math.abs(m - mid + line + 1) <= 12 ? Math.abs(m - mid + line + 1) : Math.abs(m - mid + line + 1) - 12)+'/">';			

				/*console.log('-----------------------');
				console.log('m = ' + m);
				console.log('y= ' + y);
				console.log('month_ = ' + month_);*/
				
				if (y == max_year && month_ <= 2 && m >= 9) {
					s += '&nbsp;';
				} else {					
					s += Calendar.month_name(Math.abs(m - mid + line), obj_name);
				}				
			} 
			else {
				s += '&nbsp;';
			}
			s += '</a></td>';
		}
		s += '</tr>';
	}
		
	s+='</tbody>';
	s+=IN?' ':'</table>';
	window[obj_name].container.innerHTML = s;
}

Calendar.btn_up = function (y, m, obj_name) { 
	var max_year = window[obj_name].last_year;
	var min_year = window[obj_name].first_year;
		
	if ((y <= min_year && m==0) || (y > max_year && m==0)) {
		return( '' ); 
	}
	else {
		return( 'Calendar.cal_prn('+(m>0?y:(y-1))+','+(m>0?(m-1):11)+', \'' + obj_name + '\')' ); 
	}
}

Calendar.btn_down = function (y,m, obj_name) { 
	return( 'Calendar.cal_prn('+(m<11?y:(y+1))+','+(m<11?(m+1):0)+', \'' + obj_name + '\')' ); 
}

Calendar.month_name = function (m, obj_name) {
	//var Months=['???','???','??,'???,'?','??,'??,'???,'????','???','?O?,'???'];
	//console.trace(window[obj_name].Months[ m<0 ? (12+m):( m>11?(m-12):m ) ]);
	return (window[obj_name].Months[ m<0 ? (12+m):( m>11?(m-12):m )]);
}

Calendar.generate_month = function (y,m) {
	var month=new Array( [[]] );   //??? ????N?
	var ln=new Array([]);          //????N? 

	//data.setFullYear(y>1900?(y-1900):y);

	//?????O?????a - ????????? O????????a + 1  :)
	//data.setMonth(m);             //?? ??e ??? - ????, ??m - ?????? 
	//data.setDate(Calendar.count_days(m)-1);//O??? ???, ???-1
	var data = new Date(y, m, 1);
	fd=data.getDay();           //?????N?
	//??-? ????? ??a???S????, ??? ??? Oc ????a 

	fd = (fd==0)?7:fd; 
	dc=Calendar.count_days(y,m);             //????? O? ???a

	var cnt=1;                      //?E??O?
	var i=0;                        //?E??O? ?????N? 
	var l=0;                        //?E???N? ????S??a
	//?????? ?N?
	for(i=fd;i<8;i++)
	   { ln[i-fd]=cnt++; }

	month[l++]=ln;
	ln=[];
	i=0;
//L?? ????
	do {
	   ln[i++]=cnt++;     //???? ????N? ??? ?N?
	   
	   if( (i==7) )       //????N? ?N?
			{
			month[l++]=ln;//oA??????? ?? ?N? ???e
			ln=[];        //??? ?? ?N?
			i=0;          
			}
	   if(cnt==dc)       //????N? ??a 
			{
			ln[i++]=cnt++;
			month[l++]=ln;
			}

	} while(cnt<dc);

	return month;
}

Calendar.count_days = function (y,m) {
    if (m==1) {
		if (y % 100 == 0) {
			if (y % 400 == 0) {
				return 29;
			}
			return 28;
		}
		
		if (y % 4 == 0)
			return 29;
		else
			return 28;
    }
	
    if ((m==3)||(m==5)||(m==8)||(m==10))
		return 30;
	else
		return 31;
}

