(function ($) {

$.fn.collapsible = function(options) {
  var defaults = {
    accordion: undefined,
    onOpen: undefined,
    onClose: undefined
  };

  options = $.extend(defaults, options);

  return this.each(function() {

    var $this = $(this);

    var $panel_headers = $(this).find('> li > .collapsible-header');

    var collapsible_type = $this.data("collapsible");

    // Turn off any existing event handlers
    $this.off('click.collapse', '> li > .collapsible-header');
    $panel_headers.off('click.collapse');

    /****************
    Helper Functions
    ****************/

    // Accordion Open
    function accordionOpen(object) {
      $panel_headers = $this.find('> li > .collapsible-header');
      if (object.hasClass('active')) {
        object.parent().addClass('active');
      }
      else {
        object.parent().removeClass('active');
      }
      if (object.parent().hasClass('active')){
        object.siblings('.collapsible-body').stop(true,false).slideDown({ duration: 350, easing: "easeOutQuart", queue: false, complete: function() {$(this).css('height', '');}});
      }
      else{
        object.siblings('.collapsible-body').stop(true,false).slideUp({ duration: 350, easing: "easeOutQuart", queue: false, complete: function() {$(this).css('height', '');}});
      }

      $panel_headers.not(object).removeClass('active').parent().removeClass('active');

      // Close previously open accordion elements.
      $panel_headers.not(object).parent().children('.collapsible-body').stop(true,false).each(function() {
        if ($(this).is(':visible')) {
          $(this).slideUp({
            duration: 350,
            easing: "easeOutQuart",
            queue: false,
            complete:
              function() {
                $(this).css('height', '');
                execCallbacks($(this).siblings('.collapsible-header'));
              }
          });
        }
      });
    }

    // Expandable Open
    function expandableOpen(object) {
      if (object.hasClass('active')) {
        object.parent().addClass('active');
      }
      else {
        object.parent().removeClass('active');
      }
      if (object.parent().hasClass('active')){
        object.siblings('.collapsible-body').stop(true,false).slideDown({ duration: 350, easing: "easeOutQuart", queue: false, complete: function() {$(this).css('height', '');}});
      }
      else {
        object.siblings('.collapsible-body').stop(true,false).slideUp({ duration: 350, easing: "easeOutQuart", queue: false, complete: function() {$(this).css('height', '');}});
      }
    }

    // Open collapsible. object: .collapsible-header
    function collapsibleOpen(object) {
      if (options.accordion || collapsible_type === "accordion" || collapsible_type === undefined) { // Handle Accordion
        accordionOpen(object);
      } else { // Handle Expandables
        expandableOpen(object);
      }

      execCallbacks(object);
    }

    // Handle callbacks
    function execCallbacks(object) {
      if (object.hasClass('active')) {
        if (typeof(options.onOpen) === "function") {
          options.onOpen.call(this, object.parent());
        }
      } else {
        if (typeof(options.onClose) === "function") {
          options.onClose.call(this, object.parent());
        }
      }
    }

    /**
     * Check if object is children of panel header
     * @param  {Object}  object Jquery object
     * @return {Boolean} true if it is children
     */
    function isChildrenOfPanelHeader(object) {

      var panelHeader = getPanelHeader(object);

      return panelHeader.length > 0;
    }

    /**
     * Get panel header from a children element
     * @param  {Object} object Jquery object
     * @return {Object} panel header object
     */
    function getPanelHeader(object) {

      return object.closest('li > .collapsible-header');
    }

    /*****  End Helper Functions  *****/

    // Add click handler to only direct collapsible header children
    $this.on('click.collapse', '> li > .collapsible-header', function(e) {
      var element = $(e.target);

      if (isChildrenOfPanelHeader(element)) {
        element = getPanelHeader(element);
      }

      element.toggleClass('active');

      collapsibleOpen(element);
    });

    // Open first active
    if (options.accordion || collapsible_type === "accordion" || collapsible_type === undefined) { // Handle Accordion
      collapsibleOpen($panel_headers.filter('.active').first());

    } else { // Handle Expandables
      $panel_headers.filter('.active').each(function() {
        collapsibleOpen($(this));
      });
    }

  });
};

$(document).ready(function(){
  $('.collapsible').collapsible();
});

}( jQuery ));