/* * *
 * suggestBox v2.0
 * Contains code handling suggest-box operation
 * Uses JQuery 1.2.1
 * Complements current "Search & Solve" AJAX implementation - search_ui
 * */

// Key definitions:
var LEFT_ARROW = 37;
var UP_ARROW = 38;
var RIGHT_ARROW = 39;
var DOWN_ARROW = 40;
var SPACE_BAR = 32;
var TAB = 9;
var ENTER = 13;
var BACKSPACE = 8;
var CTRL = 16;

//stop event propagation
function stopBubble(e) {
  //If an event object exists this is a non-IE browser
  if (e && e.stopPropagation) 
    e.stopPropagation();
  //else we are dealing with IE
  else
    window.event.cancelBubble = true;
}

//stop default action from occuring
function stopDefault(e) {
  //Prevent the default browser action (W3C)
  if (e && e.preventDefault)
    e.preventDefault();
  //A shortcut for stopping the browser action in IE
  else
    window.event.returnValue = false;
}

function stopAllPropagation(e) {
  stopBubble(e);
  stopDefault(e);
}

/* Singleton object with all the methods handling the suggest-box 
 *
 * Note that hideBox() function is using a global "suggest" variable pointing to this object
 * This is needed for the click-event binding
 * With minor changes an array of suggestBox objects can be used to create several drop down menus
 * This, however, is not yet implemented
 * * * * */
function suggestBox() {
  
  this.lastQuery = ''; //latest query string
  this.active = false; //"focus" (=user input on the dropdown) on suggestBox if true, 
                       //focus elsewhere, including the input field -> false
  this.visible = false; //suggestBox is visible
  this.firstLoad = true;  //this is used for reseting the suggestBox 
                         //scroll position on page load / refresh
  this.currentRow; //Currently visible row - used to determine scrolling position
  this.foundMatch = false; //whether anything is currently shown?
  this.firstRow; //first visible row - first element of the linked list comprising the visible rows
  this.selectedValue = ''; //last value under cursor / keyboard
  this.highlightedRow; //helper var used by highlightRow() and unHighlightRow()

  this.mouseMove = false;   // highlighting should follow mouse if mouse has moved, else the keyboard is used
                            // to avoid conflict between mouse and keyboard inputs
  
  this.sb = this;

  this.toggleMouseHighlight = function() {
    this.mouseMove = true;
  }

  //Highlight line under cursor and unhighlight previously highlighted one

  this.highlightRow = function(element, mouseInput) {
    var sb = this; //cache parent object for use in jQuery contexts
    if (mouseInput == true && this.mouseMove == false) {
      return;
    }

    if (this.highlightedRow) {
      this.unHighlightRow();
    }
    element.style.cursor = 'pointer';
    element.style.backgroundColor = '#adf';
    this.highlightedRow = element;
    this.currentRow = this.highlightedRow;
    $('#qt').val(sb.currentRow.cells[0].innerHTML); 
    this.selectedValue = element.cells[0].innerHTML;
  }

  this.unHighlightRow = function() {
    if (typeof this.highlightedRow == 'object') {
      this.highlightedRow.style.backgroundColor = '#fff';
    }
  }

  //Stop all event propagation if the suggest box is visible
  this.handleBubble = function(e) {
    if (this.active == true) {
      e = e || window.event;
      switch(e.keyCode) {
        //case LEFT_ARROW:
        case UP_ARROW:
        //case RIGHT_ARROW:
        case DOWN_ARROW:
        //case RIGHT_ARROW:
          stopAllPropagation(e);
          break;
        case TAB:
          this.hideBox();
      }
    }
    if (this.visible == true) {
      e = e || window.event;
      switch(e.keyCode) {
        case TAB:
          this.hideBox();
      }
    }
  }

  //match user input with the word list
  this.updateSuggestBox = function(q) {
    //Always highlight the first visible element
    var firstElement = 1;
   
   //Fetch the table row array
    var rows = document.getElementById("suggestTable").rows;

    //Assume that new query will return nothing
    this.foundMatch = false;
    
    //previously accessed row for the linked list implementation
    var previousRow;

    //Walk through the table cells, hiding unmatches, and showing matched rows,
    //while creating a linked list of consecutive table rows at the same time
    for (var i=0; i<rows.length; i++) {
      var cells = rows[i].cells;
      
      var val = cells[0].innerHTML;
      var cellText = val.toLowerCase();

      if (cellText.indexOf(q) == 0){
        //show row
        rows[i].style.display='block';

        this.foundMatch = true;
        if (firstElement) {
          this.firstRow = rows[i];
          //highlightRow(rows[i]);
          firstElement = 0;
          firstLoad = 1;
          rows[i].prev = null;
        } else {
          rows[i].prev = previousRow;
          previousRow.next = rows[i];
        }
        previousRow = rows[i];
        rows[i].next = null;
      } else {
       rows[i].style.display='none';
      }
    }
  }

  //hide suggest box
  //references the global instance of the variable - change to local context
  this.hideBox = function() {
    $('#suggestBox').css('display', 'none');
    suggest.visible = false;
    suggest.active = false;
    suggest.unHighlightRow();
    suggest.currentRow = null;
    document.onclick = '';
  }

  //filter the keywords based on the input text
  this.handleKeyboardEvent = function(e, element) {
    this.mouseMove = false;
    
    //set-up the event handler
    e = e || window.event;

    // Check whether the input is alphanumeric => keyCode value bigger than 40
    // or backspace
    var q = element.value;
    q = q.toLowerCase();
    //rebuild the keywords list if input is 1)Alpahnumeric 2)Backspace 3)Space bar 4)focus is returned 
    //to the input box with previous value still there*  
    //* 4) should be handled elsewhere 
    if (e.keyCode > 40 || e.keyCode == BACKSPACE || e.keyCode == SPACE_BAR || this.currentRow == null) {
      //get the input text
      //check whether user input has any matches in the keyword list
      if (this.highlightedRow != null) {
        this.unHighlightRow();
      }
      this.currentRow = null;
      this.updateSuggestBox(q);
    }
    
    // Hide the suggest-box if no matches are found
    if (q == '' || !this.foundMatch || ((e.keyCode == CTRL || e.keyCode == TAB) && !this.visible)) {
      this.hideBox();
    //at least one row shown in the suggest box
    } else {
      //show the suggestBox
      $('#suggestBox').css('display', 'block');
      this.visible = true;
      
      //reset the scrolling of the suggestBox on page-load / refresh
      if (this.firstLoad) {
        document.getElementById('suggestBox').scrollTop = 0;
        this.firstLoad = false;
      }

      //Handle keyboard navigation of the suggestBox
      switch(e.keyCode) {

        case ENTER:
          //submit string - allow default behaviour
          if (this.visible) {
            this.hideBox();
            //stopAllPropagation(e);
          }
          break;

        case TAB:
          this.hideBox();
      }

      //Hide the suggest box when user clicks anywhere on the screen
      //document.getElementsByTagName('BODY')[0].onclick = hide;
      document.onclick = suggest.hideBox;
    }
  }

  this.handleScrolling = function(e, element) {
    var sb = this; //cache parent object for use in jQuery contexts

    e = e || window.event;
    var q = element.value;
    q = q.toLowerCase();
    
    if (this.visible) {
      switch(e.keyCode) {
        
        case DOWN_ARROW:
          //select next row
          if (this.currentRow == null) {
            this.currentRow = this.firstRow;
            this.lastQuery = q; 
          } else if (this.currentRow.next) {
            this.currentRow = this.currentRow.next;
          }
          $('#qt').val(sb.currentRow.cells[0].innerHTML); 
          this.highlightRow(this.currentRow);
          //Scroll the element if needed
          document.getElementById('suggestBox').scrollTop = this.currentRow.offsetTop - 30;
          //turns on inputbox propagation blocking
          this.active = true;
          //stop event propagation
          stopAllPropagation(e);
          break;

        case UP_ARROW:
          //select previous row
          if (this.active && this.currentRow.prev) {
            this.currentRow = this.currentRow.prev;
            this.highlightRow(this.currentRow);
            //Scroll the element if needed
            document.getElementById('suggestBox').scrollTop = this.currentRow.offsetTop - 30;
            $('#qt').val(sb.currentRow.cells[0].innerHTML); 
          } else {
            this.unHighlightRow();
            this.active = false;
            $('#qt').val(sb.lastQuery);
            this.currentRow = null;
          }
          //stop event propagation
          stopAllPropagation(e);
          break;

        case ENTER:
          if (this.active) {
            this.useKeyword();
            //submit string - allow default behaviour
            //stopAllPropagation(e);
          }
          break;
      }
    }
  }

  //Sets the selected element as the value for input field and hides the suggestBox
  //Called by onClick event on the suggest-table
  this.useKeyword = function() {
    var sb = this; //cache parent object for use in jQuery contexts
    $('#qt').val(sb.selectedValue);
    this.hideBox();
    //Run runSearch from results_localized-2.0.js if we are on Search and Solve page
    if (typeof runSearch == 'function') {
      //runSearch('solutions');
      $('#search').submit();
    //otherwise run handleEnterKey function from ss_teaserform-2.0.js
    } else if (typeof handleEnterKey == 'function') {
        handleEnterKey(13);
    }
  }
}

