var currentPosition = new pointer();
var goSearch        = 0;
var selectEnd       = true;
var isFocused       = false;
var isFound         = true;
var targetObj       = "";
var keyCode         = "";
var waitInterval    = 300;
var focusInterval   = 300;
var firstTime       = Array();

var oldString       = "";
var request         = "";
var urlPath         = "";
var parameters      = "";
var maxCount        = "";
var itemInactive    = "";
var itemActive      = "";
var matchInput      = "";
var divWidth        = "";
var itemsDiv        = "";
var searchId        = "";
var searchElement   = "";
var foSiteIdStr     = "";
var startTime       = "";
var endTime         = "";

var session         = "";
var site_id         = "";

// Определяет, используется ли на странице LiveSearch
// Если да, то делает необходимые действия по инициализации
function checkLiveSearch() {
   var lsCount = 0;
   var key = "";
   for( key in parametersArray ) {
      var lsObj = document.getElementById( key );
      if( lsObj ) {
         lsCount++;
         lsObj.setAttribute( "autocomplete", "off" );
         addHandler( lsObj, "focus", processFocus );
         addHandler( lsObj, "blur", checkFocus );
         if( lsObj.getAttribute( "site_id" ) ) {
            foSiteIdStr = '&fo_site_id=' + lsObj.getAttribute( "site_id" );
         }

      }

   }

   if( lsCount ) {
      createDiv();
   }

}


function createDiv() {
   var itemsDivTry = document.getElementById( "divLiveSearch" );
   if( ! itemsDivTry ) {
      itemsDiv = document.createElement( "div" );
      itemsDiv.setAttribute( "id", "divLiveSearch" );
      itemsDiv.style.border = divStyleBorder;
      itemsDiv.style.background = divStyleBackground;
      itemsDiv.style.position = "absolute";
      itemsDiv.style.top = "-100px";
      itemsDiv.style.visibility = "hidden";
      itemsDiv.style.cursor = "default";
      document.body.appendChild( itemsDiv );

   }

}


// Обработка получения фокуса элементом input
function processFocus( e ) {
   trueEvent = window.event ? window.event : e;
   targetObj = trueEvent.srcElement ? trueEvent.srcElement : trueEvent.target;
   initDiv( targetObj.getAttribute( "id" ) );

}


// Инициализация контейнера элементов
function initDiv( keyName ) {
   if( ( typeof( urlPathArray ) != "undefined" ) && urlPathArray[ keyName ] ) {
      urlPath = urlPathArray[ keyName ];
   } else {
      urlPath = urlPathDefault;
   }
   parameters = parametersArray[ keyName ];
   if( ( typeof( maxCountArray ) != "undefined" ) && maxCountArray[ keyName ] ) {
      maxCount = maxCountArray[ keyName ];
   } else {
      maxCount = maxCountDefaul;
   }
   if( ( typeof( itemInactiveArray ) != "undefined" ) && itemInactiveArray[ keyName ] ) {
      itemInactive = itemInactiveArray[ keyName ];
   } else {
      itemInactive = "item-inactive";
   }
   if( ( typeof( itemActiveArray ) != "undefined" ) && itemActiveArray[ keyName ] ) {
      itemActive = itemActiveArray[ keyName ];
   } else {
      itemActive = "item-active";
   }
   if( ( typeof( itemNotFoundArray ) != "undefined" ) && itemNotFoundArray[ keyName ] ) {
      itemNotFound = itemNotFoundArray[ keyName ];
   } else {
      itemNotFound = "not-found";
   }
   if( ( typeof( matchInputArray ) != "undefined" ) && matchInputArray[ keyName ] ) {
      matchInput = matchInputArray[ keyName ];
   } else {
      matchInput = 0;
   }
   if( ( typeof( divWidthArray ) != "undefined" ) && divWidthArray[ keyName ] ) {
      divWidth = divWidthArray[ keyName ];
   } else {
      divWidth = 0;
   }

   if( session == "" ) {
      var sessionObj = document.getElementById( 'session' );
      if( sessionObj ) session = sessionObj.value;
      
   } // End if 
   var sessionStr = '';
   if( session ) sessionStr = '&session=' + session;

   if( site_id == "" ) {
      var boSiteIdObj = document.getElementById( 'site_id' );
      if( boSiteIdObj ) site_id = boSiteIdObj.value;
      
   } // End if 
   var boSiteIdStr = '';
   if( site_id ) boSiteIdStr = '&site_id=' + site_id;

   url = "http://" + window.location.hostname + "/" + urlPath + "?item_inactive=" + itemInactive + "&not_found=" + itemNotFound + "&max_count=" + maxCount + "&match_input=" + matchInput + "&s=" + Math.random() + parameters + sessionStr + boSiteIdStr + foSiteIdStr + "&string=";
   releaseDiv();
   document.body.removeChild( itemsDiv );
   createDiv();
   searchId = keyName;
   searchElement = document.getElementById( searchId );
   if( matchInput ) {
      itemsDiv.style.width = searchElement.offsetWidth + "px";
   } else if( divWidth ) {
      itemsDiv.style.width = divWidth + "px";
   } else {
      itemsDiv.style.width = "";
   }

   if( searchElement.value ) {
      var processURI = url + escapeEx( searchElement.value );
      loadXMLDocLS( processURI );

   }

   if( ! firstTime[ searchId ] ) {
      firstTime[ searchId ] = 1;
      addHandler( searchElement, "keyup", inputListener );

   }

   isFocused = true;

}


