//
// The javascript for the whole autocompletion functionality
//


    var SEPARATORS = ' .|\\-_'         // characters that separate words
    var COMPLETION_DELAY = 100         // wait that many msecs after typing before completion
    var MIN_QUERY_SIZE = 1             // no completions before this many characters typed
    var MIN_PREFIX_SIZE = 1            // no completions for words shorter than this
    var MAX_COMPLETIONS_COMP = 999999  // compute at most this many completions 
    var MAX_COMPLETIONS_SHOW = 10      // show at most this many completions 
    var ALWAYS_PREFIX = 1              // if not zero, assume implicit * after every word
  
    var completion_index          // index of completion selected
    var completions               // array of completion strings
    var pressedKey
    var too_many = true           // indicates that there are too many completions for the query
    var total_nof_hits = 0        // the number of hits for the query
    var show_nof_hits = 3         // the number of hits displayed
    var first_hit = 0             // the index of the first hit displayed
    var excerptRadius = 5         // default excerpt radius
    var query_string_has_been_nonempty_once = false  // becomes false once query string becomes non empty
    var CAPITALS = 'A-Z'
    //var CAPITALS = 'A-ZÄÖÜÑÅÉÚÓÁØÆÑÇ'  // capital characters

    // make the page loading this javascript and http://search.<subdomain> friends
    try
    {
      // href_domain = document.location.href.match(/http:\/\/www\.([^\/]+\.de)/)
      sub_domain = document.domain.match(/^www\.([^\/]+\.de)/)
      document.domain = sub_domain[1]
      //alert('document.domain = \"'+document.domain+'\"\n[JUST IGNORE THIS]')
      search_URL = "http://search." + document.domain
    }
    catch(e)
    {
      //alert('Search does not work with domain name \"'+document.domain+'\"')
      document.domain = "mpi-inf.mpg.de"
      search_URL = "http://search.mpi-inf.mpg.de"
    }
    var completions_div = 'completions'


    //
    // PROCESS QUERY IN SEARCH FIELD whenever a new character is typed
    //
    // triggers a call to autocomplete.pl (with a short delay, so that nothing
    // is called when the time between two keystrokes is less than that delay)
    //
    function processInputKey(event)
    {
      // GET QUERY STRING 
      query_string = document.getElementById('query').value
      // reload page once query string becomes empty again
      if (0 && query_string == "")
      {
        if (query_string_has_been_nonempty_once == true)
        {
          window.location = window.location
        }
        else
        {
          return
        }
      }
      query_string_has_been_nonempty_once = true
/*
      // get last word; empty if query string ends with space or colon!
      last_word = query_string.match(new RegExp('[^'+SEPARATORS+']*$')).pop()
      // DO NOTHING FOR VERY SHORT PREFIXES (unless ! or ? typed)
      if ( (query_string.length < MIN_QUERY_SIZE || last_word.length < MIN_PREFIX_SIZE)
             && !query_string.match(/[\?\!]/) ) 
      {
        document.getElementById('completions').innerHTML = " "
          // '<iframe height="0px" style="visibility:hidden"></iframe>'
        if (query_string.length < MIN_QUERY_SIZE)
        {
          document.getElementById('bufferFrame').src = "/cgi-bin/autocomplete.pl"
            + "?words=&database=" + escape(document.getElementById('database').value)
        }
      }
      else
*/
      // get last word; empty if query string ends with a separator
      last_word = query_string.match(new RegExp('[^'+SEPARATORS+']*$')).pop()
      if (last_word.length < MIN_PREFIX_SIZE && query_string.length > 0 && !query_string.match(/[\?\!]/))
      {
        document.getElementById(completions_div).innerHTML = " "
      }  
      else
      {
        // get keyCode; this works at least for IE, Mozilla, Firefox, and Opera
        k = event.keyCode
          //document.getElementById('debug').innerHTML = "keyCode = " + k

        switch (k)
        {
          case 33: // PgUp
            if (first_hit >= show_nof_hits)
            {
              first_hit -= show_nof_hits
            }
            else
            {
              first_hit = 0
            }
            searchWithAutocompletion(query_string)
            break

          case 34: // PgDown
            if (first_hit < total_nof_hits - show_nof_hits)
            {
              // WARNING: if using + java script might use string addition, e.g.  7+7=77
              first_hit -= -show_nof_hits
            }
            searchWithAutocompletion(query_string)
            break

          case 36: // Home
            if (excerptRadius > 3)
            {
              excerptRadius -= 3
              searchWithAutocompletion(query_string)
            }
            break

          case 35: // End
            excerptRadius += 3
            searchWithAutocompletion(query_string)
            break

          case 38: // arrow up
            completion_index = completion_index - 1
            completeInput()
            break

          case 40: // arrow down
            completion_index = completion_index + 1
            completeInput()
            break

          case 37: // arrow left
          case 39: // arrow right
          // case 32: // arrow left
            // do nothing
            break

          default:
            // for keys a..z or 0..9 or $ or BACKSPACE or RETURN -> new completion list
            // if (k == 8 || k == 13 || k == 16 || k >= 48 && k <= 57 || k >= 65 && k <= 90 || k == 32 || k == 190)
            
            // why was there k = 16? That is SHIFT, right?
            if (k == 8 || k == 13 || k == 32 || k >= 48)
            {
              // delayed call of getCompletions with current query string
              // getCompletions will only proceed when after the delay, the
              // then then current query string is the same as now
              // this effects that no completions are computed for a keypress
              // when another keypress follows within a time span less than 
              // the delay
              first_hit = 0;
              switch (last_word.length)
              {       
                case 0: DELAY = 1000; break
                case 1: DELAY = 800; break
                case 2: DELAY = 100; break // was 600 (changed for Leopoldina demo)
                case 3: DELAY = 0; break // was 400 
                default: DELAY = 0; break // was 100
              }
              setTimeout('searchWithAutocompletion(\''+query_string+'\')', k == 13 ? 0 : DELAY)
            }
            break
        }
      }
    }

    //
    // CALL CGI SCRIPT autocompletion.pl 
    //
    // -- the page generated by that script will call copyFromBufferToPage() when loaded
    // -- does some preprocessing on the query before sending to autocomplete.pl
    //     + query string converted to lower case (except all upper) before sending
    //     +  add * after every query word, except if it ends wit a $ 
    //
    function searchWithAutocompletion(query_string)
    {
      // PROCEED ONLY IF USER IS NOT BUSY TYPING
      query_string_after_delay = document.getElementById('query').value
      // if no change or the first new character typed was a separator
      //   BROWSER INCOMPATIBILITY ISSUE: the "new regExp" gives an error in
      //   Mozilla, but the whole thing works anyway
      if (query_string == query_string_after_delay ||
          query_string.match(/^\!FEEDBACK:/))
      {
        // treat very short queries like the empty query (exception: ? or ! or only CAPITALS)
        if (query_string.length < MIN_QUERY_SIZE 
             && !query_string.match(new RegExp('['+CAPITALS+']{2,}$'))
             && !query_string.match(/[\?\!]/))
        {
          query_string = ""
        }
        // convert query to lower and add a * after each word (with some exceptions)
        if (query_string == query_string_after_delay)
        {
          // Replace all _ by .
          query_string = query_string.replace(/_/g, '.')
          // Decapitalize (but leave all capitals as is, e.g. KENT)
          query_string = query_string.
            replace(new RegExp('(\\b['+CAPITALS+'][^'+CAPITALS+SEPARATORS+'])', 'g'), 
              function(matched_str, offset, whole_str) { return matched_str.toLowerCase() } )
          // optionally add implicit * after every token except if ended by $
          if (ALWAYS_PREFIX && query_string != "")
          {
            // append * after every word that does not end with a star already
            query_string = query_string.
              replace(new RegExp('([^'+SEPARATORS+'*])(['+SEPARATORS+'])', 'g'), '$1*$2') + '*';
            // remove all occurences of $*
            query_string = query_string.replace(/\$\*/g, '')

            // add the first hit to display and the number of hits to display
            query_string += ' ' + 'M' + MAX_COMPLETIONS_COMP +
                                  'C' + MAX_COMPLETIONS_SHOW + 
                                  'H' + show_nof_hits +
                                  'F' + first_hit +
                                  'E' + 3 +
                                  'R' + excerptRadius 
           }
         }

         // SEND QUERY TO autocomplete.pl 
         // queryURL_string = "http://search.mpi-sb.mpg.de/cgi-bin/autocomplete.pl"
         queryURL_string = search_URL + "/cgi-bin/autocomplete.pl"
            + "?words=" + escape(query_string)
            + "&database=" + escape(document.getElementById('database').value)
         // remember URL except for empty query 
         document.getElementById('queryURL').value = queryURL_string
         //document.getElementById('queryURL').value = (query_string != "" ? queryURL_string : "")
         // call the CGI script, which onload will call copyFromBufferToPage() when loaded
         document.getElementById('bufferFrame').src = queryURL_string
      }
    }


    //
    // CALLED WHEN PAGE PRODUCED BY autocomplete.pl HAS BEEN LOADED
    //
    // -- sets elements of web page
    //     + subtitle: how many documents we have zoomed on to
    //     + completions (possibly empty)
    //     + hits (possibly empty, or containing HELP, FEEDBACK FORM, COPYRIGHT NOTICE)
    // -- sets "nof_hits", "first_hit", "last_hit" (for use of PAGE UP/DOWN)
    // -- sets array "completions" (for use with CURSOR UP/DOWN)
    //
    function copyFromBufferToPage()
    {
      // GET STATUS (!!!!! must not name it "status" -> IE produces error !!!!!)
      search_status = parent.bufferFrame.document.getElementById('status').value
      // SET "nof_hits", "first_hit", "last_hit" (unless additionalinfo div is empty)
      parameters = parent.bufferFrame.document.getElementById('parameters')
        //document.getElementById('debug').innerHTML = 'parameter = '+parameters.innerHTML
      if (parameters != null) 
      {
        // the <br> may be rewritten by the browser as <BR> or <br/> or <BR/> 
        parameters = parameters.innerHTML.split(/<[Bb][Rr].?>/)
        prefix = parameters[0].replace(/\*$/,"")
        nof_completions = parameters[1]
        total_nof_hits = parameters[2]
        first_hit = parseInt(parameters[3])
        last_hit = parseInt(parameters[4])
          //document.getElementById('debug').innerHTML =   '<pre>pre: '+prefix+ ', cpl: '+nof_completions+ ', hts: '+total_nof_hits+ ', fst: '+first_hit+ ', lst: '+last_hit+'</pre>'
      }

      // SET SUBTITLE (how many documents we have zoomed on to)
      if (parameters != null) 
      {
        if (total_nof_hits < 0 && nof_completions < 0)
        {
          document.getElementById('subtitle').innerHTML = 
            '[ the search server is down ]'
        }
        else if (nof_completions < 0)
        {
          document.getElementById('subtitle').innerHTML = ''
            // 'Search MPII (' + total_nof_hits + ' documents)'
        }
        else // total_nof_hits >= 0 and nof_completions >= 0
        {
          document.getElementById('subtitle').innerHTML = 
            'zoomed in on ' + total_nof_hits + (total_nof_hits != 1 ? ' documents' : ' document')
        }
      }

      // SHOW MESSAGE in case autocomplete.pl sent one
      if (parent.bufferFrame.document.getElementById('message') != null)
      {
          document.getElementById('subtitle').innerHTML += 
            "<br/>" + parent.bufferFrame.document.getElementById('message').innerHTML
      }
        

      // SET COMPLETIONS DISPLAY 
      completions = parent.bufferFrame.document.getElementById('completions')
      if (completions != null && parameters != null) 
      { 
        completions = completions.innerHTML.replace(/\s+/g,'&nbsp;').split(/<[Bb][Rr].?>/)
          // if the HTML contains no \t, "completions" will just be that HTML
          // document.getElementById('debug').innerHTML = 
          //  'completions.length='+completions.length+'; first elem=-->'+completions[0]+ '<--'

        // div "completions" contains error message or copyright notice
        if (nof_completions < 0)
        {
          document.getElementById(completions_div).innerHTML = 
            parent.bufferFrame.document.getElementById('completions').innerHTML
        }
        // no completions (then "completions" contains as only element the empty string)
        else if (nof_completions == 0)
        {
          document.getElementById(completions_div).innerHTML =
            '<small><b style="color:#111111">No completion of \"'+prefix+'\"<br/>leading to a hit!</b></small>'
        }
        // moderate number of completions -> show all of them
        else if (nof_completions <= MAX_COMPLETIONS_SHOW) 
        {
          document.getElementById(completions_div).innerHTML =
            '<small><b style="color:#111111">Completions of "'+prefix+'"<br/>leading to a hit are:</b></small><br/>'
              + completions.join(', '); 
              //+ completions.join(',<br/>'); 
        }
        // large number of completions -> show only first few
        else 
        {
          document.getElementById(completions_div).innerHTML =
            //'<small><b style="color:#111111">More than '+MAX_COMPLETIONS+' completions of "'+prefix+
            //'"<br/>leading to a hit, type more!</b></small><br/>'
            '<small><b style="color:#111111">Completions of "'+prefix+'"<br/>leading to a hit are:</b></small><br/>'
             + completions.slice(0, MAX_COMPLETIONS_SHOW).join(', ') + ", ..."; 
             //+ completions.slice(0, MAX_COMPLETIONS).join(',<br/>') + ",<br/>..."; 
        }
      }


      // SET COMPLETIONS ARRAY
      if (completions != null)
      {
        // discard everything after the first &nbsp; for each completion (e.g. "holger (4)" -> "holger")
        for (i = 0; i < completions.length; i++)
        {
          completions[i] = completions[i].split('&nbsp;').shift()
        }
        // prepend prefix unless it is equal to the first completion (or there are no completions)
        if (completions.length > 0 && prefix != completions[0])
        {
          completions.unshift(prefix)
        }
        completion_index = 0
      }

      // SHOW HITS (may also contain copyright notice or help page or feedback form)
      // for mpi-webpages, don't do anything for copyright notice
      if (search_status != "EMPTY_QUERY" && search_status != "NO_CONNECTION")
      {
        hits_div = document.getElementById('hitsdiv').value
        document.getElementById(hits_div).innerHTML =
          parent.bufferFrame.document.getElementById('hits').innerHTML
        //document.getElementById(hits_div).innerHTML =
        //  document.getElementById(hits_div).innerHTML.replace(/\<\/[Hh]1\>/,
        //    "</h1><br><h4 style=\"color:red\" align=\"center\">"+
        //    "[this is still a beta version]</h4>")

        // keep URLS short
        document.getElementById(hits_div).innerHTML =
          document.getElementById(hits_div).innerHTML.replace(/(\<[aA][^>]*\>[^<]{80})[^<]+(<\/)/g, '$1...$2')

      }

      // ENSURE RIGHT FOCUS AND CURSOR AGAIN
      if (document.getElementById('feedback') != null)
      {
        document.getElementById('query').value = document.getElementById('query').value.replace(/[\!\?]$/,'')
        document.getElementById('feedback').focus()
      }
      else
      {
        // the order is important here so that the cursor gets positioned at the end
        document.getElementById('query').focus()
        document.getElementById('query').value = document.getElementById('query').value.replace(/[\!\?]$/,'')
      }

    }

    //
    // COMPLETE QUERY BY WORD FROM COMPLETION LIST as specified by completion_index
    //
    function completeInput()
    {
      // get completion
      if (completion_index < 0) { completion_index = 0 }
      if (completion_index >= completions.length) { completion_index = completions.length - 1 }
      completion = completions[completion_index]
      // SPECIAL: if completion is of type "PLACE:aachen", remove the "PLACE:" !!!
      if (completion.toUpperCase() != completion)
      {
        completion = completion.replace(/[A-Z]+:/, '')
      }
      // replace last token in query by completion
      query_string = document.getElementById('query').value
      document.getElementById('query').value 
        = query_string.replace(new RegExp('[^'+SEPARATORS+']+$'), completion)
    }

    //
    // INITIALIZE PAGE (called onload of search.html)
    //
    // -- if iframe is nonempty, copy its contents to page
    // -- if input field is nonempty, launch as query automatically
    // -- otherwise launch empty query to obtain splash screen
    //
    function init()
    {

      // where to copy the completions
      if (document.getElementById('completionsdiv') != null)
      {
        completions_div = document.getElementById('completionsdiv').value
      }
      else
      {
        completions_div = "completions"
      }

      // how many hits per page
      if (document.getElementById('hitsperpage') != null)
      {
        show_nof_hits = document.getElementById('hitsperpage').value
      }
      else
      {
        show_nof_hits = 3
      }


      // CASE 1: hidden iframe has contents (from a previous search)
      try 
      {
        // NOTE: parent.bufferFrame.document gave an "Access denied" error on IE
        // in the cross-scripting setting (with everything on the same host it worked)
        //
        // if (parent.bufferFrame.document.getElementById('queryCopy') != null
        //      && parent.bufferFrame.document.getElementById('queryCopy').innerHTML != "")
        // document.getElementById('completions').innerHTML = '<b style=\"color:red\">CASE 1</b>'
        queryCopy_string = parent.bufferFrame.document.getElementById('queryCopy').innerHTML
        // recover search string from what was passed to autocomplete.pl (UGLY!)
        queryCopy_string = queryCopy_string.replace(/( [A-Z0-9]+)$/,'')
        queryCopy_string = queryCopy_string.replace(/\*/g,'')
        document.getElementById('query').value = queryCopy_string
        //showCompletions()
      }
      catch(e)
      {
        // CASE 2: launch query from hidden input field (IE will pass by CASE 1 and succeed here)
        if (document.getElementById('queryURL').value != "")
        {
          // document.getElementById('completions').innerHTML = '<b style=\"color:red\">CASE 2</b>'
          document.getElementById('bufferFrame').src = document.getElementById('queryURL').value
        }
        // CASE 3: default -> launch empty query (gets collections size etc.)
        else
        {
          // document.getElementById('completions').innerHTML = '<b style=\"color:red\">CASE 3</b>'
          //document.getElementById('query').value = ""
          //searchWithAutocompletion("")
          //document.getElementById('query').focus()
        }
      }
    }
