/**
 * contacts_list_menu.js
 * @projectDescription Файл для обеспечения работоспособности меню в левом
 * сером блоке с контактной информацией.
 * <br /><br />
 * Ранее был написан на Common.js, однако в связи с разбиением на несколько
 * колонок, которое связано с активными вычислениями при инициализации меню,
 * было все переделано на jQuery.
 *<br /><br />
 * Задача: при щелчке по названию города должно выпадать меню, содержащее
 * список имеющихся контактов в городах, организованный в несколько столбцов;
 * текст в столбцах должен использовать место по максимуму (нужно выбрать
 * соотвествующее количество столбцов и строк).
 * <br /><br />
 * Для работы необходимо наличие jQuery.
 *
 * @version 1.2
 * 
 * @since 1.1 от 18.11.2008
 * 
 * @since 1.0 от 29.09.2008
 * 1. Изменения в соответствии с таском
 * http://i2/tasks/edit/?id=5270024403764216931 
 *
 * @copyright Art.Lebedev Studio (http://www.artlebedev.ru)
 * @author Станислав Муравьев <mur@design.ru> 22.12.2008
 *
 */

/**
 * Метод, вызывающийся по готовности документа.
 *
 * @author Станислав Муравьев <mur@design.ru> 22.12.2008
 */