// Обработчик нажатых клавиш элемента input
function inputListener( e ) {
   trueEvent = window.event ? window.event : e;
   targetObj = trueEvent.srcElement ? trueEvent.srcElement : trueEvent.target;
   keyCode = trueEvent.keyCode;
   var vString = targetObj.value;
   if( keyCode == 38 && isFound ) {
      if( currentPosition.position > 0 ) {
         UpDown( currentPosition.position - 1 );
      } else {
         UpDown( currentPosition.count - 1 );
      }

   } else if( keyCode == 40 && isFound ) {
      if( currentPosition.position < currentPosition.count - 1 ) {
         UpDown( currentPosition.position + 1 ); 
      } else {
         UpDown( 0 );
      }

   } else if( keyCode == 27 ) {
      releaseDiv();
   } else if( keyCode == 32 && ( ( vString == oldString + " " ) || ( vString == oldString ) ) ) {
   } else if( keyCode == 13 || keyCode == 37 || keyCode == 39 ) {
   } else if( vString.length ) {
      var dateObj = new Date();
      startTime = dateObj.getTime();
      setTimeout( "checkSpeed()", waitInterval );

   }

   if( ! vString.length ) {
      releaseDiv();
   }

   oldString = vString;

}


// Проверка скорости набора пользователем
// Если после нажатой клавиши была пауза больше, чем значение waitInterval,
// то идет обращение к скрипту за элементами
function checkSpeed() {
   var dateObj = new Date();
   endTime = dateObj.getTime();
   if( endTime - startTime > waitInterval ) {
      liveSearch( targetObj, keyCode );
   }

}


// Обращается к скрипту за элементами
function liveSearch( target, keyCode ) {
   selectEnd = true;
   var vString = target.value;
   if( keyCode == 8 || keyCode == 35 || keyCode == 36 || keyCode == 46 || keyCode == 32 ) {
      selectEnd = false;
   }

   if( vString ) {
      var processURI = url + escapeEx( searchElement.value );
      loadXMLDocLS( processURI );

   }

}


// Непосредственное обращение к скрипту за элементами через объект XMLHttpRequest
function loadXMLDocLS( url ) {
   if( window.XMLHttpRequest ) {
      // branch for native XMLHttpRequest object
      request = new XMLHttpRequest();
      request.onreadystatechange = fillDiv;
      request.open( "GET", url, true );
      request.send( null );
   
   } else if( window.ActiveXObject ) {
      // branch for IE/Windows ActiveX version
      request = new ActiveXObject( "Microsoft.XMLHTTP" );
      if( request ) {
         request.onreadystatechange = fillDiv;
         request.open( "GET", url, true );
         request.send();

      }

   }

}


