/*  
Script: carousel.js
  Builds a carousel object that manages the basic functions of a generic carousel (a carousel
  here being a collection of "slides" that play from one to the next, with a collection of
  "buttons" that reference each slide).
  
Dependancies:
   mootools - <Moo.js>, <String.js>, <Array.js>, <Function.js>, <Element.js>, <Dom.js>
  
Author:
  Aaron Newton, <aaron [dot] newton [at] cnet [dot] com>
  


Class: CNETcarousel
  This class is for the standard cnet carousel for doors on our
  network. Instantiate this carousel class, configured to your names and
  preferences, and you're done. You can have as many on a page as
  you like.
  
  This class should work for any type of layout provided that:
  - The carousel is made up of buttons and slides, and there are
    an equal amount of both.
  - The buttons have an "on state" class and an "off state" class
  - The slides are "on top" of each other; this class fades one
    out and fades another in. It does not create a slide or position
    it.
  
Arguments:
  container - a DOM element containing the slides and buttons
  options - optional, an object containing options.

Options:
  carouselContainer - the id of the parent element that contains
                      the carousel (which is typically hidden in css
                      with visibility: hidden)
                      default: "Carousel"
  slidesSelector    - the css selector for the slide elements
                      note: this is relative to the carouselContainer object,
                      so only elements that match this selector within that object
                      will be included in the carousel
                      default: ".slide"
  buttonsSelector   - the css selector for the buttons; same rules as slidesSelector
                      default: ".button"
  startIndex        - the first item to show
                      default: 0
  buttonOnClass     - the class for the "on" state of the buttons
                      default: "selected",
  buttonOffClass    - the class for the "off" state of the buttons
                      default: "off",
  rotateAction      - the action the user takes to rotate to the next button;
                      options: mouseover, click, or none
                      default: 'none'
  rotateActionDuration - the duration to use when the user interacts with the buttons
                      if rotateAction != "none". default: 100
  slideInterval     - the interval between slide rotations in the slideshow
                      default: 4000
  transitionDuration - the duration of the transition effect
                      default: 700
  autoplay          -  turn the slideshow on on instantiation
                      default: true 
  
  
  Examples:
  >var testCrsl = null;
  >window.addEvent('domready', {
  > testCrsl = new CNETcarousel({});
  >});
  >
  >OR
  >...
  > testCrsl = new CNETcarousel({
  >   slideInterval: 8000,
  >   rotateAction: 'mouseover',
  >   etc...
  > });
  
  HTML layout example:
  (start code)
    <div id="Carousel">
      <!-- SLIDE #1 -->
      <div class="slide dark">
        ...slide stuff goes here...
      </div>
      <!-- SlIDE #2 -->
      ...
      <!-- SlIDE #3 -->
      ...
      <!-- SlIDE #4 -->
      ...
    
      <div class="bubbles">
        <div class="button">
          ... bubble text or whatever goes here...
        </div>
      </div>
      <!-- BUTTON #2 -->
      <!-- BUTTON #3 -->
      <!-- BUTTON #4 -->
    </div>
  (end)
-- */
var CNETcarousel = new Class({
  initialize: function(container, options){
    this.container = $(container);
    if(!this.container.hasClass('hasCarousel')){
      this.container.addClass('hasCarousel');
      this.slides = [];
      this.buttons = [];
      this.setOptions({
        onRotate: Class.empty,
        onStop: Class.empty,
        onAutoPlay: Class.empty,
        onShowSlide: Class.empty,
        slidesSelector: ".slide",
        buttonsSelector: ".button",
        slideInterval: 4000,
        transitionDuration: 700,
        startIndex: 0,
        buttonOnClass: "selected",
        buttonOffClass: "off",
        rotateAction: "none",
        rotateActionDuration: 100,
        autoplay: true
      }, options);
      this.slides = $(container).getElements(this.options.slidesSelector);
      this.buttons = $(container).getElements(this.options.buttonsSelector);
      this.createFx();
      this.showSlide(this.options.startIndex);
      if(this.options.autoplay) this.autoplay();
      if(this.options.rotateAction != 'none') this.setupAction(this.options.rotateAction);
      return this;
    } else return false;
  },
/*
Property: setupAction
  *Private internal function; do not call directly.*
  Applies <showSlide> to the user action.
  
Arguments:
  string - the action to apply the slide change to; 'click' or 'mouseover'
  */
  setupAction: function(action) {
    this.buttons.each(function(el, idx){
      $(el).addEvent(action, function() {
        this.slideFx.setOptions(this.slideFx.options, {duration: this.options.rotateActionDuration});
        if(this.currentSlide != idx) this.showSlide(idx);
        this.stop();
      }.bind(this));
    }, this);
  },
/*  
Property: createFx
  *Private internal function; do not call directly.*
  Creates the effects objects for each slide and stores them in this.slideFx array. */
  createFx: function(){
    this.slideFx = new Fx.Elements(this.slides, {duration: this.options.transitionDuration});
    this.slides.each(function(slide){
      slide.setStyle('opacity',0);
    });
  },
/*  
Property: showSlide
  *Private internal function; do not call directly.*
  Shows a slide (and hides the others).
    
Arguments:
  slideIndex - the slide index to show
    
Example:
  >myCarousel.showSlide(0) //shows the first slide
  */
  showSlide: function(slideIndex){
    var action = {};
    this.slides.each(function(slide, index){
      if(index == slideIndex && index != this.currentSlide){ //show
        $(this.buttons[index]).removeClass(this.options.buttonOffClass).addClass(this.options.buttonOnClass);
        action[index.toString()] = {
          'opacity': [1]
        };
      } else {
        $(this.buttons[index]).removeClass(this.options.buttonOnClass).addClass(this.options.buttonOffClass);
        action[index.toString()] = {
          'opacity':[0]
        };
      }
    }, this);
    this.fireEvent('onShowSlide', slideIndex);
    this.currentSlide = slideIndex;
    this.slideFx.start(action);
  },
  
/*  
Property: autoplay
  Turns autoplay on.
  
Example:
  >myCarousel.autoplay() //start cycling slides
  */  
  autoplay: function(){
    this.createFx();
    this.slideshowInt = this.rotate.periodical(this.options.slideInterval, this);
    this.fireEvent('onAutoPlay');
  },
/*  
Property: stop
  Stops autoplaying the slides.
  
Example:
  >myCarousel.stop() //stop cycling slides
  */
  stop: function(){
    clearInterval(this.slideshowInt);
    this.fireEvent('onStop');
  },
/*  
Property: rotate
  *Private internal function; do not call directly.*
  Progresses to the next slide. */
  rotate: function(){
    current = this.currentSlide;
    next = (current+1 >= this.slides.length) ? 0 : current+1;
    this.showSlide(next);
    this.fireEvent('onRotate');
  },
/*  
Property: show
  Shows the carousel component (visibility: visible); 
  
  >myCarousel.show() //makes the carousel visible
  */
  show: function() {
    $(this.options.carouselContainer).setStyle('visibility','visible');
    if(!$(this.options.carouselContainer).isVisible())$(this.options.carouselContainer).setStyle('display','block');
  },
/*  
Property: hide
  Hides the carousel component (visibility: hidden);
  
Example:
  >myCarousel.hide() //makes the carousel invisible
    */
  hide: function(){
    $(this.options.carouselContainer).setStyle('visibility','hidden');
  }
});
CNETcarousel.implement(new Options);
CNETcarousel.implement(new Events);

