// This is the code that makes the search interface go

dojo.provide("bl.search");

dojo.require("dojo.event");
dojo.require("dojo.event.browser");
dojo.require("dojo.string");
dojo.require("dojo.lfx.html");
dojo.require("dojo.io.cookie");
dojo.require("dojo.html.extras");
dojo.require("bl.dom-extensions");
dojo.require("bl.html-extensions");
dojo.require("bl.alg");
dojo.require("bl.event");

bl.search.parseUrlForSiteAndPost = function(url) {
  var siteMatch = url.match(/siteid=(\d+)/);
  var itemMatch = url.match(/itemid=(\d+)/);
  return {
        success: siteMatch != null && itemMatch != null,
        site: siteMatch == null ? -1 : siteMatch[1],
        item: itemMatch == null ? -1 : itemMatch[1]
    };
}

bl.search.parseUrlForSite = function(url) {
  var siteMatch = url.match(/siteid=(\d+)/);
  return {
        success: siteMatch != null,
        site: siteMatch == null ? -1 : siteMatch[1]
    };
}

bl.search.changeNumPerPage = function(n) {
  var url = window.location.search;
  url = url.replace(/&?f=\d+/, "");
  if(url.search(/([\?&])n=\d+/) >= 0) 
    url = url.replace(/([\?&])n=\d+/, "$1n=" + n.toString());
  else 
    url += "&n=" + n.toString();

  dojo.io.cookie.set("bl_search_n", n, 365*100);

  window.location.search = url;
}

bl.search.changePop = function(pop) {
  var url = window.location.search;
  if(url.search(/([\?&])pop=\w+/) >= 0)
    url = url.replace(/([\?&])pop=\w+/, "$1pop=" + pop); 
  else
    url += "&s=f&pop=" + pop;

  dojo.io.cookie.set("bl_search_pop", pop, 365*100);

  window.location.search = url;
}

bl.search.changeLastModifier = function(last) {
  var url = window.location.search;

  if(url.search(/last:\w+/) >= 0)
    url = url.replace(/last:\w+/, last);
  else if(url.search(/([\?&])q=([^\&]+)/) >= 0)
    url = url.replace(/([\?&])q=([^\&]+)/, "$1q=$2+"+last); 
  else 
    alert(url);
  window.location.search = url;
}

bl.search._delayedPreviewTimer = null;
bl.search._delayedPreviewUrl = null;

bl.search.delayedPreviewShow = function(evt) {
  var myEvt = bl.event.clone(evt);
  var bubble = bl.search.PreviewBubble();
  var urls = bl.search.getPreviewUrlsFromEvent(evt);
  if(!urls) return;
  if(bubble.isShowing(bl.search.getMatch(evt.target))) return;
  bl.search._delayedPreviewTimer = window.setTimeout(function() {
    if(!bubble.isShowing(bl.search.getMatch(myEvt.target))) bubble.load(myEvt, urls.data, urls.tracking);
    bl.search._delayedPreviewTimer = null;
    bl.search._delayedPreviewUrl = null;
  }, 500);
  bl.search._delayedPreviewUrl = urls.data;
}

bl.search.delayedPreviewCancel = function(evt) {
  if(bl.search._delayedPreviewTimer != null) {
    window.clearTimeout(bl.search._delayedPreviewTimer);
    bl.search._delayedPreviewTimer = null;
    bl.search._delayedPreviewUrl = null;
  }
}

bl.search.getPreviewUrlsFromEvent = function(evt) {

  var srcAnchor = dojo.html.getFirstAncestorByTag(evt.target, "a");
  var container = dojo.html.getFirstAncestorByTag(evt.target, "div");

  if(!srcAnchor || !container) {
    return;
  }
  var urls = {};

  var blogInfo = bl.search.parseUrlForSite(srcAnchor.getAttribute("js_href"));
  if(!blogInfo.success) return null;
    
  urls.data = bl.search.urlToPreview(srcAnchor.getAttribute("js_href"));
  urls.tracking = srcAnchor.href;
  return urls;

}

bl.search.togglePreviewClick = function(evt) {
  
  evt.preventDefault();
  evt.stopPropagation();
  bl.search.delayedPreviewCancel(evt);
  var urls = bl.search.getPreviewUrlsFromEvent(evt);
  if(!urls) return;
  var bubble = bl.search.PreviewBubble();
  if(bubble.isShowing(bl.search.getMatch(evt.target))) bubble.close();
  else bubble.load(evt, urls.data, urls.tracking);
 
}

