/*
    Календарь

    Пример добавления календаря на страницу

    <link rel="stylesheet" type="text/css" href="calendar.css"/>
    <script type="text/javascript" src="calendar.js"></script>
    ...
    <form action="..." method="..." id="form_name">
        <input type="input" value="01.01.1970 00:00:00" name="field_name"/>
        <a href="" onclick="Calendar.show( document.forms['form_name']['field_name'], this, 'full' ); return false">...</a>
    </form>
*/

var Calendar =
{
    // Массив с названиями месяцев
    monthNames: [
        'lang_calendar_january', 'lang_calendar_february', 'lang_calendar_march', 'lang_calendar_april',
        'lang_calendar_may', 'lang_calendar_june', 'lang_calendar_july', 'lang_calendar_august',
        'lang_calendar_september', 'lang_calendar_october', 'lang_calendar_november', 'lang_calendar_december' ],

    // Массив с названиями дней недели
    weekNames: [
        'lang_calendar_monday', 'lang_calendar_tuesday', 'lang_calendar_wednesday', 'lang_calendar_thursday',
        'lang_calendar_friday', 'lang_calendar_saturday', 'lang_calendar_sunday' ],

    // Показ календаря
    show: function( control, hidden, source, mode )
    {

        this.mode = mode;
        this.control = document.getElementById(control);
        control = this.control;
        this.hidden = document.getElementById(hidden);
        hidden = this.hidden;

        this.ua = navigator.userAgent.toLowerCase();
        this.isMSIE = (this.ua.indexOf('msie') != -1) && (this.ua.charAt(this.ua.indexOf('msie') + 5) < 6);

        // В зависимости от режима создаем внутренный объект для работы с датами
        //         short - только дата (по умолчанию)
        //         long - дата и время
        //         long - дата и время с секундами
        if ( this.mode == 'long' )
            this.internalDate = new DateLong();
        else if ( this.mode == 'full' )
            this.internalDate = new DateFull();
        else
            this.internalDate = new DateShort();

        // Забираем дату из поля ввода и парсим ее
        try {
            //this.currentDate = this.internalDate.toDate( this.control.value );
            this.currentDate = this.internalDate.toDate(this.control.innerHTML);

        } catch ( e ) {
            alert( e ); this.currentDate = new Date();
        }

        // В первый раз создаем div календаря, задаем ему стиль
        if ( !this.divCalendar )
        {

            var oParentNode = control.parentNode;
            while ( oParentNode = oParentNode.parentNode )
                if ( oParentNode.tagName == 'BODY' || oParentNode.className == 'adm' )
                    break;

            this.divCalendar = document.createElement('div');
            this.divCalendar.className = 'calendar';
            oParentNode.appendChild( this.divCalendar );
        }

        // В первый раз создаем iframe календаря, задаем ему стиль
        if ( this.isMSIE && !this.iframeCalendar )
        {
            this.iframeCalendar = document.createElement( '<iframe class="calendar-iframe" frameborder="no" src="about:blank"></iframe>' );
            oParentNode.appendChild( this.iframeCalendar );
        }

        // Заполняем календарь таблицей чисел текущего месяца
        this.display( this.currentDate );

        // Определяем абсоблютные координаты опорных элементов
        var rSource = this.getPosition( source );
        var rControl = this.getPosition( this.control );

        // Позиционируем календарь в зависимости от его положения на странице
        var expand_right = rSource.x + source.offsetWidth + 4 + this.divCalendar.offsetWidth <
            this.getClientWidth() + this.getBodyScrollLeft();
        var expand_bottom = rControl.y + control.offsetHeight + this.divCalendar.offsetHeight <
            this.getClientHeight() + this.getBodyScrollTop();

        if ( expand_right )
            this.divCalendar.style.left = ( rSource.x + source.offsetWidth + 4 ) - 100 + 'px';
        else
            this.divCalendar.style.left = ( rSource.x + source.offsetWidth - this.divCalendar.offsetWidth ) + 'px';

        if ( expand_bottom )
            this.divCalendar.style.top = ( expand_right ? rControl.y : rControl.y + control.offsetHeight + 4 ) + 'px';
        else
            this.divCalendar.style.top = ( expand_right ? rControl.y + control.offsetHeight - this.divCalendar.offsetHeight :
                rControl.y + control.offsetHeight - this.divCalendar.offsetHeight -  + control.offsetHeight - 4 ) + 'px';

        // Позиционируем iframe календарь в зависимости от его положения на странице
        if ( this.iframeCalendar )
        {
            this.iframeCalendar.style.left = this.divCalendar.offsetLeft + 'px';
            this.iframeCalendar.style.top = this.divCalendar.offsetTop + 'px';

            this.iframeCalendar.style.width = this.divCalendar.offsetWidth + 'px';
        }

        // Показываем календарь
        this.divCalendar.style.visibility = 'visible';

        // Показываем iframe
        if ( this.iframeCalendar )
            this.iframeCalendar.style.visibility = 'visible';
    },

    // Метод возвращает абсолютные координаты объекта
    getPosition: function( oObj )
    {
        var x = oObj.offsetLeft, y = oObj.offsetTop;
        while ( oObj = oObj.offsetParent )
            if ( oObj.tagName != 'HTML' )
                x += oObj.offsetLeft, y += oObj.offsetTop;

        return { 'x': x, 'y': y };
    },

    // Метод возвращает проскролленность страницы по горизонтали
    getBodyScrollLeft: function()
    {
        return ( document.documentElement && document.documentElement.scrollLeft ) ||
            ( document.body && document.body.scrollLeft );
    },

    // Метод возвращает проскролленность страницы по вертикали
    getBodyScrollTop: function()
    {
        return ( document.documentElement && document.documentElement.scrollTop ) ||
            ( document.body && document.body.scrollTop );
    },

    // Метод возвращает ширину клиентской части окна
    getClientWidth: function()
    {
        return ( !window.opera && document.documentElement && document.documentElement.clientWidth ) ||
            ( document.body && document.body.clientWidth );
    },

    // Метод возвращает высоту клиентской части окна
    getClientHeight: function()
    {
        return ( !window.opera && document.documentElement && document.documentElement.clientHeight ) ||
            ( document.body && document.body.clientHeight );
    },

    // Скрытие календаря
    hide: function()
    {
        if ( this.divCalendar )
            this.divCalendar.style.visibility = 'hidden';
        if ( this.iframeCalendar )
            this.iframeCalendar.style.visibility = 'hidden';
    },

    // Заполнение поля ввода выбранной датой. Скрытие календаря
    writeDate: function( date )
    {
        this.displayDate.setDate( date );

        //this.control.value = this.internalDate.toString( this.displayDate );
        this.control.innerHTML = this.internalDate.toString( this.displayDate );
        this.hidden.value = this.internalDate.toString( this.displayDate );

        this.hide();
    },

    // Смена месяца
    setMonth: function(select)
    {
        var tDate =
            new Date(
                this.displayDate.getFullYear(), select.selectedIndex, 1,
                this.displayDate.getHours(), this.displayDate.getMinutes(), this.displayDate.getSeconds() );
        this.display( tDate );
    },

    // Смена года
    setYear: function( year )
    {
        var tDate =
            new Date(
                year, this.displayDate.getMonth(), 1,
                this.displayDate.getHours(), this.displayDate.getMinutes(), this.displayDate.getSeconds() );
        if( this.divCalendar.style.visibility == 'visible' )
            this.display( tDate );
    },

    // Смена года стрелками
    changeYear: function( shift )
    {
        var tDate =
            new Date(
                this.displayDate.getFullYear() + shift, this.displayDate.getMonth(), 1,
                this.displayDate.getHours(), this.displayDate.getMinutes(), this.displayDate.getSeconds() );
        this.display( tDate );
    },

    // Смена часа
    setHours: function( hours )
    {
        this.displayDate.setHours( hours );
    },

    // Смена минут
    setMinutes: function( minutes )
    {
        this.displayDate.setMinutes( minutes );
    },

    // Смена секунд
    setSeconds: function( seconds )
    {
        this.displayDate.setSeconds( seconds );
    },

    // Сравнение дат
    isEqualDate: function( dDate1, dDate2 )
    {
        return    ( dDate1.getFullYear() == dDate2.getFullYear() ) &&
                ( dDate1.getMonth() == dDate2.getMonth() ) &&
                ( dDate1.getDate() == dDate2.getDate() );
    },

    // Заполнение таблицы календаря числами текущего месяца
    display: function( oDate )
    {
        if ( isNaN( oDate ) )
            return;

        // Отображаемая в данный момент дата
        this.displayDate = oDate;

        var year  = this.displayDate.getFullYear();
        var month = this.displayDate.getMonth();

        var hours  = this.displayDate.getHours();
        var minutes = this.displayDate.getMinutes();
        var seconds = this.displayDate.getSeconds();

        var text = '';

        // Шапка календаря (месяц, год, кнопки смены года, кнопка закрытия)
        text += '<div class="top">';
        text += '    <img src="" style="width: 0px; height: 0px"/>';
        text += '</div>';
        text += '<div class="middle">';
        text += '    <table class="header">';
        text += '        <tr>';
        text += '            <td rowspan="2" align="center"  style="padding-left: 0px;">';
        text += '                <select class="month" onchange="Calendar.setMonth( this )">';
        for ( i = 0; i < this.monthNames.length; i++ )
            text += '                    <option value="' + i + '"' + ( ( i == month ) ? ' selected="selected"' : '' ) + '>' + Dictionary.translate( this.monthNames[i] ) + '</option>';
        text += '                </select>';
        text += '            </td>';
        text += '            <td rowspan="2" width="65" align="right">';
        text += '                <input type="text" class="year" value="' + year + '" onchange="Calendar.setYear( this.value )" maxlength="4"/>';
        text += '            </td>';
        text += '            <td class="year-up" onmousedown="Calendar.changeYear(1)"/>';
        text += '            <td rowspan="2" class="close" onmousedown="Calendar.hide()"/>';
        text += '        </tr>';
        text += '        <tr>';
        text += '            <td class="year-down" onmousedown="Calendar.changeYear(-1)"/>';
        text += '        </tr>';
        text += '    </table>';

        // Тело календаря (дни недели, числа текущегно месяца)
        text += '    <table class="date">';
        text += '        <tr>';
        for ( i = 0; i < this.weekNames.length; i++ )
            text += '            <td class="weekdays" style="width: 14%">' + Dictionary.translate( this.weekNames[i] ) + '</td>';
        text += '        </tr>';

        // Определение дня недели первого числа месяца
        var firstDayInstance = new Date( year, month, 1 )
        var firstDay = firstDayInstance.getDay();
        if (firstDay == 0) firstDay = 7;

        // Определение числа дней в текущем месяце
        var lastDateInstance = new Date( year, month + 1, 0 );
        var lastDate = lastDateInstance.getDate();

        var day = 1; var curCell = 1;
        var displayDay = ''; var tDate = null;

        for ( row = 0; row < Math.ceil( ( lastDate + firstDay - 1 ) / 7 ); row++ )
        {
            text += '        <tr>';
            for ( col = 0; col < 7; col++ )
            {
                // Пропускаем дни до первого числа месяца
                if ( curCell < firstDay )
                {
                    text += '            <td>&nbsp;</td>'; curCell++;
                }
                // Пропускаем дни после последнего числа месяца
                else if ( day > lastDate )
                {
                    text += '            <td>&nbsp;</td>';
                }
                else
                {
                    sLink = 'javascript:Calendar.writeDate(' + day + ')';

                    // Установленная дата
                    if ( this.isEqualDate( this.currentDate, new Date( year, month, day ) ) )
                        text += '            <td class="today"><a class="today" href="' + sLink + '">' + day + '</a></td>';
                    // Выходные дни
                    else if ( col > 4 )
                        text += '            <td class="weekend"><a class="weekend" href="' + sLink + '">' + day + '</a></td>';
                    // Обычные дни
                    else
                        text += '            <td><a href="' + sLink + '">' + day + '</a></td>';

                    day++;
                }
            }
            text += '        </tr>';
        }
        text += '    </table>';

        // Подвал календаря (время)
        if ( this.mode == 'long' || this.mode == 'full' )
        {
            // Часы и минуты
            text += '    <table class="time">';
            text += '        <tr>';
            text += '            <td class="time_select">';
            text += '                <select class="time" onchange="Calendar.setHours(this.value)">';
            for ( i = 0; i < 24; i++ )
                text += '                    <option value="' + i + '"' + ( ( i == hours ) ? ' selected="selected"' : '' ) + '>' + lpad( i, 2, '0' ) + '</option>';
            text += '                </select>';
            text += '            </td>';
            text += '            <td class="time_separator"/>';
            text += '            <td class="time_select">';
            text += '                <select class="time" onchange="Calendar.setMinutes(this.value)">';
            for ( i = 0; i < 60; i++ )
                text += '                    <option value="' + i + '"' + ( ( i == minutes ) ? ' selected="selected"' : '' ) + '>' + lpad( i, 2, '0' ) + '</option>';
            text += '                </select>';
            text += '            </td>';

            // Секунды
            if ( this.mode == 'full' )
            {
                text += '            <td class="time_separator"/>';
                text += '            <td class="time_select">';
                text += '                <select class="time" onchange="Calendar.setSeconds(this.value)">';
                for ( i = 0; i < 60; i++ )
                    text += '                    <option value="' + i + '"' + ( ( i == seconds ) ? ' selected="selected"' : '' ) + '>' + lpad( i, 2, '0' ) + '</option>';
                text += '                </select>';
                text += '            </td>';
            }

            text += '        </tr>';
        }
        text += '    </table>';
        text += '</div>';

        text += '<div class="bottom">';
        text += '    <img src="" style="width: 0px; height: 0px"/>';
        text += '</div>';

        this.divCalendar.innerHTML = text;

        if ( this.iframeCalendar )
            this.iframeCalendar.style.height = ( this.divCalendar.offsetHeight - 3 ) + 'px';
    }
}

