function UIControlCalendar()
{
//Свойства
    this.prefix = ""; //префикс
    this.postfix = ""; //постфикс
    
    this.beginYear = 0; //начальный год
    this.beginMonth = 0; //начальный месяц
    this.beginDay = 0 //начальный день
    this.beginDate = null; //начальная дата
    
    this.endYear = 0; //конечный год
    this.endMonth = 0; //конечный месяц
    this.endDay = 0 //конечный день
    this.endDate = null; //конечная дата
    
    this.currentYear = 0; //текущий год
    this.currentMonth = 0; //текущий месяц
    this.currentDay = 0 //текущий день
    this.currentDate = null; //текущая дата
    
    this.daysExistList = null; //массив дней
    
    this.url = ""; //URL страницы

//Методы
    this.Init = Init;
    
    this.IsLeap = IsLeap;
    this.GetDateDayIndex = GetDateDayIndex;
    this.GetDateByDayIndex = GetDateByDayIndex;
    this.TwoDigHex = TwoDigHex;

    this.PrintYear = PrintYear;
    this.PrintMonth = PrintMonth;
    
    this.Show = PrintCalendar;

//Глобальные переменные
    var yearStep; //шаг
    var firstYear; //первый год
    var lastYear; //последний год
    var urlRegExp; //регулярное выражение для подстановки даты в URL
    var monthRome; //массив римских цифр (месяцы)
    var dayCount; //масив последних дней месяца
    var useDaysExistList = false; //признак использования списка дней
    
//Инициализирует свойства и глобальные переменные
    function Init()
    {
        if (IsEmpty(this.daysExistList) == false && daysExistList.length > 0)
        {
            this.endDate = GetDateByDayIndex(this.daysExistList.length - 1);
            useDaysExistList = true;
        }
    
        this.beginYear = this.beginDate.getFullYear();
        this.beginMonth = this.beginDate.getMonth();
        this.beginDay = this.beginDate.getDate();        
        
        this.endYear = this.endDate.getFullYear();
        this.endMonth = this.endDate.getMonth();
        this.endDay = this.endDate.getDate();
        
        this.currentYear = this.currentDate.getFullYear();
        this.currentMonth = this.currentDate.getMonth();
        this.currentDay = this.currentDate.getDate();
    
	    yearStep = 2;
	    firstYear = this.currentYear;

	    if ((firstYear - 2) > this.beginYear)
	    {
		    firstYear = (firstYear - 2);
        }
	    else
	    {
		    firstYear = this.beginYear;
	    }

        lastYear = firstYear + 2;
        
	    monthRome = new Array("I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", "X", "XI", "XII");
	    dayCount = new Array();

	    dayCount[0] = new Array (31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31); // для високосных
	    dayCount[1] = new Array (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31); // для не високосных
	    
        urlRegExp = /\[date\]/g;

	    lastYear = ((firstYear + yearStep) > this.endYear) ? this.endYear : firstYear + yearStep;
    	
        document.writeln("<table cellpadding=\"0\" cellspacing=\"0\" border=\"0\" class=\"calendar\">");
        document.writeln("    <tr>");
        document.writeln("        <td>");
        document.writeln("            <div id=\"year\" class=\"years\"></div>");
        document.writeln("        </td>");
        document.writeln("        <td>");
        document.writeln("            <div id=\"month\" class=\"months\"></div>");
        document.writeln("        </td>");
        document.writeln("    </tr>");
        document.writeln("    <tr>");
        document.writeln("        <td colspan=\"2\">");
        document.writeln("            <div id=\"day\" class=\"days\"></div>");
        document.writeln("        </td>");
        document.writeln("    </tr>");
        document.writeln("</table>");        
    }

//Проверяет является ли год високосным
	function IsLeap(Year)
	{
	    return !(Year % 4) && !( !(Year % 100) && (Year % 400));
	}
	
//Получение индекса массива по дате
	function GetDateDayIndex(date) 
	{
		var index = 0;
		index = ((date.valueOf() - this.beginDate.valueOf()) / (60 * 1000 * 60 * 24)).toFixed(0) * 1;
		
		return index;
	}

//Получение даты по индексу массива
	function GetDateByDayIndex(index)
	{
		var result = new Date((index * 60 * 1000 * 60 * 24) + this.beginDate.valueOf());
		
		return result;
	}

//Вывод списка лет
	function PrintYear(year)
	{
		var htmlContent = "";
		
		if (year < firstYear)
		{
			firstYear -= 1;
		}
		else if (year > lastYear)
		{
			firstYear += 1;
	    }
	    
		lastYear = ((firstYear + yearStep) > this.endYear) ? this.endYear : (firstYear + yearStep);
		if (firstYear > this.beginYear)
		{
			htmlContent += "<span class=\"arrow\" onclick=\"" + this.prefix + "Calendar" + this.postfix + ".PrintYear(" + (firstYear - 1) + ")\">&larr;</span>";
	    }
			
        for (y = firstYear; y <= lastYear; y++)
        {
            htmlContent += "<span " + (y == year ? "class=\"cur\"" : "onclick=\"" + this.prefix + "Calendar" + this.postfix + ".PrintYear(" + y + ")\"" ) + ">" + y + "</span>";
        }

		if (lastYear < this.endYear)
		{
			htmlContent += "<span class=\"arrow\" onclick=\"" + this.prefix + "Calendar" + this.postfix + ".PrintYear(" + (lastYear + 1) + ")\">&rarr;</span>";
		}
		
		document.getElementById("year").innerHTML = htmlContent;
		
		if (year == this.endYear)
		{
			this.PrintMonth(year, this.endMonth + 1);
		}
		else
		{
			this.PrintMonth(year, 12);
	    }
	}

//Вывод списка месяцев и дней
	function PrintMonth(year, month)
	{
		var dcIndex = 1;
		dcIndex = this.IsLeap(year) ? 0:1;
		var tempDate = null;
		var tempDayIndex = 0;
		var endDayIndex = 0; 
		
		var htmlContent = "";
		
		for (i = 1; i <= 12; i++)
		{
			tempDate = new Date(year, i - 1, dayCount[dcIndex][i - 1]);
			
			htmlContent += "<span "
			if (tempDate.valueOf() >= this.beginDate.valueOf()
			    && tempDate.setMonth(tempDate.getMonth() - 1).valueOf() <= this.endDate.valueOf())
			{
			    if (i == month)
			    {
			        htmlContent += "class=\"cur\""
			    }
			    else
			    {
			        htmlContent += "onclick=\"" + this.prefix + "Calendar" + this.postfix + ".PrintMonth(" + year + "," + i + ")\""
			    }
	        }
	        else
	        {
                htmlContent += "class=\"no\""
	        }
            htmlContent += ">" + monthRome[i - 1] + "</span>&nbsp;";
		}
		
		document.getElementById("month").innerHTML = htmlContent;
		
		htmlContent = "";
		htmlContent += "<table cellpadding=\"0\" cellspacing=\"0\" border=\"0\" class=\"days\">"
		htmlContent += "  <tr>";
		for (f = 1; f <= dayCount[dcIndex][month - 1]; f++)
		{
			tempDate = new Date(year, month - 1, f);
			tempDayIndex =  this.GetDateDayIndex(tempDate);
			endDayIndex = this.GetDateDayIndex(this.endDate);
			
			if (tempDayIndex >= 0 && tempDayIndex <= endDayIndex)
			{
				var dcls = ((tempDate.valueOf() == this.currentDate.valueOf()) ? "class=\"cur\" " : (((tempDate.getDay() == 0) || (tempDate.getDay() == 6)) ? "class=\"holiday\" " : ""));
				if ((useDaysExistList == true && daysExistList[tempDayIndex] > 0)
				    || (useDaysExistList == false && tempDate.setMonth(tempDate.getMonth() - 1).valueOf() <= this.endDate.valueOf()))
				{
					htmlContent += "      <td>";
					htmlContent += "          <div " + dcls + "><a href=\"";
					if (this.url.search(urlRegExp) != -1)
					{
                        htmlContent += this.url.replace(urlRegExp, this.TwoDigHex(f) + this.TwoDigHex(month) + this.TwoDigHex(year));
                    }
                    else
                    {
                        htmlContent += this.url;
                        if (this.url.indexOf("?") != -1)
                        {
                            htmlContent += "&";
                        }
                        else
                        {
                            htmlContent += "?";
                        }
                        htmlContent += this.prefix + "Year" + this.postfix + "=" + year;
                        htmlContent += "&" + this.prefix + "Month" + this.postfix + "=" + month;
                        htmlContent += "&" + this.prefix + "Day" + this.postfix + "=" + f;
                    }
			        htmlContent += "\">" + f + "</a></div>";
					htmlContent += "      </td>";
				}
				else
				{
					htmlContent += "      <td class=\"no\">";
					htmlContent += "          <div " + dcls + ">" + f + "</div>";
					htmlContent += "      </td>";
                }
			}
			else
			{
				htmlContent += "      <td class=\"no\">";
				htmlContent += "          <div>" + f + "</div>";
				htmlContent += "      </td>";
			}
		}
		
		htmlContent += "  </tr>";
		htmlContent += "</table>";
		
		document.getElementById("day").innerHTML = htmlContent;
	}
	
//Преобразование десятиричных чисел в шестнадцатиричные
	function TwoDigHex(snum)
    {
		if (snum.toString(16).length == 1)
		{
			return "0" + snum.toString(16).toUpperCase();
		}
		else
		{
			return snum.toString(16).toUpperCase();
		}
	}
	
//Отображение календаря
	function PrintCalendar()
	{
	    this.Init();
	
	    this.PrintYear(this.currentYear);
	    this.PrintMonth(this.currentYear, this.currentMonth + 1);
    }
}