;(function($) {

// TODO make this a widget, allow some flexibility over css classes
// TODO make vertical / horizontal carousel an option

var defaults = {
  orientation : 'vertical',
  pagesize    : 3,
  deltasize   : 3,
  speed       : 3,
  timeunit    : 500,
  index       : 0,
  items       : [],
  previews    : [],
  count       : 0,
  animating   : false
};

var state;


$.carouselize = function( elem, opts ) {

  state = $.extend( {}, defaults, opts );
  state.items = $( '.carousel-lister .carousel-item', elem );
  state.previews = $( '.carousel-preview .carousel-preview-item', elem );
  state.count = state.items.length;

  // When pagination prev or next control is clicked.

  $( '.carousel-pagination a', elem ).click( function() {

    if (state.animating)
      return false;

    // Determine direction of scroll
 
    var dir = 0;

    if ($(this).hasClass( 'carousel-next' ))
      dir = +1;
    else if ($(this).hasClass( 'carousel-prev' ))
      dir = -1;

    var new_index = state.index + dir * state.deltasize;

    return carousel_scrollto( elem, new_index );

  } );


  // When a carousel item is clicked directly.

  $( '.carousel-item a', elem ).click( function() { 

    state.items.removeClass('active');
    state.previews.removeClass('active');

    $(this).parents('.carousel-item').addClass('active');

    var href = $(this).attr('href');
    var id = href.replace(/^#/,'');
    $( '#carousel-preview-'+id ).addClass('active');

    // $('.gallery-preview img').attr('src', $(this).attr('href'));
    // $('.gallery-preview .caption').html($(this).attr('title'));

    return false;

  } );


  // When a carousel preview item is clicked, send click to the carousel item,
  // scrolling the carousel to reveal it.

  $( '.carousel-preview-item a', elem ).click( function() {

    var id = $(this).parent().attr('id').replace(/^carousel-preview-/,'');
    var item = $( '.carousel-item a[href=#'+id+']', elem ).parent();
    var index = parseInt( $(item).attr('id').replace(/^carousel-index-/,'') );

    carousel_scrollto( elem, index, item );

    return false;

  } );

  $( '.carousel-next', elem ).addClass('active'); // FIXME only if enough items
  $( '.carousel-item a:first', elem ).click();

}


function carousel_scrollto( elem, index, item ) {

  // Can't scroll past the first item on the first page.

  if (index < 0)
    index = 0;

  // Can't scroll past the first item on the last page.

  if (index > state.count - state.pagesize)
    index = state.count - state.pagesize;

  // Do nothing if scroll position wouldn't change.

  if (index == state.index) {
    if (item) $( 'a', item ).click();
    return false;
  }

  // Compute duration of scroll based on relatively constant speed.

  var distance = Math.abs( state.index - index );
  var duration = state.timeunit * Math.max( 1, Math.round( distance / state.speed ) );

  // Compute offset of new leftmost item
  // after the scroll, and slide animate to it.

  state.index = index;

  // The carousel item to select after scrolling.
  // Defaults to the top item on the page.

  if (item == null)
    item = state.items[state.index];

  // Determine css properties to animate, based on carousel orientation.

  var first = $( state.items[state.index] );
  var css;

  if (state.orientation == 'vertical') {
    var top = -first.position().top;
    css = { top: top + 'px' };
  }
  else if (state.orientation == 'horizontal') {
    var left = -first.position().left;
    css = { left: left + 'px' };
  }
  else {
    return false; // TODO throw
  }

  // Execute the animation

  state.animating = true;

  $( '.carousel-lister', elem ).animate(
    css,
    duration,
    'swing',       // easing function
    function() {   // completion callback
      $( 'a', item ).click();
      state.animating = false;
    }
  );

  // Update pagination controls

  if (state.index > 0)
    $( '.carousel-prev', elem ).addClass('active').removeAttr('disabled');
  else
    $( '.carousel-prev', elem ).removeClass('active').attr('disabled','true');

  if (state.index + state.pagesize < state.count)
    $( '.carousel-next', elem ).addClass('active').removeAttr('disabled');
  else
    $( '.carousel-next', elem ).removeClass('active').attr('disabled','true');

  return false;
}


})(jQuery);