// Заполнение контейнера элементов (происходит каждый раз при получении результатов)
function fillDiv() {
   searchElement = document.getElementById( searchId );
   if( request.readyState == 4 && request.status == 200 && searchElement.value ) {
      if( ! request.responseText ) {
         itemsDiv.innerHTML = "";
         releaseDiv();
         return;

      }

      var endPosition = request.responseText.indexOf( "<" );
      var selectStart = request.responseText.substring( 0, endPosition );
      itemsDiv.innerHTML = request.responseText.substring( endPosition );
      var count = itemsDiv.childNodes.length;
      if( count != 1 ) {
         itemsDiv.innerHTML = "";
         releaseDiv();
         return;

      }

      var bodyElement = document.documentElement || document.body;
      var clientH = bodyElement.clientHeight;
      var clientW = bodyElement.clientWidth;
      var scrollT = bodyElement.scrollTop;
      var scrollL = bodyElement.scrollLeft;
      var scrollW = bodyElement.scrollWidth;
      var scrollH = bodyElement.scrollHeight;
      var searchX = getPosX( searchElement );
      var searchY = getPosY( searchElement );
      var divTop = 0;
      var divLeft = 0;
      var divHeight = 0;
      var divWidth = 0;
      var callScroll = false;
      var scrollParam = false;

      if( searchX + parseInt( itemsDiv.offsetWidth ) > scrollW ) {
         itemsDiv.style.left = searchX + parseInt( searchElement.offsetWidth ) - parseInt( itemsDiv.offsetWidth ) + "px";
         divLeft = searchX + parseInt( searchElement.offsetWidth ) - parseInt( itemsDiv.offsetWidth );

      } else {
         itemsDiv.style.left = searchX + "px";
         divLeft = searchX;

      }
      
      if( ( searchY + parseInt( searchElement.offsetHeight ) + parseInt( itemsDiv.offsetHeight ) > scrollH ) && ( searchY - parseInt( itemsDiv.offsetHeight ) > 0 ) ) {
         itemsDiv.style.top = searchY - parseInt( itemsDiv.offsetHeight ) + "px";
         divTop = searchY - parseInt( itemsDiv.offsetHeight );
         scrollParam = true;

      } else {
         itemsDiv.style.top = searchY + parseInt( searchElement.offsetHeight ) + "px";
         divTop = searchY + parseInt( searchElement.offsetHeight );

      }

      divWidth = parseInt( itemsDiv.offsetWidth );
      divHeight = parseInt( itemsDiv.offsetHeight );

      if( divTop < scrollT || divTop + divHeight > scrollT + clientH || divLeft < scrollL || divLeft + divWidth > scrollL + clientW ) {
         callScroll = true;
      }

      itemsDiv.style.visibility = "visible";
      if( callScroll ) {
         itemsDiv.scrollIntoView( scrollParam );
      }

      currentPosition.count = itemsDiv.firstChild.firstChild.childNodes.length;
      var notFoundObj = document.getElementById( "ls_404" );
      if( notFoundObj ) {
         isFound = false;
      } else {
         isFound = true;
      }
      
      if( currentPosition.count ) {
         if( selectEnd && isFound ) {
            var row = itemsDiv.firstChild.firstChild.firstChild;
            var unselected = searchElement.value;
            searchElement.value = row.firstChild.innerHTML;
            currentPosition.position = 0;
            row.className = "item-active";
            searchElement.select();
            if( document.selection ) {
               var sel = document.selection;
               var textRange = sel.createRange();
               if( textRange ) {
                  textRange.moveStart( "character", selectStart );
                  textRange.select();

               }

            } else if( searchElement.selectionEnd ) {
               searchElement.selectionStart = selectStart;
            }

         } else {
            currentPosition.position = -1;
         }

      } else {
         releaseDiv();
      }

      if( searchElement.onchange ) {
         searchElement.onchange();
      }

   }

   oldString = searchElement.value;

}


// Скрывает контейнер элементов
function releaseDiv() {   
   currentPosition.position = -1;
   itemsDiv.style.visibility = "hidden";

}


// Обработка выбора элемента из списка
function processClick( itemDiv ) {
   searchElement = document.getElementById( searchId );
   if( submitOnSelect ) {
      goSearch = 1;
      var inputCollection = searchElement.form.getElementsByTagName( "INPUT" );
      var buttonExists = false;
      for( i = 0; i < inputCollection.length; i++ ) {
         var typeName = new String( inputCollection.item( i ).getAttribute( "type" ) );
         if( typeName.toLowerCase() == "submit" ) {
            inputCollection.item( i ).click();
            buttonExists = true;
            break;

         }

      }

      if( ! buttonExists ) {
         searchElement.form.submit();
      }

   } else {
      goSearch = 0;
      releaseDiv();

   }

}