// Объект для работы с датами формата DD.MM.YY (режим 'short', по умолчанию)
function DateShort()
{
    // Метод преобразуем строку в объект типа Date
    this.toDate = function( sDate )
    {
        if ( !sDate ) return new Date();

        var aMatch = sDate.match( /^(\d{2})\.(\d{2})\.(\d{4})/ );
        if ( !aMatch )
            throw Dictionary.translate( 'lang_check_date' );

        return new Date( aMatch[3], aMatch[2] - 1, aMatch[1] );
    }

    // Метод преобразуем объект типа Date в строку
    this.toString = function( oDate )
    {
        return '' +
            lpad( oDate.getDate(), 2, '0' ) + '.' +
            lpad( oDate.getMonth() + 1, 2, '0' ) + '.' +
            lpad( oDate.getFullYear(), 4, '0' );
    }
}

// Объект для работы с датами формата DD.MM.YY HH:MM (режим 'long')
function DateLong()
{
    // Метод преобразуем строку в объект типа Date
    this.toDate = function( sDate )
    {
        if ( !sDate ) return new Date();

        var aMatch = sDate.match( /^(\d{2})\.(\d{2})\.(\d{4})\s+(\d{2})\:(\d{2})/ );
        if ( !aMatch )
            throw Dictionary.translate( 'lang_check_datetime' );

        return new Date( aMatch[3], aMatch[2] - 1, aMatch[1], aMatch[4], aMatch[5] );
    }

    // Метод преобразуем объект типа Date в строку
    this.toString = function( oDate )
    {
        return '' +
            lpad( oDate.getDate(), 2, '0' ) + '.' +
            lpad( oDate.getMonth() + 1, 2, '0' ) + '.' +
            lpad( oDate.getFullYear(), 4, '0' ) + ' ' +
            lpad( oDate.getHours(), 2, '0' ) + ':' +
            lpad( oDate.getMinutes(), 2, '0' );
    }
}

