/*******************************************************************
 *              Построение схем метро, районов, шоссе              *
 *******************************************************************/

/**
 * Добавляет в селект метро из другого селекта для расширенного поиска.
 *
 * @param in_id1 (string): айди селекта, из которого необходимо перенести метро.
 * @param in_id2 (string): айди селекта, в который необходимо перенести метро. 
 */
function changeMetroSelect(in_id1, in_id2) {

  if (gebi(in_id1).selectedIndex == -1 || gebi(in_id1).options.length == 0) return;
  // Выделенная опция.
  var opt = gebi(in_id1).options[gebi(in_id1).selectedIndex];
  var i = 0;
  var option_arr = new Array;
  // Определяем выделенные опции.
  while (i < gebi(in_id1).options.length) {
    if (gebi(in_id1).options[i].selected == true) {
      if (gebi(in_id2).options.length > 0) {
        // Делаем вставку.
        _mergeSortMetro(gebi(in_id2).options, gebi(in_id1).options[i]);
      } else {
        // Копируем выделенную опцию.
        gebi(in_id2).options.add(new Option(gebi(in_id1).options[i].text, gebi(in_id1).options[i].value));
        gebi(in_id2).options[gebi(in_id2).options.length - 1].id = gebi(in_id1).options[i].id;
      }
      // Удаляем опцию.
      gebi(in_id1).remove(i);
    } else i++;
  }
}

/**
 * Сортировка метро вставкой.
 *
 * @param in_array(array):
 * массив опций, в который необходимо вставить переданную опцию с метро.
 *
 * @param in_opt(object):
 * опция с метро, которую необходимо вставить в список.
 */
function _mergeSortMetro(in_array, in_opt) {
 
  var arr = in_array;
  var o = in_opt;
  var len = arr.length;
  var left = 0;
  var right = len - 1;
  
  function _mSort(in_l, in_r) {
    
    var l = in_l;
    var r = in_r;
    var m = Math.ceil((l + r) / 2);
    
    ox_text = arr[m].text;
    ox_value = arr[m].value;
    ox_id = arr[m].id;
    
    do {
      
      while (ox_text > o.text && r != l) {
        
        r = m;
        m = Math.floor((l + r) / 2); 
        ox_text = arr[m].text;
        ox_value = arr[m].value;
        ox_id = arr[m].id;
        
      }
      
      while (ox_text < o.text && r != l) {
        
        l = m;
        m = Math.ceil((l + r) / 2);
        ox_text = arr[m].text;
        ox_value = arr[m].value;
        ox_id = arr[m].id;
        
      }
      
    } while (r - l > 1);
    
    if (arr[l].text > o.text) r = l;
    
    return r;
    
  }
  
  var x = _mSort(left, right);
  
  
  arr[len] = new Option('', '');
  arr[len].text = o.text;
  arr[len].value = o.value;
  arr[len].id = o.id;
  
  if (len == 1) {
    
    if (arr[0].text < o.text) {
      
      arr[len].text = o.text;
      arr[len].value = o.value;
      arr[len].id = o.id;
      
    } else {
      
      arr[len].text = arr[0].text;
      arr[len].value = arr[0].value;
      arr[len].id = arr[0].id;
      arr[0].text = o.text;
      arr[0].value = o.value;
      arr[0].id = o.id;
      
    }
    
  } else if (arr[x].text > o.text) {
    
    for (var i = len - 1; i >= x; i--) {
      
      arr[i + 1].text = arr[i].text;
      arr[i + 1].value = arr[i].value;
      arr[i + 1].id = arr[i].id;
      
    }
    
    arr[x].text = o.text;
    arr[x].value = o.value;
    arr[x].id = o.id;
   
  }
      
}

/**
 * Сбрасывает селект с отобранными метро в расширенном поиске.
 */
function resetSelectMetro() {
  // Выделяем все опции в списке.
  for (var i = 0; i < gebi('search-ext-metro').options.length; i++) gebi('search-ext-metro').options[i].selected = true; 
  // Переносим города в левый список.
  changeMetroSelect('search-ext-metro', 'search-ext-metro1');
}

/**
 * Добавляет или убирает из списка метро, которые принадлежат выбранной станции на карте.
 *
 * @param in_id (string): код выбранного метро на карте.
 */