//Initialize suggestBox and populate the suggestTable from XML
$(document).ready(function() {
  //clear the input field from old values
  //$('#qt').focus().val('');
  //Focus needs to be fixed in IE 6
  //$('#qt').focus().trigger('click');
  
  //init suggestBox as a global variable
  //With minor changes an array can be used
  //so that several suggestBox object can co-exist, 
  //and be referenced by their indices.
  //This is not yet implemented, however.
  window.suggest = new suggestBox();

  //bind keyboard and mouse events
  $('#qt').bind("keyup", function(e) {
    suggest.handleKeyboardEvent(e, this);
  });

  $('#qt').bind("keydown", function(e) {
    suggest.handleScrolling(e, this); 
    suggest.handleBubble(e);
  });

  $('document').bind("click", function() {
    suggest.hideBox();
  });

  $('#suggestTable').bind("click", function() {
    suggest.useKeyword();
  });
  
  //Get the table element
  var suggestTable = $('#suggestTable');
  
  //Load the suggested keywords list
  $.ajax( {
    url: keywordsXML,
    type: 'GET',
    dataType: 'xml',
    timeout: 10000,
    error: function() {
      //alert("Error encountered!");
    },
    
    success: function(xml) {
      $(xml).find('#keywords > item').each(function() {
        var keyword = $(this).attr('id');
        var suggestRow = $('<tr onmouseover="suggest.highlightRow(this, true)" onmousemove="suggest.toggleMouseHighlight()"></tr>');
        $('<td></td>').html(keyword).appendTo(suggestRow);

        suggestRow.appendTo(suggestTable);
      });
    }
  } );
} );