// Объект для работы с датами формата DD.MM.YY HH:MM:SS (режим 'full')
function DateFull()
{
    // Метод преобразуем строку в объект типа Date
    this.toDate = function( sDate )
    {
        if ( !sDate ) return new Date();

        var aMatch = sDate.match( /^(\d{2})\.(\d{2})\.(\d{4})\s+(\d{2})\:(\d{2})\:(\d{2})/ );
        if ( !aMatch )
            throw Dictionary.translate( 'lang_check_datetime_full' );

        return new Date( aMatch[3], aMatch[2] - 1, aMatch[1], aMatch[4], aMatch[5], aMatch[6] );
    }

    // Метод преобразуем объект типа Date в строку
    this.toString = function( oDate )
    {
        return '' +
            lpad( oDate.getDate(), 2, '0' ) + '.' +
            lpad( oDate.getMonth() + 1, 2, '0' ) + '.' +
            lpad( oDate.getFullYear(), 4, '0' ) + ' ' +
            lpad( oDate.getHours(), 2, '0' ) + ':' +
            lpad( oDate.getMinutes(), 2, '0' ) + ':' +
            lpad( oDate.getSeconds(), 2, '0' );
    }
}

// Метод дополняет строку другой строкой до заданной длины слева
function lpad( sText, iLength, sSpace )
{
    var sResult = sText;
    for ( var i = 0; i < iLength - sText.toString().length; i++ )
        sResult = sSpace + sResult;
    return sResult;
}