bl.search.closePreview = function(evt) {
  var bubble = bl.search.PreviewBubble();
  bubble.close();
}

var toggleArticleIcons = {};
toggleArticleIcons.open = new Image();
toggleArticleIcons.open.src = "/images/ico_minus.gif";
toggleArticleIcons.closed = new Image();
toggleArticleIcons.closed.src = "/images/ico_plus.gif";
toggleArticleIcons.disabled = new Image();
toggleArticleIcons.disabled.src = "/images/ico_disabled.gif";


bl.search.toggleArticle = function(evt) {
  
  var inA = dojo.html.getFirstAncestorByTag(evt.target, "a");
  if(inA != null && !dojo.html.hasClass(inA, "more-link")) return; // if the target has an A as a parent, don't handle this click

  // otherwise, keep going
  evt.preventDefault();
  evt.stopPropagation();
  inA.blur();

  var alg = bl.alg;
  
  var sumDiv = dojo.html.getAncestors(evt.target, alg.hasTagAndClass("div", "summary"), true);
  var shorty = dojo.dom.getFirstChild(sumDiv, alg.hasTagAndClass("div", "shorty"));
  var full = dojo.dom.getFirstChild(sumDiv, alg.hasTagAndClass("div", "full"));
  var flip = dojo.dom.getFirstChild(sumDiv, alg.hasTagAndClass("a", "more-link"));
  var flipIco = dojo.dom.getFirstChild(flip, alg.hasTag("img"));

  if(full == null) {
    if(dojo.html.hasAttribute(sumDiv, "bl_failedToLoad")) return;

    var match = bl.search.parseUrlForSiteAndPost(flip.getAttribute("js_href"));
    if(!match.success) {
      return;
    }

    dojo.io.bind({
      url: bl.search.urlToArticle(flip.getAttribute("js_href")),
      load: function(type, data, evt) {
        data = data.replace(/<\!--[\s\S]*-->/g, "");
        if(dojo.string.trim(data) == "") {
          bl.search.disableArticleToggle(flip, flipIco);
          sumDiv["bl_failedToLoad"] = true;
          sumDiv["bl_failureReason"] = "Empty response for full article";
        } else if(data.match(/<html>/)) {
          bl.search.disableArticleToggle(flip, flipIco);
          sumDiv["bl_failedToLoad"] = true;
          sumDiv["bl_failureReason"] = "Found html tag in content";
        } else {
          full = document.createElement("div");
          dojo.html.setClass(full, "full");
          full.innerHTML = data + bl.search.trackingImg(flip.href);
          sumDiv.appendChild(full);
          dojo.style.hide(shorty);
          dojo.style.show(full);
          flipIco.src = toggleArticleIcons.open.src;
          flip.setAttribute("fulltitle", flip.title);
          flip.title = dojo.html.getAttribute(flip, "collapsetitle");
          dojo.lfx.highlight(full, 500, "#ddd", 0, null, false);
        }
        bl.controls.Spinner.hide();
      },
      error: function(type, err) {
        sumDiv["bl_failedToLoad"] = true;
        sumDiv["bl_failureReason"] = err;
        bl.search.disableArticleToggle(flip, flipIco);
        bl.controls.Spinner.hide();
        
      },
      mimetype: "text/html"
    });
    bl.controls.Spinner.show(evt);
    
  } else {
    if(dojo.html.isShowing(full)) {
      flipIco.src = toggleArticleIcons.closed.src;
      flip.title = dojo.html.getAttribute(flip, "fulltitle");
      dojo.style.hide(full);
      dojo.style.show(shorty);
    } else {
      flipIco.src = toggleArticleIcons.open.src;
      flip.title = dojo.html.getAttribute(flip, "collapsetitle");
      dojo.style.hide(shorty);
      dojo.style.show(full);
      dojo.lfx.highlight(full, 500, "#ddd", 0, null, false);
    }
  }
}

bl.search.disableArticleToggle = function(link, icon) {
  link.title = "No full text available for this post";
  icon.src = toggleArticleIcons.disabled.src;
}


bl.search.urlToPreview = function(baseurl) {
  return baseurl+"&format=inline&limit=5";
}