function switchMetroMap(in_id) {
  // Убираем выделение с метро в левом селекте.
  if (gebi('search-ext-metro1').selectedIndex != -1) {
    gebi('search-ext-metro1').options[gebi('search-ext-metro1').selectedIndex].selected = false;
  }
  // Показываем или гасим выбранное метро на карте.
  var src = gebi('metro' + in_id).src;
  var src2 = src;
  src = src.substr(src.length - 9);
 
    var reg = new RegExp(gebi('src_pixel').value, 'g');
    if (reg.test(src2)) {
      gebi('metro' + in_id).src = gebi('src_blinkcircle').value;
      var id_sel_from = 'search-ext-metro1';
      var id_sel_in = 'search-ext-metro';
    } else {
      gebi('metro' + in_id).src = gebi('src_pixel').value;
      var id_sel_from = 'search-ext-metro';
      var id_sel_in = 'search-ext-metro1';
    }
 
  for (var i = 0; i < gebi(id_sel_from).options.length; i++) {
    if (gebi(id_sel_from).options[i].value == in_id) {
      gebi(id_sel_from).options[i].selected = true;
    }
  }
  changeMetroSelect(id_sel_from, id_sel_in);
}

/**
 * Отмечает метро на карте, которые есть в переданном селекте.
 *
 * @param in_id_sel (string): айди селекта, который проверяется на наличие в нём метро.
 */
function checkMapMetro(in_id_sel, in_id_sel1) {
  for (var i = 0; i < gebi(in_id_sel).options.length; i++) {
    var opt = gebi(in_id_sel).options[i];
    var src = gebi('metro' + opt.value).src;
    var src2 = src;
    src = src.substr(src.length - 9);
   
    // Выделяем метро на карте.
    
      var reg = new RegExp(gebi('src_pixel').value, 'g');
      if (reg.test(src2)) gebi('metro' + opt.value).src = gebi('src_blinkcircle').value;
     
	
  }
  for (var i = 0; i < gebi(in_id_sel1).options.length; i++) {
    var opt = gebi(in_id_sel1).options[i];
    var src = gebi('metro' + opt.value).src;
    var src2 = src;
    src = src.substr(src.length - 9);
    
    // Гасим метро на карте.
    if (gebi('src_blinkcircle')) {
      var reg = new RegExp(gebi('src_blinkcircle').value, 'g');
      if (reg.test(src2)) gebi('metro' + opt.value).src = gebi('src_pixel').value;
    }
	
  }
}

/**
 * Начало отображения схемы метро - показывает фон.
 */
function mapMetro() {
  var divEl = ce('div');
  divEl.setAttribute('id', 'search-metromapbg');
  divEl.className = 'search-ext-mapbg';
  gebtn('body')[0].appendChild(divEl);
  var dxScroll = (window.scrollX != null) ? window.scrollX : document.documentElement.scrollLeft; // для Chrome, IE
  divEl.style.width = gebtn('body')[0].offsetWidth + dxScroll + 'px';
  divEl.style.height = gebtn('body')[0].offsetHeight + 'px';
  var funcArr = {
    name: '_mapMetroStep2',
    divbg: divEl
  };
  $('#search-metromapbg').fadeTo(400, 0.5, function(){_mapMetroStep2(funcArr)});
}

/**
 * Второй шаг схемы метро - показывает схему.
 */
function _mapMetroStep2(in_array) {
  var divEl = in_array['divbg'];
  //gebtn('body')[0].appendChild(gebi('kartamet'));
  gebi('kartamet').className = 'vid';
  // Центруем карту.
  _setCenterMetroMap();
  divEl.onclick = _closeMetroMap;  
}

/**
 * Центрует карту метро и её фон.
 */
