(function($){
  jQuery.fn.SearchHighlight = function(options) {
    var ref = options.debug_referrer || document.referrer;
	if(!ref && options.keys==undefined) return this;
	
    
    SearchHighlight.options = $.extend({exact:"exact",style_name:'hilite',style_name_suffix:true},options);
    
    if(options.engines) SearchHighlight.engines.unshift(options.engines);  
    var q = options.keys!=undefined?options.keys.toLowerCase().split(/[\s,\+\.]+/):SearchHighlight.decodeURL(ref,SearchHighlight.engines);
    if(q && q.join("")) {
      SearchHighlight.buildReplaceTools(q);
      return this.each(function(){
        var el = this;
        if(el==document) el = $("body")[0];
        SearchHighlight.hiliteElement(el, q); 
      })
    } else return this;
  }    

  var SearchHighlight = {
    options: {},
    regex: [],
    engines: [
    [/^http:\/\/(www\.)?google\./i, /q=([^&]+)/i],                            // Google
    [/^http:\/\/(www\.)?search\.yahoo\./i, /p=([^&]+)/i],                     // Yahoo
    [/^http:\/\/(www\.)?search\.msn\./i, /q=([^&]+)/i],                       // MSN
    [/^http:\/\/(www\.)?search\.live\./i, /query=([^&]+)/i],                  // MSN Live
    ],
    subs: {},
    decodeURL: function(URL,reg) {
      URL = decodeURIComponent(URL);
      var query = null;
      $.each(reg,function(i,n){
        if(n[0].test(URL)) {
          var match = URL.match(n[1]);
          if(match) {
            query = match[1].toLowerCase();
			return false;
          }
        }
      })
      if (query) {
      query = query.replace(/(\'|")/, '\$1');
	  query = '+'+query+'+';
	  do { query = query.replace('+en+','+');} while(query.indexOf('+en+') >= 0);
  	  do { query = query.replace('+una+','+');} while(query.indexOf('+una+') >= 0);
	  do { query = query.replace('+de+','+');} while(query.indexOf('+de+') >= 0);
  	  do { query = query.replace('+para+','+');} while(query.indexOf('+para+') >= 0);
  	  do { query = query.replace('+es+','+');} while(query.indexOf('+es+') >= 0);
	  do { query = query.replace('+un+','+');} while(query.indexOf('+un+') >= 0);
  	  do { query = query.replace('+la+','+');} while(query.indexOf('+la+') >= 0);
	  do { query = query.replace('+el+','+');} while(query.indexOf('+el+') >= 0);
	  do { query = query.replace('+mi+','+');} while(query.indexOf('+mi+') >= 0);
	  do { query = query.replace('+que+','+');} while(query.indexOf('+que+') >= 0);
	  do { query = query.replace('+por+','+');} while(query.indexOf('+por+') >= 0);
	  do { query = query.replace('+si+','+');} while(query.indexOf('+si+') >= 0);
	  do { query = query.replace('+los+','+');} while(query.indexOf('+los+') >= 0);
	  do { query = query.replace('+las+','+');} while(query.indexOf('+las+') >= 0);
	  do { query = query.replace('+a+','+');} while(query.indexOf('+a+') >= 0);
	  do { query = query.replace('+por+','+');} while(query.indexOf('+por+') >= 0);
	  do { query = query.replace('+y+','+');} while(query.indexOf('+y+') >= 0);
	  do { query = query.replace('+te+','+');} while(query.indexOf('+te+') >= 0);
  	  do { query = query.replace('+tu+','+');} while(query.indexOf('+tu+') >= 0);
 	  do { query = query.replace('+con+','+');} while(query.indexOf('+con+') >= 0);
   	  do { query = query.replace('+carta+','+');} while(query.indexOf('+carta+') >= 0);
   	  do { query = query.replace('+cartas+','+');} while(query.indexOf('+cartas+') >= 0);
   	  do { query = query.replace('+Carta+','+');} while(query.indexOf('+Carta+') >= 0);
   	  do { query = query.replace('+Cartas+','+');} while(query.indexOf('+Cartas+') >= 0);
   	  do { query = query.replace('+mensaje+','+');} while(query.indexOf('+mensaje+') >= 0);
   	  do { query = query.replace('+mensajes+','+');} while(query.indexOf('+mensajes+') >= 0);
	  query = query.split(/[\s,\+\.]+/);
      }
      
      return query;
    },
		regexAccent : [
      [/[\xC0-\xC5\u0100-\u0105]/ig,'a'],
      [/[\xC7\u0106-\u010D]/ig,'c'],
      [/[\xC8-\xCB]/ig,'e'],
      [/[\xCC-\xCF]/ig,'i'],
      [/\xD1/ig,'n'],
      [/[\xD2-\xD6\xD8]/ig,'o'],
      [/[\u015A-\u0161]/ig,'s'],
      [/[\u0162-\u0167]/ig,'t'],
      [/[\xD9-\xDC]/ig,'u'],
      [/\xFF/ig,'y'],
      [/[\x91\x92\u2018\u2019]/ig,'\'']
    ],
    matchAccent : /[\x91\x92\xC0-\xC5\xC7-\xCF\xD1-\xD6\xD8-\xDC\xFF\u0100-\u010D\u015A-\u0167\u2018\u2019]/ig,  
		replaceAccent: function(q) {
		  SearchHighlight.matchAccent.lastIndex = 0;
      if(SearchHighlight.matchAccent.test(q)) {
        for(var i=0,l=SearchHighlight.regexAccent.length;i<l;i++)
          q = q.replace(SearchHighlight.regexAccent[i][0],SearchHighlight.regexAccent[i][1]);
      }
      return q;
    },
    escapeRegEx : /((?:\\{2})*)([[\]{}*?|])/g, //the special chars . and + are already gone at this point because they are considered split chars
    buildReplaceTools : function(query) {
        var re = [], regex;
        $.each(query,function(i,n){
            if(n = SearchHighlight.replaceAccent(n).replace(SearchHighlight.escapeRegEx,"$1\\$2"))
              re.push(n);        
        });
        
        regex = re.join("|");
        switch(SearchHighlight.options.exact) {
          case "exact":
            regex = '\\b(?:'+regex+')\\b';
            break;
          case "whole":
            regex = '\\b\\w*('+regex+')\\w*\\b';
            break;
        }    
        SearchHighlight.regex = new RegExp(regex, "gi");
        
        $.each(re,function(i,n){
            SearchHighlight.subs[n] = SearchHighlight.options.style_name+
              (SearchHighlight.options.style_name_suffix?i+1:''); 
        });       
    },
    nosearch: /s(?:cript|tyle)|textarea/i,
    hiliteElement: function(el, query) {
        var opt = SearchHighlight.options, elHighlight, noHighlight;
        elHighlight = opt.highlight?$(opt.highlight):$("body"); 
        if(!elHighlight.length) elHighlight = $("body"); 
        noHighlight = opt.nohighlight?$(opt.nohighlight):$([]);
                
        elHighlight.each(function(){
          SearchHighlight.hiliteTree(this,query,noHighlight);
        });
    },
    hiliteTree : function(el,query,noHighlight) {
        if(noHighlight.index(el)!=-1) return;
        var matchIndex = SearchHighlight.options.exact=="whole"?1:0;
        for(var startIndex=0,endIndex=el.childNodes.length;startIndex<endIndex;startIndex++) {
          var item = el.childNodes[startIndex];
          if ( item.nodeType != 8 ) {//comment node
  				  //text node
            if(item.nodeType==3) {
              var text = item.data, textNoAcc = SearchHighlight.replaceAccent(text);
              var newtext="",match,index=0;
              SearchHighlight.regex.lastIndex = 0;
              while(match = SearchHighlight.regex.exec(textNoAcc)) {
                newtext += text.substr(index,match.index-index)+'<span class="'+
                SearchHighlight.subs[match[matchIndex].toLowerCase()]+'">'+text.substr(match.index,match[0].length)+"</span>";
                index = match.index+match[0].length;
              }
              if(newtext) {
                //add the last part of the text
                newtext += text.substring(index);
                var repl = $.merge([],$("<span>"+newtext+"</span>")[0].childNodes);
                endIndex += repl.length-1;
                startIndex += repl.length-1;
                $(item).before(repl).remove();
              }                
            } else {
              if(item.nodeType==1 && item.nodeName.search(SearchHighlight.nosearch)==-1)
                  SearchHighlight.hiliteTree(item,query,noHighlight);
            }	
          }
        }    
    }
  };
})(jQuery)