bl.search.urlToArticle = function(baseurl) {
  return baseurl+"&format=inline&desconly=true";
}

bl.search.trackingImg = function(href) {
  return "<img src=\"" + href + "\" width=\"0\" height=\"0\" />"
}

bl.search.getMatch = function(node) {
  var match = dojo.dom.getAncestors(node, function(n) { return dojo.html.hasClass(n, "match"); }, true);
  if(match == null) return null;
  return match.id;
}

bl.search.Bubble = function(node, mixer) {
  var self = this;
  this.domNode = node;
  this.domNode.style.zIndex = 7;
  this.url = "";
  this.body = dojo.html.getElementsByClass("bl_bub2_body", this.domNode, null, 0, true)[0];
  this.title = dojo.html.getElementsByClass("bl_bub2_title", this.domNode, null, 0, true)[0];
  if(dojo.render.html.mozilla && parseInt(dojo.render.html.geckoVersion) >= 20060111) {
    this.body.addEventListener("DOMMouseScroll", dojo.lang.hitch(this, "_checkMouseWheel"), false);
  }
  this.closers = dojo.html.getElementsByClass("bl_bub2_close", this.domNode, null, 0, true);
  dojo.lang.forEach(this.closers, function(n) {
    dojo.event.connect(n, "onclick", self, "_handleCloseClick");
  });

  this.domNodeBg = new dojo.html.BackgroundIframe();
  this.loading = false;

  dojo.lang.mixin(this, mixer);
  var es = dojo.html.getElementsByClass("bl_bub2_tailup", this.domNode, "img", 0, true);
  this.tailUp = es[0];
  this.tailUp.style.zIndex = 6;
  this.tailDown = dojo.html.getElementsByClass("bl_bub2_taildown", this.domNode, "img", 0, true)[0];
  this.tailDown.style.zIndex = 6;
  this.tail = null;
  this.createShadow();
  if(!bl.search.Bubble._watchingDoc) {
    bl.search.Bubble._watchingDoc = true;
    dojo.event.connect(document, "onclick", bl.search.Bubble._docClick);
  }
}

bl.search.Bubble.__instance = {};

bl.search.Bubble.currZ = 100;

bl.search.Bubble.nextZ = function() {
  return bl.search.Bubble.currZ += 2;
}

bl.search.Bubble.forId = function(id, mixer) {
  if(!bl.search.Bubble.__instance[id]) {
    var node = dojo.byId(id);
    if(!node) return null;
    bl.search.Bubble.__instance[id] = new bl.search.Bubble(node, mixer);
  }
  return bl.search.Bubble.__instance[id];
}


bl.search.Bubble._docClick = function(evt) {
  for(var n in bl.search.Bubble.__instance) {
    var bub = bl.search.Bubble.__instance[n];
    if(bub.isOpen() && !bub.clickInSelf(evt)) bub.close();
  }
}

