( function( $ ) {
  $.fn.foldr = function() {
    var wrapper = $(this);
    var options = $.extend( $.fn.foldr.defaults, {} );

    var opened_text = "&mdash;";
    var closed_text = "&nbsp;+";
    var collapser = $("<div class='" + options.collapserClass + "'></div>");
    var msg = $("<div class='" + options.msgClass + "'>show code listing</div>");

    function speed( event ) {
      return event.shiftKey ? options.slowSpeed : options.regSpeed;
    }

    function collapse( event ) {
      $(this).html( opened_text ).unbind( 'click' ).click( expand );
      $(this).siblings('div.' + options.msgClass).hide();
      $(this).siblings('pre').animate( { height: 'show' }, speed( event ) );
    }

    function expand( event ) {
      var expander = $(this);
      expander.siblings('pre').animate(
        { height: 'hide' }, speed( event ),
        function() {
          $(this).siblings('div.' + options.msgClass).show();
          expander.html( closed_text ).unbind( 'click' ).click( collapse );
        }
      );
    }

    return wrapper.each( function() {
      var block = $(this);
      var open = block.parent().attr( 'title' ) != 'collapsed';
      if( !open ) {
        block.hide();
        collapser.html( closed_text );
      }
      else {
        collapser.html( opened_text );
      }

      block
        .before( collapser.clone() )
        .before( msg.clone() )
        .parent()
          .after( $("<br style='height: 0px; clear: both;' />") )
          .find( '.' + options.collapserClass )
            .click( open ? expand : collapse )
        .end()
        .find('div.' + options.collapserClass)
          .hover(
            function() { $(this).addClass( 'over' ); },
            function() { $(this).removeClass( 'over' ); }
          );

      if( $.browser.msie ) { block.before( $("<br style='clear:both;' />") ); }
    } );
  };

  $.fn.foldr.defaults = {
    collapserClass:  'code_collapser',
    msgClass:        'code_msg',
    regSpeed:        'fast',
    slowSpeed:       4000
  };
} )( jQuery );
