/**
 * Extending jQuery with autocomplete
 * Version: 1.4.2
 * Author: Yanik Gleyzer (clonyara)
 */
(function($) {

// some key codes
 var RETURN = 13;
 var TAB = 9;
 var ESC = 27;
 var ARRLEFT = 37;
 var ARRUP = 38;
 var ARRRIGHT = 39;
 var ARRDOWN = 40;
 var BACKSPACE = 8;
 var DELETE = 46;

 // This is called if the user clicks the 'Undergraduate courses' or 'Postgraduate courses' headers in the SAYT data
 var DEFAULT_SEARCH_URL;
 var DEFAULT_PROSPECTUS_PAGE = "/ruskin/en/home/prospectus.html";
 var URL_PREFIX = "http://" + document.location.host;

if (document.URL.indexOf("author") != -1) {
	DEFAULT_SEARCH_URL = URL_PREFIX + "/author" + DEFAULT_PROSPECTUS_PAGE;
} else {
	DEFAULT_SEARCH_URL = URL_PREFIX + DEFAULT_PROSPECTUS_PAGE;
}

// This cannot go live until the Google Search Box goes live...
//var DEFAULT_SEARCH_URL = "http://search.anglia.ac.uk/search?btnG=Search&entqr=0&output=xml_no_dtd&sort=date%3AD%3AL%3Ad1&client=anglia_frontend&ud=1&oe=UTF-8&ie=UTF-8&proxystylesheet=anglia_frontend&site=Prospectuses-all&filter=0";

function debug(s){
  $('#info').append(htmlspecialchars(s)+'<br>');
}
// getting caret position obj: {start,end}
function getCaretPosition(obj){
  var start = -1;
  var end = -1;
  if(typeof obj.selectionStart != "undefined"){
    start = obj.selectionStart;
    end = obj.selectionEnd;
  }
  else if(document.selection&&document.selection.createRange){
    var M=document.selection.createRange();
    var Lp;
    try{
      Lp = M.duplicate();
      Lp.moveToElementText(obj);
    }catch(e){
      Lp=obj.createTextRange();
    }
    Lp.setEndPoint("EndToStart",M);
    start=Lp.text.length;
    if(start>obj.value.length)
      start = -1;
    
    Lp.setEndPoint("EndToStart",M);
    end=Lp.text.length;
    if(end>obj.value.length)
      end = -1;
  }
  return {'start':start,'end':end};
}
// set caret to
function setCaret(obj,l){
  obj.focus();
  if (obj.setSelectionRange){
    obj.setSelectionRange(l,l);
  }
  else if(obj.createTextRange){
    m = obj.createTextRange();      
    m.moveStart('character',l);
    m.collapse();
    m.select();
  }
}
// prepare array with velued objects
// required properties are id and value
// rest of properties remaines
function prepareArray(jsondata){
  var new_arr = [];
  for(var i=0;i<jsondata.length;i++){
    if(jsondata[i].id != undefined && jsondata[i].value != undefined){
      jsondata[i].id = jsondata[i].id+"";
      jsondata[i].value = jsondata[i].value+"";
      if(jsondata[i].info != undefined)
        jsondata[i].info = jsondata[i].info+"";
      new_arr.push(jsondata[i]);
    }
  }
  return new_arr;
}
// php analogs
function escapearg(s){
  if(s == undefined || !s) return '';
  return s.replace('\\','\\\\').
           replace('*','\\*').
           replace('.','\\.').
           replace('/','\\/');
}
function htmlspecialchars(s){
  if(s == undefined || !s) return '';
  return s.replace('&','&amp;').
           replace('<','&lt;').
           replace('>','&gt;');
}
function ltrim(s){
  if(s == undefined || !s) return '';
  return s.replace(/^\s+/g,'');
}

// extending jQuery
$.fn.autocomplete = function(options){ return this.each(function(){
  // take me
  var me = $(this);
  var me_this = $(this).get(0);

  // test for supported text elements
  if(!me.is('input:text,input:password,textarea'))
  return;

  // get or ajax_get required!
  if(!options && (!$.isFunction(options.get) || !options.ajax_get)){
  return;
  }  
  // check plugin enabled
  if(me.attr('jqac') == 'on') return;

  // plugin on!
  me.attr('jqac','on');

  // no browser's autocomplete!
  me.attr('autocomplete','off');

  // default options
  options = $.extend({ 
                      delay     : 500 ,
                      timeout   : 5000 ,
                      minchars  : 3 ,
                      multi     : false ,
                      cache     : false , 
                      height    : 150 ,
                      autowidth : false ,
                      noresults : 'No results'
                      },
                      options);
  // bind key events
  // handle special keys here
  me.keydown(function(ev){
    switch(ev.which){
      // return choose highlighted item or default propogate
      case RETURN:
		return true
        //if(!suggestions_menu) return true;
        //else setHighlightedValue();
        // setHighlightedValue();
		// return false;
      // escape clears menu
      case ESC:
        clearSuggestions();
        return false;
    }
    return true;
  });
  me.keypress(function(ev){
    // ev.which doesn't work here - it always returns 0
    switch(ev.keyCode){
      case RETURN: case ESC:
        return false;
      // up changes highlight
//PW      case ARRUP:
//PW        changeHighlight(ev.keyCode);
//PW        return false;
      // down changes highlight or open new menu
//PW      case ARRDOWN:
//PW        if(!suggestions_menu) getSuggestions(getUserInput());
//PW        else changeHighlight(ev.keyCode);
//PW        return false;
     }
     return true;
  });
  // handle normal characters here
  me.keyup(function(ev) {
      switch(ev.which) {
      case ARRUP: //PW
        changeHighlight(ev.keyCode); //PW
        return false; //PW
      // down changes highlight or open new menu //PW
      case ARRDOWN: //PW
        if(!suggestions_menu) getSuggestions(getUserInput()); //PW
        else changeHighlight(ev.keyCode); //PW
        return false; //PW
      case RETURN:
//alert("suggestions_menu = " + suggestions_menu + "       current_highlight = " + current_highlight);
			if (suggestions_menu) setHighlightedValue();   // {window.location = suggestions[current_highlight-1].url; //PW
			else window.location = DEFAULT_SEARCH_URL;
//PW case ESC: case ARRLEFT: case ARRRIGHT: //PW
//PW        case RETURN: case ESC: case ARRLEFT: case ARRRIGHT: case ARRUP: case ARRDOWN:
          return false;
        default:
          getSuggestions(getUserInput());
      }
      return true;
  });

  // init variables
  var user_input = "";
  var input_chars_size  = 0;
  var suggestions = [];
  var current_highlight = 0;
  var suggestions_menu = false;
  var suggestions_list = false;
  var loading_indicator = false;
  var clearSuggestionsTimer = false;
  var getSuggestionsTimer = false;
  var showLoadingTimer = false;
  var zIndex = me.css('z-index');

  // get user input
  function getUserInput(){
    var val = me.val();
    if(options.multi){
      var pos = getCaretPosition(me_this);
      var start = pos.start;
      for(;start>0 && val.charAt(start-1) != ',';start--){}
      var end = pos.start;
      for(;end<val.length && val.charAt(end) != ',';end++){}
      var val = val.substr(start,end-start);
    }
    return ltrim(val);
  }
  // set suggestion
  function setSuggestion(val){
    user_input = val;
    if(options.multi){
      var orig = me.val();
      var pos = getCaretPosition(me_this);
      var start = pos.start;
      for(;start>0 && orig.charAt(start-1) != ',';start--){}
      var end = pos.start;
      for(;end<orig.length && orig.charAt(end) != ',';end++){}
      var new_val = orig.substr(0,start) + (start>0?' ':'') + val + orig.substr(end);
      me.val(new_val);
      setCaret(me_this,start + val.length + (start>0?1:0));
    }
    else{
      me_this.focus();
      me.val("");  //PW Blank out the search term to avoid the user having to do so themselves
    }
  }
  // get suggestions
  function getSuggestions(val){
    // input length is less than the min required to trigger a request
    // reset input string
    // do nothing
    if (val.length < options.minchars){
      clearSuggestions();
      return false;
    }
    // if caching enabled, and user is typing (ie. length of input is increasing)
    // filter results out of suggestions from last request
    if (options.cache && val.length > input_chars_size && suggestions.length){
      var arr = [];
      for (var i=0;i<suggestions.length;i++){
        var re = new RegExp("\b"+escapearg(val),'ig');
        if(re.exec(suggestions[i].value))
          arr.push( suggestions[i] );
      }
      user_input = val;
      input_chars_size = val.length;
      suggestions = arr;
      createList(suggestions);
      return false;
    }
    else{// do new request
      clearTimeout(getSuggestionsTimer);
      user_input = val;
      input_chars_size = val.length;
      getSuggestionsTimer = setTimeout( 
        function(){ 
          suggestions = [];
          // call pre callback, if exists
          if($.isFunction(options.pre_callback))
            options.pre_callback();
          // call get
          if($.isFunction(options.get)){
            suggestions = prepareArray(options.get(val));
            createList(suggestions);
          }
          // call AJAX get
          else if($.isFunction(options.ajax_get)){
            clearSuggestions();
            showLoadingTimer = setTimeout(show_loading,options.delay);
            options.ajax_get(val,ajax_continuation);
          }
        },
        options.delay );
    }
    return false;
  };
  // AJAX continuation
  function ajax_continuation(jsondata){
    hide_loading();
    suggestions = prepareArray(jsondata);
    createList(suggestions);
  }
  // shows loading indicator
  function show_loading(){
    if(!loading_indicator){
      loading_indicator = $('<div class="jqac-menu"><div class="jqac-loading">Loading</div></div>').get(0);
      $(loading_indicator).css('position','absolute');
      var pos = me.offset();
      $(loading_indicator).css('left', pos.left + "px");
      $(loading_indicator).css('top', ( pos.top + me.height() + 2 ) + "px");
      if(!options.autowidth)
        $(loading_indicator).width(me.width());
      $('body').append(loading_indicator);
    }
    $(loading_indicator).show();
    setTimeout(hide_loading,10000);
  }
  // hides loading indicator 
  function hide_loading(){
    if(loading_indicator)
      $(loading_indicator).hide();
    clearTimeout(showLoadingTimer);
  }
  // create suggestions list
  function createList(arr){
    if(suggestions_menu)
      $(suggestions_menu).remove();
    hide_loading();
    killTimeout();

    // create holding div
    suggestions_menu = $('<div class="jqac-menu"></div>').get(0);

    // ovveride some necessary CSS properties 
    $(suggestions_menu).css({'position':'absolute',
                             'z-index':zIndex,
                             'max-height':options.height+'px',
                             'overflow-y':'auto'});

    // create and populate ul
    suggestions_list = $('<ul></ul>').get(0);
    // set some CSS's
    $(suggestions_list).
      css('list-style','none').
      css('margin','0px').
      css('padding','2px').
      css('overflow','hidden');
    // regexp for replace 
//PW var re = new RegExp("("+escapearg(htmlspecialchars(user_input))+")",'ig');
     var re = new RegExp("\\b("+escapearg(htmlspecialchars(user_input))+")",'i'); //PW
    // loop throught arr of suggestions creating an LI element for each suggestion
    for (var i=0;i<arr.length;i++){
      var val = new String(arr[i].value);
	  var info = new String(arr[i].info);
      // using RE
      var output = htmlspecialchars(val).replace(re,'<span class="searchmatch">$1</span>');
	  var span = $('<span class="jqac-link">'+output+'</span>').get(0);
//PW	if (arr[i].info != undefined && arr[i].info != ""){
//PW		$(span).append($('<div class="jqac-info">'+arr[i].info+'</div>'));
//PW	}

      $(span).attr('name',i+1);
      $(span).click(function () { setHighlightedValue(); });
      $(span).mouseover(function () { setHighlight($(this).attr('name'),true); });

      var li = $('<li></li>').get(0);

	if (arr[i].id == -1) //PW
		li.className = "jqac-header-" + info; //PW
	else //PW
		li.className = "jqac-link-" + info;   //PW Set the style of the pg/ug li to differentiate between the two course levels
	li.id = info;   //PW pick this up later to restore the colour after the li has been highlighted and another row has been moved on to

      $(li).append(span);

      $(suggestions_list).append(li);
    }

    // no results
    if (arr.length == 0){
      $(suggestions_list).append('<li class="jqac-warning">'+options.noresults+'</li>');
    }
    $(suggestions_menu).append(suggestions_list);

    // get position of target textfield
    // position holding div below it
    // set width of holding div to width of field
    var pos = me.offset();

    $(suggestions_menu).css('left', pos.left + "px");
    $(suggestions_menu).css('top', ( pos.top + me.height() + 2 ) + "px");
    if(!options.autowidth)
      $(suggestions_menu).width(me.width());

    // set mouseover functions for div
    // when mouse pointer leaves div, set a timeout to remove the list after an interval
    // when mouse enters div, kill the timeout so the list won't be removed
    $(suggestions_menu).mouseover(function(){ killTimeout() });
    $(suggestions_menu).mouseout(function(){ resetTimeout() });

    // add DIV to document
    $('body').append(suggestions_menu);

    // bgIFRAME support
    if($.fn.bgiframe)
      $(suggestions_menu).bgiframe({height: suggestions_menu.scrollHeight});

    // adjust height: add +20 for scrollbar
    if(suggestions_menu.scrollHeight > options.height){
      $(suggestions_menu).height(options.height);
      $(suggestions_menu).width($(suggestions_menu).width()+20);
    }

    // currently no item is highlighted
    current_highlight = 0;

    // remove list after an interval
    clearSuggestionsTimer = setTimeout(function () { clearSuggestions() }, options.timeout);
  };
  // set highlighted value
  function setHighlightedValue(){
    if(current_highlight && suggestions[current_highlight-1]){
      var sugg = suggestions[ current_highlight-1 ];
	  //if (sugg.id == -1) return; //PW Don't do anything if the user clicks on a 'Undergraduate/Postgraduate' heading
      if(sugg.affected_value != undefined && sugg.affected_value != '')
        setSuggestion(sugg.affected_value);
      else
      {
         // They've either clicked on the 'Undergraduate courses' or 'Postgraduate
         // courses' headings so send them to the course search page.
         window.location = DEFAULT_SEARCH_URL;   // + "&q=" + document.getElementById("q").value;
      }

      // pass selected object to callback function, if exists
      if ($.isFunction(options.callback))
        options.callback( suggestions[current_highlight-1] );
      //PWclearSuggestions();
      //PW: Code to automatically redirect to the selected prospectus page when clicked
		if (sugg.id != -1) window.location = sugg.url; //PW Don't redirect if they're on a 'Undergraduate/Postgraduate' heading
    }
  };
  // change highlight according to key
  function changeHighlight(key){
    if(!suggestions_list || suggestions.length == 0) return false;
    var n;
    if (key == ARRDOWN)
      n = current_highlight + 1;
    else if (key == ARRUP)
      n = current_highlight - 1;

    if (n > $(suggestions_list).children().size())
      n = 1;
    if (n < 1)
      n = $(suggestions_list).children().size();
    setHighlight(n);
  };

  // change highlight
  function setHighlight(n,mouse_mode){
    if (!suggestions_list) return false;
    if (current_highlight > 0) clearHighlight();
    current_highlight = Number(n);
    var li = $(suggestions_list).children().get(current_highlight-1);
//PW    li.className = 'jqac-highlight';
	var cRow = $(suggestions_list).children().get(current_highlight-1).className; //PW
	if (cRow.indexOf("header") > -1) //PW
		li.className = cRow.replace(/header/,"header-highlight"); //PW
	else //PW
		li.className = cRow.replace(/link/, "highlight"); //PW
	// for mouse mode don't adjust scroll! prevent scrolling jumps
    if(!mouse_mode) adjustScroll(li);
    killTimeout();
  };
  // clear highlight
  function clearHighlight(){
    if (!suggestions_list)return false;
    if (current_highlight > 0){
    // User is moving to a different li so restore the colour of the row that WAS being highlighted
	var cRow = $(suggestions_list).children().get(current_highlight-1).className;
	if (cRow.indexOf("header") > -1) //PW
		$(suggestions_list).children().get(current_highlight-1).className = cRow.replace(/highlight-/,""); //PW
	else //PW
	    $(suggestions_list).children().get(current_highlight-1).className = cRow.replace(/highlight/, "link"); //PW
//	  $(suggestions_list).children().get(current_highlight-1).className = 'jqac-link-' + $(suggestions_list).children().get(current_highlight-1).id; //PW
      current_highlight = 0; //PW
    }
  };
  // clear suggestions list
  function clearSuggestions(){
    killTimeout();
    if(suggestions_menu){
      $(suggestions_menu).remove();
      suggestions_menu = false;
      suggestions_list = false;
      current_highlight = 0;
    }
  };
  // set scroll
  function adjustScroll(el){
    if(!suggestions_menu) return false;
    var viewportHeight = suggestions_menu.clientHeight;        
    var wholeHeight = suggestions_menu.scrollHeight;
    var scrolled = suggestions_menu.scrollTop;
    var elTop = el.offsetTop;
    var elBottom = elTop + el.offsetHeight;
    if(elBottom > scrolled + viewportHeight){
      suggestions_menu.scrollTop = elBottom - viewportHeight;
    }
    else if(elTop < scrolled){
      suggestions_menu.scrollTop = elTop;
    }
    return true; 
  }
  // timeout funcs
  function killTimeout(){
    clearTimeout(clearSuggestionsTimer);
  };
  function resetTimeout(){
    clearTimeout(clearSuggestionsTimer);
    clearSuggestionsTimer = setTimeout(function () { clearSuggestions() }, 1000);
  };

})};

})($);