var map_top = null;
function _setCenterMetroMap() {
  // Размеры большого изображения.
  var imgHeight = gebi('kartamet').offsetHeight;
  var imgWidth = gebi('kartamet').offsetWidth;
  // Определяем количество прокрученных пикселей вертикальным скролом от начала документа.
  var dyScroll = (window.scrollY != null) ? window.scrollY : document.documentElement.scrollTop; // для Chrome, IE
  // Определяем количество прокрученных пикселей горизонтальным скролом от начала документа.
  var dxScroll = (window.scrollX != null) ? window.scrollX : document.documentElement.scrollLeft; // для Chrome, IE
  if (screen.height > 768) {
    // Определяем внутреннюю высоту окна.
    var winHeight = document.documentElement.clientHeight;
    // Вычисляем вертикальную позицию для отображения большой картинки.
    var divTop = dyScroll + Math.round(winHeight / 2) - Math.round(imgHeight / 2);
  } else {
    var divTop = (map_top == null) ? dyScroll + 15 : map_top;
  }
  if (divTop < 0) divTop = 0;
  if (divTop + imgHeight + 50 > gebtn('body')[0].offsetHeight) divTop = gebtn('body')[0].offsetHeight - imgHeight - 50;
  map_top = divTop;

  var mW = $('#kartamet').width();
  var bW = $('body').outerWidth();

  divLeft = Math.round((bW - mW) / 2) + dxScroll;

  if (divLeft + imgWidth + 50 > gebtn('body')[0].offsetWidth) divLeft = gebtn('body')[0].offsetWidth - imgWidth - 50;
  gebi('kartamet').style.left = divLeft + 'px';
  gebi('kartamet').style.top = divTop + 'px';
  divEl = gebi('search-metromapbg');
  
  var dy = 0;
  dy = isFF || isIE8 ? 60 : dy;
  dy = isOpera || isChrome ? 20 : dy; 
  
  divEl.style.width = gebtn('body')[0].offsetWidth + dxScroll + 'px';
  divEl.style.height = gebtn('body')[0].offsetHeight + dy + 'px';
}

/**
 * Закрывает карту - начинает процесс.
 */
function _closeMetroMap() {
  $('#search-metromapbg').fadeTo(400, 0, function(){_closeMetroMapStep2()});
}

/**
 * Шаг 2. Гасит фон схемы.
 */
function _closeMetroMapStep2() {
  gebi('kartamet').className = 'nevid';
  if (gebi('search-metromapbg')) rn(gebi('search-metromapbg'));
}

/**
 * Подчёркивает текст названия станции на схеме.
 *
 * in_id
 * (string) айди названия метро на схеме.
 * in_bool
 * (bool) true - подчёркиваем название, false - убираем подчёркивание.
 */
function onMouseMetro(in_id, in_bool) {
  gebi(in_id).style.borderBottom = (in_bool == true) ? '1px solid black' : 'none';
}

/*********** Шоссе ************/


/**
 * Начало отображения схемы шоссе - показывает фон.
 */
function mapHighway() {
  var divEl = ce('div');
  divEl.setAttribute('id', 'search-highwaymapbg');
  divEl.className = 'search-ext-mapbg';
  gebtn('body')[0].appendChild(divEl);
  var dxScroll = (window.scrollX != null) ? window.scrollX : document.documentElement.scrollLeft; // для Chrome, IE
  divEl.style.width = gebtn('body')[0].offsetWidth + dxScroll + 'px';
  divEl.style.height = gebtn('body')[0].offsetHeight + 'px';
  $('#search-highwaymapbg').fadeTo('fast', 0.5, function () {_mapHighwayStep2();});
}

/**
 * Второй шаг схемы шоссе - показывает схему.
 */
function _mapHighwayStep2() {
  var divEl = gebi('search-highwaymapbg');
  //gebtn('body')[0].appendChild(gebi('kartashosse'));
  // Показываем карту.
  gebi('kartashosse').className = 'vid';
  // Центруем карту.
  _setCenterHighwayMap();
  divEl.onclick = function () {_closeHighwayMap();};  
}

/**
 * Центрует карту шоссе и её фон.
 */
function _setCenterHighwayMap() {
  // Размеры изображения.
  var imgHeight = gebi('kartashosse').offsetHeight;
  var imgWidth = gebi('kartashosse').offsetWidth;
  var dyScroll = (window.scrollY != null) ? window.scrollY : document.documentElement.scrollTop; // для Chrome, IE
  var dxScroll = (window.scrollX != null) ? window.scrollX : document.documentElement.scrollLeft; // для Chrome, IE
  var winHeight = document.documentElement.clientHeight;
  var divTop = dyScroll + Math.round(winHeight / 2) - Math.round(imgHeight / 2);
  if (divTop < 0) divTop = 0;
  if (divTop + imgHeight + 50 > gebtn('body')[0].offsetHeight) divTop = gebtn('body')[0].offsetHeight - imgHeight - 50;

  var mW = $('#kartashosse').width();
  var bW = $('body').outerWidth();

  divLeft = Math.round((bW - mW) / 2) + dxScroll;

  gebi('kartashosse').style.left = divLeft + 'px';
  gebi('kartashosse').style.top = divTop + 'px';
  divEl = gebi('search-highwaymapbg');
  
  var dy = 0;
  dy = isFF || isIE8 ? 60 : dy;
  dy = isOpera || isChrome ? 20 : dy;
  
  divEl.style.width = gebtn('body')[0].offsetWidth + dxScroll + 'px';
  divEl.style.height = gebtn('body')[0].offsetHeight + dy + 'px';
}

