/**
 * @requires javelin-install
 *           javelin-dom
 *           javelin-stratcom
 *           javelin-util
 *           phabricator-notification-css
 * @provides phabricator-notification
 * @javelin
 */

/**
 * Show a notification popup on screen. Usage:
 *
 *   var n = new JX.Notification()
 *     .setContent('click me!');
 *   n.listen('activate', function(e) { alert('you clicked!'); });
 *   n.show();
 *
 */
JX.install('Notification', {

  events : ['activate', 'close'],

  members : {
    _container : null,
    _visible : false,
    _hideTimer : null,
    _duration : 12000,

    show : function() {
      if (!this._visible) {
        this._visible = true;

        var self = JX.Notification;
        self._show(this);
        this._updateTimer();
      }
      return this;
    },

    hide : function() {
      if (this._visible) {
        this._visible = false;

        var self = JX.Notification;
        self._hide(this);
        this._updateTimer();
      }
      return this;
    },

    alterClassName : function(name, enable) {
      JX.DOM.alterClass(this._getContainer(), name, enable);
      return this;
    },

    setContent : function(content) {
      JX.DOM.setContent(this._getContainer(), content);
      return this;
    },

    /**
     * Set duration before the notification fades away, in milliseconds. If set
     * to 0, the notification persists until dismissed.
     *
     * @param int Notification duration, in milliseconds.
     * @return this
     */
    setDuration : function(milliseconds) {
      this._duration = milliseconds;
      this._updateTimer(false);
      return this;
    },

    _updateTimer : function() {
      if (this._hideTimer) {
        clearTimeout(this._hideTimer);
        this._hideTimer = null;
      }

      if (this._visible && this._duration) {
        this._hideTimer = setTimeout(JX.bind(this, this.hide), this._duration);
      }
    },

    _getContainer : function() {
      if (!this._container) {
        this._container = JX.$N(
          'div',
          {
            className: 'jx-notification',
            sigil: 'jx-notification'
          });
      }
      return this._container;
    }
  },

  statics : {
    _container : null,
    _listening : false,
    _active : [],
    _show : function(notification) {
      var self = JX.Notification;

      self._installListener();
      self._active.push(notification);
      self._redraw();
    },
    _hide : function(notification) {
      var self = JX.Notification;

      for (var ii = 0; ii < self._active.length; ii++) {
        if (self._active[ii] === notification) {
          notification.invoke('close');
          self._active.splice(ii, 1);
          break;
        }
      }

      self._redraw();
    },
    _installListener : function() {
      var self = JX.Notification;

      if (self._listening) {
        return;
      } else {
        self._listening = true;
      }

      JX.Stratcom.listen(
        'click',
        'jx-notification',
        function(e) {
          // NOTE: Don't kill the event since the user might have clicked a
          // link, and we want to follow the link if they did. Instead, invoke
          // the activate event for the active notification and dismiss it if it
          // isn't handled.

          var target = e.getNode('jx-notification');
          for (var ii = 0; ii < self._active.length; ii++) {
            var n = self._active[ii];
            if (n._getContainer() === target) {
              var activation = n.invoke('activate');
              if (!activation.getPrevented()) {
                n.hide();
              }
              return;
            }
          }

        });
    },
    _redraw : function() {
      var self = JX.Notification;

      if (!self._active.length) {
        if (self._container) {
          JX.DOM.remove(self._container);
          self._container = null;
        }
        return;
      }

      if (!self._container) {
        self._container = JX.$N(
          'div',
          {
            className: 'jx-notification-container'
          });
        document.body.appendChild(self._container);
      }

      // Show only a limited number of notifications at once.
      var limit = 5;

      var notifications = [];
      for (var ii = 0; ii < self._active.length; ii++) {
        notifications.push(self._active[ii]._getContainer());
        if (!(--limit)) {
          break;
        }
      }

      JX.DOM.setContent(self._container, notifications);
    }
  }

});