dojo.lang.extend(bl.search.Bubble, {

  load: function(evt, url, trackingUrl) {
    if(this.loading) return;
    this.loading = true;
    if(dojo.lang.isFunction(this.getTitle)) this.setTitle(this.getTitle(evt));
    this.url = url;
    this.match = bl.search.getMatch(evt.target);
    this.trackingUrl = trackingUrl;
    this.fillContent(evt, url, trackingUrl);
    this.showNear(evt.target);
  },

  showNear: function(node) {
    if(this.isOpen()) this.close();
    var loc = dojo.html.toCoordinateArray(node, true);
    var view = dojo.html.getViewportSize();
    var scroll = dojo.html.getScrollOffset();
    // scroll represents the top right of the window
    // view represents the width and height of the window
   this.domNode.style.top = "-1000px";
   this.domNode.style.left = "-1000px";
   dojo.style.show(this.domNode);
   var size = dojo.html.toCoordinateArray(this.domNode, true);
   dojo.style.hide(this.domNode);

   // prefer to go above, unless there is no room
   var coords = [0,0];
   coords[0] = loc.x + loc.w/2;
   coords[1] = loc.y - (5 + size.h + 29);
   
   if(coords[1] < scroll.y) {
     coords[1] = loc.y + loc.h + 5;
     this.tail = this.tailUp;
     this.shadowTail = this.shadowTailUp;
     this.moveTo(this.tail, 0, -29);
     coords[1] = coords[1] + 29;
   } else {
     this.tail = this.tailDown;
     this.shadowTail = this.shadowTailDown;
     this.moveTo(this.tail, 0, size.h);
   }
  
   this.show(coords[0], coords[1]);
  },

  moveTo: function(node, x, y) {
    node.style.top = y + "px";
    node.style.left = x + "px";
  },

  show: function(x,y) {
    this.moveTo(this.domNode, x, y);
    if(!dojo.render.html.safari) this.body.scrollTop = 0;
    this.updateZ();
    dojo.html.show(this.domNode);
    this.domNodeBg.size(this.domNode);
    this.domNodeBg.show();
    this.tail.style.display = "block";
    this.positionShadow();
  },

  updateZ: function() {
    var z = bl.search.Bubble.nextZ();
    this.domNode.style.zIndex = z;
    this.shadow.style.zIndex = z-1;
    this.shadowTail.style.zIndex = z-1;
    this.domNodeBg.setZIndex(z-2);
  },

  positionShadow: function() {
    var bubCoord = dojo.html.toCoordinateArray(this.domNode, true);
    bubCoord.w += 5;
    bubCoord.h += 5;
    this.moveTo(this.shadow, bubCoord.x+4, bubCoord.y+5);
    this.shadow.style.width = bubCoord.w + "px";
    this.shadow.style.height = bubCoord.h + "px";
    this.shadow.top.style.width = this.shadow.bottom.style.width = bubCoord.w - 40 + "px";
    this.shadow.left.style.height = this.shadow.right.style.height = bubCoord.h - 40 + "px";
    this.shadow.tr.style.left = this.shadow.right.style.left = this.shadow.br.style.left = bubCoord.w - 20 + "px";
    this.shadow.bl.style.top = this.shadow.bottom.style.top = this.shadow.br.style.top = bubCoord.h - 20 + "px";
    
    dojo.style.show(this.shadow);
    var tailCoord = dojo.html.toCoordinateArray(this.tail, true);
    if(this.shadowTail == this.shadowTailUp) {
      this.moveTo(this.shadowTail, tailCoord.x-2, tailCoord.y);
    } else { 
      this.moveTo(this.shadowTail, tailCoord.x-2, tailCoord.y-7);
    }
    dojo.style.show(this.shadowTail);
  },
          
  close: function(evt) {
    dojo.style.hide(this.tail);
    dojo.style.hide(this.shadowTail);
    dojo.style.hide(this.domNode);
    dojo.style.hide(this.shadow);
    this.domNodeBg.hide();
    this.url = "";
    this.match = null;
    this.tail = null;
    this.shadowTail = null;
  },

  _handleCloseClick: function(evt) {
    evt.preventDefault();
    evt.stopPropagation();
    if(this.isOpen()) this.close();
  },

  isOpen: function() {
    return dojo.style.isShowing(this.domNode);
  },

  isShowing: function(match) {
    return this.isOpen() && this.match == match;
  },

  setTitle: function(txt) {
    this.title.innerHTML = txt;
  },

  setContent: function(txt) {
    this.body.innerHTML = txt;
    if(!dojo.render.html.safari) this.body.scrollTop = 0;    
  },

  _checkMouseWheel: function(evt) {
    var c = this.body;
    var wheelCount = ((evt.detail > 0) ? -1 : 1);
    if(c.scrollTop == 0 && wheelCount > 0) dojo.event.browser.stopEvent(evt);
    if((c.scrollTop + c.offsetHeight  == c.scrollHeight) && wheelCount < 0) dojo.event.browser.stopEvent(evt);
  },

  createShadow: function() {
    if(this.shadow) return;
    this.shadow = document.createElement("div");

    this.shadow.tl = this.createShadowPart({ x: 0, y: 0, w: 20, h: 20 }, "/images/shadowbox/tl.png", "no-repeat");
    this.shadow.top = this.createShadowPart({ x: 20, y: 0, w: 200, h: 20 }, "/images/shadowbox/top.png", "repeat-x");
    this.shadow.tr = this.createShadowPart({ x: 220, y: 0, w: 20, h: 20 }, "/images/shadowbox/tr.png", "no-repeat");
    this.shadow.right = this.createShadowPart({ x: 220, y: 20, w: 20, h: 200 }, "/images/shadowbox/right.png", "repeat-y");
    this.shadow.br = this.createShadowPart({ x: 220, y: 220, w: 20, h: 20 }, "/images/shadowbox/br.png", "no-repeat");
    this.shadow.bottom = this.createShadowPart({ x: 20, y: 220, w: 200, h: 20 }, "/images/shadowbox/bottom.png", "repeat-x");
    this.shadow.bl = this.createShadowPart({ x: 0, y: 220, w: 20, h: 20 }, "/images/shadowbox/bl.png", "no-repeat");
    this.shadow.left = this.createShadowPart({ x: 0, y: 20, w: 20, h: 200 }, "/images/shadowbox/left.png", "repeat-y");
    
    this.shadow.style.display = "none";
    this.shadow.style.position = "absolute";
    this.shadow.style.zIndex = 5;
 
    this.shadowTailUp = this.createShadowTail("up");
    this.shadowTailDown = this.createShadowTail("down");

    this.shadow = document.body.appendChild(this.shadow);
    this.shadowTailUp = document.body.appendChild(this.shadowTailUp);
    this.shadowTailDown = document.body.appendChild(this.shadowTailDown);
  },

  createShadowPart: function(size, img, repeat) {
    var p = document.createElement("div");
    p.style.left = size.x + "px";
    p.style.top = size.y + "px";
    p.style.width = size.w + "px";
    p.style.height = size.h + "px";
    p.style.position = "absolute";
    if(dojo.render.html.ie) {
      p.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+img+"', sizingMethod='scale')";
    } else {
      p.style.backgroundImage = "url(" + img + ")";
      p.style.backgroundRepeat = repeat;
      p.style.backgroundPosition = "top left";
    }
    p.style.zIndex = 5;
    return this.shadow.appendChild(p);
  },

  createShadowTail: function(which) {
    var tail = null;
    if(dojo.render.html.ie) {
      tail = document.createElement("div");
      tail.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='/images/shadowbox/tail-"+which+".png', sizingMethod='scale')";
    } else {
     tail  = document.createElement("img");
     tail.src = "/images/shadowbox/tail-"+which+".png";
    }
    
    tail.style.position = "absolute";
    tail.style.display = "none";
    tail.style.zIndex = 5;
    tail.style.margin = "0px";
    tail.style.padding = "0px";
    tail.style.width = "39px";
    tail.style.height = "44px";
    return tail;
  }
});