/**
 * Закрывает карту - начинает процесс.
 */
function _closeHighwayMap() {
  gebi('kartashosse').className = 'nevid';
  $('#search-highwaymapbg').fadeOut('fast', function () {_closeHighwayMapStep2();});
}

/**
 * Гасит фон карты.
 */
function _closeHighwayMapStep2() {
  gebi('kartashosse').className = 'nevid';
  if (gebi('search-highwaymapbg')) rn(gebi('search-highwaymapbg'));
}

/**
 * Добавляет в селект шоссе из другого селекта для расширенного поиска.
 *
 * in_id1 (string):
 * айди селекта, из которого необходимо перенести шоссе.
 *
 * in_id2 (string):
 * айди селекта, в который необходимо перенести шоссе. 
 */
function changeHighwaySelect(in_id1, in_id2) {
  if (gebi(in_id1).selectedIndex == -1 || gebi(in_id1).options.length == 0) return;
  var i = 0;
  var option_arr = new Array;
  while (i < gebi(in_id1).options.length) {
    if (gebi(in_id1).options[i].selected == true) {
      if (gebi(in_id2).options.length > 0) {
        // Делаем вставку.
        _mergeSortHighway(gebi(in_id2).options, gebi(in_id1).options[i]);
      } else {
        // Копируем выделенную опцию.
        gebi(in_id2).options.add(new Option(gebi(in_id1).options[i].text, gebi(in_id1).options[i].value));
        gebi(in_id2).options[gebi(in_id2).options.length - 1].id = gebi(in_id1).options[i].id;
      }
      // Удаляем опцию.
      gebi(in_id1).remove(i);
    } else i++;
  }
}

/**
 * Сортировка шоссе вставкой.
 *
 * @param in_array(array):
 * массив опций, в который необходимо вставить переданную опцию с шоссе.
 *
 * @param in_opt(object):
 * опция с шоссе, которую необходимо вставить в список.
 */
function _mergeSortHighway(in_array, in_opt) {
 
  var arr = in_array;
  var o = in_opt;
  var len = arr.length;
  var left = 0;
  var right = len - 1;
  
  function _mSort(in_l, in_r) {
    
    var l = in_l;
    var r = in_r;
    var m = Math.ceil((l + r) / 2);
    
    ox_text = arr[m].text;
    ox_value = arr[m].value;
    ox_id = arr[m].id;
    
    do {
      
      while (ox_text > o.text && r != l) {
        
        r = m;
        m = Math.floor((l + r) / 2); 
        ox_text = arr[m].text;
        ox_value = arr[m].value;
        ox_id = arr[m].id;
        
      }
      
      while (ox_text < o.text && r != l) {
        
        l = m;
        m = Math.ceil((l + r) / 2);
        ox_text = arr[m].text;
        ox_value = arr[m].value;
        ox_id = arr[m].id;
        
      }
      
    } while (r - l > 1);
    
    if (arr[l].text > o.text) r = l;
    
    return r;
    
  }
  
  var x = _mSort(left, right);
  
  arr[len] = new Option('', '');
  arr[len].text = o.text;
  arr[len].value = o.value;
  arr[len].id = o.id;
  
  if (len == 1) {
    
    if (arr[0].text < o.text) {
      
      arr[len].text = o.text;
      arr[len].value = o.value;
      arr[len].id = o.id;
      
    } else {
      
      arr[len].text = arr[0].text;
      arr[len].value = arr[0].value;
      arr[len].id = arr[0].id;
      arr[0].text = o.text;
      arr[0].value = o.value;
      arr[0].id = o.id;
      
    }
    
  } else if (arr[x].text > o.text) {
    
    for (var i = len - 1; i >= x; i--) {
      
      arr[i + 1].text = arr[i].text;
      arr[i + 1].value = arr[i].value;
      arr[i + 1].id = arr[i].id;
      
    }
    
    arr[x].text = o.text;
    arr[x].value = o.value;
    arr[x].id = o.id;
    
  }
      
}

