/* jQuery Notify UI Widget 1.5 by Eric Hynds
 * http://www.erichynds.com/jquery/a-jquery-ui-growl-ubuntu-notification-widget/
 *
 * Depends:
 *   - jQuery 1.4+
 *   - jQuery UI 1.8 widget factory
 *
 * Dual licensed under the MIT and GPL licenses:
 *   http://www.opensource.org/licenses/mit-license.php
 *   http://www.gnu.org/licenses/gpl.html
*/
(function($){

  $.widget("ech.notify", {

    options: {
      speed: 500,
      expires: 5000,
      stack: "below",
      custom: false,
      queue: false
    },

    _create: function(){
      var self = this;
      this.templates = {};
      this.keys = [];

      // build and save templates
      this.element.addClass("ui-notify").children().addClass("ui-notify-message ui-notify-message-style").each(function(i){
        var key = this.id || i;
        self.keys.push(key);
        self.templates[key] = $(this).removeAttr("id").wrap("<div></div>").parent().html(); // because $(this).andSelf().html() no workie
      }).end().empty().show();
    },

    create: function(template, msg, opts){
      if(typeof template === "object"){
        opts = msg;
        msg = template;
        template = null;
      }

      var tpl = this.templates[ template || this.keys[0]];

      // remove default styling class if rolling w/ custom classes
      if(opts && opts.custom){
        tpl = $(tpl).removeClass("ui-notify-message-style").wrap("<div></div>").parent().html();
      }

      this.openNotifications = this.openNotifications || 0;

      // return a new notification instance
      return new $.ech.notify.instance(this)._create(msg, $.extend({}, this.options, opts), tpl);            
    }
  });

  // instance constructor
  $.extend($.ech.notify, {
    instance: function(widget){
      this.__super = widget;
      this.isOpen = false;
    }
  });

  // instance methods
  $.extend($.ech.notify.instance.prototype, {

    _create: function(params, options, template){
      this.options = options;

      var self = this,

      // build html template
      html = template.replace(/#(?:\{|%7B)(.*?)(?:\}|%7D)/g, function($1, $2){
        return ($2 in params) ? params[$2] : '';
      }),

      // the actual message
      m = (this.element = $(html)),

      // close link
      closelink = m.find(".ui-notify-close");

      // clickable?
      if(typeof this.options.click === "function"){
        m.addClass("ui-notify-click").bind("click", function(e){
          self._trigger("click", e, self);
        });
      }

      // show close link?
      if(closelink.length){
        closelink.bind("click", function(){
          self.close();
          return false;
        });
      }

      this.__super.element.queue("notify", function(){
        self.open();

        // auto expire?
        if(typeof options.expires === "number" && options.expires > 0){
          setTimeout($.proxy(self.close, self), options.expires);
        }
      });

      if(!this.options.queue || this.__super.openNotifications <= this.options.queue - 1) {
        this.__super.element.dequeue("notify");
      }

      return this;
    },

    close: function(){
      var speed = this.options.speed;

      this.element.fadeTo(speed, 0).slideUp(speed, $.proxy(function(){
        this._trigger("close");
        this.isOpen = false;
        this.element.remove();
        this.__super.openNotifications -= 1;
        this.__super.element.dequeue("notify");
      }, this));

      return this;
    },

    open: function(){
      if(this.isOpen || this._trigger("beforeopen") === false){
        return this;
      }

      var self = this;

      this.__super.openNotifications += 1;

      this.element[this.options.stack === "above" ? "prependTo" : "appendTo"](this.__super.element).css({ display:"none", opacity:"" }).fadeIn(this.options.speed, function(){
        self._trigger("open");
        self.isOpen = true;
      });

      return this;
    },

    widget: function(){
      return this.element;
    },

    _trigger: function(type, e, instance){
      return this.__super._trigger.call( this, type, e, instance );
    }
  });

})(jQuery);
