(function($){

  /** 
   * @class Dropdown
   * @constructor
   * A class used to encapsulate functionality provided by $.fn.dropdown and store data.
   * TODO: Tightly coupled to the markup, might be helpful to allow customization.
   * @param {HTMLElement} element
   * @param {Object} settings
   */
  function Dropdown( element, settings ){
    this.element = $('.dropdown-trigger', element);
    this.content = $('.dropdown-menu', element);
    this.counter = $('.dropdown-count', element);
    this.settings = $.extend({
      url:'/',         /* The url to which requests for data to populate Dropdown containers should be made. */
      template_id: '', /* The ID of the HTML template used for data binding. */
      setup: null      /* A method called prior to initialization. You can use this for delegate events on the Dropmenu for behaviors invoked within the Dropmenu container. */
    }, settings);
    this.init();
  }

  Dropdown.prototype = {
    /**
     * Called when a new Dropdown is constructed.
     */
    init: function(){
      this.settings.setup && this.settings.setup.call(this);
      this.template = new $.EJS({
        type:'<',
        text: $('#'+this.settings.template_id).text()
      });      
      this.element.click($.proxy(this.click, this));  
      this.fetch();
    },

    /**
     * Handles behavior when the Dropdown trigger is clicked.
     * @param {Event} e The standard jQuery event object.
     */  
    click: function( e ){    
      this.content.is(':visible') ?
        this.hide() : this.show();

      return false;
    },

    /**
     * Retreives data from the server to be bound to a template that then replaces the current Dropmenu container's content. 
     * If the call is successfull, the data_received method is invoked
     */  
    fetch: function(){
      $.ajax({
        url: this.settings.url,
        dataType: 'json',
        success: $.proxy(this.data_received, this)
      });
    },

    /**
     * Hides the Dropmenu container.
     */    
    hide: function(){
      this.element.removeClass('dropdown-selected');
      this.content.css({ 
        display: 'none',
        visibility: 'hidden' 
      });  
    },

    /**
     * Shows the Dropmanu container.
     */    
    show: function(){
      this.position();
      this.element.addClass('dropdown-selected');
      this.content.css({ 
        display: 'block',
        visibility: 'visible' 
      });
    },
    
    /**
     * Determines and applies a top offset to the Dropdown container based on the height of the Dropdown trigger.
     */    
    position: function(){
      this.content.css({ 
        top: this.element.outerHeight() 
      });
    },

    /**
     * The callback fired when a fetch is successful.
     * @param {Object} data The response.   
     */      
    data_received: function( data ){
      this.content.removeClass('ui-loading');
      this.render( data );    
    },

    /**
     * Binds fetched data to the specified template and replaces the current Dropdown container content with the bound template.
     * @param {Object} data to bind to the template.   
     */        
    render: function( data ){
      this.content.find('.templated-content').html(
        this.template.render({ alerts:data })
      );
    }  
  };

  $.fn.dropdown = function( settings ){
    if (!this.length) return;
    return this.each(function(){
      (new Dropdown(this, settings));
    });
  };

})(jQuery);
