var Calendar = {
	//инциализация переменных верхней и левой координат (чтобы была возможность календарь, при необходимости, двигать)
    left 			:	0,
    top  			:	0,
	
	//создание массивов со вспомогательными данными
    daysOfWeek		:	['пн','вт','ср','чт','пт','сб','вс'],
    namesOfMonths	:	['Январь','Февраль','Март','Апрель','Май','Июнь','Июль','Август','Сентябрь','Октябрь','Ноябрь','Декабрь'],
    daysOfMonths	:	[31,28,31,30,31,30,31,31,30,31,30,31],
	
	//запоминаем сегодняшнюю дату в переменные (она будет открываться по умолчанию при показе календаря)
	todayDay		:	new Date().getDate(),
	todayMonth		:	new Date().getMonth()+1,
	todayYear		:	new	Date().getFullYear(),
	
	//инициализируем переменные формата вывода, минимальной и максимальной даты диапазона (сюда будем считывать значения параметров функции инициализации)
	format			:	null,
	minDate			:	null,
	maxDate			: 	null,
	
	//инициализируем переменные, в которых будет храниться выбранная дата
	currentDay		:	null,
    currentMonth	:	null,
    currentYear		:	null,
	
	//устанавливаем период просматриваемых лет (задается минимальной и максимальной датой из параметров функции инициализации)
    minYear			:	null,
    maxYear			:	null,

    css				:	document.createElement('link'),
    div				:	document.createElement('div'),

	selectMonth		:	null,
	selectYear		:	null,
	
	//инициализируем вспомогательную переменную идентификатора, она будет использоваться при проверке в функции show()
	idTo			:	null,

	//инициализируем переменную, в которую будем запоминать объект документа, около которого будет появляться календарь	
	objectWhereTo	:	null,
	
	//инициализируем переменную, в которой будет храниться название класса ячейки, чтобы присвоить его обратно после срабатывания onmouseout
	rememberHClass	:	null,

	//функция проверки года на високосность
	isLeap			:	function(year) {
							return (((year % 4)==0) && ((year % 100)!=0) || ((year % 400)==0)) ? true : false;
						},

	//функция инициализации календаря
	init			:	function(minD, maxD, formatD) {
							//запоминаем параметры, указываемые при инициализации
							this.format = formatD;
							
							//создаём регулярное выражение, чтобы распарсивать минимальную и максимальную дату
							var regExpToParse = /\d{1,4}/g;
							
							//распарсиваем минимальную и максимальную дату из строки в объекты Date
							this.minDate = new Date(minD.match(regExpToParse)[2], minD.match(regExpToParse)[1]-1, minD.match(regExpToParse)[0]);
							this.maxDate = new Date(maxD.match(regExpToParse)[2], maxD.match(regExpToParse)[1]-1, maxD.match(regExpToParse)[0]);
							
							//запоминаем в свойства год минимальной и максимальной даты (используется для построения выпадающего списка selectYear)
							this.minYear = minD.match(regExpToParse)[2];
							this.maxYear = maxD.match(regExpToParse)[2];
							
//							alert(this.minDate);
//							alert(this.maxDate);

							//создаём ссылку на ЦСС-стиль
							this.css.rel = 'stylesheet';
							this.css.href = 'calendar.css';
							document.body.appendChild(this.css);
							
							//создаём див, в котором всё будет лежать
							this.div.id = 'calendar';
							this.div.innerHTML = this.html();
							document.body.appendChild(this.div);
							
							//создаём выпадающий список с месяцами
							this.selectMonth = document.getElementById('calendarMonth');
							
							//забиваем в форму все значения (месяцы)
							for (var i = 0; i < this.namesOfMonths.length; i++) {
								this.selectMonth.options[i] = new Option(this.namesOfMonths[i], i+1);
							}
							
							//создаем выпадающий список с годами
							this.selectYear = document.getElementById('calendarYear');
							
							//забиваем в форму все значения (годы)
							for (var i = 0; i <= this.maxYear-this.minYear; i++) {
								this.selectYear.options[i] = new Option(this.maxYear-i, this.maxYear-i);
							}
						},
	//функция рисует html-сетку
	html			:	function() {
							//инициализируем переменную, в которую будем выводить результат (возвращать)
							var resultHTML = '';
							//создаём пустой массив (вспомогательный), чтобы быстро загнать туда много строк HTML-кода и затем преобразовать его в string
							var arrayHTML = [];
							//забиваем в массив нужный HTML - для быстрого создания кода использовался parserHtmlToJavascriptString.html
							arrayHTML	=	[
												'<table cellpadding="0" cellspacing="0" width="100%" class="controls"> \n',
												'    <tbody> \n', 
												'        <tr class="global"> \n', 
												'            <td class="todayButton" width="50%"><a href="#" onclick="Calendar.makeTodayCurrent();Calendar.returnDate(Calendar.todayDay);return false;">сегодня</a></td> \n', 
												'            <td class="closeButton" width="50%"><a href="#" onclick="Calendar.hide(); return false;">закрыть</a></td> \n', 
												'        </tr> \n', 
												'        <tr class="selectArea"> \n', 
												'			 <td colspan="2"> \n',
												'            <a href="#" onclick="Calendar.scrollMonthToCur(-1); return false;">&lt;&lt;</a> \n', 
												'                <form action=""> \n', 
												'                    <select id="calendarMonth" onchange="Calendar.changeMonth(this.value);"></select> \n', 
												'                    <select id="calendarYear"  onchange="Calendar.changeYear(this.value);"></select> \n', 
												'                </form> \n', 
												'            <a href="#" onclick="Calendar.scrollMonthToCur(1); return false;">&gt;&gt;</a> \n', 
												'            </td> \n', 
												'        </tr> \n', 
												'		<tr> \n',
												'			<td colspan="2" class="daysOfWeekCarrier"> \n',
												'				<table cellpadding="0" cellspacing="0" class="daysOfWeek"> \n', 
												'					<thead> \n', 
												'						<tr> \n', 
												'							<td>Пн</td> \n', 
												'							<td>Вт</td> \n', 
												'							<td>Ср</td> \n', 
												'							<td>Чт</td> \n', 
												'							<td>Пт</td> \n', 
												'							<td>Сб</td> \n', 
												'							<td>Вс</td> \n', 
												'						</tr> \n', 
												'					</thead> \n', 
												'					<tbody> \n'
											]
							//динамически содаем таблицу, каждая ячейка которой имеет идентификатор (сюда будем заносить даты)
							for (var y = 1; y <= 6; y++) {
								arrayHTML.push('        <tr> \n');
								for (var x = 1; x <=7; x++) {
									arrayHTML.push('            <td id="cell_'+y+'_'+x+'" onmouseover="Calendar.dateMouseOver(this);" onmouseout="Calendar.dateMouseOut(this);" onclick="Calendar.returnDate(this.innerHTML)" unselectable="on"></td> \n');
								}
								arrayHTML.push('        </tr> \n');
							}
							arrayHTML.push('    </tbody> \n');
							arrayHTML.push('</table> \n'); 
							arrayHTML.push('</td> \n'); 
							arrayHTML.push('</tr> \n'); 
							arrayHTML.push('</tbody> \n');
							arrayHTML.push('</table> \n'); 
							//теперь сшиваем массив в строку и выводим в результирующую переменную
							resultHTML = arrayHTML.join('');
							//возвращаем результат
							return resultHTML;
						},
	//функция проверки всех элементов управления (кроме ячеек в таблице чисел) - можно ли с помощью нажатия на тот или иной элемент выбрать дату, которая не будет попадать в заданный диапазон? если можно - его надо затемнить
	checkAllControls:	function() {
							//проверка выпадающего списка с месяцами
							for (var i = 0; i < this.selectMonth.options.length; i++) {
								if (this.checkIsDateMatch(this.currentYear, this.selectMonth.options[i].value, this.currentDay)) {
									this.selectMonth.options[i].disabled = true;
								}
								else {
									this.selectMonth.options[i].disabled = false;
								}
							}
							//проверка выпадающего списка с годами
							for (var i = 0; i < this.selectYear.options.length; i++) {
								if (this.checkIsDateMatch(this.selectYear.options[i].value, this.currentMonth, this.currentDay)) {
									this.selectYear.options[i].disabled = true;
								}
								else {
									this.selectYear.options[i].disabled = false;
								}
							}
						},						
	//функция заполняет объект данными (датами)
	draw			:	function() {
							//расставляем классы для ячеек "выходных дней" - может это надо в функцию html() вынести???
							for (var y = 1; y <= 6; y++) {
								for (var x = 1; x <=7; x++) {
									var cellIsTesting = document.getElementById('cell_'+y+'_'+x);
									cellIsTesting.className   = (x <6) ? 'day' : 'weekEnds';
	    							cellIsTesting.style.cursor = 'default';
									cellIsTesting.innerHTML   = '&nbsp;';						
								}
							}
							//создаем переменную allDays, в которую записываем количество дней в данном месяце
							//попутно проверяем год на високосность
							var allDays = (this.currentMonth == 2 && this.isLeap(this.currentYear)) ? 29 : this.daysOfMonths[this.currentMonth-1];
							//определяем начальную дату (первое число) месяца
							var beginDate = new Date(this.currentYear,this.currentMonth-1,1).getDay();
							//заполняем месяц
							y = 1;
							x = (beginDate!=0 ? beginDate : 7);
							for (var c = 1; c <= allDays; c++) {
								var cellIsTesting = document.getElementById('cell_'+y+'_'+x);
								//проверяем, не является ли дата в данной ячейке сегодняшней, применяем, если надо, цсс-класс
								if (this.checkIsDateToday(c)) {
									cellIsTesting.className = "todayDate";
								}
								//прописываем в ячейку дату
								cellIsTesting.innerHTML = c;
								cellIsTesting.style.cursor = 'pointer';
								//переходим в следующую колонку, если дошли до конца - прыгаем на след. строку
								x++;
								if (x > 7) {
									x = 1;
									y++;
								}
							}
							//функция скрывающая последнюю строку таблица, если та оказалась пустой (зависит от количества дней в месяце)
							this.killLastRow();
							this.checkAllControls();
						},
	//функция проверки - не является ли данная дата сегодняшней
	checkIsDateToday:	function(day) {
							return (this.todayDay==day && this.currentMonth==this.todayMonth && this.currentYear == this.todayYear) ? true : false;
						},
	//функция (по сути, самая главная) показывает, собственно, календарь пользователю - под левым нижним углом инпута, куда будет выводиться итоговая дата
	show			:	function(idWhereToPlace) {
							//если функция уже отрабатывала (и переменная idTo уже сохранена в свойстве объекта) скрываем календарь и выходим
							if (idWhereToPlace==this.idTo) {
								this.hide();
								return false;
							}
							//запоминаем в переменную объект документа, около которого будет появляться календарь
							this.objectWhereTo = document.getElementById(idWhereToPlace);
							//делаем сегодняшнюю дату выбранной
							this.makeTodayCurrent();
							
							//высчитываем позицию календаря на экране и прибавляем (если нужно) заданные в объекте значения
							var realPosition = this.computePosition(this.objectWhereTo);
							realPosition.x += this.left;
							realPosition.y += this.top+this.objectWhereTo.offsetHeight;
							//показываем див с календарём
							this.div.style.display = 'block';
							this.div.style.left = realPosition.x+'px';
							this.div.style.top = realPosition.y+'px';
						},
	
	//функция скрывает календарь
	hide			:	function() {
							//обнуляем свойство объекта idTo
							this.idTo = null;
							//убираем с экрана div
							this.div.style.display = 'none';
						},
	//функция делает сегодняшнюю дату выбранной
	makeTodayCurrent:	function(){
							this.currentDay = this.todayDay;
							this.currentMonth = this.todayMonth;
							this.currentYear = this.todayYear;
							this.scrollMonthToCur(0);
						},
	//проверка попадания currentDate в заданный диапазон
	checkIsDateMatch:	function(someYear, someMonth, someDay) {
							var currentDate = new Date(someYear, someMonth - 1, someDay);
							if ((currentDate <= this.maxDate) && (currentDate >= this.minDate)) {
								return false;
							}
							else if (currentDate > this.maxDate) {
								var result = 'current date bigger than max date'
								return result;
							}
							else if (currentDate < this.minDate) {
								var result = 'current date smaller than min date'
								return result;
							}
						},
	//функция скроллит календарь на выбранный месяц + ещё на указанное в параметре число месяцев и проверяет при этом, чтобы правильно перескочить
	//с января на декабрь (или наоборот)
    scrollMonthToCur: 	function (numberOfMonthsToAdd) {
    						//проверка на попадание новой даты (ПОСЛЕ перехода) в заданный диапазон
    						if (this.checkIsDateMatch(this.currentYear, this.currentMonth + numberOfMonthsToAdd, this.currentDay)) return false;
							this.currentMonth = this.currentMonth + numberOfMonthsToAdd;
							if (this.currentMonth < 1) {
								this.currentMonth = 12;
								this.currentYear -= 1;
							}
							if (this.currentMonth > 12) {
								this.currentMonth = 1;
								this.currentYear += 1;
							}
							//делаем, чтобы в выпадающем списке с месяцами был выбран нужный месяц
							document.getElementById('calendarMonth').selectedIndex=this.currentMonth-1;
							//теперь скроллим год
							this.scrollYearToCur(0);
						},
	scrollYearToCur	:	function (numberOfYearsToAdd) {
    						//проверка на попадание новой даты (ПОСЛЕ перехода) в заданный диапазон
							if (this.checkIsDateMatch(this.currentYear + numberOfYearsToAdd, this.currentMonth, this.currentDay)) return false;
							this.currentYear = this.currentYear + numberOfYearsToAdd;
							if (this.currentYear < this.minYear) this.currentYear = this.minYear;
							if (this.currentYear > this.maxYear) this.currentYear = this.maxYear;
							document.getElementById('calendarYear').value = this.currentYear;
							//всё готово, рисуем календарь
							this.draw();
						},
	//функция высчитывает позицию элемента, с учётом offsetParent
	computePosition	:	function(objectToCompute) {
							var resultPosition = { x : 0, y : 0 };
							while(objectToCompute) {
								resultPosition.x += objectToCompute.offsetLeft;
								resultPosition.y += objectToCompute.offsetTop;
								objectToCompute = objectToCompute.offsetParent;
							}
							return resultPosition;
						},
	dateMouseOver	:	function(cellIsTesting) {
							if (cellIsTesting == '&nbsp;') return false;
							this.rememberHClass = cellIsTesting.className;
							cellIsTesting.className = 'dayMouseOver';
						},
	dateMouseOut	:	function(cellIsTesting) {
							if (cellIsTesting == '&nbsp;') return false;
							cellIsTesting.className = this.rememberHClass;
							this.rememberHClass = null;
						},
	returnDate		:	function(selectedDate) {
							if (!selectedDate || selectedDate == '&nbsp;') return false;
							resultDateInFormat = this.format;
							resultDateInFormat = resultDateInFormat.replace('%d', (selectedDate < 10 ? '0' : '') + selectedDate);
							resultDateInFormat = resultDateInFormat.replace('%m', (this.currentMonth < 10 ? '0' : '') + this.currentMonth);
							if (resultDateInFormat.match('%Y')) {
								resultDateInFormat = resultDateInFormat.replace('%Y', this.currentYear);
							}
							else if (resultDateInFormat.match('%y')) {
								var cuttedYear;
								cuttedYear = (this.currentYear+'').substring(2,4);
								resultDateInFormat = resultDateInFormat.replace('%y', cuttedYear);
							}
							this.objectWhereTo.value = resultDateInFormat;
							this.hide();
						},
	selDateToBig	:	function() {
							//alert('current date bigger than max date');
							this.currentDay = this.maxDate.getDate();
							this.currentMonth = this.maxDate.getMonth()+ 1;
							this.currentYear = this.maxDate.getFullYear();
							document.getElementById('calendarMonth').selectedIndex=this.currentMonth-1;
							this.scrollYearToCur(0);
						},
	selDateToSmall	:	function() {
							//alert('current date smaller than min date');
							this.currentDay = this.minDate.getDate();
							this.currentMonth = this.minDate.getMonth()+ 1;
							this.currentYear = this.minDate.getFullYear();
							document.getElementById('calendarMonth').selectedIndex=this.currentMonth-1;
							this.scrollYearToCur(0);
						},
	changeMonth		:	function(numberOfMonthToChange) {
							//проверка на попадание новой даты (ПОСЛЕ перехода) в заданный диапазон
    						var checkDateMatchResult = this.checkIsDateMatch(this.currentYear, numberOfMonthToChange, this.currentDay); 
							if (checkDateMatchResult == 'current date bigger than max date') {
								this.selDateToBig();
								return false;
							}
							else if (checkDateMatchResult == 'current date smaller than min date') {
								this.selDateToSmall();
								return false;
							}		
							this.currentMonth = numberOfMonthToChange*1;
							this.scrollYearToCur(0);
						},
	changeYear		:	function(yearToChange) {
							//проверка на попадание новой даты (ПОСЛЕ перехода) в заданный диапазон
    						var checkDateMatchResult = this.checkIsDateMatch(yearToChange, this.currentMonth, this.currentDay); 
							if (checkDateMatchResult == 'current date bigger than max date') {
								this.selDateToBig();
								return false;
							}
							else if (checkDateMatchResult == 'current date smaller than min date') {
								this.selDateToSmall();
								return false;
							}		
							this.currentYear = yearToChange*1;
							this.scrollYearToCur(0);
						},
	killLastRow		:	function() {
							if (document.getElementById('cell_6_1').innerHTML == '&nbsp;') {
								document.getElementById('cell_6_1').parentNode.className = 'killRow';
							}
							else {
								document.getElementById('cell_6_1').parentNode.className = 'liveRow';
							}
						}
}

