function FeedPopup(container, _options) {
  var o = this;
  
  /* References to core DOM objects **/
  this.options = _options || {};
  var container = this.container = container;
  this.contentList = this.container.down('ol.fp-content');
  this.idCache = [];
  
  function determineOptions(options) {
    var so = options;
    
    // Specify time lengths in seconds
    var options = {
      maximumItems:       so.maximumItems     || 5,         /* PVDB half of FeedPopup::POLL_BUFFER */
      pollFrequency:      so.pollFrequency    || 10,        /* PVDB this if FeedPopup::POLL_FREQUENCY */
      itemLifetime:       so.itemLifetime     || 15,
      widgetLifetime:     so.widgetLifetime   || 600,       /* 600 seconds == 10 minutes */
      minimized:          so.minimized        || false,
      pollPath:           so.pollPath         || "/feed_popups?scope=recent",
      togglePath:         so.pollPath         || "/feed_popups/toggle/",
      closePath:          so.closePath        || "/feed_popups/close/"
    }
    so = undefined;
    return options;
  }
  
  function isCSS3Available() {
    var isAvailable = false;
    var b = ["Webkit", "Moz"];
    for(var i = 0; i < b.length; i++) {
      if(typeof(container.style[b[i] + "BorderRadius"]) != "undefined") {
        isAvailable = true;
        i = undefined;
      };
    };
    var prevColour = container.style.color;
    try {
  	  container.style.color = 'rgba(0,0,0,0)';
  	} catch(e) {};
    isAvailable = (container.style.color != prevColour);
  	container.style.color = prevColour;
    prevColour = undefined;
    return isAvailable;
  };

  function isPositionFixedSupported() {
    var isSupported = null;
    if (document.createElement) {
        var el = document.createElement("div");
        if (el && el.style) {
            el.style.width = "1px";
            el.style.height = "1px";
            el.style.position = "fixed";
            el.style.top = "10px";
            var root = document.body;
            if (root && root.appendChild && root.removeChild) {
                root.appendChild(el);
                isSupported = el.offsetTop === 10;
                root.removeChild(el);
            }
            el = null;
        }
    }
    return isSupported;
  };
  
  /* Initialize options */
  this.options = determineOptions(this.options);
  this.options.useBorderRadius = isCSS3Available();
  this.options.usePositionFixed = isPositionFixedSupported();
  
  /* Setup component behavior */
  var components =  this.container.getElementsByClassName("component");
  this.components = {};
  for(i = 0; i < components.length; i++) {
    (function() {
      var c = components[i];
      switch(c.className.substring(c.className.lastIndexOf(" ") + 1)) {
        case "fp-toggle":
          o.components.toggle = c;
          c.onclick = function() { o.toggle() };
          break;
        case "fp-close":
          o.components.close = c;
          c.onclick = function() { o.confirmClose() };
          break;
      };
    })();
  };
  
  /* Enable CSS for non-borderRadius browsers */
  
  function createCornersForContainer() {
    var dTop = document.createElement('div');
    var dBottom = document.createElement('div');
    dTop.className = "fpc fpc-top";
    dBottom.className = "fpc fpc-bottom";
    o.container.insertBefore(dTop, o.container.firstChild);
    o.container.appendChild(dBottom);
    dTop = undefined;
    dBottom = undefined;
    o.components.toggle.parentNode.parentNode.appendChild(o.components.toggle.parentNode);
    for(var c in o.components) {
      (function() {
        var li = o.components[c].parentNode;
        var d = document.createElement('div');d.className="fpb-left";
        li.insertBefore(d, li.firstChild);
        d = document.createElement('div');d.className="fpb-right";
        li.appendChild(d);
      })();
    };
  };

  if(!this.options.useBorderRadius) {
    this.container.addClassName("noBorderRadius");
    createCornersForContainer();
    this.container.onmouseover = function() {
      o.container.addClassName("noBorderRadius-hover");
    };
    this.container.onmouseout = function(e) {
      var e = e || window.event;
      if(isMouseLeaveOrEnter(e, o.container)) {
        o.container.removeClassName("noBorderRadius-hover");
      };
    };
  };

  function fixPosition() {
    container.style.position = "absolute";
    window.onscroll = window.onresize = function() {
      container.style.bottom = 5 + "px";
      container.style.bottom = 6 + "px";
    };
  };

  /* Fix position for browsers that do not support position: fixed */
  if(!this.options.usePositionFixed) fixPosition();
  
  /* Create the prototype LI element for browsers that do not support borderRadius */
  function createItemContainer(extraRequired) {
    var extraRequired = extraRequired || false;
    var e = document.createElement("li");
    e.style.display = "none";
    
    if(extraRequired == true) {
      var dTop = document.createElement("div");
      var dBottom = document.createElement("div");
      var dBody = document.createElement("div");
      dTop.className =    "fpi fpi-top";
      dBottom.className = "fpi fpi-bottom";
      dBody.className =    "fpi fpi-body";
      e.appendChild(dTop);e.appendChild(dBody);e.appendChild(dBottom);
      dTop = dBottom = dBody = undefined;
    }
    return e;
  };
  
  this.itemContainer = createItemContainer(!this.options.useBorderRadius);
  
  this.options.minimized = this.container.hasClassName("fp-minimized");
  
  this.poller;
  if(this.options.minimized === false) {
    this.start();
    this.enabled = true;
  } else {
    this.components.toggle.innerHTML = "Maximize";
  };
  
};