$(function(){

    /**
     * Див с городом по умолчанию
     *
     * @type {jQuery}
     */
    var jqSelectedCityDiv = $("#cities_list #cities_contacts_selected_city");

    /**
     * Див с меню
     *
     * @type {jQuery}
     */
    var jqCityMenuDiv = $(".chooser #cities_list #cities_contacts_menu");

    /**
     * Див с контактами
     *
     * @type {jQuery}
     */
    var jqCityContactsDiv = $(".chooser #cities_contacts");

    //0. Прелоад используемых картинок
    loadImages();

    //1. Генерим меню
    makeMenu(jqCityMenuDiv);

    //2. Назначаем обработчики. Так как тут некоторые вещи должны быть глобаль-
    //   ными, то тут мы их и определим

    /**
     * Обработчик события mouseover для дива с городом по умолчанию. Задача -
     * добавить класс hover
     *
     * @author Станислав Муравьев <mur@design.ru> 29.09.2008
     */
    jqSelectedCityDiv.mouseover(function(){
        $(this).addClass("hover").find("ins").addClass("hover");
        
    });

    /**
     * Обработчик события mouseout для дива с городом по умолчанию. Задача -
     * убрать класс hover
     *
     * @author Станислав Муравьев <mur@design.ru> 29.09.2008
     */
    jqSelectedCityDiv.mouseout(function(){
        $(this).removeClass("hover").find("ins").removeClass("hover");
    });

    /**
     * Обработчик события click для дива с городом по умолчанию. Задача -
     * показать меню.
     *
     * @author Станислав Муравьев <mur@design.ru> 29.09.2008
     */
    jqSelectedCityDiv.click(function(/* Event */ eEvent){
        //Показывалка меню
        jqCityContactsDiv.addClass("with_visible_overflow");
        jqCityMenuDiv.removeClass("hidden");
        eEvent.stopPropagation(); //Стоять! А то боди заматчится
    });

    /**
     * Обработчик события click для body. Задача - убрать меню.
     *
     * @author Станислав Муравьев <mur@design.ru> 29.09.2008
     */
    $("body").click(function(){
        jqCityContactsDiv.removeClass("with_visible_overflow");
        jqCityMenuDiv.addClass("hidden");
        jqSelectedCityDiv.find("ins").removeClass("hover");
    });
    
    /**
     * Обработчик события click для серой плашки в адресном меню. Задача:
     * если щелчок мыши произведен не в элементе ins и не в крестике, запретить
     * дальнейшее всплывание события.
     * 
     * @author Станислав Муравьев <mur@design.ru> 18.11.2008
     */
    jqCityMenuDiv.click(function(/* Event */ eEvent){
        /**
         * Элемент-получатель события
         * 
         * @type {jQuery}
         */
        if(!($(eEvent.target).is("ins, nobr, img"))){
            eEvent.stopPropagation(); //Стоять!
        }
     });

    /**
     * Обработчик события click для пункта меню.
     *
     * @author Станислав Муравьев <mur@design.ru> 29.09.2008
     */
    jqCityMenuDiv.find("table tr td div ins").click(function(eEvent){
        updateCityMenu($(this).parent().attr("id"), 500);
    });

    /**
     * Формирует само меню со списком городов.
     *
     * @param {jQuery} jqDivForMenu Див, в котором будем формировать меню.
     *
     * @author Станислав Муравьев <mur@design.ru> 29.09.2008
     */
    function makeMenu(jqDivForMenu){

        //1. Достаем дивы с городами, куда-нибудь их сохраняем.

        /**
         * Максимальное количество строк в раскрывающемся списке.
         * @type {jQuery}
         */
        var jqElements = $("#cities_contacts .contact_city_menu_envelope");

        //2. Исходя из количества найденных дивов, рассчитываем оптимальный
        //   вариант размещения городов в списке: количество пустых строк в
        //   конце последнего столбца должно быть минимальным.

        /**
         * Количество городов на один столбец
         * @type {Number}
         */
        var iRowsPerColumn = getMaxRowsPerColumn(jqElements.length,
                                                 getMaximumNumberOfColumns(),
                                                 getMaximumNumberOfRows());

        //3. Строим список с рассчитанными параметрами.
        /**
         * HTML, который нужно вставить в div, где располагается само меню
         * @type {String}
         */
        var sHTMLToInsert = generateMenuHTMLCode(jqElements, iRowsPerColumn) + 
                            generateCloseButtonCode();
     
           jqDivForMenu.addClass("with_transparent_menu_background");


        //5. Добавляем этот список в менюшку.
       jqDivForMenu.html(sHTMLToInsert);

        //6. Убираем лишние элементы из блока контактов. Нефига засорять
        jqElements.remove();

        //7. Установим дефолтные значения
        updateCityMenu($.cookie("sCity"), 0);
    }

    /**
     * Метод создает код для отображения кнопки с крестиком, предназначенной
     * для закрывания меню.
     * 
     * @return {String} Сформированный код
     * 
     * @author Станислав Муравьев <mur@design.ru> 18.11.2008
     */
    function generateCloseButtonCode(){
        /**
         * В этом диве находится код кнопки-img, нужно его забрать, див убрать.
         * 
         * @type {jQuery}
         */
        var jqCodeDiv = $("#cities_contacts_menu_closer");
        
        /**
         * Собственно, искомый код.
         * 
         * @type {String}
         */
        var sCode = jqCodeDiv.html();

        jqCodeDiv.remove();
        return sCode;
    }
    
    /**
     * Обновление меню. Если параметр sSelectedID не указан, считается, что
     * это "начальная" инициализация меню в случае, если не установлена кука.
     * В этом случае метод находит город "по умолчанию" (этот статус нам
     * поставил XSLT), внутри дива с городом находится ins, у него убирается
     * класс "pseudo-link" для корректного отображения его в меню.
     * <br />
     * <br />
     * По умолчанию задержка анимации равна 0, то есть никаких красивых эффектов
     * не производится, однако если установить iAnimationDelay в отличное от
     * нуля значение, будет производиться слайдинг контактной информации при
     * смене города.
     *
     * @param {String} [sSelectedID] Айдишник выбранного города.
     * @param {Number} [iAnimationDelay] Длительность анимации в миллисекундах
     *
     * @author Станислав Муравьев <mur@design.ru> 29.09.2008
     */
    function updateCityMenu(sSelectedID, iAnimationDelay){
        if(sSelectedID){
            //Да, что-то передали. Давайте проверим, а не по текущему блоку
            //щелкнули-то...
            /**
             * Адресный блок, у которого есть класс, соответствующий куке
             *
             * @type {jQuery}
             */
            var jqAddressBlock = $(".chooser #cities_contacts div." +
                                   sSelectedID);
            /**
             * Соответствующий пункт меню
             *
             * @type {jQuery}
             */
            var jqMenuItem = jqCityMenuDiv.find("#" + sSelectedID);
            //И если все есть...
            if((jqMenuItem.length == 1) &&
               (jqAddressBlock.length == 1) &&
               (!(jqMenuItem.hasClass("current_city")))){
                //Все то же самое, только без анимации
                jqSelectedCityDiv.html(jqMenuItem.html())
                /**
                 * Бывший текущий пункт меню.
                 *
                 * @type {jQuery}
                 */
                 jqCityMenuDiv.find("div.current_city ins").addClass(
                                                                 "pseudo-link");

                 //3. Убираем pseudo-link у инса, что в кликнутом диве
                 jqMenuItem.find("ins").removeClass("pseudo-link");

                 //4. Ставим новую куку с айдишником кликнутого города
                 /**
                   * Айдишник кликнутого города.
                   *
                   * @type {String}
                   */
                //dtDate = new Date(Date() + 2592000000);
                $.cookie("sCity", sSelectedID, {path : "/"});

                //5. Перелистываем контактный блок
                //У this есть айдишник. Нужно убрать имеющийся блок контактов и
                //показать тот, у которого есть класс, имя которого совпадает с
                //нашим айдишником. если указан параметр iAnimationDelay,
                //тогда это делаем "красиво", иначе тупо меняем.
                /**
                 * Два блока: тот, что видимый, и тот, что нужно сделать
                 * видимым
                 *
                 * @type {jQuery}
                 */
                var jqBlocksToToggle = $("#cities_contacts div." + sSelectedID +
                                         ", #cities_contacts div:visible");
                //Дальнейшие операции стоит делать только тогда, когда их 2
                if(jqBlocksToToggle.length == 2){
                   if(iAnimationDelay){
                        jqBlocksToToggle.slideToggle(iAnimationDelay, function(){
                            toggleHiddenClass(this);
                        });
                    }
                    else{
                        $.each(jqBlocksToToggle, function(/* Number */iNumber, /* Element */ eElement){
                            toggleHiddenClass(eElement);
                        });
                    }
                    //6. Переставить статус
                    jqCityMenuDiv.find(".current_city").removeClass("current_city");
                    jqMenuItem.addClass("current_city");
                }
            }
            else{
                removePseudoLinkOnCurrentCity();
            }
        }
        else{
            removePseudoLinkOnCurrentCity();
        }
    }

    /**
     * Если у элемента нет класса <code>hidden</code>,
     * добавляет его, иначе - убирает.
     *
     * @param {Element} Элемент, о котором идет речь
     *
     * @author Станислав Муравьев <mur@design.ru> 12.10.2008
     */
    function toggleHiddenClass(eElement){
        /**
         * Элемент, найденный с помощь. jQuery
         *
         *  @type {jQuery}
         */
        var jqElement = $(eElement);
        if(jqElement.hasClass("hidden")){
            jqElement.removeClass("hidden");
        }
        else{
            jqElement.addClass("hidden");
        }
    }

    /**
     * Убирает класс pseudo-link у элемента ins, содержащегся в выбранном диве
     *
     * @author Станислав Муравьев <mur@design.ru> 29.09.2008
     */
    function removePseudoLinkOnCurrentCity(){
        jqCityMenuDiv.find("div.current_city ins").removeClass("pseudo-link");
    }


    /**
     * Возвращает максимально возможное количество столбцов.
     * @see getMaximumNumberOfRows
     *
     * @return {Number} Максимально возможное количество столбцов списка
     *
     * @author Станислав Муравьев <mur@design.ru> 29.09.2008
     */
    function getMaximumNumberOfColumns(){
        return 4;
    }

    /**
     * Возвращает максимально возможное количество строк в одном столбце.
     * @see getMaximumNumberOfColumns
     *
     * @return {Number} Максимально возможное количество строк в столбце списка
     *
     * @author Станислав Муравьев <mur@design.ru> 29.09.2008
     */
    function getMaximumNumberOfRows(){
        return 16;
    }

    /**
     * Метод возвращает оптимальное число строк в одном столбце списка.<br />
     * Критерий определения оптимального числа строк: минимум  пустого места
     * в конце последнего столбца списка.
     * <br />
     * <br />
     * <strong>Особый случай</strong>
     * <br />
     * Если общее число элементов оказывается больше, чем произведение
     * количества строк на количество столбцов, метод возвратит максимальное
     * количество строк (что вполне естественно, так как в этом случае мы должны
     * уместить максимальное количество городов в видимой части списка).
     *
     * @param {Number} iItemsCount Общее количество элементов в списке
     * @param {Number} iMaximumColumns Максимальное количество столбцов
     * @param {Number} iMaximumRows Максимальное количество строк
     *
     * @return {Number} Оптимальное число строк в одном столбце (в последнем
     *                  столбце их может быть быть меньше)
     *
     * @author Станислав Муравьев <mur@design.ru> 29.09.2008
     */
    function getMaxRowsPerColumn(iItemsCount, iMaximumColumns, iMaximumRows){

        /**
         * Текущее рассматриваемое количество строк
         * @type {Number}
         */
        var iCurrentRowsCount = iMaximumRows;

        /**
          * Текущее оптимальное количество строк на столбец
          * @type {Number}
          */
        var iOptimalRowsCount = iCurrentRowsCount;

        /**
         * Текущее рассматриваемое количество столбцов
         * @type {Number}
         */
        var iCurrentColumnsCount = Math.ceil(iItemsCount / iMaximumRows);

        /**
         * Текущий остаток пустых строк в последнем столбце
         * @type {Number}
         */
        var iLinesRemains = iCurrentRowsCount * iCurrentColumnsCount -
                            iItemsCount;

        //Собственно, основной цикл.
        while((iLinesRemains > 0) &&
              (iCurrentColumnsCount <= iMaximumColumns)){

            while((iLinesRemains > 0) &&
                   (iCurrentRowsCount > 0) &&
                   (iCurrentRowsCount * iCurrentColumnsCount >= iItemsCount)){
                /**
                  * Остаток строк при заданных в цикле параметрах
                  * @type {Number}
                  */
                var iCurrentLinesRemains = iCurrentRowsCount *
                                           iCurrentColumnsCount -
                                           iItemsCount;
                if(iCurrentLinesRemains < iLinesRemains){
                    iLinesRemains = iCurrentLinesRemains;
                    iOptimalRowsCount = iCurrentRowsCount;
                }
                iCurrentRowsCount--;
            }
            iCurrentColumnsCount++;
        }
        //Все, возвращаемся
        return iOptimalRowsCount;
    }

    /**
     * Создает HTML-код, который нужно вставить в слой, где должно <
     * располагаться меню.
     *
     * @param {jQuery} jqElements JQuery-набор элементов меню
     * @param {Number} iRowsNumber Количество строк в одном столбце меню
     *
     * @see getMaxRowsPerColumn
     *
     * @return {String} Строка HTML-кода меню
     */
    function generateMenuHTMLCode(jqElements, iRowsNumber){
        /**
         * HTML-код, полученный в результате выполнения функции - таблица
         * с двумя колонками
         * @type {String}
         * 
         * @author Станислав Муравьев <mur@design.ru> 29.09.2008
         */
        var sHTML = "<table><tr><td>";
		var prevLetter = "";
        //Начали код с того, что открыли колонку таблицы
        $.each(jqElements, function(/* Number */ iIndex,
                                    /* Element */ eElement){
			/* Прячем индексную букву */
			if($(eElement).find("span.letter").html() != prevLetter){
				prevLetter = $(eElement).find("span.letter").html();
			} else {
				/* if( iIndex % iRowsNumber != 0 ){
					$(eElement).find("span.letter").css( {"visibility": "hidden"} );
				}*/
				$(eElement).find("span.letter").css( {"visibility": "hidden"} );
			}
            if((iIndex > 0) && (iIndex % (iRowsNumber) == 0)){
                //Тут нужно закрыть одну колонку и начать новую
                sHTML = sHTML + "</td><td>";
            }
            sHTML = sHTML + $(eElement).html();
        });
        //И возвращаем, не забывая закрыть таблицу
        return sHTML + "</td></tr></table>"
    }
    
    /**
     * Предварительная загрузка используемых картинок (прелоадинг).
     * 
     * @author Станислав Муравьев <mur@design.ru> 29.09.2008
     */
    function loadImages(){
        /**
         * Массив адресов, по которым располагаются загружаемые картинки
         * 
         * @type {Array}
         */
        var aImagesToLoad = ["/f/1/global/chooser_button.gif",
                             "/f/1/global/thermo_bg.png"]
        /**
         * Массив загруженных картинок
         * 
         * @type {Array}
         */
        var aImageCache = new Array();
       
        /**
         * Счетчик
         * 
         * @type {Number}
         */
        for(var iCounter= 0; iCounter < aImagesToLoad.length; iCounter++){
            /**
             * Загружаем картинку
             */
            aImageCache[iCounter] = new Image();
            aImageCache[iCounter].src = aImagesToLoad[iCounter];
        }
    }
});

function getInternetExplorerVersion()
// Returns the version of Internet Explorer or a -1
// (indicating the use of another browser).
{
  var rv = -1; // Return value assumes failure.
  if (navigator.appName == 'Microsoft Internet Explorer')
  {
    var ua = navigator.userAgent;
    var re  = new RegExp("MSIE ([0-9]{1,}[\.0-9]{0,})");
    if (re.exec(ua) != null)
      rv = parseFloat( RegExp.$1 );
  }
  return rv;
}
