/**
 ***********************************************************************************************
    СКРИПТЫ ДЛЯ РАБОТЫ С ВВОДОМ ДАТ
 ***********************************************************************************************
 */

/**
 * Переводит дату из MySql в объект даты.
 * Параметры:                        
 *      date - строка даты в формате YYYY-MM-DD
 */
function dhMysql2Date( date )
{
    var year  = date.substring( 0, 4 );
    var month = date.substring( 5, 7 );
    var day   = date.substring( 8 );

    return new Date( year, Number( month ) - 1, day );
}

/**
 * @todo Сделать
 */
function dhAssumeDateIsLower( )
{
    var date = dhMysqlDate( dateStr );
    dhDeleteDaysHigher( yearId, monthId, dayId, date );
}

/**
 * Удаляет старые даты в выпадающих списках.
 *
 * Параметры:
 *   yearsElem  - элемент списка лет.
 *   monthsElem - элемент списка месяцев.
 *   daysElem   - элемент списка дней.
 *   lowDateUtc - элемент нижнего ограничения даты.
 *
 * 1. Удаляет все даты меньшие чем переданная.
 * 2. В выбранном месяце отображает столько дней, сколько в нём есть.
 *
 * TODO: Падежи.
 * TODO: removeChildRange
 * TODO: Вынести года в инициализацию.
 */
function dhAssumeDateIsHigher( yearsId, monthsId, daysId, lowDate )
{
    // -----------------------------
    //  Подготовительная часть
    // -----------------------------

    var i, selectedYear, selectedMonth, selectedDay;
    var daysElem   = $( daysId );
    var monthsElem = $( monthsId );
    var yearsElem  = $( yearsId );
    var lowYear  = lowDate.getFullYear();
    var lowMonth = lowDate.getMonth()+1;
    var lowDay   = lowDate.getDate();

    if ( ( daysElem == null ) && ( monthsElem == null ) && ( yearsElem == null ) ) return;

    // Текущие выбранные значения.
    if ( yearsElem != null )  { selectedYear = yearsElem.value; }
    if ( monthsElem != null ) { selectedMonth = monthsElem.value; }
    if ( daysElem != null )   { selectedDay = daysElem.value; }

    // -----------------------------
    //  Коррекция лет
    // -----------------------------
    if ( yearsElem != null )
    {
//TODO: ТУТ СДЕЛАТЬ УВЕЛИЧЕНЕ ЛЕТ
        for ( i = 0; i < yearsElem.length; i++ )
        {
            if ( yearsElem[ i ].value < lowYear )
            {
                Element.remove( yearsElem[ i ].id );
            }
        }

        selectedYear = boundValue( selectedYear, yearsElem );
        yearsElem.value = selectedYear;
    }   

    // -----------------------------
    //  Коррекция месяцев
    // -----------------------------
    if ( ( yearsElem != null ) && ( monthsElem != null ) )
    {
        var minMonth = 1;
        var maxMonth = 12;

        // Если выбран текущий год - значит, нужно удалить прошедшие месяцы
        if ( lowYear == selectedYear )
        {
            minMonth = lowMonth;
        }

        // Если количество месяцев не совпадает с расчётным
        if ( monthsElem.length != maxMonth-minMonth+1 )
        {
            // Если в начало нужно добавить месяцы - добавляем
            if ( minMonth < monthsElem[ 0 ].value )
            {
                var startEl = monthsElem[ 0 ];
                var currentStartMonth = startEl.value;
                for ( i = 1; i < Number( currentStartMonth ); i++ )
                {
                    createMonth( i, monthsElem, startEl );
                }
            }

            // Если в начале нужно удалить месяцы
            if ( minMonth > monthsElem[ 0 ].value )
            {
                var monthsToDrop = minMonth-monthsElem[ 0 ].value-1;
                for ( i = monthsToDrop; i > -1; i-- )
                {
                    Element.remove( monthsElem[ i ].id );
                }
            }
        }
        selectedMonth = boundValue( selectedMonth, monthsElem );
        monthsElem.value = selectedMonth;
    }

    // -----------------------------
    //  Коррекция дней
    // -----------------------------
    dhUpdateDays( yearsElem, monthsElem, daysElem, lowDate );
}