/**
 * Сбрасывает селект с отобранными шоссе в расширенном поиске.
 */
function resetSelectHighway() {
  // Выделяем все опции в списке.
  for (var i = 0; i < gebi('search-ext-highway2').options.length; i++) {
    gebi('search-ext-highway2').options[i].selected = true; 
  }
  // Переносим шоссе в левый список.
  changeHighwaySelect('search-ext-highway2', 'search-ext-highway1');
}

/**
 * Обрабатывает клик по эмулированному чекбоксу.
 *
 * @param in_id (string):
 * айди чекбокса.
 */
function onclickCheckbox(in_id) {
  
  if (/^search-ext-maphighway-/.test(in_id)) {
    
    // Перенаправление на функцию, обрабатывающую клики по чекбоксам на карте с шоссе в расширенном поиске.
    _addOrRemoveHighwayInSelect(in_id);
    
  }
  
}

/**
 * Добавляет или удаляет из правого селекта шоссе отмеченные на карте в расширенном поиске.
 *
 * @param in_id (string):
 * айди чекбокса.
 */
function _addOrRemoveHighwayInSelect(in_id) {
  
  if (/^search-ext-maphighway-pw/.test(in_id)) {

    var check = gebi(in_id).checked;
    var inputs = gebtn('input');
    
    // Перебираем все чекбоксы для выбранного направления.
    for (var i = 0; i < inputs.length; i++) {
      
      if (/search-ext-maphighway-chbox/.test(inputs[i].id) && inputs[i].value == gebi(in_id).value) {
        
        // Отмечаем или убираем галочку в чекбоксе для заданого направления.
        inputs[i].checked = check;
        
        if (gebi('img_' + inputs[i].id)) {
          
          // Показываем или скрыаем галочку в чекбоксе направления.
          gebi('img_' + inputs[i].id).style.visibility = (gebi(inputs[i].id).checked) ? 'visible' : 'hidden';
          
        }
        
      }
      
    }
    
    // Выделяем выбранные шоссе в соответствующем селекте и переносим в противоположный.
    _relocateSelectHighway(in_id, true);
    
  } else {
    
    // Проверяем все чекбоксы по этому же направлению и отмечаем или снимаем чекбокс
    // направления при необходимости.
    var check = _checkMapHighwayDirectAllCheckboxes(in_id);
    var id_pw = 'search-ext-maphighway-pw' + gebi(in_id).value;
    
    if (check == 1) {
      
      // Отмечаем чекбокс направления.
      gebi(id_pw).checked = true;
      
    } else if (gebi(id_pw).checked) {
      
      // Отчищаем чекбокс направления.
      gebi(id_pw).checked = false;
      
    }
    
    if (gebi('img_' + id_pw)) {
      
      // Показываем или скрыаем галочку в чекбоксе направления.
      gebi('img_' + id_pw).style.visibility = (gebi(id_pw).checked) ? 'visible' : 'hidden';
      
    }
    
    // Выделяем выбранное шоссе в соответствующем селекте и переносим в противоположный.
    _relocateSelectHighway(in_id);
    
  }
  
}

/**
 * Проверяет все ли чекбоксы отмечены по направлению, к которму принадлежит чекбокс с переданным айди.
 *
 * @param in_id (string):
 * айди чекбокса.
 *
 * @return (int):
 * 0 - все не отмечены, 1 - все отмечены, 2 - отмечены некоторые.
 */
function _checkMapHighwayDirectAllCheckboxes(in_id) {
  
  var count = 0;
  var count_check = 0;
  
  // Массив всех элементов input.
  var inputs = gebtn('input');
  
  for (var i = 0; i < inputs.length; i++) {
    
    if (/search-ext-maphighway-chbox/.test(inputs[i].id) && inputs[i].value == gebi(in_id).value) {
      
      count++;
      count_check += (inputs[i].checked == true) ? 1 : 0;
      
    }
    
  }
  
  var check = (count_check > 0 && count == count_check) ? 1 : ((count_check > 0) ? 2 : 0);
  
  return check;
  
}

