/*
 * jQuery 'Archiver' plugin
 * Copyright (c) 2008 -- Ryan Funduk
 *
 * Version 0.1 (15/10/2008)
 * Requires jQuery 1.2.6+
 *
 * You may use this code under the MIT license.
 * ( http://www.opensource.org/licenses/mit-license.php )
 *
 *
 * OPTIONS:
 *
 *  option        default         description
 *  ---------------------------------------------------------------------------
 *  animate       {}              Animation settings (can be null).
 *                                Includes options:
 *                                 in: {}, out: {}, inSpeed: int, outSpeed: int
 *  speed         600             Speed of the animation in milliseconds.
 *  initItem      'all'           The initial 'chosen' menu item. Can be 'null'.
 *  includeAll    true            Whether or not to include the 'all' item.
 *  trigger       'mouseover'     How you wish to interact with the menu.
 *  topSelector   'year'          The containers to work with. They should
 *                                contain headSelectors and itemSelectors.
 *  itemSelector  'ul li'         Used to attach the link behavior to it's
 *                                container (eg, clicking on the li will act
 *                                as if you clicked the link). Setting this to
 *                                null will cause this to not happen.
 *  idPrefix:     'archiver-'     Name your container divs "archiver-2008" (for
 *                                example), especially useful since "2008" is
 *                                not a valid DOM id.
 *  menuClass:    'archiver-menu' Allows you to re-class the menu container that
 *                                is created at the top of your wrapper element.
 *
 *
 * EXAMPLE:
 *
 *  <div id="archives">
 *    <div class="year" id="archiver-2007">
 *      <h2>Items from 2007</h2>
 *      <ul>
 *        <li><a href="/item1">Item 1</a></li>
 *        <li><a href="/item2">Item 2</a></li>
 *        <li><a href="/item3">Item 3</a></li>
 *      </ul>
 *    </div>
 *    <div class="year" id="archiver-2008">
 *      <h2>Items from 2008</h2>
 *      <ul>
 *        <li><a href="/item4">Item 4</a></li>
 *        <li><a href="/item5">Item 5</a></li>
 *        <li><a href="/item6">Item 6</a></li>
 *      </ul>
 *    </div>
 *  </div>
 *
 * Note that the heirarchy here is required. A top level div with multiple
 * div's inside it -- these divs' id's are the menu items and they must have
 * a class which you pass as an option (the default being 'year' since that is
 * most likely the common use case).
 *
 * Then, you'll have simple code like:
 *
 *  $(document).ready( function () {
 *    $('#archives').archiver();
 *  } );
 *
 */

( function( $ ) {
  $.fn.archiver = function( opts ) {
    var wrapper = this;
    var options = $.extend( $.fn.archiver.defaults, opts );
    var all = [];
    var total_width = 1;

    if( options.includeAll ) { all.push( "ALL" ); }

    function createMenu() {
      var html = [];
      for( var i = 0; i < all.length; i++ ) {
        var raw = all[i];
        if( all[i] != 'ALL' ) { raw = all[i].slice( options.idPrefix.length ); }
        html.push( '<a id="' + raw.toLowerCase() + '_link" class="' +
                   ( i + 1 == all.length ? 'last' : '' ) + '" href="#">' +
                   raw + '</a>' );
      }
      wrapper.prepend( '<div class="' + options.menuClass + '">' +
                       html.join('') +
                       '</div><div style="clear:both"></div>' );

      $('.' + options.menuClass + ' a').each( function() {
        total_width += findOuterWidth( $(this) );
      } );
      $('.' + options.menuClass).css( 'width', total_width + "px" );
    }

    function setupMenuHandlers() {
      // .archiver-menu a
      wrapper.find( '.' + options.menuClass + ' a' ).bind( options.trigger, function() {
        // remove ugly dotted line from menu incase the user clicks
        $(this).blur();

        var id = $(this).attr( 'id' ).split( '_' )[0];
        var sel = '.' + options.topSelector;
        var hideMatches, showMatches;

        // narrow down the topSelector for all menu items except 'all'
        if( id != 'all' ) { sel += "#" + options.idPrefix + id }

        // animate the appropriate containers
        hideMatches = wrapper.find( '.' + options.topSelector ).not( sel );
        showMatches = wrapper.find( sel )
        if( options.animate ) {
          hideMatches.animate( options.animate['out'], options.animate.outSpeed );
          showMatches.animate( options.animate['in'],  options.animate.inSpeed );
        }
        else {
          hideMatches.hide();
          showMatches.show();
        }

        $('.' + options.menuClass + ' a.selected').removeClass( 'selected' );
        $(this).addClass( 'selected' );

        // set the hash in the window so that if you click a link
        // you can use the back button and see the same list
        window.location.hash = "_" + id;
        return false;
      } );
    }

    function setupListHandlers() {
      wrapper.find( '.' + options.topSelector +
                    ' ' + options.itemSelector ).click( function() {
        window.location = $(this).find( 'a:first' ).attr( 'href' );
      } );
    }

    function findOuterWidth( e ) {
        return parseInt( e.css( 'padding-left' ),       10 ) +
               parseInt( e.css( 'padding-right' ),      10 ) +
               parseInt( e.css( 'margin-left' ),        10 ) +
               parseInt( e.css( 'margin-right' ),       10 ) +
               parseInt( e.css( 'border-left-width' ),  10 ) +
               parseInt( e.css( 'border-right-width' ), 10 ) +
               e.width();
    }

    return wrapper.each( function() {
      $(this).find( '.' + options.topSelector ).each( function( _, div ) {
        // we're going to take this head element and append it
        // to the list of head elements that already begins
        // with 'all'
        all.push( div.id.toString() );
        $(div).hide();
      } );

      createMenu();
      setupMenuHandlers();
      setupListHandlers();

      var initial = window.location.hash.split( '#_' )[1];
      if( !initial ) { initial = options.initItem.toString(); }

      if( ( initial == 'all' && options.includeAll ) || initial != 'all' ) {
        $( '.' + options.menuClass + ' a#' + initial + '_link' ).addClass( 'selected' );
        wrapper.find(
            ( initial == 'all' ?
              '.' + options.topSelector :
              "#" + options.idPrefix + initial + '.' + options.topSelector )
        ).show();
      }
    } );
  };

  $.fn.archiver.defaults = {
    animate:           { 'in':  { opacity: 'show', height: 'show' },
                         'out': { opacity: 'hide', height: 'hide' },
                         inSpeed: 600, outSpeed: 600 },
    trigger:           'mouseover',
    topSelector:       'year',
    itemSelector:      'ul li',
    initItem:          'all',
    includeAll:        true,
    idPrefix:          'archiver-',
    menuClass:         'archiver-menu'
  };
} )( jQuery );
