/**
 * @requires javelin-install
 *           javelin-dom
 *           javelin-vector
 *           javelin-request
 *           javelin-uri
 * @provides phabricator-hovercard
 * @javelin
 */

JX.install('Hovercard', {

  statics : {
    _node : null,
    _activeRoot : null,
    _visiblePHID : null,

    fetchUrl : '/search/hovercard/retrieve/',

    /**
     * Hovercard storage. {"PHID-XXXX-YYYY":"<...>", ...}
     */
    _cards : {},

    getAnchor : function() {
      return this._activeRoot;
    },

    getCard : function() {
      var self = JX.Hovercard;
      return self._node;
    },

    show : function(root, phid) {
      var self = JX.Hovercard;
      // Already displaying
      if (self.getCard() && phid == self._visiblePHID) {
        return;
      }
      self.hide();

      self._visiblePHID = phid;
      self._activeRoot = root;

      if (!(phid in self._cards)) {
        self._load([phid]);
      } else {
        self._drawCard(phid);
      }
    },

    _drawCard : function(phid) {
      var self = JX.Hovercard;
      // card is loading...
      if (self._cards[phid] === true) {
        return;
      }
      // Not the current requested card
      if (phid != self._visiblePHID) {
        return;
      }
      // Not loaded
      if (!(phid in self._cards)) {
        return;
      }

      var root = self._activeRoot;
      var node = JX.$N('div',
        { className: 'jx-hovercard-container' },
        JX.$H(self._cards[phid]));

      self._node = node;

      // Append the card to the document, but offscreen, so we can measure it.
      node.style.left = '-10000px';
      document.body.appendChild(node);

      // Retrieve size from child (wrapper), since node gives wrong dimensions?
      var child = node.firstChild;
      var p = JX.$V(root);
      var d = JX.Vector.getDim(root);
      var n = JX.Vector.getDim(child);

      // Move the tip so it's nicely aligned.
      // I'm just doing north/south alignment for now
      // TODO: Fix southern graceful align
      var margin = 20;
      // We can't shift left by ~$margin or more here due to Pholio, Phriction
      var x = parseInt(p.x, 10) - margin / 2;
      var y = parseInt(p.y - n.y, 10) - margin;

      // If more in the center, we can safely center
      if (x > (n.x / 2) + margin) {
        x = parseInt(p.x - (n.x / 2) + d.x, 10);
      }

      // Temporarily disabled, since it gives weird results (you can only see
      // a hovercard once, as soon as it's hidden, it cannot be shown again)
      // if (y < n.y) {
      //   // Place it southern, since northern is not enough space
      //   y = p.y + d.y + margin;
      // }

      node.style.left = x + 'px';
      node.style.top  = y + 'px';
    },

    hide : function() {
      var self = JX.Hovercard;
      self._visiblePHID = null;
      self._activeRoot = null;
      if (self._node) {
        JX.DOM.remove(self._node);
        self._node = null;
      }
    },

    /**
     * Pass it an array of phids to load them into storage
     *
     * @param list phids
     */
    _load : function(phids) {
      var self = JX.Hovercard;
      var uri = JX.$U(self.fetchUrl);

      var send = false;
      for (var ii = 0; ii < phids.length; ii++) {
        var phid = phids[ii];
        if (phid in self._cards) {
          continue;
        }
        self._cards[phid] = true; // means "loading"
        uri.setQueryParam("phids["+ii+"]", phids[ii]);
        send = true;
      }

      if (!send) {
        // already loaded / loading everything!
        return;
      }

      new JX.Request(uri, function(r) {
        for (var phid in r.cards) {
          self._cards[phid] = r.cards[phid];

          // Don't draw if the user is faster than the browser
          // Only draw if the user is still requesting the original card
          if (self.getCard() && phid != self._visiblePHID) {
            continue;
          }

          self._drawCard(phid);
        }
      }).send();
    }
  }
});