/**
 * Добавляет или удаляет из правого селекта шоссе отмеченные на карте в расширенном поиске.
 *
 * @param in_id (string):
 * айди чекбокса.
 *
 * @param in_all (bool):
 * true - перенести все шоссе, которые принадлежат одному направлению.
 */
function _relocateSelectHighway(in_id, in_all) {
  
  var id_sel_from = (gebi(in_id).checked) ? 'search-ext-highway1' : 'search-ext-highway2';
  var id_sel_in = (gebi(in_id).checked) ? 'search-ext-highway2' : 'search-ext-highway1';
  
  // Параметры чекбокса.
  var id_ch = in_id.substr(27);
  var val_ch = gebi(in_id).value;
  
  for (var i = 0; i < gebi(id_sel_from).options.length; i++) {
    
    // Параметры опции.
    var id_sel = gebi(id_sel_from).options[i].id.substr(21);
    var val_sel = gebi(id_sel_from).options[i].value;
    
    if (id_sel == id_ch || (in_all && val_sel == val_ch)) {
      
      // Выделяем опцию шоссе, если оно принадлежит выбранному чекбоксу на карте. 
      gebi(id_sel_from).options[i].selected = true;

    } else {
      
      gebi(id_sel_from).options[i].selected = false;
      
    }
    
  }

  // Переносим выделенные города в противоположный список.
  changeHighwaySelect(id_sel_from, id_sel_in);
  
}

/**
 * Отмечает на карте только те чекбоксы, шоссе для которых занесены в правый селект.
 */
function _checkMapHighway() {
  // Правый селект.
  var sel = gebi('search-ext-highway2');
  var inputs = gebtn('input');
  for (var i = 0; i < inputs.length; i++) {
    if (/search-ext-maphighway-chbox/.test(inputs[i].id)) {
      var id_ch = inputs[i].id.substr(27);
      inputs[i].checked = false;
      // Проверяем чекбокс на вхождение в правый селект.
      for (var j = 0; j < sel.options.length; j++) {
        var id_sel = sel.options[j].id.substr(21);
        if (id_sel == id_ch) inputs[i].checked = true;
      }
      if (gebi('img_' + inputs[i].id)) {
        // Показываем или скрываем галочку в чекбоксе.
        gebi('img_' + inputs[i].id).style.visibility = (inputs[i].checked) ? 'visible' : 'hidden';
      }
      // Проверяем все чекбоксы по этому же направлению и отмечаем или снимаем чекбокс
      // направления при необходимости.
      var check = _checkMapHighwayDirectAllCheckboxes(inputs[i].id);
      var id_pw = 'search-ext-maphighway-pw' + inputs[i].value;
      if (check == 1) {
        // Отмечаем чекбокс направления.
        gebi(id_pw).checked = true;
      } else if (gebi(id_pw).checked) {
        // Отчищаем чекбокс направления.
        gebi(id_pw).checked = false;
      }
      if (gebi('img_' + id_pw)) {
        // Показываем или скрыаем галочку в чекбоксе направления.
        gebi('img_' + id_pw).style.visibility = (gebi(id_pw).checked) ? 'visible' : 'hidden';
      }
    }
  }
}


/***************ГОРОДА****************************/

function mapCity() {
  var divEl = ce('div');
  divEl.setAttribute('id', 'search-citymapbg');
  divEl.className = 'search-ext-mapbg';
  gebtn('body')[0].appendChild(divEl);
  var dxScroll = (window.scrollX != null) ? window.scrollX : document.documentElement.scrollLeft; // для Chrome, IE
  divEl.style.width = gebtn('body')[0].offsetWidth + dxScroll + 'px';
  divEl.style.height = gebtn('body')[0].offsetHeight + 'px';
  $('#search-citymapbg').fadeTo('fast', 0.5, function () {_mapCityStep2();});  
}

function _mapCityStep2() {
  var divEl = gebi('search-citymapbg');
  gebtn('body')[0].appendChild(gebi('kartamo'));
  gebi('kartamo').className = 'vid';
  _setCenterCityMap();
  divEl.onclick = function () {_closeCityMap();};
}