bl.search.PreviewBubbleMixin = {
  getTitle: function(evt) {
    var alg = bl.alg;    
    var container = dojo.dom.getAncestors(evt.target, alg.hasTagAndClass("div", "match"), true);
    var blogTitle = dojo.html.getElementsByClass("blog-name", container, null, 0, true);
    if(blogTitle.length == 1) 
      return blogTitle[0].innerHTML;
    else 
      return bl.translate.get("FeedPreview");
  },

  getErrorInfo: function(evt) {
    var e = {};
    e.title = bl.translate.get("FeedPreviewErrorTitle");
    e.body = bl.translate.get("FeedPreviewErrorBody");
    return e;
  },
  
  fillContent: function(evt, url, trackingUrl) {
    this.setContent("<p>" + bl.translate.get("Loading") + "</p>");
    dojo.io.bind({
      "url": url,
      load: dojo.lang.hitch(this, "__loadCallback"),
      error: dojo.lang.hitch(this, "__errorCallback"),
      mimetype: "text/html"
    });
  },

  __loadCallback: function(type, data, evt) {
    this.loading = false;
    this.setContent(data + bl.search.trackingImg(this.trackingUrl));
    this.url = null;
    this.trackingUrl = null;
  },

  __errorCallback: function(type, error) {
    this.loading = false;
    var e = this.getErrorInfo(error);
    this.setTitle(e.title);
    this.setContent("<p>" + e.body + "</p>");
    this.url = null;
    this.trackingUrl = null;
  },

  clickInSelf: function(evt) {
    if(bl.alg.hasTagAndClass("a", "preview")(evt.target)) return true;
    var n = dojo.dom.getAncestors(evt.target, function(n) { return n.id == "bl-preview-bubble"; }, true);
    return n != null;
  }
}

bl.search.PreviewBubble = function() {
  return bl.search.Bubble.forId("bl-preview-bubble", bl.search.PreviewBubbleMixin);
}

