/* =========================================================
// jquery.innerFade.js

// Date: 2009-07-21
// Author: Wes Baker
// Mail: wes@wesbaker.com	
// Web: http://www.wesbaker.com
// ========================================================= */

(function ($) {
  var container, elements, settings;
  var currentTimeout = null;
  var count = 0;

  $.fn.innerFadePN = function (options) {
    return this.each(function () {
      $.innerFadePN(this, options);
    });
  };

  $.innerFadePN = function (container, options) {
    // Define default settings
    settings = {
      'animationType': 'fade',
      'easing': 'linear',
      'speed': 'normal',
      'type': 'sequence',
      'timeout': 2000,
      'loop': true,
      'containerHeight': 'auto',
      'runningClass': 'innerFade',
      'children': null,
      'cancelLink': null,
      'pauseLink': '.pause',
      'prevLink': '.prev',
      'nextLink': '.next',
      'indexContainer': null,
      'currentItemContainer': null,
      'totalItemsContainer': null
    };


    // Combine default and set settings or use default
    if (options) { settings = $.extend(settings, options); }

    // If children option is set use that as elements, otherwise use the called jQuery object
    elements = (settings.children === null) ? $(container).children() : $(container).children(settings.children);

    container = container;

    // Start the loop
    if (elements.length > 1) {
      // Establish the Next and Previous Handlers
      $.bindControls();

      // Establish Cancel Handler
      if (settings.cancelLink) { $.bindCancel(); };

      // Set outer container as relative, and use the height that's set and add the running class
      $(container).css({ 'position': 'relative' }).addClass(settings.runningClass);
      if (settings.containerHeight == 'auto') {
        height = $(elements).filter(':first').height();
        $(container).css({ 'height': height + 'px' });
      } else {
        $(container).css({ 'height': settings.containerHeight });
      };

      // Build the Index if one is specified
      if (settings.indexContainer) {
        $.innerFadeIndex();
      };

      $(elements).filter(':gt(0)').hide(0);
      // Set the z-index from highest to lowest (20, 19, 18...) and set their position as absolute
      for (var i = 0; i < elements.length; i++) {
        $(elements[i]).css('z-index', String(elements.length - i)).css('position', 'absolute');
      }

      var toShow = '';
      var toHide = '';

      if (settings.type == "random") {
        toHide = Math.floor(Math.random() * elements.length);
        do {
          toShow = Math.floor(Math.random() * elements.length);
        } while (toHide == toShow);

        $.fadeTimeout(toShow, toHide, true);
        $(elements[toHide]).show();
      } else if (settings.type == 'random_start') {
        settings.type = 'sequence';
        toShow = Math.floor(Math.random() * (elements.length));

        $.fadeTimeout((toShow + 1) % elements.length, toShow, true);
        $(elements[toShow]).show();
      } else {
        // Otherwise and if its sequence
        toShow = 0;
        toHide = elements.length - 1;

        $.fadeTimeout(toShow, toHide, true);
        $(elements[0]).show();
      }

      // Set item count containers
      if (settings.currentItemContainer) { $.currentItem(toShow); };
      if (settings.totalItemsContainer) { $.totalItems(); };

      // Establish the Pause Handler
      $.bindPause();
    }
  };


  /**
  * Fades the slideshow to the item selected from the previous item
  * @param {Number} toShow The position in the elements array of the item to be shown
  * @param {Number} toHide The position in the elements array of the item to be hidden
  */
  $.fadeToItem = function (toShow, toHide) {
    // Update the next and previous controls
    var buildControls = function () {
      if (settings.nextLink || settings.prevLink) { $.bindControls(); }
    };

    if (settings.animationType == 'slide') {
      $(elements[toHide]).slideUp(settings.speed);
      $(elements[toShow]).slideDown(settings.speed, function () { buildPreviousNext(); });
    } else if (settings.animationType == 'slideOver') {
      var itemWidth = $(elements[0]).width();
      $(container).css({ 'overflow': 'hidden' });
      $(elements[toHide]).css({ 'left': '0px', 'position': 'absolute', 'right': 'auto', 'top': '0px' });
      $(elements[toShow]).css({ 'left': 'auto', 'position': 'absolute', 'right': '-' + itemWidth + 'px', 'top': '0px' }).show();

      $(elements[toHide]).animate({ 'left': '-' + itemWidth + 'px' }, settings.speed, settings.easing, function () {
        $(this).hide();
      });
      $(elements[toShow]).animate({ 'right': '0px' }, settings.speed, settings.easing, function () {
        buildControls();
      });
    } else {
      $(elements[toHide]).fadeOut(settings.speed);
      $(elements[toShow]).fadeIn(settings.speed, function () {
        buildControls();
      });
    }
    // Update the toShow item
    if (settings.currentItemContainer) {
      $.currentItem(toShow);
    };

    // Update indexes with active classes
    if (settings.indexContainer) {
      $.updateIndexes(toShow);
    };
  };

  /**
  * Fades to the item of your choosing and establishes the timeout for the next item to fade to
  * @param {Number} toShow The position in the elements array of the item to be shown
  * @param {Number} toHide The position in the elements array of the item to be hidden
  * @param {Boolean} firstRun If this is the first run of innerfade, pass true, otherwise pass false
  */
  $.fadeTimeout = function (toShow, toHide, firstRun) {
    // If its not the first run, then fade
    if (firstRun != true) {
      $.fadeToItem(toShow, toHide);
    };

    // Increment the count of slides shown
    count++;

    // Check if loop is false, if it is check to see how many slides have been shown.
    // In the case that you're at the last slide, stop the slideshow and return.
    if (settings.loop == false && count >= elements.length) {
      $.stopSlideshow();
      return;
    };

    // Get ready for next fade
    if (settings.type == "random") {
      toHide = toShow;
      while (toShow == toHide) { toShow = Math.floor(Math.random() * elements.length); }
    } else {
      toHide = (toHide > toShow) ? 0 : toShow;
      toShow = (toShow + 1 >= elements.length) ? 0 : toShow + 1;
    }

    // Set the time out
    currentTimeout = setTimeout((function () { $.fadeTimeout(toShow, toHide, false); }), settings.timeout);
  };

  /* Allows the unbind function to be called from javascript */
  $.fn.innerFadeUnbind = function () {
    return this.each(function (index) {
      $.stopSlideshow();
    });
  };

  /**
  * Stops the slideshow
  * @param {jQuery Object} container The container that first calls the innerfade plugin
  */
  $.stopSlideshow = function () {
    //clearTimeout(currentTimeout);
    //currentTimeout = null;
  };

  /**
  * Establishes the Next and Previous link behavior
  * @param {jQuery Object} container The container that first calls the innerfade plugin
  * @param {Array} elements The elements within the container
  * @param {Object} settings The settings object which contains speed, style, selectors of the items and so on
  */
  $.bindControls = function () {
    $(settings.nextLink).unbind().one('click', function (event) {
      event.preventDefault();
      $.stopSlideshow();

      var $currentElement = $(elements).filter(':visible');
      var currentElementIndex = $(elements).index($currentElement);

      var $nextElement = ($currentElement.next().length > 0) ? $currentElement.next() : $(elements).filter(':first');
      var nextElementIndex = $(elements).index($nextElement);

      $.fadeToItem(nextElementIndex, currentElementIndex);
    });

    $(settings.prevLink).unbind().one('click', function (event) {
      event.preventDefault();
      $.stopSlideshow();

      var $currentElement = $(elements).filter(':visible');
      var currentElementIndex = $(elements).index($currentElement);

      var $previousElement = ($currentElement.prev().length > 0) ? $currentElement.prev() : $(elements).filter(':last');
      var previousElementIndex = $(elements).index($previousElement);

      $.fadeToItem(previousElementIndex, currentElementIndex);
    });
  };

  /**
  * Establishes the Pause Button
  * @param {jQuery Object} container The container that first calls the innerfade plugin
  * @param {Array} elements The array of elements within the container
  * @param {Object} settings The settings object which contains speed, style, selectors of the items and so on
  */
  $.bindPause = function () {
    $(settings.pauseLink).unbind().click(function (event) {
      event.preventDefault();
      if (currentTimeout != null) {
        $.stopSlideshow();
      } else {
        var tag = $(container).children(':first').attr('tagName').toLowerCase();
        var nextItem = '';
        var previousItem = '';

        if (settings.type == "random") {
          previousItem = Math.floor(Math.random() * elements.length);
          do {
            nextItem = Math.floor(Math.random() * elements.length);
          } while (previousItem == nextItem);
        } else if (settings.type == "random_start") {
          previousItem = Math.floor(Math.random() * elements.length);
          nextItem = (previousItem + 1) % elements.length;
        } else {
          previousItem = $(tag, $(container)).index($(tag + ':visible', $(container)));
          nextItem = ((previousItem + 1) == elements.length) ? 0 : previousItem + 1;
        }

        $.fadeTimeout(nextItem, previousItem, false);
      }
    });
  };

  /**
  * Establishes the Cancel Button
  */
  $.bindCancel = function () {
    $(settings.cancelLink).unbind().click(function (event) {
      event.preventDefault();
      $.stopSlideshow();
    });
  };

  /**
  * Updates the indexes and adds an active class to the visible item
  * @param {Number} toShow The position in the elements array of the item to be shown
  */
  $.updateIndexes = function (toShow) {
    $(settings.indexContainer).children().removeClass('active');
    $('> :eq(' + toShow + ')', $(settings.indexContainer)).addClass('active');
  };

  /**
  * Creates handlers for the links created by the $.handleIndexes and $.generateIndexes functions
  * @param {Number} count The item to be setting the link on
  * @param {jQuery Object} link The selector or jQuery object of the link
  */
  $.createIndexHandler = function (count, link) {
    $(link).click(function (event) {
      event.preventDefault();
      var $currentVisibleItem = $(elements).filter(':visible');
      var currentItemIndex = $(elements).index($currentVisibleItem);
      $.stopSlideshow();
      if ($currentVisibleItem.size() <= 1) {
        $.fadeToItem(count, currentItemIndex);
      };
    });
  };

  /**
  * Creates one link for each item in the slideshow, to show that item immediately
  */
  $.createIndexes = function () {
    var $indexContainer = $(settings.indexContainer);

    for (var i = 0; i < elements.length; i++) {
      var $link = $('<li>' + (i + 1) + '</li>');
      if (i == 0) {
        $($link).addClass('active');
      }
      //console.log(i + " " + $link);
      $.createIndexHandler(i, $link);
      $indexContainer.append($link);
      //return $link;
    };
  };

  /**
  * Establishes links between the slide elements and index items in the indexContainer
  */
  $.linkIndexes = function () {
    var $indexContainer = $(settings.indexContainer);
    var $indexContainerChildren = $('> :visible', $indexContainer);

    if ($indexContainerChildren.size() == elements.length) {
      var count = elements.length;
      for (var i = 0; i < count; i++) {
        $('a', $indexContainer).click(function (event) { event.preventDefault(); });
        $.createIndexHandler(i, $indexContainerChildren[i]);
      };
    } else {
      alert("There is a different number of items in the menu and slides. There needs to be the same number in both.\nThere are " + $indexContainerChildren.size() + " in the indexContainer.\nThere are " + elements.length + " in the slides container.");
    };
  };

  /**
  * Determines if the index container is empty or not. If its empty then it generates links, if its not empty it links one to one
  */
  $.innerFadeIndex = function () {
    //var $indexContainer = $(settings.indexContainer);

    //if ($indexContainer.html().length <= 0) {
    // $.createIndexes();
    //} else {
    //$.linkIndexes();
    //};
  };

  /**
  * Changes the text of the current item selector to the index of the current item
  */
  $.currentItem = function (current) {
    var $container = $(settings.currentItemContainer);
    $container.text(current + 1);
  };

  /**
  * Changes the text of the total item selector to the total number of items
  */
  $.totalItems = function () {
    var $container = $(settings.totalItemsContainer);
    $container.text(elements.length);
  };
})(jQuery);