/**
 * Функция обновления списка дней. В месяце отображает столько дней сколько в нём есть.
 *
 * Параметры:
 *   yearsElem    - элемент списка лет.
 *   daysElem     - элемент списка месяцев.
 *   monthsElem   - элемент списка дней.
 */
function dhUpdateDays( yearsElem, monthsElem, daysElem, lowDate )
{
    if ( ( daysElem == null ) || ( monthsElem == null ) ) return;

    // Максимальное количество дней, помесячно.
    var maxDays = [ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ];

    if ( yearsElem != null )  { selectedYear = yearsElem.value; }
    if ( monthsElem != null ) { selectedMonth = monthsElem.value; }
    if ( daysElem != null )   { selectedDay = daysElem.value; }

    // Вычисляем диапазон дней в выбранном месяце.
    var minDay = 1;
    var maxDay = maxDays[ selectedMonth-1 ];

    if ( lowDate )
    {
        // Текущая дата.
        var lowYear  = lowDate.getFullYear();
        var lowMonth = lowDate.getMonth()+1;
        var lowDay   = lowDate.getDate();

        if ( ( lowYear == selectedYear ) && ( lowMonth == selectedMonth ) )
        {
            minDay = lowDay;
        }
    }

    // Создаём недостающие дни в начале списка.
    if ( daysElem[ 0 ].value > minDay )
    {
        var startEl = daysElem[ 0 ];
        var currentStartDay = startEl.value;

        for ( i = minDay; i < currentStartDay; i++ )
        {
            createDay( i, daysElem, startEl );
        }
    }

    // Создаём недостающие дни в конце списка.
    var lastDay = daysElem[ daysElem.length - 1 ].value;
    if ( lastDay < maxDay )
    {
        for ( i = Number(lastDay)+1; i < maxDay+1; i++ )
        {
            createDay( i, daysElem, null );
        }
    }

    // Корректируем список дней: удаляем дни которых нет.
    for ( i = daysElem.length-1; i > -1; i-- )
    {
        if ( ( daysElem[ i ].value < minDay ) || ( daysElem[ i ].value > maxDay ) )
        {
            Element.remove( daysElem[ i ].id );
        }
    }

    // Корректируем выбранный день: в случае, если он выходит за границы,
    // сдвигаем его к краям списка.
    selectedDay = boundValue( selectedDay, daysElem );
    daysElem.value = selectedDay;
}

/**
 * Эмулирует событие change
 */
function simulateChange( elem )
{
var cb = $(elem);

if(document.createEventObject)
{
  var evt = document.createEventObject();
  cb.fireEvent('onchange', evt);
}
if (document.createEvent)
{
  var evt = document.createEvent("HTMLEvents");
  evt.initEvent("change", true, false);
  cb.dispatchEvent(evt);
}

}

/*-----------*/
/*-----------*/
/*-----------*/
/*-----------*/
/* СТАААААААААААААРОООООООООЕЕЕЕЕ */


/**
 * Переводит дату в таймстамп.
 *
 * Параметры:
 *   date - Объект даты.
 */
function dhToUtc( date )
{
    return Date.parse( date.toString() );
}

/**
 * Возвращает значение в контейнере даты в виде таймстампа.
 *
 * Параметры:
 *   containerId - Имя контейнера.
 */
function dhGetContainerValue( containerId )
{
    return Number( $( containerId ).value );
}

/**
 * Вызывает функцию обновления даты для контейнера.
 *
 * Параметры:
 *   containerId - Имя контейнера.
 */
function dhRefreshContainer( containerId )
{
    $( containerId ).onchange();
}

/** 
 * Устанавливает значение в контейнере даты.
 *
 * Параметры:
 *   containerId - Имя контейнера.
 *   value       - Значение даты в виде таймстампа.
 */
function dhSetContainerValue( containerId, value )
{
    $( containerId ).value = value;
    dhRefreshContainer( containerId );
}

/**
 * Обновляет выпадающие списки датой контейнера.
 *
 * Параметры:
 *   value       - Значение контейнера.
 *   prefix      - Префикс связанных с контейнером списков.
 */