bl.search.FilterBubble = function() {
  this.node = dojo.byId("bl-filter-bubble");
  var closer = dojo.html.getElementsByClass("bl_bubble_closer", this.node, null, 0, true);
  var self = this;
  dojo.lang.forEach(closer, function(n) {
    dojo.event.connect(n, "onclick", self, "handleClose");
  });
  this.fading = false;
}

bl.search.FilterBubble.instance = function() {
  if(!bl.search.FilterBubble.__instance) bl.search.FilterBubble.__instance = new bl.search.FilterBubble();
  return bl.search.FilterBubble.__instance;
}

dojo.lang.extend(bl.search.FilterBubble, {
  handleClick: function(evt) {
    dojo.event.browser.fixEvent(evt);
    evt.preventDefault();
    evt.stopPropagation();
    if(dojo.style.isShowing(this.node)) this.hide();
    else this.show();
  },
  show: function() {
    if(this.fading) return;
    var orig = dojo.style.toCoordinateArray(dojo.byId("bl-filters"), true);
    var xc = orig.x + (orig.w / 2);
    this.node.style.display = "block";
    this.node.style.position = "absolute";
    var width = dojo.style.getBorderBoxWidth(this.node);
    this.node.style.display = "none";
    this.node.style.top = (orig.y + orig.h) + "px";
    this.node.style.left = (orig.x - (width - orig.w)) + "px";
    var self = this;
    this.fading = true;
    dojo.lfx.fadeShow(this.node, 150, dojo.lfx.easeIn, function() {
      dojo.event.connect(document.body, "onclick", self, "handleBodyClick");
      self.fading = false;
    }).play();
    
  },
  hide: function() {
    if(this.fading) return;
    var self = this;
    self.fading = true;
    dojo.event.disconnect(document.body, "onclick", this, "handleBodyClick");
    dojo.lfx.fadeHide(this.node, 150, dojo.lfx.easeOut, function() { self.fading = false; }).play();
  },
  handleClose: function(evt) {
    evt.preventDefault();
    evt.stopPropagation();
    this.hide();
  },
  handleBodyClick: function(evt) {
    var o = dojo.dom.getAncestors(evt.target, function(n) { return n.id == "bl-filter-bubble"; }, true);
    if(o == null) this.hide();
  }

  
});

bl.search.toggleInfo = function(evt) {
  evt.preventDefault();
  evt.stopPropagation();
  bl.search.delayedInfoCancel(evt);
  var ib = bl.search.MoreInfoBubble();
  if(ib.isShowing(bl.search.getMatch(evt.target))) ib.close();
  else ib.load(evt, evt.target.href, evt.target.href);
}

bl.search.delayedInfoTimer = null;

bl.search.delayedInfoShow = function(evt) {
  var myEvt = bl.event.clone(evt);
  var ib = bl.search.MoreInfoBubble();
  if(ib.isShowing(bl.search.getMatch(evt.target))) return;
  bl.search.delayedInfoTimer = window.setTimeout(function() {
    ib.load(myEvt, myEvt.target.href, myEvt.target.href);
  }, 500);
}

bl.search.delayedInfoCancel = function(evt) {
  if(bl.search.delayedInfoTimer!=null) window.clearTimeout(bl.search.delayedInfoTimer);
}


bl.search.MoreInfoBubbleMixin = {
  fillContent: function(evt, url, trackingUrl) {
    var node = evt.target;
    var b = new dojo.string.Builder();
    b.append("<dl>");
    if (node.getAttribute("bl_subs") != "-1") {
      b.append("<dd>" + dojo.string.paramString(bl.translate.get("BloglinesSubs"), { subs: node.getAttribute("bl_subs"), url: "/userdir?siteid=" + node.getAttribute("bl_site") } ) + "</dd>"); 
    }
    if (node.getAttribute("bl_cite") >= 0 ) {
      b.append("<dd>" + dojo.string.paramString(bl.translate.get("Citations"), { cite: node.getAttribute("bl_cite"), url: "/search?q=bcite:" + node.getAttribute("bl_cite_url") } ) + "</dd>"); 
    }
    b.append("</dl>");
    this.body.innerHTML =  b.toString() + bl.search.trackingImg(this.trackingUrl);
    this.loading = false;
  },

  clickInSelf: function(evt) {
    if(bl.alg.hasTagAndClass("a", "bl_info")(evt.target)) return true;
    var o = dojo.dom.getAncestors(evt.target, function(n) { return n.id == "bl-mi-bubble"; }, true);
    return o != null;
  }
}

