///// COMMON


///////////////////////////////////////////////////////////////////////////////
/*                             DOM RELATED                                   */ 
///////////////////////////////////////////////////////////////////////////////

//Removed an element from its parent
//function removeElement(id)
//{
//  var e = $(id);
//  if (e!=null)
//  {
//    var p = e.parentNode || e.parentElement;
//    if (p!=null)
//      p.removeChild(e);
//  }
//}

if (!document.selection && typeof(HTMLElement)!="undefined")
{
  HTMLElement.prototype.__defineSetter__("innerText", function (sText) {
     this.innerHTML = sText.replace(/\&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
  });
}

function sanitize(text)
{
  return String(text).stripTags();
  var d = document.createElement("DIV");
  d.innerHTML = text;
  return d.innerText || d.textContent;
}

function emptyElement(elem)
{
  if (!elem)
    return;
  var c = elem.firstChild,d;
  while(c)
  {  
    d = c.nextSibling;
    elem.removeChild(c);
    c = d;
  }  
}

function hashToUrl(obj)
{
  return $H(obj).toQueryString();
}

function addScript(url,id)
{
  var s = document.createElement('SCRIPT');
  s.type = 'text/javascript';
  s.src = url;
  s.id = id;
  s.charset ='utf-8';
  document.body.appendChild(s);
}

function createElement(type, props, children)
{
  var ret = document.createElement(type);
  if (props)
  {
    for (var i in props)
    {
      if (props.hasOwnProperty(i))
      {
        if (i=="style")
          ret.cssText = props[i];
        else
          ret[i] = props[i];
      }
    }
  }
  if (children)
  {
    for (var i=0,j=children.length;i<j;i++)
    {
      ret.appendChild(children[i]);
    }
  }
  return ret;
}

function setHomepage(url,title)
{
  title = title||document.title;
  try
  {
    document.body.style.behavior='url(#default#homepage)';
    document.body.setHomePage(url);
    return true;
  } 
  catch(e1)
  {
  }
  
  try
  {
    if (window.external && window.external.AddFavorite)
    {
      window.external.AddFavorite(url,title);
      return true;
    }
  } 
  catch(e2)
  {
  }
  
  try
  {
    if (window.sidebar)
    {
      if(window.netscape)
      {
        try
        {  
              netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");  
        }  
        catch(e)  
        {  
          //alert("this action was aviod by your browser，if you want to enable，please enter about:config in your address line,and change the value of signed.applets.codebase_principal_support to true");  
          //netscape.security.PrivilegeManager.enablePrivilege('UniversalPreferencesWrite'); 
          //navigator.preference('signed.applets.codebase_principal_support', true);
          //navigator.preference('browser.startup.homepage', url);
        }
      } 
      var prefs = Components.classes['@mozilla.org/preferences-service;1'].getService(Components. interfaces.nsIPrefBranch);
      prefs.setCharPref('browser.startup.homepage',url);    
      return true;
    }
  }
  catch(e3)
  {
  }
  return false;
}

function addBookmark(url,title)
{
  title = title||document.title;
  try
  {
      if (window.sidebar) 
      { // Mozilla Firefox Bookmark
		    window.sidebar.addPanel(title, url,"");
	    } 
	    else if (window.external)
	    { // IE Favorite
		    window.external.AddFavorite(url, title); 
		  }
	    else if (window.opera && window.print) 
	    { // Opera Hotlist
		    return true; 
		  }
  } catch(e)
  {
  }
  return false;
}


///////////////////////////////////////////////////////////////////////////////
/*                           SEARCH RELATED                                  */ 
///////////////////////////////////////////////////////////////////////////////

var searchPending = false;
var searchEnginesPending = [];
var loaded = false;
var searchResultsToShow = 16;
var searchResults = {current:0};
var searchEngines = {count:0,data:{}};

// Once everything is loaded, allow the search button, and search if a request is pending
function allowSearching()
{
  loaded = true;
  for(var i=0;i<searchEnginesPending.length;i++)
    RegisterSearchEngine(searchEnginesPending[i]);
  RegisterSearchEngine = function(){};
  
  if (searchPending)
  {
    searchPending = false;
    doSearchNow();
    return;
  }
  var qa = new Querystring();
  var term = qa.get("q");  
  var st = new TabControl("SearchType");
  st.OnSelectionChanged = refreshAdvancedMode;
  var searchType = qa.get("searchType");
  if (searchType)
    st.SetValue(searchType);
  var adv = qa.get("advanced")=="true";
  if (adv)
    advancedMode();
    
  var checkedEngines = qa.get("engines");
  if (checkedEngines)
  {
    setEngines(checkedEngines);
  }
    
  
  $('searchTb').focus(); 
}

function refreshAdvancedMode(sel)
{
  webAdv = $('advancedWeb');
  imgAdv = $('advancedImg');
  if (sel.value == "image")
  {
    if (webAdv.style.display!="none")
    {
      imgAdv.style.display = webAdv.style.display;
      webAdv.style.display = "none";
    }
  }
  if (sel.value == "web")  
  {
    if (imgAdv.style.display!="none")
    {
      webAdv.style.display = imgAdv.style.display;
      imgAdv.style.display = "none";
    }
  }  
}

function setEngines(checkedEngines)
{
  checkedEngines = checkedEngines.split(",");
  for(var i in searchEngines.data)
    searchEngines.data[i].Disable();    
  
  for(var i=0;i<checkedEngines.length;i++)
  {
    if (searchEngines.data[checkedEngines[i]])
    {
          searchEngines.data[checkedEngines[i]].Enable();
    }
  }
}

function advancedMode()
{
  var advancedDiv = null;
  if ($('WebSearchCb').checked)
    advancedDiv = $('advancedWeb');
  else if ($('ImageSearchCb').checked)
    advancedDiv = $('advancedImg');


  var toAdv =  advancedDiv.style.display=='none';
//  if (advancedDiv._effect)
//    advancedDiv._effect.Stop();
//  if (toAdv)
//  {    
//    advancedDiv._effect = Effect.BlindDown(advancedDiv.id);
//  }
//  else
//  {
//    advancedDiv._effect = Effect.BlindUp(advancedDiv.id);
//  }
  advancedDiv.style.display= toAdv ? '' : 'none';
  var ftn = getFirstTextNode($('advancedToggle'));
  ftn.nodeValue = toAdv ? 'Basic' : 'Advanced';
  $('searchTb').focus();
}

function getFirstTextNode (n)
{
  var ret = null;
  var siblings = $A(n.childNodes).each(function(t)
  {
    if (ret!=null)
      return;
    if (t.nodeType == 3 && !t.nodeValue.blank())
      ret = t;
    else if (t.nodeType == 1)
      ret = getFirstTextNode(t);
  });
  return ret;
}

// Logs the process of a search engine
function logProgress(engine,progress)
{
  var engineData = searchEngines.data[engine];
  if (engineData)
    engineData.progressCtrl.reportProgress(progress);
}

String.prototype.Trim = function(s) 
{
  s = s || this;
  s = s.replace(/\s*((\S+\s*)*)/, "$1");
  s = s.replace(/((\s*\S+)*)\s*/, "$1");
	return s;
}

function getCheckedEngines()
{
  var ce = [];
  for(var i in searchEngines.data)
    if (searchEngines.data[i].IsEnabled())
    {
      ce.push(i);
    }
  return ce.join(",");
}

function getAdvancedOptions()
{
  var opts = {};
  if ($('WebSearchCb').checked)
  {
    opts.searchType = "web";
    opts.ilang =  $('ILanguageSb').value;
    opts.lang =  $('LanguageSb').value;
    opts.country = $('CountrySb').value;
    opts.advanced = $('advancedWeb').style.display!="none";  
  }
  else if ($('ImageSearchCb').checked)
  {
    opts.searchType = "image";
    opts.adult_ok= $('AdultOk').checked;
    opts.colorOnly= $('ImageColoration').value=="Color Only";
    opts.blackWhiteOnly= $('ImageColoration').value=="B&W Only";
    opts.format = $('ImageFormat').value;
    opts.advanced = $('advancedImg').style.display!="none";  
  }
  return opts;
}

function doSearch()
{
  term = $('searchTb').value;
  var opts = getAdvancedOptions();  
  opts.engines = getCheckedEngines();
  //opts.q = term;
  //if ($('advancedToggle').style.display=='none')
  //  opts.adv = "true";
  var href = "?q="+encodeURIComponent(term)+"&"+hashToUrl(opts);
  location.href = href;
}

function resizeRect(h,w,maxh,maxw)
{
  var candidates = [];
  if (h > 0 && w > 0)
  {  
    var oh=h, ow=w, hwRatio = h/w;
    if (h > maxh)
    {
      h = maxh;
      w = h / hwRatio;
    }
    if (w > maxw)
    {
      w = maxw;
      h = w * hwRatio;
    }
    candidates.push({height:h, width:w, rank: w*h});
    h = oh; w = ow;    
    if (w > maxw)
    {
      w = maxw;
      h = w * hwRatio;
    }
    if (h > maxh)
    {
      h = maxh;
      w = h / hwRatio;
    }
  }
  candidates.push({height:h, width:w, rank: w*h});
  candidates.sort(function(a,b){return a.rank-b.rank;});
  return candidates[0];;
}


function doSearchNow(term)
{
  if (!loaded) { searchPending = true; return; }
  term = term || $('searchTb').value;
  if (term.Trim().length==0)
  {
    alert('Please enter a search term');
    return;
  }
  term = term.Trim();
  var id = new Date().valueOf();            
  searchResults.current = id;   
  
  var activeEngines = 0;  
  for(var i in searchEngines.data)
  {
    if (searchEngines.data[i].IsEnabled())
    {
      searchEngines.data[i].DoSearch(term,id,getAdvancedOptions());
      activeEngines++;
    }  
  }
  
  var asq = new AutoSuggestQuery(term,15);
  asq.completionData = {
    onSuccess : function(results)
    {
      suggestRelatedQueries(results);
      //Build tag cloud / Did you mean / Related searches
      
    }
  }
  
    
  if (activeEngines==0)
  {
    alert("Please select some search engines to search in.");    
  }    
}

function suggestRelatedQueries(suggestions)
{
  if (!suggestions || !(suggestions.length))
  {
    return;
  }
  
  $('ReleatedSearchesTable').style.display = "";
  var elem;
  for(var i=0,j=suggestions.length;i<j;i++)
  {
    if (i%5 == 0)
    {
      elem = $('ReleatedSearches'+String((i/5)+1));  
      if (!elem)
        return;
      elem.style.padding = "2px";
    }
    var sug = suggestions[i].value;
    var d = document.createElement('DIV');
    var a = $(document.createElement('A'))
    a.href="javascript:void(0)";
    a.innerText = sug;
    a.observe('click', SearchRelatedTerm.curry(sug));
    d.appendChild(a);
    elem.appendChild(d);
  }
}
function SearchRelatedTerm(txt)
{
  $('searchTb').value = txt;
  doSearch();
}
function CreateProgressTable()
{
  var engineProgressTbl = document.createElement("TABLE");
  engineProgressTbl.cellSpacing = "0px";
  engineProgressTbl.cellPadding = "0px";
  engineProgressTbl.style.width = "100%";  
  var tbody = document.createElement("TBODY");      
  engineProgressTbl.appendChild(tbody);
  var tr = document.createElement("TR");
  tr.style.height="5px";
  tbody.appendChild(tr);
  var cell1 = document.createElement("TD");
  cell1.innerHTML = "<div/>";//<img src='Images/blank.gif'>";
  cell1.style.width="0%";
  cell1.style.backgroundColor="black";
  var cell2 = document.createElement("TD");
  cell2.innerHTML = "<div/>";//"<img src='Images/blank.gif'>";
  cell1.style.width="100%";
  cell2.style.backgroundColor="gray";
  tr.appendChild(cell1);
  tr.appendChild(cell2);
  
  engineProgressTbl.reportProgress = function(progress)
  {
    if (progress=='done')
    {   
      cell1.style.width="100%";   
      cell2.style.width="0%";
    }
    else
    {
      progress = progress*100;
      cell1.style.width=progress+"%";
      cell2.style.width=(100-progress)+"%";
    }
  }
  
  return engineProgressTbl;
}    

function RegisterSearchEngine(searchEngine)
{
  if (!loaded)
  {
    searchEnginesPending.push(searchEngine);
    return;
  }  
  var rp = new ResultsPanel(searchEngine);
  searchEngines.data[searchEngine.name] = rp;
  rp.Initialize();
}

function Register(engineURL)
{
  engineURL= engineURL || "http://www.searchall.com/getallresult.xml";
  try
  {
    window.external.AddSearchProvider(engineURL)
  }
  catch(e)
  {
    alert('Installation failed.');
  }
}  


/* Client-side access to querystring name=value pairs
	Version 1.3
	28 May 2008
	
	License (Simplified BSD):
	http://adamv.com/dev/javascript/qslicense.txt
*/
function Querystring(qs) { // optionally pass a querystring to parse
	this.params = {};
	
	if (qs == null) qs = location.search.substring(1, location.search.length);
	if (qs.length == 0) return;

// Turn <plus> back to <space>
// See: http://www.w3.org/TR/REC-html40/interact/forms.html#h-17.13.4.1
	qs = qs.replace(/\+/g, ' ');
	var args = qs.split('&'); // parse out name/value pairs separated via &
	
// split out each name=value pair
	for (var i = 0; i < args.length; i++) {
		var pair = args[i].split('=');
		var name = decodeURIComponent(pair[0]);
		
		var value = (pair.length==2)
			? decodeURIComponent(pair[1])
			: name;
		
		this.params[name] = value;
	}
}

Querystring.prototype.get = function(key, default_) {
	var value = this.params[key];
	return (value != null) ? value : default_;
}

Querystring.prototype.contains = function(key) {
	var value = this.params[key];
	return (value != null);
}

///////////////////////////////////////////////////////////////////////////////
/*                             Paging Control                                */ 
///////////////////////////////////////////////////////////////////////////////

function PagingControl(div, pages, callback)
{
  this.Container = $(div);
  this.pageCount = pages;
  this.callback = callback;
  this.pagesToShow = 9;
  this.Setup();  
  this.SelectPage(1); 
}

PagingControl.prototype.ReInitialize = function(pages,callback)
{
  for (var i=0;i<this.cells.length;i++)
  {
    this.tr.removeChild(this.cells[i]);
    this.cells[i].onclick = null;
  }
  this.pageCount = pages;
  this.callback = callback || this.callback;
  this.BuildCells();
  this.SelectPage(1,true);
}

PagingControl.prototype.Setup = function()
{
  var tbl = document.createElement("TABLE");
  tbl.className = "pagerTable";
  tbl.cellSpacing = 1;
  tbl.cellPadding = 0;
  this.Container.appendChild(tbl);
  var tbody = document.createElement("TBODY");
  tbl.appendChild(tbody);
  var tr = document.createElement("TR");
  this.tr = tr;
  tbody.appendChild(tr);
  this.BuildCells();
}

PagingControl.prototype.BuildCells = function()
{
  this.cells = [];
  var cellCount = Math.min(this.pagesToShow, this.pageCount);
  this.currentPage = 0;
  var me = this;
  for (var i=0;i<cellCount;i++)
  {
    var td = document.createElement("TD");
    this.tr.appendChild(td); 
    td.onclick = function()
    {
      me.SelectPage(this.value);
    }         
    this.cells.push(td);
  }
}

PagingControl.prototype.SelectPage = function(page, preventCallback)
{
  this.currentPage = page;
  
  var firstPage = Math.ceil(Math.max(page-(this.pagesToShow)/2,1));
  var lastPage = Math.ceil(Math.min(firstPage+this.pagesToShow-1,this.pageCount));
  
  if (lastPage - firstPage + 1 < this.cells.length)
  {
    firstPage = Math.max(lastPage - this.cells.length + 1,1);
  }
  
  for (var i=firstPage, j=0;i<=lastPage;i++,j++)
  {
    var cell = this.cells[j];
    var str = i.toString();
    if(i==page)
    {
      //if (i>firstPage)
        //str = "&raquo;"+str;
      //if (i < lastPage)
        //str = str+"&laquo;";
        cell.className = "pagerSelected" ;
    }
    else  
    {
      cell.className = "pagerUnselected";
    }
    //str = "<a href='javascript://' onclick='this.parentElement.click()'>"+str+"</a>";
    if (cell.value!=i)
    {
      cell.innerHTML = str;
      cell.value = i;
    }
  }  
  if (this.callback && !preventCallback)  
    this.callback(page);
}

///////////////////////////////////////////////////////////////////////////////
/*                             Search Engine Model                           */ 
///////////////////////////////////////////////////////////////////////////////

//A SearchEngine is a factory for Search objects. It represents a single web search engine.
function SearchEngine(data)
{
  this.name = data.name;
  this.desc = data.desc;
  this.imageUrl = data.imageUrl;
  this.searchFunc = data.searchFunc;  
}
SearchEngine.prototype.Register = function()
{
  RegisterSearchEngine(this); 
}
// To be overridden by instantiated classes
SearchEngine.prototype.CreateSearch = function(term, id, options)
{
  return new Search(this, term, id, options);
}

// A Search object is created by an engine to process a search response for a single term and multiple pages
function Search(engine, term, id, options)
{
  this.engine = engine;
  this.term = term;
  this.id = id;
  this.Pages = [];
  
  if (options)
    for(var on in options)
      if (options.hasOwnProperty(on))
        this[on] = options[on];
}
Search.prototype.GetPage = function(pageNumber, pageReadyCallback, notifyEstimatesCallback)
{
  //Save these for later requests, so that they can be cached internally
  pageReadyCallback = pageReadyCallback || this.pageReadyCallback;
  if (pageReadyCallback)
    this.pageReadyCallback = pageReadyCallback;
  
  notifyEstimatesCallback = notifyEstimatesCallback || this.notifyEstimatesCallback;
  if (notifyEstimatesCallback)
    this.notifyEstimatesCallback = notifyEstimatesCallback;
  
  if (this.Pages[pageNumber] && this.Pages[pageNumber].isReady)
  {
    var id = this.id;
    (function()
    {
      if (pageReadyCallback)
        pageReadyCallback(id, pageNumber);
    }).delay(0);
  }
  else
  {  
    this.InternalGetPage(pageNumber, pageReadyCallback, (pageNumber==1 && notifyEstimatesCallback));
  }
}

function appendHighlightedContents(elem, txt, words)
{   
  var span = document.createElement("span");
  span.innerHTML = txt;  
  if (span.childNodes.length>0)
    elem.appendChild(span.childNodes[0]);
  var iHtml = elem.innerHTML;
  var lHtml = iHtml.toLowerCase();
  var highlightIdx = [];
  
  for(var i=0,j=words.length;i<j;i++)
  {
    var lwrd = words[i].toLowerCase();    
    var ll = lwrd.length;
    var temp = lHtml.split(lwrd);
    if (temp.length==1)
      continue;
    var idx = 0;
    for (var k=0,l=temp.length;k<l;k++)
    {
      idx += temp[k].length;
      highlightIdx.push({len:ll, idx:idx});
      idx += ll;
    }
  }
  if (highlightIdx.length>0)
  {
    highlightIdx.sort(function(a,b){return a.idx-b.idx;});
    var idx = 0;
    var sb = [];
    for (var i=0,j=highlightIdx.length;i<j;i++)
    {
      var p = highlightIdx[i];
      if (p.idx>0)
      {
        sb.push(iHtml.substr(idx,p.idx-idx));
        idx = p.idx;
      }
      sb.push("<span class='wordHighlight'>"+iHtml.substr(p.idx,p.len)+"</span>");
      idx += p.len;
    }
    iHtml = sb.join('');
  }
  
  elem.innerHTML = iHtml;
}

function ResultsPanel(engine)
{
  this.engine = engine;
  this.initialized = false;
  this.isShown = false;
  this.nameShown = false;
}

ResultsPanel.prototype.Clear = function()
{
  emptyElement(this.dataTd);
}

ResultsPanel.prototype.DoSearch = function(term,id, options)
{
  if (!this.nameShown)
  {
    this.nameTh.style.display = "";
    this.nameShown = true;
  }
  this.Clear();
  if (this.estimationTitle!=null)
  {
    $(this.estimationTitle).up().style.display="";
    this.estimationTitle.innerHTML = "Searching...";
  }
  //.innerHTML = ""; //Clear estimation title  
  this.PageNumber = 1;
  //this.progressTable.style.display = "";
  this.Search = this.engine.CreateSearch(term,id,options);
  this.Search.GetPage(1, this.PageReadyCallback.bind(this), this.NotifyEstimationCallback.bind(this));    
}
ResultsPanel.prototype.CreateItemCell = function(item,paren, searchType,words)
{
  switch(searchType)
  {
    case "image":
      return this.CreateImageItemCell(item,paren,words);
    case "web":
      return this.CreateWebItemCell(item,paren,words);
  }
}

ResultsPanel.prototype.CreateImageItemCell = function(item,paren,words)
{
  var div = document.createElement('DIV');
  div.className = 'result imageResult';
  if (item.message)
  {
    div.innerHTML = item.message;
    return div;
  }  
  
  var title = document.createElement('A');
  title.className = 'title';
  title.href = item.ClickUrl;
  var img = document.createElement('IMG');
  img.src = item.ThumbnailUrl;  
  
  var oh = item.ThumbnailHeight, ow = item.ThumbnailWidth;
  var newDim = resizeRect(oh, ow, 150,200);
  img.style.width = newDim.width+"px";
  img.style.height = newDim.height+"px";
  
  img.style.border = "0px";
  title.appendChild(img); 
  title.appendChild(document.createElement('BR'));
  div.appendChild(title);
  
  
  //var description = document.createElement('DIV');
  //description.className = 'description imageDescription';
  //appendHighlightedContents(description, this.FormatEllipsis(item.Text || item.Summary,50).stripTags(), words);
  //description.innerHTML = this.FormatEllipsis(item.Text || item.Summary,50);
  title.title = (item.Text || item.Summary).stripTags();
  //title.appendChild(description);
  
  var metadata = document.createElement('DIV');
  metadata.className = 'imageMetadata';
  metadata.innerHTML = this.FormatImageMetadata(item);  
  div.appendChild(metadata);
  paren.appendChild(div);
  return div;
}

ResultsPanel.prototype.FormatImageMetadata = function(item)
{
  var ret = [];
  ret.push(item.Width);
  ret.push("x");
  ret.push(item.Height);
  
  if (item.FileSize)
  {
    ret.push(" ");
    var units = "Kb";
    var sz = item.FileSize / 1024;
    if (sz > 1048)
    {
      sz = sz / 1024;
      units = "Mb";
    }
    if (sz > 1048)
    {
      sz = sz / 1024;
      units = "Gb";
    }
    if (String(sz).length>7)
    {
      sz = Math.floor(sz*100) / 100;      
    }
    
    ret.push(sz);
    ret.push(" ");
    ret.push(units);
  }
  if (item.FileFormat)
  {
    ret.push(" ");
    ret.push(item.FileFormat);
  }
  
  return ret.join('');
}

ResultsPanel.prototype.CreateWebItemCell = function(item,paren,words)
{
  var div = document.createElement('DIV');
  div.className = 'result';
  
  var title = document.createElement('A');
  title.className = 'title';
  title.innerHTML = (item.clearTitle || item.title).stripTags();
  
  div.appendChild(title);
  title.href = item.url;
  
  var description = document.createElement('DIV');
  description.className = 'description';
  appendHighlightedContents(description, item.description.stripTags(), words);
  //description.appendChild(document.createTextNode(page[i].description));
  description.title = item.description;
  div.appendChild(description);  
  
  var url = document.createElement('DIV');
  url.className = 'url';
  var urlText = item.visibleUrl || item.url;
  urlText = this.FormatEllipsis(urlText.stripTags(),50);  
  url.appendChild(document.createTextNode(urlText));
  div.appendChild(url);   
  paren.appendChild(div);
  resizeUntilMaxHeight(description,100);
  return div;
}
ResultsPanel.prototype.FormatEllipsis = function(txt, len)
{
  if (txt && txt.length>len)
    txt = txt.substring(0,len-3)+"...";
  return txt;
}
ResultsPanel.prototype.PageReadyCallback = function(id, pageNumber)
{
  if (!this.isShown)
    this.Show();  
  if (this.Search && this.Search.id == id && pageNumber == this.PageNumber)
  { 
    this.Clear();
    var page = this.Search.Pages[pageNumber];
    postSearchResults(page);
    
    var words = [];
    if (page.length==0 && pageNumber==1)
    {
      page.push({message:"No Results were found", title:"", url:"", description: "No Results were found", urlText:""});
    }
    else
    {
      words = this.Search.term.split(' ');
    }    
    for (var i=0,j=page.length;i<j;i++)
    {          
      var div = this.CreateItemCell(page[i], this.dataTd, this.Search.searchType, words);
      //this.dataTd.appendChild(div);
    }
    if (this.pc.pageCount>1)
      this.dataTd.appendChild(this.pcContainer);    
    
    //Display results
    //this.progressTable.style.display = "none";    
  }
}

ResultsPanel.prototype.NotifyEstimationCallback = function(id, estimation, usableResultEstimation)
{
  if (!this.isShown)
    this.Show();
  if (this.Search && this.Search.id == id)
  {
    //Display estimates
    if (this.estimationTitle!=null)
    {
      var estText = parseInt(estimation).toString();
      var i=estText.length%3;
      if (i==0)
        i = 3;
      while(i<estText.length)
      {
        estText = estText.substr(0,i)+","+estText.substr(i);
        i+=4;
      } 
      $(this.estimationTitle).up().style.display = "";
      if (estText=="0")
        estText = "no";
      this.estimationTitle.innerHTML = estText+" results";
    }
    if (!usableResultEstimation)
      usableResultEstimation = estimation;
    
    var pages = Math.ceil(usableResultEstimation / searchResultsToShow);
    this.pc.ReInitialize(pages);
    if (pages<2)
    {
      var container = $(this.pc.Container);
      if (container && container.parentElement!=null)
        $(this.pc.Container).remove();
    }
  }
}

ResultsPanel.prototype.ShowWaitingImage = function()
{    
    var img = this.waitingImage;
    if (!img)
    { 
      this.waitingImage = img = new Image(); 
      img.src = "Images/ajax-loader.gif";
    }
    this.dataTd.appendChild(img);
}

ResultsPanel.prototype.NaviageToPage = function(page)
{
  if (this.Search)
  {
    //this.progressTable.style.display = "";
    this.Clear();
    this.ShowWaitingImage();        
    this.PageNumber = page;
    this.Search.GetPage(page);
  }
}
ResultsPanel.UniqueIDs = 0;
ResultsPanel.prototype.Initialize = function()
{
  if (this.initialized)
    return;
  this.initialized = true; 
  var engineData = $('engineData'); //REFACTOR ID 'engineData'
  var engineDataRow;
  if (engineData.rows.length==0)
  {
    engineDataRow = createElement("TR");
    engineData.appendChild(engineDataRow)
  }
  else
    engineDataRow = engineData.rows[0];
  
  this.nameTh = document.createElement("TH");      
  this.nameTh.className = "engineResults";
  this.nameTh.style.display = "none";
  this.nameTh.style.height = "25px";
  this.nameTh.style.verticalAlign = "top";
  
  //Create title
  if (this.engine.imageUrl)
  {
    this.nameTh.appendChild(createElement("IMG",{src:this.engine.imageUrl,title: this.engine.desc}));    
  }
  else
  {
    this.nameTh.appendChild(createElement("B",{innerHTML:this.engine.name}));
  }
  //this.nameTh.appendChild(createElement("BR"));
  //$('SearchEstimations').innerHTML += "<div>"+this.engine.name+": "+estimation+" results</div>"
  var se = $('SearchEstimations');
  if (se!=null)
  {
    var tr = createElement("TR");
    var td1 = createElement("TD");
    td1.innerHTML = this.engine.name+": ";
    this.estimationTitle = createElement("TD");
    tr.appendChild(td1);
    tr.appendChild(this.estimationTitle);
    tr.style.display="none";
    se.appendChild(tr);    
  }
  
  //Create search engine enabler
  this.cb = createElement("INPUT", {type:"CheckBox"});  
  this.cb.id = "toggle_"+this.engine.name;
  $('engineEnablers').appendChild(this.cb);
  var lbl = document.createElement("LABEL");
  lbl.htmlFor = this.cb.id;  
  lbl.setAttribute("for",this.cb.id);
  lbl.appendChild(document.createTextNode(this.engine.name));
  $('engineEnablers').appendChild(lbl);
  //$('engineEnablers').appendChild(createElement("BR"));
  
  this.cb.checked = true;
  
  //Create progress bar
//  this.progressTable = CreateProgressTable();
//  this.progressTable.reportProgress(0);
//  this.progressTable.style.display = "none";
//  this.nameTh.appendChild(this.progressTable);
  
  engineDataRow.appendChild(this.nameTh);
  
  var engineResults = $('resultsBody');
  var engineResultsRow;
  if (engineResults.rows.length==0)
  {
    engineResultsRow = createElement("TR");
    engineResults.appendChild(engineResultsRow)
  }
  else
    engineResultsRow = engineResults.rows[0];
  this.dataTd = document.createElement("TD");
  this.dataTd.style.display = "none";
  this.dataTd.style.verticalAlign = "top";
  engineResultsRow.appendChild(this.dataTd);
  
  this.pcContainer = createElement("DIV");  
  this.pc = new PagingControl(this.pcContainer,1,this.NaviageToPage.bind(this));
}

ResultsPanel.prototype.Show = function()
{
  //this.nameTh.style.display = "";
  this.dataTd.style.display = "";
  this.isShown = true;
}

ResultsPanel.prototype.Hide = function()
{
  //this.nameTh.style.display = "none";
  this.dataTd.style.display = "none";
  this.isShown = false;
}


ResultsPanel.prototype.IsEnabled = function()
{
  return this.cb.checked;
}

ResultsPanel.prototype.Enable = function()
{
  this.cb.checked = true;
}

ResultsPanel.prototype.Disable = function()
{
  this.cb.checked = false;
}


function notifyEngineResultsEstimation(engine, id, count, count2)
{
  var sed = searchEngines.data[engine];
  if (!sed) return;
  var search = sed.Search;
  if (!search) return;
  if (search.id != id)
    return;
  search.notifyEstimatesCallback(id, count, count2);
}

function notifyEngineResults(engine, id, results, offset, hasMore)
{
  var sed = searchEngines.data[engine];
  if (!sed) return;
  var search = sed.Search;
  if (!search) return;
  if (search.id != id)
    return;
  var pageOffset = offset % searchResultsToShow;
  var pageNumber = 1 + ((offset-pageOffset) / searchResultsToShow);
  if (!search.Pages[pageNumber])
    search.Pages[pageNumber] = [];
    
  var searchPage = search.Pages[pageNumber];
  var currentPageNumber = pageNumber;
  for(var i=0;i<results.length;i++)
  {
    if (i+pageOffset==searchResultsToShow)
    {
      currentPageNumber++;
      if (!search.Pages[currentPageNumber])
        search.Pages[currentPageNumber] = [];
      searchPage = search.Pages[currentPageNumber];
      pageOffset=i*-1;      
    }
    searchPage[i+pageOffset] = results[i];
  }
  searchPage = search.Pages[pageNumber];
  var resultsInPage = searchPage.length;
  if (resultsInPage == searchResultsToShow || !hasMore)
  {
    searchPage.isReady = true;
    (function(){search.pageReadyCallback(id, pageNumber);}).delay(0);
  }
}


/**
*
*  URL encode / decode
*  http://www.webtoolkit.info/
*
**/

var Url = {

	// public method for url encoding
	encode : function (string) {
		return escape(this._utf8_encode(string));
	},

	// public method for url decoding
	decode : function (string) {
		return this._utf8_decode(unescape(string));
	},

	// private method for UTF-8 encoding
	_utf8_encode : function (string) {
		string = string.replace(/\r\n/g,"\n");
		var utftext = "";

		for (var n = 0; n < string.length; n++) {

			var c = string.charCodeAt(n);

			if (c < 128) {
				utftext += String.fromCharCode(c);
			}
			else if((c > 127) && (c < 2048)) {
				utftext += String.fromCharCode((c >> 6) | 192);
				utftext += String.fromCharCode((c & 63) | 128);
			}
			else {
				utftext += String.fromCharCode((c >> 12) | 224);
				utftext += String.fromCharCode(((c >> 6) & 63) | 128);
				utftext += String.fromCharCode((c & 63) | 128);
			}

		}

		return utftext;
	},

	// private method for UTF-8 decoding
	_utf8_decode : function (utftext) {
		var string = "";
		var i = 0;
		var c = c1 = c2 = 0;

		while ( i < utftext.length ) {

			c = utftext.charCodeAt(i);

			if (c < 128) {
				string += String.fromCharCode(c);
				i++;
			}
			else if((c > 191) && (c < 224)) {
				c2 = utftext.charCodeAt(i+1);
				string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
				i += 2;
			}
			else {
				c2 = utftext.charCodeAt(i+1);
				c3 = utftext.charCodeAt(i+2);
				string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
				i += 3;
			}

		}

		return string;
	}

}

/*************************************************************************************/
/*                                  AutoSuggest                                      */
/*************************************************************************************/
if (typeof(window.google)=='undefined')
  window.google = {};
window.google.ac = {};
window.google.ac.Suggest_apply = function(frameelement,term,suggestsions,more)
{
  var q = AutoSuggestQuery.current;
  if (q && !q.abort && q.term==term)
  {
    var s = [];
    for(var i=1;i<suggestsions.length-1;i+=2)
    {
      s.push({value:suggestsions[i]});//,info:suggestsions[i+1]});
    }  
    q.notifyResults('Google',s);
    
   //$('AutoSuggestQuery_Google_'+q.id).remove.delay(0);
  }
}
window.live = {};
window.live.ac = {};
window.live.ac.Callbacks = {};
window.live.ac.CreateCallback = function(id)
{
  
  window.live.ac.Callbacks[id] = function(results)
  {   
    var q = AutoSuggestQuery.current;
    if (q && !q.abort && q.id==id)
    {
      var s = [];
      if (results && results.SearchResponse && results.SearchResponse.RelatedSearch && results.SearchResponse.RelatedSearch.Results)
      {
        var r = results.SearchResponse.RelatedSearch.Results;  
        for (var i=0;i<r.length;i++)
        {
          s.push({value:r[i].Title});
        }
      }
      if (results && results.SearchResponse && results.SearchResponse.Spell && results.SearchResponse.Spell.Results)
      {
        var r = results.SearchResponse.Spell.Results;  
        for (var i=0;i<r.length;i++)
        {
          s.push({value:r[i].Value});
        }
      }      
      q.notifyResults('Live',s);
    }
  }
}

window.yahoo = {};
window.yahoo.ac = {};
window.yahoo.ac.Callbacks = {};
window.yahoo.ac.CreateCallback = function(id)
{
  window.yahoo.ac.Callbacks[id] = function(results)
  {    
    var q = AutoSuggestQuery.current;
    if (q && !q.abort && q.id==id)
    {
      var r = results && results.ResultSet && results.ResultSet.Result;
      var r2=[];
      if (r)
      {
        if (typeof(r)=='string')
        {
          r2.push({value:r});
        }
        else
        {
          for (var i=0;i<r.length;i++)
            r2.push({value:r[i]});
        }
      };
      q.notifyResults('Yahoo',r2);
      (function(){
        window.yahoo.ac.Callbacks[id] = null;
      }).delay(0);
    }
  }
}
window.yahoo.ac.Suggest_apply = function(suggestions)
{
  //debugger;
}
var AutoSuggestQuery = Class.create();
AutoSuggestQuery.prototype = {
  initialize : function(term,max)
  {
    if (AutoSuggestQuery.current)
      AutoSuggestQuery.current.abort = true;
    AutoSuggestQuery.current = this;
    this.id = new Date().valueOf();
    this.term = term;
    this.max = max || 10;
    this.results = {};
    this.searchGoogle();
    this.searchYahoo();
    this.searchLive();
    this.term = decodeURIComponent(this.term);
  },
  
  searchGoogle : function()
  {
    var url = "http://www.google.com/complete/search?hl=en&js=true&q="+this.term;
    var sid = "AutoSuggestQuery_Google_"+this.id;
    addScript.curry(url,sid).delay(0);
    this.results.Google = false;
  },
  
  searchYahoo : function()
  {
    window.yahoo.ac.CreateCallback(this.id);
    var url = "http://search.yahooapis.com/WebSearchService/V1/relatedSuggestion?appid=keIChznV34GJf03Uj6O3C_XWbpAOjEoqZExGlIDZE0ukywtt0zlsYp4DQmBqxI3px9tyJlA1F5OuXg--&output=json&callback=window.yahoo.ac.Callbacks["+this.id+"]&query="+this.term;
    var sid = "AutoSuggestQuery_Yahoo_"+this.id;
    addScript.curry(url,sid).delay(0);
    this.results.Yahoo = false;    
  },
  
  searchLive : function()
  {
    window.live.ac.CreateCallback(this.id);
    var sid = "AutoSuggestQuery_Live_"+this.id;
    var url = "http://api.search.live.net/json.aspx?"
        
            // Common request fields (required)
            + "AppId=5DE6D123674B9E08A96B4E4D1B9ED8F19B53AD34"
            + "&Query="+this.term
            + "&Sources=RelatedSearch+Spell"
            
            // Common request fields (optional)
            + "&Version=2.0"
            + "&Market=en-us"
            //+ "&Options=EnableHighlighting"

            // JSON-specific request fields (optional)
            + "&JsonType=callback"
            + "&JsonCallback=window.live.ac.Callbacks["+this.id+"]";
    addScript.curry(url,sid).delay(0);
    this.results.Live = false;    
  },
  
  notifyResults : function(engine, results)
  {
    if (this.results[engine])
      return;
    this.results[engine] = results;
    for(var i in this.results)
      if (this.results.hasOwnProperty(i) && this.results[i]===false)
        return; //If found an engine that hasn't completed, wait for it
        
    var results = this.joinResults();
    if (this.completionData && this.completionData.onSuccess)
      this.completionData.onSuccess(results);
     
    this.abort = true;
    AutoSuggestQuery.current = null; 
  },
  
  joinResults : function()
  {
    var results = {};
    var resultsLC = {};
    var resultsArr = [];
    for(var engineName in this.results)
    {
      if (this.results.hasOwnProperty(engineName))
      {
        var engineResults = this.results[engineName];
        for (var i=0;i<engineResults.length;i++)
        {
          var value = engineResults[i].value;
          var info = engineResults[i].info && (engineResults[i].info+"("+engineName+")");
          if (resultsLC[value.toLowerCase()])
            value = resultsLC[value.toLowerCase()];
          else
            resultsLC[value.toLowerCase()] = value;
          if (results[value])
          {
            results[value].count++;
          }
          else
          {
            results[value] = {count:1, data: [], value:value};
            resultsArr.push(results[value]);            
          }
          if (info)
              results[value].data.push(info);
        }
      }
    }
    var arr2 = resultsArr.sort(function(a,b) {return (b.count-a.count)*100 + (a.value.length-b.value.length);});
    var arr3 = [];
    for (var i=0;i<arr2.length && i<this.max;i++)
    {
      arr3.push({id:i,value:arr2[i].value,info:arr2[i].data.join(', ')});
    }
    return arr3;
  }
};

Object.extend(AutoSuggestQuery,
{
  current : null
  ,create : function(x){return new AutoSuggestQuery(x);}
  ,abort : function(){if(this.current){this.current.abort=true;this.current=null;};}
});

function searchTbFocus()
{
  AutoSuggestQuery.isShown = false;
  var options = {
		script:AutoSuggestQuery.create//'test.php?json=true&limit=6&'
		,varname:'input'
		//,json:true
		,manualJson:true
		,shownoresults:false
		,maxresults:10
		,timeout : 20000
		,cache:false
		,onChoose : function() 
		{ 		  
		  doSearch.delay(0);
		 }
		//,callback: function (obj) { $('log').update('you have selected: '+obj.id + ' ' + obj.value + ' (' + obj.info + ')'); }
	};
	var json = new AutoComplete('searchTb',options);
	return true;
}

/*

<script type="text/javascript"><!--
google_ad_client = "pub-8180791779577024";
// 120x600, created 9/30/08
google_ad_slot = "1774577800";
google_ad_width = 120;
google_ad_height = 600;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>

*/

function updateAds(id)
{
  var d=$(id);
	if(d){	
		var s=d.getElementsByTagName('iframe');
		if(s && s.length){
			s[0].src=s[0].src+'&'+new Date().getTime();
		}
	}
}

function updatehighlight()
{
  var cb = $('highlightCb');
  if (!cb)
    return;
  var hl = cb.checked;
  var stylesheet = document.styleSheets[0];
  var rules = stylesheet.rules || stylesheet.cssRules; //CSS RULES!!  
  for (var i=0,j=rules.length;i<j;i++)
  {
    if (rules[i].selectorText=='.wordHighlight')
    {
      rules[i].style.fontWeight = hl ? "bold" : "";
      //rules[i].style.backgroundColor = hl ? "yellow" : "";
      return;
    }
  }
}

function resizeUntilMaxHeight(elem, h)
{
  if (h<20)
    return;
  var tn = elem.childNodes[0];  
  var resized = false;
  var txt="";
  while (elem.offsetHeight > h)
  {    
    txt = elem.textContent || elem.innerText;
    if (!txt || txt.length==0)
      return;
    if (!txt.substring)
      return;
    txt = txt.substring(0,txt.length-1);
    
    if (elem.textContent)
      elem.textContent = txt;
    else
      elem.innerText = txt;
    resized = true;
  }
  if (resized)
  {
    elem.innerText = txt.substring(0,txt.length-4)+"...";
  }  
}

var allSearchResults = [];
var postTimer = 0;
function postSearchResults(json)
{
  if (allSearchResults==null)
    return;
  allSearchResults.push(json);
  if (postTimer!=0)
    window.clearTimeout(postTimer);
  postTimer = window.setTimeout(postSearchResults2,1000);
}

function postSearchResults2()
{
  if (allSearchResults==null)
    return;
  var txt = allSearchResults.toJSON();
  allSearchResults = null;
  var q = new Querystring().get('q');
  q = Url.encode(q);
  new Ajax.Request("PostResults.aspx?q="+q, {
    method: 'post',
    postBody : txt,
    onSuccess: function(transport) { showAds(); }
    });
}

function showAds()
{
  var q = new Querystring().get('q');
  q = Url.encode(q);
  document.getElementById('resultFrm').src = "Results.aspx?q="+q;
}

///// GOOGLE
var GoogleWebSearch = new SearchEngine({name:"Google", desc:"Google Web Search", imageUrl:"Images/new/google.gif"});
GoogleWebSearch.searchData = {};
GoogleWebSearch.searchFunc = function doGoogleSearch(term, id, offset, opts)
{
  var search = GoogleWebSearch.searchData[id] || {id: id, total:0, required: searchResultsToShow, offset:offset, term:term, options:opts};
  GoogleWebSearch.searchData = {};
  GoogleWebSearch.searchData[id] = search;
  var url = [];
  if (search.options.searchType=="web")
  {  
    url.push("http://ajax.googleapis.com/ajax/services/search/web?v=1.0"); 
    url.push("&rsz=large");
    if (search.options.ilang && this.interfaceLanguages && this.interfaceLanguages[search.options.ilang])
    url.push("&hl="+this.interfaceLanguages[search.options.ilang]);
      if (search.options.lang && this.languages && this.languages[search.options.lang])
    url.push("&lr="+this.languages[search.options.lang]);
      if (search.options.country && this.countries && this.countries[search.options.country])
    url.push("&cr="+this.countries[search.options.country]);
  }
  else if (search.options.searchType=="image")
  {
    url.push("http://ajax.googleapis.com/ajax/services/search/images?v=1.0");
    if (search.options.adult_ok)
      url.push("&safe=off");
    else if (search.options.safeContent)
      url.push("&safe=active");
    if (search.options.imageSize)
    {
      switch(search.options.imageSize)
      {
        case "icon":
        case 1:
         url.push("&imgsz=icon");
         break;
        case "small":
        case 2:
         url.push("&imgsz=small");
         break;
        case "medium":
        case 3:
         url.push("&imgsz=medium");
         break;
        case "large":
        case 4:
         url.push("&imgsz=large");
         break;
        case "xlarge":
        case 5:
         url.push("&imgsz=xlarge");
         break;
        case "xxlarge":
        case 6:
         url.push("&imgsz=xxlarge");
         break;         
        case "huge":
        case 7:
          url.push("&imgsz=huge");
          break;
      }
    }
        
    if (search.options.colorOnly)
      url.push("&imgc=color");
    else if (search.options.blackWhiteOnly)
      url.push("&imgc=gray");
    if (search.options.format) //bmp, gif, jpeg, png, or any (default)
      url.push("&format=search.options.format");
  }
  
  
  url.push("&q="+encodeURIComponent(term)); 
  url.push("&key=ABQIAAAA9cRPVM_n_SVX8o_xWz8Q0BT2yXp_ZAY8_ufC3CFXhHIE1NvwkxS6irDhqsSmBJoJM0R6LYp4pL-8Bw");
  url.push("&start="+offset);
  url.push("&callback=GoogleWebSearch.SearchCallback");
  url.push("&context="+id);  
  
  url.push("&r="+new Date().valueOf());
  addScript(url.join(''),"GoogleSearch_"+id);
}

GoogleWebSearch.SearchCallback = function(id,googleresults,c,d,e,f,g,h)
{
  //$("GoogleSearch_"+id).remove.delay(0);
  
  var search = GoogleWebSearch.searchData[id];
  if (!search)
    return;
  var resultsArr = googleresults && googleresults.results;
  var cursor = googleresults && googleresults.cursor;        
  if (!cursor || !resultsArr || !cursor.pages) //nothing found
  {
    notifyEngineResultsEstimation("Google",id,0);
    notifyEngineResults("Google",id, [], search.offset, false);
    GoogleWebSearch.searchData[id] = null;
    return;
  }
  var hasMore = cursor.currentPageIndex+1 < cursor.pages.length;
  var resultIdx = parseInt(cursor.pages[cursor.currentPageIndex].start);
  var lastResultIdx = parseInt(resultIdx + resultsArr.length);  
  var ret = [];
  if (resultIdx==0)
  {    
    var lastResultIdx = cursor.pages.length * resultsArr.length;
    notifyEngineResultsEstimation("Google",id,cursor.estimatedResultCount, Math.min(cursor.estimatedResultCount,lastResultIdx));
  }
  for(var i=0,j=resultsArr.length;i<j;i++)
  {
    if (search.options.searchType=="web")
    {
      ret.push( 
      {
        rank : i,
        title: resultsArr[i].title,
        description: sanitize(resultsArr[i].content),
        url: Url.decode(resultsArr[i].url),
        visibleUrl: Url.decode(resultsArr[i].visibleUrl),
        clearTitle : resultsArr[i].titleNoFormatting
      });
    } 
    else if (search.options.searchType=="image")
    {
      ret.push(
      {
        Url: resultsArr[i].visibleUrl,
        ClickUrl : resultsArr[i].unescapedUrl,
        //FileFormat : resultsArr[i].FileFormat,
        //FileSize : resultsArr[i].FileSize,
        Height : resultsArr[i].height,
        Width : resultsArr[i].width,
        Summary: resultsArr[i].content,
        SummaryText: resultsArr[i].contentNoFormatting,
        Title : resultsArr[i].titleNoFormatting,
        ThumbnailUrl: resultsArr[i].tbUrl,
        ThumbnailHeight: resultsArr[i].tbHeight,
        ThumbnailWidth: resultsArr[i].tbWidth        
      });
    }
  }
  notifyEngineResults("Google",id,ret,resultIdx, hasMore);
  search.total += ret.length;
  if (search.total <= search.required && hasMore)
  {      
    GoogleWebSearch.searchFunc(search.term, search.id, search.offset+search.total, search.options);
  }
  else
    GoogleWebSearch.searchData[id] = null;
}


GoogleWebSearch.CreateSearch = function(term, id, options)
{
  var srch = new Search(this, term, id, options);
  srch.InternalGetPage = function (pageNumber, pageReadyCallback, notifyEstimatesCallback)
  {
    var additionalOffset = 0;
    if (this.Pages[pageNumber])
    {
      additionalOffset = this.Pages[pageNumber].length;
    }
    
    GoogleWebSearch.searchFunc(this.term, this.id, additionalOffset+(pageNumber-1)*searchResultsToShow, options);
  }
  return srch;
}
GoogleWebSearch.Register();
///// LIVE    
var LiveSearch = new SearchEngine({name:"Live", desc:"MSN Live Search", imageUrl:"Images/new/live.gif"});
/*LiveSearch.searchFunc = function(term, id, offset, opts)
{  
  var url = "LiveSearch.ashx?q="+escape(term)+"&id="+id+"&num="+searchResultsToShow;
  if (offset)
    url += "&o="+offset;
    
//  if (opts.ilang && this.interfaceLanguages && this.interfaceLanguages[opts.ilang])
//    url += ("&lr="+this.interfaceLanguages[opts.ilang]);
  if (opts.lang && this.languages && this.languages[opts.lang])
    url += ("&language="+this.languages[opts.lang]);
  if (opts.country && this.countries && this.countries[opts.country])
    url += ("&country="+this.countries[opts.country]);  
    
  addScript(url,"LiveSearch_"+id);
}   

LiveSearch.CreateSearch = function(term, id, options)
{
  var srch = new Search(this, term, id, options);
  srch.InternalGetPage = function (pageNumber, pageReadyCallback, notifyEstimatesCallback)
  {
    LiveSearch.searchFunc(this.term, this.id, (pageNumber-1)*searchResultsToShow, options);
  }
  return srch;
}*/
LiveSearch.searchData = {};
LiveSearch.liveCallbacks = {};
LiveSearch.searchFunc = function doGoogleSearch(term, id, offset, opts)
{
  var search = LiveSearch.searchData[id] || {id: id, total:0, required: searchResultsToShow, offset:offset, term:term, options:opts};
  LiveSearch.searchData = {};
  LiveSearch.searchData[id] = search;
  var url = [];
  LiveSearch.liveCallbacks[id] = function(response) { LiveSearch.ProcessSearchResults(response,id);}
  url.push("http://api.search.live.net/json.aspx?Version=2.0");
  url.push("&AppId=5DE6D123674B9E08A96B4E4D1B9ED8F19B53AD34");
  url.push("&Query="+encodeURIComponent(term));  
  url.push("&JsonType=callback");
  url.push("&JsonCallback=LiveSearch.liveCallbacks["+id+"]");  
  url.push("&r="+new Date().valueOf());
  
  if (search.options.country && this.countries && this.countries[search.options.country])
      url+=("&Market="+this.countries[search.options.country]);
  if (search.options.adult_ok)
     url.push("&Adult=Off");
  else if (search.options.safeContent)
     url.push("&Adult=Strict");
  else
     url.push("&Adult=Moderate");
     
  if (search.options.searchType=="web")
  {  
    url.push("&Sources=Web");
    url.push("&Web.Count=8");
    url.push("&Web.Offset="+offset);    
  }
  else if (search.options.searchType=="image")
  {
    url.push("&Sources=Image");
    url.push("&Image.Count=8");
    url.push("&Image.Offset="+offset);    
  }
  addScript(url.join(''),"LiveSearch_"+id);
}


LiveSearch.ProcessSearchResults = function(response,id)
{
  var search = LiveSearch.searchData[id];
  if (!search)
    return;
  var errors = response.SearchResponse.Errors;
  var results = null;
  if (search.options.searchType=="image")
  {
    results = response.SearchResponse.Image;
  } else if (search.options.searchType=="web")
  {
    results = response.SearchResponse.Web;
  }
  
  if (errors != null || results.Results == null)
  {
      // There are errors in the response. Display error details.
    notifyEngineResultsEstimation("Live",id,0);
    notifyEngineResults("Live",id, [], search.offset, false);
    LiveSearch.searchData[id] = null;
    return;
  }

  
  
  var offset = results.Offset;
  var total = results.Total;
  var resultCount = results.Results.length;
  
  var hasMore = offset+resultCount < total;
  var resultIdx = offset;
  var lastResultIdx = offset + resultCount;
  var ret = [];
  if (resultIdx==0)
  {    
    notifyEngineResultsEstimation("Live",id,total, total);
  }
  for(var i=0,j=results.Results.length;i<j;i++)
  {
    var item = results.Results[i];
    if (search.options.searchType=="web")
    {
      ret.push(
      {
        rank : i,
        title: item.Title || "",
        description: item.Description || "",
        url: item.Url || "",
        visibleUrl: item.DisplayUrl || ""
      });
    }
    else if (search.options.searchType=="image")
    {
      ret.push(
      {
        Url: item.DisplayUrl || "",
        ClickUrl : item.MediaUrl || "",
        FileSize : item.FileSize,
        Height : item.Height,
        Width : item.Width,
        Summary: item.Title || "",
        Title : item.Title || "",
        ThumbnailUrl: item.Thumbnail.Url || "",
        ThumbnailHeight: item.Thumbnail.Height,
        ThumbnailWidth:item.Thumbnail.Width    
      });
    }
  }
  notifyEngineResults("Live",id,ret,resultIdx, hasMore);
  search.total += ret.length;
  if (search.total <= search.required && hasMore)
  {      
    LiveSearch.searchFunc(search.term, search.id, search.offset+search.total, search.options);
  }
  else
    LiveSearch.searchData[id] = null;
}

LiveSearch.CreateSearch = function(term, id, options)
{
  var srch = new Search(this, term, id, options);
  srch.InternalGetPage = function (pageNumber, pageReadyCallback, notifyEstimatesCallback)
  {
    var additionalOffset = 0;
    if (this.Pages[pageNumber])
    {
      additionalOffset = this.Pages[pageNumber].length;
    }
    
    LiveSearch.searchFunc(this.term, this.id, additionalOffset+(pageNumber-1)*searchResultsToShow, options);
  }
  return srch;
}

LiveSearch.Register();
///// YAHOO
var YahooSearch = new SearchEngine({name:"Yahoo", desc:"Yahoo Web Search",imageUrl:"Images/new/yahoo.gif"});
YahooSearch.yahooSearches = {};
YahooSearch.yahooCallbacks = {};
YahooSearch.SearchFunc = function(term, id, offset, opts)
{
  var search = YahooSearch.yahooSearches[id] || {id: id, total:0, required: searchResultsToShow, offset:offset, term:term, options:opts};
  YahooSearch.yahooSearches = {};
  YahooSearch.yahooSearches[id] = search;

  if (search.options.searchType=="web")
  {
    var url = 'http://search.yahooapis.com/WebSearchService/V1/webSearch?appid=keIChznV34GJf03Uj6O3C_XWbpAOjEoqZExGlIDZE0ukywtt0zlsYp4DQmBqxI3px9tyJlA1F5OuXg--&output=json&callback=YahooSearch.yahooCallbacks['+id+']&results='+searchResultsToShow+'&query=' + term;
    if (offset)
      url +="&start="+String(offset+1);
    if (search.options.lang && this.languages && this.languages[search.options.lang])
      url+=("&language="+this.languages[search.options.lang]);
    if (search.options.country && this.countries && this.countries[search.options.country])
      url+=("&country="+this.countries[search.options.country]);
      
    YahooSearch.yahooCallbacks[id] = function(response) { YahooSearch.ProcessYahooSearchResults(response,id);}
  }
  else if (search.options.searchType=="image")
  {
    var url = 'http://search.yahooapis.com/ImageSearchService/V1/imageSearch?appid=keIChznV34GJf03Uj6O3C_XWbpAOjEoqZExGlIDZE0ukywtt0zlsYp4DQmBqxI3px9tyJlA1F5OuXg--&output=json&callback=YahooSearch.yahooCallbacks['+id+']&results='+searchResultsToShow+'&query=' + term;
    if (search.options.adult_ok)
      url+=("&adult_ok=1");
    if (search.options.colorOnly)
      url+=("&coloration=color");
    else if (search.options.blackWhiteOnly)
      url+=("&coloration=bw");
    if (search.options.format) //bmp, gif, jpeg, png, or any (default)
      url+=("&format="+search.options.format);
      
    YahooSearch.yahooCallbacks[id] = function(response) { YahooSearch.ProcessYahooSearchResults(response,id);}
  }
  if (offset)
      url +="&start="+String(offset+1);
  addScript(url,'YahooSearch_'+id);
}
YahooSearch.ProcessYahooSearchResults = function(response,id)
{
  //Cleanups
  YahooSearch.yahooCallbacks[id] = null;
  //$("YahooSearch_"+id).remove.delay(0);
  
  var search = YahooSearch.yahooSearches[id];    
  var ret = [];
  if (response.Error)
  {
    notifyEngineResults("Yahoo", id, ret, false, false);
    return;
  }
  if (search.offset==0)
  {
    notifyEngineResultsEstimation("Yahoo",id,response.ResultSet.totalResultsAvailable);
  } 
  var resultsArr = response.ResultSet.Result;
  for (var i=0,j=resultsArr.length;i<j;i++)
  {
    if (search.options.searchType=="web")
    {
      ret.push(
      {
        rank : i,
        title: resultsArr[i].Title,
        description: resultsArr[i].Summary,
        url: "http://"+resultsArr[i].DisplayUrl
      });
    } else if (search.options.searchType=="image")
    {
      ret.push(
      {
        Url: resultsArr[i].ReferrerUrl,
        ClickUrl : resultsArr[i].ClickUrl,
        FileFormat : resultsArr[i].FileFormat,
        FileSize : resultsArr[i].FileSize,
        Height : resultsArr[i].Height,
        Width : resultsArr[i].Width,
        Summary: resultsArr[i].Summary,
        Title : resultsArr[i].Title,
        ThumbnailUrl: resultsArr[i].Thumbnail.Url,
        ThumbnailHeight: resultsArr[i].Thumbnail.Height,
        ThumbnailWidth: resultsArr[i].Thumbnail.Width        
      });
    }
  }
  var firstResponse = response.ResultSet.firstResultPosition;
  var lastResponse = firstResponse + response.ResultSet.Result.length - 1;
  var hasMore = lastResponse < response.ResultSet.totalResultsAvailable;
  
  if (!hasMore || ret.length == searchResultsToShow)
  {
    notifyEngineResults("Yahoo", id, ret, search.offset, hasMore);
    YahooSearch.yahooSearches = {};
  } 
  //if need to search more: doYahooSearch(null,id,response.ResultSet.moreUrl);
}

YahooSearch.CreateSearch = function(term, id, options)
{
  var srch = new Search(this, term, id, options);
  srch.InternalGetPage = function (pageNumber, pageReadyCallback, notifyEstimatesCallback)
  {
    YahooSearch.SearchFunc(this.term, this.id, (pageNumber-1)*searchResultsToShow, options);
  }
  return srch;
}
YahooSearch.Register();
/** 
 * Author and Version Information {{{
 * author: Antonio Ramirez http://webeaters.blogspot.com
 *
 * class: AutoComplete for Prototype 1.6.0
 *
 * version: 1.2.1 - 2007-11-11 
 * 		(based on AutoSuggest 2.1.3 - 2007-07-19)
 * version: 1.3.0 - 2008-01-03 by Andrew Nicols <andrew@nicols.co.uk>
 *  - Fixed incorrect title-casing - CSS is Case Sensitive!!!
 *  - Adjusted the way in which the Notifier images are loaded.
 *  - Changed json code to pass all json variables back instead of just id, value and name
 *  - Fixed 'GMAIL' code such that if valueSep is undefined, it is ignored
 *  - Changed the default for valueSep to null
 *  - Fixed the resetTimeout function
 * version: 1.3.1 - 2008-09-13 (AW)
 *  - Fixed caching filtering when the filtered set is empty(refresh cache)
 *  - Added support for non-AJAX calls ("manualJson:true", using providers and callbacks)
 *
 * REFERENCES AND THANKS 
 * this class is based on the work in AutoSuggest.js of
 * Timothy Groves - http://www.brandspankingnew.net
 * and adapted for use with prototype 1.6.0
 *
 * UPDATED by R��da HADJOUTI
 * GMAIL like AutoComplete (semicolon separator) Update
 *
 * UPDATED by Alon Weiss
 * version 1.3.1
 *
 }}}*/

var AutoComplete = Class.create();

AutoComplete.prototype = { // {{{
  Version: '1.3.0',
  REQUIRED_PROTOTYPE: '1.6.0',

  initialize: function (id, param) { // {{{
  	// check whether we have the appropiate javascript libraries
  	this.PROTOTYPE_CHECK();
	
    // Get the field we're watching.
    // It needs to be a valid field so throw an error if it's not valid or can't be found.
    this.fld = $(id);
    if (!this.fld)
    {
      throw("AutoComplete requires a field id to initialize");
    }
	
    // Init variables
    this.sInp 	= ""; // input value 
    this.nInpC 	= 0;	// input value length
    this.aSug 	= []; // suggestions array 
    this.iHigh 	= 0;	// level of list selection 
	
  // Parameter Handling {{{
	// Set the use specified options
	this.options = param ? param : {};
	// These are the default settings {{{
  var k, def = {
    valueSep:null,
    minchars:1,
    meth:"get",
    varname:"input",
    className:"autocomplete",
    timeout:3000,
    delay:500,
    offsety:-5,
    shownoresults: true,
    noresults: "No results were found.",
    maxheight: 250,
    cache: true,
    maxentries: 25,
    onAjaxError:null,
    setWidth: false,
    minWidth: 100,
    maxWidth: 200,
    useNotifier: true
  };
  //}}}
  // Overlay any values which weren't user specified.
	for (k in def) 
	{
		if (typeof(this.options[k]) != typeof(def[k]))
			this.options[k] = def[k];
	}
  // End of Parameter Handling }}}

  // Not everyone wants to use the Notifier. Give them the option	
	if (this.options.useNotifier)
  {
    this.fld.addClassName('ac_field');
  }

	// set keyup handler for field
	// and prevent AutoComplete from client
	var p = this;
	
	// NOTE: not using addEventListener because UpArrow fired twice in Safari		
	this.enterHandler = this.options.onChoose;
	this.fld.onkeypress 	= function(ev){ return p.onKeyPress(ev); };
	this.fld.onkeyup      = function(ev){ return p.onKeyUp(ev); };
	this.fld.onkeydown      = function(ev){ return p.onKeyDown(ev); };
	
  // ARN-DEBUG Chances are we want to reset the timeout when they lose focus, at least that's what I prefer
	this.fld.onblur			  = function(ev){ p.resetTimeout(); return true; };	
  // ARN-DEBUG Not sure what this is about!
	this.fld.setAttribute("AutoComplete","off");

  }, //}}}

  convertVersionString: function (versionString){ // {{{
      var r = versionString.split('.');
      return parseInt(r[0])*100000 + parseInt(r[1])*1000 + parseInt(r[2]);
  }, // }}}

  PROTOTYPE_CHECK: function() { // {{{
    if((typeof Prototype=='undefined') || 
       (typeof Element == 'undefined') || 
       (typeof Element.Methods=='undefined') ||
       (this.convertVersionString(Prototype.Version) < 
        this.convertVersionString(this.REQUIRED_PROTOTYPE)))
       throw("AutoComplete requires the Prototype JavaScript framework >= " +
        this.REQUIRED_PROTOTYPE);
  }, // }}}

  // set responses to keypress events in the field
  // this allows the user to use the arrow keys to scroll through the results
  // ESCAPE clears the list
  // RETURN sets the current highlighted value
  // UP/DOWN move around the list

  onKeyPress: function (e) { // {{{
  	if (!e) e = window.event;
  	var key	= e.keyCode || e.which;
  	

    switch(key)
    {
      case Event.KEY_RETURN:
      if (this.iHigh && this.acID && $(this.acID))
      {
          this.setHighlightedValue();
          Event.stop(e);
      } else if (this.enterHandler)
        this.enterHandler();
      break;
      case Event.KEY_TAB:
        this.setHighlightedValue();
        //Event.stop(e);
        break;
      case Event.KEY_ESC:
        this.clearSuggestions();
        break;
    }
    return true;
  }, //}}}

  onKeyDown : function(e)
  {
    if (!e) e = window.event;
  	var key	= e.keyCode || e.which;
  	
    if (key == Event.KEY_UP || key == Event.KEY_DOWN)
    {
    this.changeHighlight(key);
  		  Event.stop(e);
    }
  },

  onKeyUp: function (e) { // {{{
  	if (!e) e = window.event;
  	
  	var key = e.keyCode || e.which;
  	
  	if (false && (key == Event.KEY_UP || key == Event.KEY_DOWN)) 
  	{
  		this.changeHighlight(key);
  		Event.stop(e);
  	}
  	else this.getSuggestions(this.fld.value);
  	
	return true;
  }, //}}}

  getSuggestions: function(val) { // {{{
  	// input the same? do nothing
  	if(val==this.sInp) return false;
  	// kill the old list
  	if($(this.acID)) $(this.acID).remove();
  	AutoSuggestQuery.abort();
  	this.sInp = val;
  	
  	// input length is less than the min required to trigger a request
  	// do nothing
  	if (val.length < this.options.minchars)
  	{
  		this.aSug 	= [];
  		this.nInpC	= val.length; 
  		return false;
  	}

  	// Here we will detect if there is a comma and the splitted value has a value to check
  	// comma stars a new search and val is converted to the new value after the comma
  	var ol	= this.nInpC; // old length
  	this.nInpC	= val.length ? val.length : 0;
  	
  	// if caching enabled, and we didn't receive the maxentries value
    // and user is typing (ie. length of input is increasing)
  	// filter results out of suggestions from last request
  	var l = this.aSug.length;
  	var success = false;
  	if( this.options.cache && ( this.nInpC > ol ) && l && ( l < this.options.maxentries ) )
  	{
  		var arr = new Array();
  		for (var i=0;i<l;i++) {
  			if (this.aSug[i].value.toLowerCase().indexOf(val.toLowerCase()) != -1)
        {
  				arr.push(this.aSug[i]);
        }
  		}
  		this.aSug = arr;
  		if (arr.length>0)
  		{
  		  success = true;
  		  // recreate the list
  		  this.createList(this.aSug);
  		}
  	}
  	if (!success) {
  		// do new request
  		var p = this;
  		//var input	= this.sInp; // send the converted new value (comma)
  		clearTimeout(this.ajID); // ajax id timer
  		this.ajID = setTimeout( function () {p.doAjaxRequest(p.sInp)}, this.options.delay);
  	}
    document.helper = this;	
  	return false;
  }, // }}}

  getLastInput : function(str) { // {{{
  	var ret = str;
  	if (undefined != this.options.valueSep) {
  		var idx = ret.lastIndexOf(this.options.valueSep);
      ret = idx == -1 ? ret : ret.substring(idx + 1, ret.length);
  	}
  	
  	return ret;
  }, // }}}

  doAjaxRequest: function (input) { // {{{
  	// we have to check here if there is a new splitted value (, or ;)
  	// always check against the last part of the comma and then check
  	// saved input is still the value of the field
  	if (input != this.fld.value) 
  		return false;
  	
  	// Gmail like : get only the last user's input
  	this.sInp = this.getLastInput(this.sInp);
 	
  	// create ajax request
  	// do we need to call a function to recreate the url?
  	if (typeof this.options.script == 'function')
  		var url = this.options.script(encodeURIComponent(this.sInp));
  	else
  		var url = this.options.script+this.options.varname+'='+encodeURIComponent(this.sInp);
  	
  	if(!url) return false;
  	
  	var p = this;
  	var m = this.options.meth;  // get or post?
    if( this.options.useNotifier )
    {
      this.fld.removeClassName('ac_field');
	    this.fld.addClassName('ac_field_busy');
    };
  	
  	var options = {
  		method: m,
  		onSuccess: function (req) { // {{{
        if( p.options.useNotifier )
        {
          p.fld.removeClassName('ac_field_busy');
          p.fld.addClassName('ac_field');
        };
        p.setSuggestions(req,input);
  		}, // }}}

  		onFailure: (typeof p.options.onAjaxError == 'function')? function (status) { // {{{
        if (p.options.useNotifier)
        {
          p.fld.removeClassName('ac_field_busy');
          p.fld.addClassName('ac_field');
        }
        p.options.onAjaxError(status)
      } : // }}}

      function (status) { // {{{
        if (p.options.useNotifier)
        {
          p.fld.removeClassName('ac_field_busy');
          p.fld.addClassName('ac_field');
        }
        alert("AJAX error: "+status); 
      } // }}}
    }
    if (typeof(url)=="object")
    {
      url.completionData = options;
    }  
    else
    {
  	  // make new ajax request
  	  new Ajax.Request(url, options);
  	}
  }, // }}}

  setSuggestions: function (req, input) { // {{{
	  // if field input no longer matches what was passed to the request
	  // don't show the suggestions
	  // here we need to check against the splitted values if any (, or ;)
    if (input != this.fld.value)
      return false;
	
    this.aSug = [];
	
	  if(this.options.manualJson) 
	  {
	    this.aSug = req;
	  }
    else if(this.options.json) 
    { // response in json format?
      var jsondata = eval('(' + req.responseText + ')');
      this.aSug = jsondata.results;
    } else {
      // response in xml format?
      var results = req.responseXML.getElementsByTagName('results')[0].childNodes;
    
      for(var i=0;i<results.length;i++)
      {
        if(results[i].hasChildNodes())
          this.aSug.push(  { 'id':results[i].getAttribute('id'), 'value':results[i].childNodes[0].nodeValue, 'info':results[i].getAttribute('info') }  );
      }
    }
    this.acID = 'ac_'+this.fld.id;
    this.createList(this.aSug);
  }, // }}}

  createDOMElement: function ( type, attr, cont, html ) { // {{{
    var ne = document.createElement( type );
	
    if (!ne)
      return 0;
      
    for (var a in attr)
      ne[a] = attr[a];
    
    var t = typeof(cont);
    
    if (t == "string" && !html)
      ne.appendChild( document.createTextNode(cont) );
    else if (t == "string" && html)
      ne.innerHTML = cont;
    else if (t == "object")
      ne.appendChild( cont );

    return ne;
  }, // }}}

  createList:	function(arr) { // {{{
    // get rid of the old list if any  
  	if($(this.acID)) $(this.acID).remove();
  	
  	// clear list removal timeout
  	this.killTimeout();
  	
  	// if no results, and showNoResults is false, do nothing
  	if (arr.length == 0 && !this.options.shownoresults) return false;
  	
  	// create holding div
  	var div	= this.createDOMElement('div', {id:this.acID, className:this.options.className});
  	
  	// create div header
  	var hcorner = this.createDOMElement('div', {className: 'ac_corner'});
  	var hbar	= this.createDOMElement('div', {className: 'ac_bar'});
  	var header	= this.createDOMElement('div', {className: 'ac_header'});
  	header.appendChild(hcorner);
  	header.appendChild(hbar);
  	div.appendChild(header);
  	
    // create and populate ul
    var ul	= this.createDOMElement('ul', {id:'ac_ul'});
    var p 	= this; // pointer that we will need later on
    // no results?
    if (arr.length == 0 && this.options.shownoresults)
    {
      var li = this.createDOMElement('li', {className: 'ac_warning'}, this.options.noresults );
      ul.appendChild(li);
    } else {
      var sInpLength = this.sInp.strip().length;
      // loop through arr of suggestions creating an LI element for each of them
      for (var i=0,l = arr.length; i<l; i++)
      {
        // format output with the input enclosed in a EM elementFromPoint
        // (as HTML not DOM)
        var val 	= arr[i].value;
        var st 		= val.toLowerCase().indexOf(this.sInp.toLowerCase()); // HERE WE CHECK AGAINST THE SPLITTED VALUE IF ANY***
        var output 	= (st<0) ? val : (val.substr(0,st) + '<em>' + val.substr(st,st+sInpLength) + '</em>' + val.substr(st+sInpLength));
			
        var span	= this.createDOMElement('span',{},output,true); // type of, properties, output, isHTML?
			
        if(arr[i].info != '') // do we need to add extra info?
        {
          var br	= this.createDOMElement('br',{});
          span.appendChild(br);
          
          var small = this.createDOMElement('small',{}, arr[i].info);
          span.appendChild(small);
        }
        var a 	= this.createDOMElement('a',{href:'#'});
        
        var tl	= this.createDOMElement('span',{className:'tl'},'&nbsp;',true);
        var tr	= this.createDOMElement('span',{className:'tr'},'&nbsp;',true);
        
        a.appendChild(tl);
        a.appendChild(tr);
        a.appendChild(span); // add the object span into the link
			
        a.name = i+1;
        
        a.onclick 		= function () { // {{{
          p.setHighlightedValue();
          return false; 
        }; // }}}
        a.onmouseover	= function () { // {{{
          p.setHighlight(this.name); 
        }; // }}} 
			
        var li = this.createDOMElement('li', {}, a); // add the link element to a li element
        
        // finally add the newly created li element to the ul element 
        ul.appendChild(li);
      }
    }
    
    div.appendChild(ul); // add the newly created list to the div element
    
    // create div footer
    var fcorner = this.createDOMElement('div', {className: 'ac_corner'});
  	var fbar	= this.createDOMElement('div', {className: 'ac_bar'});
  	var footer	= this.createDOMElement('div', {className: 'ac_footer'});
  	footer.appendChild(fcorner);
  	footer.appendChild(fbar);
  	div.appendChild(footer);
  	
  	// get position of target textfield
    // position holding div below it
    // set width of holding div to width of field 
    // if 
    
    var pos         = this.fld.cumulativeOffset();
    div.style.left 	= pos[0] + "px";
    div.style.top 	= pos[1] + this.fld.offsetHeight + "px";
    
    var w = 
    (
      this.options.setWidth && this.fld.offsetWidth < this.options.minWidth
    )
    ? this.options.minWidth : 
    (
      this.options.setWidth && this.fld.offsetWidth > this.options.maxWidth
    )
    ? this.options.maxWidth : 
    this.fld.offsetWidth;

    
    div.style.width 	= w + "px";
    
    // 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
    //
    div.onmouseover 	= function(){ p.killTimeout() };
    div.onmouseout 		= function(){ p.resetTimeout() };
    
    // add DIV to document
    document.getElementsByTagName("body")[0].appendChild(div);
    
    
    // highlight first item
    //this.iHigh = 1;
    //this.setHighlight(1);
    this.iHigh = 0;
    
    // remove list after interval
    this.toID	= setTimeout(
      function () {
        p.clearSuggestions() 
      }, this.options.timeout
    );
	
  }, // }}}

  changeHighlight:	function(key) { // {{{
  	var list = $("ac_ul");
    if (!list)
      return false;
	
    var n;

    n = (key == Event.KEY_DOWN || key == Event.KEY_TAB)? this.iHigh + 1 : this.iHigh - 1; // false assumed to be Event.KEY_UP
    
    n = (n > list.childNodes.length)? list.childNodes.length : ((n < 1)? 1 : n);	
    
    this.setHighlight(n);
  }, // }}}

  setHighlight:		function(n) { // {{{
  	var list = $('ac_ul');
  	
  	if (!list) return false;
  	
  	if (this.iHigh > 0) this.clearHighlight();
  	
  	this.iHigh = Number(n);
  	
  	list.childNodes[this.iHigh-1].className = 'ac_highlight';
  	this.killTimeout();
  }, // }}}

  clearHighlight:	function() { // {{{
  	var list = $('ac_ul');
  	
  	if(!list) return false;
  	
  	if(this.iHigh > 0)
  	{
  		list.childNodes[this.iHigh-1].className = '';
  		this.iHigh = 0;
  	}
  	
  }, // }}}

  setHighlightedValue:	function() { // {{{
  	if (this.iHigh)
  	{
  		// HERE WE NEED TO IMPLEMENT THE GMAIL LIKE SPLITTED VALUE
  		if (!this.aSug[this.iHigh - 1]) return;
  		
  		// Gmail like
      if (undefined != this.options.valueSep) {
        var str = this.getLastInput(this.fld.value);
        var idx = this.fld.value.lastIndexOf(str);
        str = this.aSug[ this.iHigh -1 ].value + this.options.valueSep;
        this.sInp = this.fld.value = idx == -1 ? str : this.fld.value.substring(0, idx) + str;
      } else {
        var str = this.getLastInput(this.fld.value);
        var idx = this.fld.value.lastIndexOf(str);
        str = this.aSug[ this.iHigh -1 ].value;
        this.sInp = this.fld.value = idx == -1 ? str : this.fld.value.substring(0, idx) + str;
      }
  		
  		// move cursor to end of input (safari)
  		this.fld.focus();
  		if(this.fld.selectionStart)
  			this.fld.setSelectionRange(this.sInp.length, this.sInp.length);
  			
  		this.clearSuggestions();
  		
  		// pass selected object to callback function, if exists
  		if (typeof this.options.callback == 'function')
  			this.options.callback(this.aSug[this.iHigh-1]); // the object has the properties we want, it will depend of
  	}
  }, // }}}

  killTimeout:	function() { // {{{
  	clearTimeout(this.toID);
  }, // }}}

  resetTimeout:	function() { // {{{
  	this.killTimeout();
  	var p = this;
  	this.toID = setTimeout(
      function () { 
        p.clearSuggestions();
      }, p.options.timeout
    );
    // ARN-DEBUG Added p.options.timeout back :|
  }, // }}}

  clearSuggestions:	function () { // {{{
    this.killTimeout();
    if ($(this.acID))
    {
      this.fadeOut(300,function () {
        $(this.acID).remove();
      } );
    }
  }, // }}}

  fadeOut:	function (milliseconds, callback) { // {{{
  	this._fadeFrom 	= 1;
  	this._fadeTo	= 0;
  	this._afterUpdateInternal = callback;
  	
  	this._fadeDuration	= milliseconds;
  	this._fadeInterval = 50;
  	this._fadeTime = 0;
  	var p = this;
  	this._fadeIntervalID = setInterval(
      function() {
        p._changeOpacity()
      }, this._fadeInterval
    );
  
  }, // }}}

  _changeOpacity: function() { // {{{
 
    if (!$(this.acID))
    {
  		this._fadeIntervalID=clearInterval(this._fadeIntervalID);
  		return;
  	} 
  	this._fadeTime += this._fadeInterval;
  	
  	var ieop = Math.round( (this._fadeFrom + ((this._fadeTo - this._fadeFrom) * (this._fadeTime/this._fadeDuration))) * 100)
  	var op = ieop / 100;
 
  	var el = $(this.acID);
  	if (el.filters) // internet explorer
  	{
      try {
        el.filters.item("DXImageTransform.Microsoft.Alpha").opacity = ieop;
      } catch (e) { 
        // If it is not set initially, the browser will throw an error.
        // This will set it if it is not set yet.
        el.style.filter = 'progid:DXImageTransform.Microsoft.Alpha(opacity='+ieop+')';
      }
    } else	{
      el.style.opacity = op;
    }
	
    if (this._fadeTime >= this._fadeDuration)
    {
      clearInterval( this._fadeIntervalID );
      if (typeof this._afterUpdateInternal == 'function')
        this._afterUpdateInternal();
    }

  } // }}}
 
} // }}}

// vim: set filetype=javascript foldmethod=marker foldlevel=5:


TabControl = function(id)
{
  this.build(id);
}
TabControl.prototype.build = function(id)
{
  this._element = $(id);
  this._control = this;
  this.cells = this._element.cells || this._element.tBodies[0].rows[0].childNodes;
  
  var selectedIdx = -1;
  var selectedCell = null;
  for (var i=0,j=this.cells.length,k=0;i<j;i++)
  {
    var cell = $(this.cells[i]);
    if (cell.nodeType!=1)
      continue;
    if (k++ == 0)
      selectedCell= cell;
    cell.tabPageIndex = k;
    
    if (cell.hasClassName('Spacer'))
      continue;
    if (cell.hasClassName('SelectedTab'))
      selectedCell = cell;   
     else
      cell.addClassName('UnselectedTab');
    cell.value = cell.readAttribute('value'); 
      
    cell.observe('click', this.TabPageClicked.bind(this, cell));
  }
  this.TabPageClicked(selectedCell);    
}
TabControl.prototype.TabPageClicked = function(cell)
{
  if (this._selectedCell == cell)
    return;
  if (this._selectedCell!=null)
  {
    this._selectedCell.removeClassName('SelectedTab');
    this._selectedCell.addClassName('UnselectedTab');
    this._selectedCell.checked = false;
  }
  if (cell!=null)
  {
    cell.removeClassName('UnselectedTab');
    cell.addClassName('SelectedTab');
    cell.checked = true;
  }
  this._selectedCell = cell;
  if (this.OnSelectionChanged)
    this.OnSelectionChanged(cell);
}
TabControl.prototype.GetValue = function()
{
  return this._selectedCell && this._selectedCell.value;
}
TabControl.prototype.SetValue = function(v)
{
  var cells = this._element.cells;
  for (var i=0,j=this.cells.length;i<j;i++)
  {
    var cell = $(this.cells[i]);
    if (cell.value==v)
    {
      this.TabPageClicked(cell);
      return;
    }
  }
}