function dhSelectValue( value, prefix )
{
    currentDate = new Date( value );

    $( prefix + 'year' ).value  = currentDate.getFullYear();
    $( prefix + 'month' ).value = currentDate.getMonth()+1;
    $( prefix + 'day' ).value   = currentDate.getDate();
}

/**
 * Обновляет значение в контейнере, считывая его из выпадающих списков.
 *
 * Параметры:
 *   containerId - Имя контейнера.
 *   thisPrefix  - Префикс выпадающих списков.
 */
function dhUpdateContainer( containerId, thisPrefix )
{
    date = new Date( $( thisPrefix + 'year' ).value, $( thisPrefix + 'month' ).value-1, $( thisPrefix + 'day' ).value );
    dhSetContainerValue( containerId, dhToUtc( date ) );
}

/**
 * Обновляет дату в выпадающих списках.
 *
 * 1. Устанавливает в выпадающих списках значения равные текущему значению контейнера.
 * 2. Удаляет прошедшие дни в текущей дате.
 * 3. Удаляет прошедшие относительно выбранной даты дни в подчинённой дате.
 * 4. Обновляет количество дней в зависимости от выбранного месяца.
 * 5. При изменении, устанавливает подчинённую дату +1 день от выбранной.
 *
 * Параметры:
 *   containerId           - Имя контейнера.
 *   thisPrefix            - Префикс выпадающих списков даты с которой ведётся работа.
 *   lowDateContainerId    - Имя контейнера нижнего ограничения даты. Все даты ниже ограничения удаляются из списков.
 *   childDateContainerIds - Имя контейнера подчинённой даты.
 */
function dhUpdateDate( containerId, thisPrefix, lowDateContainerId, highDateContainerId, childDateContainerIds )
{
    currentDateUtc = dhGetContainerValue( containerId );

    if ( lowDateContainerId )
    {
        lowDateUtc = dhGetContainerValue( lowDateContainerId );
        if ( currentDateUtc < lowDateUtc ) currentDateUtc = lowDateUtc;
    }

    dhSelectValue( currentDateUtc, thisPrefix );

    if ( lowDateUtc )
    {
        dhSelectDeleteOldDates( 
            $( thisPrefix + 'year' ),
            $( thisPrefix + 'month' ),
            $( thisPrefix + 'day' ),
            lowDateUtc
        );
    } else {
        dhSelectDaysCountUpdate(
            $( thisPrefix + 'year' ),
            $( thisPrefix + 'month' ),
            $( thisPrefix + 'day' )
        );
    }

    if ( childDateContainerIds )
    {
        datePlusUtc = currentDateUtc + 1000*60*60*24;
        childDateCurUtc = dhGetContainerValue( childDateContainerIds );
        if ( childDateCurUtc < datePlusUtc )
        {
            dhSetContainerValue( childDateContainerIds, datePlusUtc );
        } else {
            dhSetContainerValue( childDateContainerIds, childDateCurUtc );
        }
    }
}


/**
 * Выбирает значение в выпадающем списке. Если значение не найдено,
 * выбирает первый элемент.
 */
function boundValue( value, elem )
{
    if ( value > Number( elem[ elem.length - 1 ].value ) )
    {
        value = Number( elem[ elem.length - 1 ].value );
    }
    if ( value < Number( elem[ 0 ].value ) )
    {
        value = Number( elem[ 0 ].value );
    }

    return value;
}

/**
 * Создаёт год.
 */
function createYear( i, yearsElem, startEl )
{
    yearElem = Builder.node( 'option', {'value': i, id: yearsElem.id+'_year_'+i}, i );
    if ( startEl == null ) 
    {
        daysElem.appendChild( yearElem );
    } else {
        daysElem.insertBefore( yearElem, startEl );
    }
}

/**
 * Создаёт день.
 */
function createDay( i, daysElem, startEl )
{
    dayElem = Builder.node( 'option', {'value': i, id: daysElem.id+'_day_'+i}, i );
    if ( startEl == null ) 
    {
        daysElem.appendChild( dayElem );
    } else {
        daysElem.insertBefore( dayElem, startEl );
    }
}