bl.search.MoreInfoBubble = function() {
  return bl.search.Bubble.forId("bl-mi-bubble", bl.search.MoreInfoBubbleMixin);
}


bl.search.SidebarItems = function() {
  this.items = {};
};

dojo.lang.extend(bl.search.SidebarItems, {
  register: function(name, item) {
    this.items[name] = item;
  },

  load: function(loadCallback) {
    var allLoaded = true;
    this.loadCallback = loadCallback
    for(var k in this.items) {
      if(!(this.items[k].isComplete())) {
        allLoaded = false;
        dojo.event.connect(this.items[k], "loaded", this, "_loadHandler");
        dojo.event.connect(this.items[k], "errored", this, "_loadHandler");
        this.items[k].load();
      }
    }
    if(allLoaded) loadCallback(this);
   
  },

  _allComplete: function() {
    for(var k in this.items) {
      if(!this.items[k].isComplete()) return false;
    }
    return true;
  },

  _loadHandler: function() {
    if(this._allComplete() && this.loadCallback) {
      this.loadCallback(this);
      this.loadCallback = null;
    }
  },

  show: function(order) {
    var self = this;
    for(var i = 0; i < order.length; i++) {
      var item = this.items[order[i]];
      if(item && item.isLoaded) window.setTimeout(this._makeShowFunc(item), 400 * i);
    }
  },

  _makeShowFunc: function(i) { return function() { i.show(); } },

  get: function(name) {
    return this.items[name];
  },

  remove: function(name) {
    if(this.items[name] != null) delete this.items[name];
  }
});


bl.search.SidebarItem = function(node, url, howMany, alreadyLoaded) {
  this.node = dojo.byId(node);
  if(this.node == null) return;
  this.list = dojo.dom.getFirstChild(this.node, bl.alg.hasTag("dl"));
  this.moreLink = dojo.html.getElementsByClass("bl_more", this.node, "a", 0, true)[0];
  this.url = url;
  this.numLoaded = alreadyLoaded ? this.list.getElementsByTagName("dt").length : 0;
  this.howMany = howMany || 5;
  this.isLoaded = alreadyLoaded;
  this.isError = false;
}

dojo.lang.extend(bl.search.SidebarItem, {
  load: function(showOnLoad) {
    if(this.node == null || this.isLoaded) return;
    this.showOnLoad = showOnLoad;
    dojo.io.bind({
      url: this.url,
      mimetype: "text/json",
      load: dojo.lang.hitch(this, "onLoad"),
      error: dojo.lang.hitch(this, "onError"),
      sendTransport: false
    });
  },

  onLoad: function(type, data, evt) {
    if(this.isLoaded) return;
    var b = new dojo.string.Builder();
    if(data.items && data.items.length > 0) {
    var upper = Math.min(data.items.length, this.howMany);
      for(var i = 0; i < upper; i++) {
        var n = data.items[i];
        b.append("<dt><a href=\"");
        b.append(n.url);
        b.append("\">");
        b.append(n.title);
        b.append("</a></dt>");
        this.numLoaded++;
      }
    
      this.list.innerHTML = b.toString();
      this.moreLink.href = data.more.url;
      if(this.showOnLoad) this.show();
      
      
    }
    this.loaded();

  },

  show: function() {
    dojo.style.setOpacity(this.node, 0);
    dojo.lfx.fadeShow(this.node, 400, dojo.lfx.easeIn).play();
  },

  showItems: function(howMany) {
    var elems = this.list.getElementsByTagName("dt");
    for(var i = elems.length; i > howMany; i--) {
      var elem = elems[i-1];
      if(dojo.style.isShowing(elem)) dojo.style.hide(elem);
    }
    var top = Math.min(elems.length, howMany) - 1;
    for(; top >= 0; top--) {
      if(!dojo.style.isShowing(elems[top])) dojo.style.show(elems[top]);
    }
  },

  loaded: function() { this.isLoaded = true; },
  errored: function() { this.isError = true; },
  isComplete: function() { return this.isError || this.isLoaded; },

  onError: function(type, errObj) {
    //alert(errObj);
    this.errored();

  }
});