function _setCenterCityMap() {
  // Размеры большого изображения.
  var imgHeight = gebi('kartamo').offsetHeight;
  var imgWidth = gebi('kartamo').offsetWidth;
  var dyScroll = (window.scrollY != null) ? window.scrollY : document.documentElement.scrollTop; // для Chrome, IE
  var dxScroll = (window.scrollX != null) ? window.scrollX : document.documentElement.scrollLeft; // для Chrome, IE
  var winHeight = document.documentElement.clientHeight;
  var divTop = dyScroll + Math.round(winHeight / 2) - Math.round(imgHeight / 2);
  if (divTop < 0) divTop = 0;
  if (divTop + imgHeight + 50 > gebtn('body')[0].offsetHeight) divTop = gebtn('body')[0].offsetHeight - imgHeight - 50;
  divLeft = getCenterHorizontal(gebi('kartamo')) + dxScroll;
  gebi('kartamo').style.left = divLeft + 'px';
  gebi('kartamo').style.top = divTop + 'px';
  divEl = gebi('search-citymapbg');
  var dy = 0;
  dy = isFF || isIE8 ? 60 : dy;
  dy = isOpera || isChrome ? 20 : dy;
  divEl.style.width = gebtn('body')[0].offsetWidth + dxScroll + 'px';
  divEl.style.height = gebtn('body')[0].offsetHeight + dy + 'px';
}

function _closeCityMap() {
  $('#search-citymapbg').fadeOut('fast', function () {_closeCityMapStep2();});
}

function _closeCityMapStep2(in_array) {
  gebi('kartamo').className = 'nevid';
  if (gebi('search-citymapbg')) rn(gebi('search-citymapbg'));
}


/**
 * Сбрасывает селект с отобранными городами в расширенном поиске.
 */
function resetSelectCity() {
  // Выделяем все опции в списке.
  for (var i = 0; i < gebi('search-ext-city2').options.length; i++) {
    gebi('search-ext-city2').options[i].selected = true; 
  }
  // Переносим города в левый список.
  changeCitySelect('search-ext-city2', 'search-ext-city1');
  // Очищаем карту.
  for (var i = 1; i < 40; i++) {
  	var id = 'mo' + i;
  	gebi(id).className = 'none';
  }
}

/**
 * Добавляет или убирает из списка города, которые принадлежат выбранному району на карте области.
 *
 * in_id (string):
 * айди выбранной области на карте.
 */
function switchAreaMap(in_id) {
  
  // Убираем выделение с города в левом селекте.
  if (gebi('search-ext-city1').selectedIndex != -1) {
    gebi('search-ext-city1').options[gebi('search-ext-city1').selectedIndex].selected = false;
  }
  // Айди района, в котором находится город.
  var id_area = in_id.substr(2);
  //log(id_area);
  // Айди селекта, из которого будет происходит перенос города.
  var id_sel_from = (gebi(in_id).className == 'none') ? 'search-ext-city1' : 'search-ext-city2';
  // Айди селекта, в который будет происходит перенос города.
  var id_sel_in = (gebi(in_id).className == 'none') ? 'search-ext-city2' : 'search-ext-city1';
  // Показываем или гасим выбранный район на карте области.
  //gebi(in_id).className = (gebi(in_id).className == 'none') ? 'block' : 'none';
  if (gebi(in_id).className == 'none') {
    $('#'+in_id).fadeTo(0, 1, function (){gebi(in_id).className = 'block';});
  } else {
    $('#'+in_id).fadeTo(0, 0, function (){gebi(in_id).className = 'none';});
  }
  for (var i = 0; i < gebi(id_sel_from).options.length; i++) {
    if (gebi(id_sel_from).options[i].value == id_area) {
      // Выделяем опцию города, если он принадлежит выбранному району на карте. 
      gebi(id_sel_from).options[i].selected = true;
    }
  }
  // Переносим выделенные города в противоположный список.
  changeCitySelect(id_sel_from, id_sel_in);
}

/**
 * Сортировка городов вставкой.
 *
 * @param in_array(array):
 * массив опций, в который необходимо вставить переданную опцию с городом.
 *
 * @param in_opt(object):
 * опция с городом, которую необходимо вставить в список.
 */