FeedPopup.prototype.start = function() {
  var o = this;
  var allowPoll = true;
  totalPolls = 0;
  
  function verifyRequest(response) {
    if(response.status == 200) {
      allowPoll = true;
      totalPolls++;
    };

    // Should be moved elsewhere.
    if(allowPoll === false || totalPolls + 1 >= (o.options.widgetLifetime / o.options.pollFrequency)) o.stop();
  };
  
  this.poller = new PeriodicalExecuter(function() {
    if(allowPoll) {
      new Ajax.Request(o.options.pollPath, { onComplete: verifyRequest });
      allowPoll = false;
    };
  }, o.options.pollFrequency);
  
};

FeedPopup.prototype.stop = function() {
  // Call stop method on PeriodicalExecuter
  if(typeof(this.poller) != "undefined") this.poller.stop();
  this.poller = undefined;
};

FeedPopup.prototype.push = function(id, content) {
  if(this.enabled && this.idCache.indexOf(id) < 0 && (this.contentList.childElements().length < this.options.maximumItems)) {
    var o = this;
    var item = Element.extend(this.itemContainer.cloneNode(true));
    item.id = "fpi-" + id;
    var body = (this.options.useBorderRadius ? item : item.getElementsByClassName("fpi-body")[0]);
    body.innerHTML = content;
    this.contentList.insertBefore(item, this.contentList.firstChild);
    body = undefined;
    new Effect.Appear(item);
  
    setTimeout(function() {
      o.deleteItem(item);
    }, this.options.itemLifetime * 1000);

    this.idCache.push(id);
    if(this.idCache.length > 20) this.idCache = [];
  };
};

FeedPopup.prototype.deleteItem = function(item) {
  var item = item;
  new Effect.Fade(item, { afterFinish: function() { Element.remove(item) } });
};

FeedPopup.prototype.toggle = function() {
  var minimized = this.container.hasClassName("fp-minimized");
  if(!minimized) {
    this.stop();
    this.container.addClassName("fp-minimized") 
    this.components.toggle.innerHTML = "Maximize";
  } else {
    this.start();
    this.container.removeClassName("fp-minimized");
    this.components.toggle.innerHTML = "Minimize";
  }
  this.enabled = minimized;
  new Ajax.Request(this.options.togglePath, { parameters: { toggle: !this.enabled, authenticity_token: AUTH_TOKEN } });
};

FeedPopup.prototype.confirmClose = function() {
  this.confirmCloseModal = new Modal('confirm-disable-feedpopup');
  this.confirmCloseModal.retrieveContent(this.options.closePath, 'get');
  return false;
};

FeedPopup.prototype.close = function() {
  this.stop();
  this.container.parentNode.removeChild(this.container);
  new Ajax.Request(this.options.closePath, { parameters: { authenticity_token: AUTH_TOKEN } });
};
var fp;
var feedPopupListener = Behavior.create({
  initialize: function() { fp =  new FeedPopup(this.element); }
});
Event.addBehavior({ "div#feedpopup" : feedPopupListener });