// Возвращает ссылку на объект формы, в которой находится элемент input
// Если форма не найдена, то возвращает 0
function getForm( elementObj ) {
   while( elementObj.parentNode != null && elementObj.parentNode.nodeName != "FORM" ) {
      elementObj = elementObj.parentNode;
   }

   if( elementObj.parentNode ) {
      return elementObj.parentNode;
   } else {
      return 0;
   }

}


// Обработка нажатой клавиши "вверх" или "вниз"
function UpDown( number ) {
   if( itemsDiv.style.visibility == "visible" && itemsDiv.childNodes.length == 1 ) {
      if( currentPosition.position >= 0 ) {
         itemsDiv.firstChild.firstChild.childNodes[ currentPosition.position ].className = itemInactive;
      }
      currentPosition.position = number;
      itemsDiv.firstChild.firstChild.childNodes[ currentPosition.position ].className = itemActive;
      searchElement = document.getElementById( searchId );
      searchElement.value = itemsDiv.firstChild.firstChild.childNodes[ currentPosition.position ].firstChild.innerHTML;
      if( searchElement.onchange ) {
         searchElement.onchange();
      }

   }

}


// Обработка потери фокуса элемента input
function checkFocus() {
   isFocused = false;
   setTimeout( "checkState()", focusInterval );

}


// Определяет, что делать, когда элемент input теряет фокус
function checkState() {
   if( ( ! isFocused ) && ( ! goSearch ) ) {
      releaseDiv();
   }

}


// Создает объект для текущей позиции активного элемента в списке
function pointer() {
   this.position = -1;
   this.count = 0;

}


// Определяет координату по оси X элемента input
function getPosX( obj ) {
   var currentX = 0;
   while( obj.offsetParent != null ) {
      currentX += obj.offsetLeft;
      obj = obj.offsetParent;

   }

   return currentX + obj.offsetLeft;
   
}


// Определяет координату по оси Y элемента input
function getPosY( obj ) {
   var currentY = 0;
   while( obj.offsetParent != null ) {
      currentY += obj.offsetTop;
      obj = obj.offsetParent;

   }

   return currentY + obj.offsetTop;

}


// Кодирует строку для отправки
function escapeEx( str ) {
   var ret = '';
   for( i = 0; i < str.length; i++ ) {
      var n = str.charCodeAt( i );
      if( n >= 0x410 && n <= 0x44F ) {
         n -= 0x350;
      } else if( n == 0x451 ) {
         n = 0xB8;
      } else if( n == 0x401 ) {
         n = 0xA8;
      }
      if ( (n < 65 || n > 90 ) && ( n < 97 || n > 122 ) && n < 256 ) {
         if ( n < 16 )
             ret += '%0' + n.toString( 16 );
         else
             ret += '%'+ n.toString( 16 );
      } else {
         ret += String.fromCharCode( n );
      }

   }

   return ret;

}


// Разрешать ли отправлять данные, если не указано что искать
function allowSubmit( objId ) {
   var currentId = objId;
   searchElement = document.getElementById( currentId );
   if( searchElement.value ) {
      return true;
   } else {
      return false;
   }

}


// sub addHandler
// подключает обработчики событий (кроссбраузерная)
function addHandler( object, event, handler ) {
if( typeof( object.addEventListener ) != 'undefined' ) {
   object.addEventListener( event, handler, false );
} else if( typeof( object.attachEvent ) != 'undefined' ) {
   object.attachEvent('on' + event, handler);
} else {
   var handlersProp = '_handlerStack_' + event;
   var eventProp = 'on' + event;
   if( typeof( object[ handlersProp ] ) == 'undefined' ) {
      object[ handlersProp ] = [];
      if( typeof( object[ eventProp ] ) != 'undefined' ) {
         object[ handlersProp ].push( object[ eventProp ] );
      }
      object[ eventProp ] = function( e ) {
         var ret = true;
         for( var i = 0; ret != false && i < object[ handlersProp ].length; i++ ) {
            ret = object[ handlersProp ][ i ]( e );
         }
         return ret;
      }
   }
   object[ handlersProp ].push( handler );
}
}