function _mergeSortCity(in_array, in_opt) {
 
  var arr = in_array;
  var o = in_opt;
  var len = arr.length;
  var left = 0;
  var right = len - 1;
  
  function _mSort(in_l, in_r) {
    
    var l = in_l;
    var r = in_r;
    var m = Math.ceil((l + r) / 2);
    
    ox_text = arr[m].text;
    ox_value = arr[m].value;
    ox_id = arr[m].id;
    
    //alert([l,r,m,ox_text]);
    
    do {
      
      while (ox_text > o.text && r != l) {
        
        //alert('1: сравниваемый - '+ox_text+', вставляемый - '+o.text+', л - '+l+', п - '+r+', с - '+m);
        r = m;
        m = Math.floor((l + r) / 2); 
        ox_text = arr[m].text;
        ox_value = arr[m].value;
        ox_id = arr[m].id;
        
      }
      
      while (ox_text < o.text && r != l) {
        
        //alert('2: сравниваемый - '+ox_text+', вставляемый - '+o.text+', л - '+l+', п - '+r+', с - '+m);
        l = m;
        m = Math.ceil((l + r) / 2);
        ox_text = arr[m].text;
        ox_value = arr[m].value;
        ox_id = arr[m].id;
        
      }
      
    } while (r - l > 1);
    
    if (arr[l].text > o.text) r = l;
    
    return r;
    
  }
  
  var x = _mSort(left, right);
  
  //alert(x);
  
  arr[len] = new Option('', '');
  arr[len].text = o.text;
  arr[len].value = o.value;
  arr[len].id = o.id;
  
  if (len == 1) {
    
    if (arr[0].text < o.text) {
      
      arr[len].text = o.text;
      arr[len].value = o.value;
      arr[len].id = o.id;
      
    } else {
      
      arr[len].text = arr[0].text;
      arr[len].value = arr[0].value;
      arr[len].id = arr[0].id;
      arr[0].text = o.text;
      arr[0].value = o.value;
      arr[0].id = o.id;
      
    }
    
  } else if (arr[x].text > o.text) {
    
    for (var i = len - 1; i >= x; i--) {
      
      arr[i + 1].text = arr[i].text;
      arr[i + 1].value = arr[i].value;
      arr[i + 1].id = arr[i].id;
  
      //alert(i + 1 + ' - ' + arr[i + 1].text);
      
    }
    
    arr[x].text = o.text;
    arr[x].value = o.value;
    arr[x].id = o.id;
    
    //alert(arr[x].text + ' done!');
    
  }
      
}

/**
 * Отмечает районы на карте, которые есть в переданном селекте.
 *
 * @param in_id_sel (string): айди селекта, который проверяется на наличие в нём районов.
 */
function checkMapCity(in_id_sel) {
  for (var i = 0; i < gebi(in_id_sel).options.length; i++) {
    var opt = gebi(in_id_sel).options[i];
    var isArea = opt.text.substr(opt.text.length - 3) == 'р-н';
    if (isArea) gebi('mo' + opt.value).className = 'block';
  }
}

/**
 * Добавляет в селект города из другого селекта для расширенного поиска.
 *
 * in_id1 (string): айди селекта, из которого необходимо перенести города.
 * in_id2 (string): айди селекта, в который необходимо перенести города. 
 */
function changeCitySelect(in_id1, in_id2) {
  if (gebi(in_id1).selectedIndex == -1 || gebi(in_id1).options.length == 0) return;
  // Выделенная опция.
  var opt = gebi(in_id1).options[gebi(in_id1).selectedIndex];
  // Определяем выбран ли район.
  var isArea = opt.text.substr(opt.text.length - 3) == 'р-н';
  if (isArea) {
    // Выделяем район на карте.
    gebi('mo' + opt.value).className = (!gebi(in_id1).multiple) ? 'block' : 'none';
  }
  var i = 0;
  var option_arr = new Array;
  // Определяем выделенные опции или опции принадлежащие выделенному району и переносим их.
  while (i < gebi(in_id1).options.length) {
    if (gebi(in_id1).options[i].selected == true || (isArea && opt.value == gebi(in_id1).options[i].value)) {
      if (gebi(in_id2).options.length > 0) {
        // Делаем вставку.
        _mergeSortCity(gebi(in_id2).options, gebi(in_id1).options[i]);
      } else {
        // Копируем выделенную опцию.
        gebi(in_id2).options.add(new Option(gebi(in_id1).options[i].text, gebi(in_id1).options[i].value));
        gebi(in_id2).options[gebi(in_id2).options.length - 1].id = gebi(in_id1).options[i].id;
      }
      // Удаляем опцию.
      gebi(in_id1).remove(i);
    } else i++;
  }
}