/*  Class: CNETcarouselWithButtons
    Extends <CNETcarousel> to include button imgs that are rotated with the slides.
    
    Arguments:
    el - the element containing the carousel
    options - the options object
    
    Options:
    bubbleButtonBGImgSelector - (optional) the selector to find the images inside the carousel container.
        defaults to ".bbg".
    buttonOnGifSrc - (optional) the url to the "on" button. defaults to
        http://i.i.com.com/cnwk.1d/i/fd/c/green_button.gif
    buttonOffSrc - (optional) the url to the "off" button. defaults to
        http://i.i.com.com/cnwk.1d/i/fd/c/gray_button.gif

    See <CNETcarousel> for additional options.
      */

var CNETcarouselWithButtons = CNETcarousel.extend({
  initialize:function(el, options){
    this.parent(el, $merge({
      bubbleButtonBGImgSelector: '.bbg',
      buttonOnGifSrc: 'http://i.i.com.com/cnwk.1d/i/fd/c/green_button.gif',
      buttonOffGifSrc: 'http://i.i.com.com/cnwk.1d/i/fd/c/gray_button.gif'
    }, options));
  },
  showSlide: function(slideIndex){
    this.buttons.each(function(button, index){
      $(button).getElement(this.options.bubbleButtonBGImgSelector).src = (index == slideIndex)?this.options.buttonOnGifSrc:this.options.buttonOffGifSrc;
    }, this);
    this.parent(slideIndex);
  }
});
/*
var carousel = null;
window.addEvent('domready', function(){
  if($('Carousel')) {
    carousel = new CNETcarouselWithButtons($('Carousel'),{buttonsSelector:'.bubble', rotateAction:'mouseover'});
  }
});
*/