﻿YAHOO.namespace("Hollow.Widget");

(function() {
  var SELECTED_CLASS_NAME = "HollowSlideSelected";
  var STATES = {PAUSED: "Paused", AUTO_PLAYING: "AutoPlaying"};
  var BUTTON_CLASS_NAMES = {NEXT: "Next", PREVIOUS: "Previous", PLAY_PAUSE: "PlayPause", SHOW: "Show", SELECTED: "Selected"};
  var STATE_CLASS_NAMES = STATES;
  var DEFAULT_AUTO_PLAY_MILLISECONDS = 5000;
  
  YAHOO.Hollow.Widget.Slideshow = function(container, slides, cfg){
    var cfg = (null == cfg) ? {} : cfg;
    this.slides = slides;
    this.container = YAHOO.util.Dom.get(container);
    this.key = YAHOO.util.Dom.generateId(container);
    this.currentIndex = (cfg.currentIndex) ? cfg.currentIndex : 0;
    this.state = (cfg.autoPlay) ? STATES.AUTO_PLAYING : STATES.PAUSED;
    this.autoPlayDuration = (cfg.autoPlayDuration) ? cfg.autoPlayDuration : DEFAULT_AUTO_PLAY_MILLISECONDS;
    if (STATES.AUTO_PLAYING == this.state) this.startTimer();
    this.autoPlayTimer = null;
    this.slideChanged = new YAHOO.util.CustomEvent("slideChanged", this);
    this.stateChanged = new YAHOO.util.CustomEvent("stateChanged", this);
    YAHOO.Hollow.Widget.SlideshowCallbackHandler.register(this, this.key);
  };

  YAHOO.Hollow.Widget.Slideshow.prototype = {
    
    show: function(newIndex){
      if (newIndex == this.currentIndex) {
        return this.currentIndex;
      }
      else if (null == newIndex || newIndex == NaN || newIndex < 0 || newIndex >= this.slides.length) {
        throw("Slide Index Out Of Range, max:" + (this.slides.length - 1) + ", min:0, given:" + newIndex);
      }
      this.transition(newIndex, this.currentIndex);
      this.currentIndex = newIndex;
      this.slideChanged.fire(this.currentIndex);
    },
    
  	next: function(){
  	  var nextIndex = this.currentIndex + 1;
      return this.show((nextIndex >= this.slides.length) ? 0 : nextIndex);	
    },
  
    previous: function(){
  	  var previousIndex = this.currentIndex - 1;
      return this.show((previousIndex < 0) ? this.slides.length - 1 : previousIndex);
    },
  
    handleTransitionComplete: function(type, args, cfg){
      if (cfg.index == cfg.that.currentIndex) {
        return false;
      }
      YAHOO.util.Dom.removeClass(cfg.that.slides[cfg.index], SELECTED_CLASS_NAME);
      YAHOO.util.Dom.setStyle(cfg.that.slides[cfg.index], "z-index", 0);
    },
    
    // stopTransition: function(){
    //   // for(var i=0;i<this.transitions.length;i++){
    //   //   this.transitions[i].stop(false);
    //   // }
    //   this.transition.stop(false);
    // },
    
    transition: function(newIndex, oldIndex){
      //this.state = STATES.TRANSITIONING;
    
      YAHOO.util.Dom.setStyle(this.slides[newIndex], "opacity", 0);
      YAHOO.util.Dom.setStyle(this.slides[newIndex], "z-index", 2);
      YAHOO.util.Dom.setStyle(this.slides[oldIndex], "z-index", 1);
      
      //TODO: this stacking is a hack to minimize the visual effect of the race condition
      // Implement an additional "transitioning" state and properly cancel old transitions 
      // before starting a new one
      for(var i=0;i<this.slides.length;i++){
        if (i != newIndex && i != oldIndex){
          YAHOO.util.Dom.setStyle(this.slides[i], "z-index", 0);
        }
      }
      YAHOO.util.Dom.addClass(this.slides[newIndex], SELECTED_CLASS_NAME);
      //var fadeOut = new YAHOO.util.Anim(this.slides[oldIndex], {opacity: {to: 0} }, 0.5);
    
      //fadeOut.onComplete.subscribe(this.hideSlide, {that: this, index: oldIndex});
      var fadeIn = new YAHOO.util.Anim(this.slides[newIndex], {opacity: {to: 1} }, 1);
      fadeIn.onComplete.subscribe(this.handleTransitionComplete, {that: this, index: oldIndex});
      //fadeOut.animate();
      
      fadeIn.animate();
      return newIndex;
    },
    
    play: function(){
      if(this.state == STATES.AUTO_PLAYING){
        return false;
      }
      this.state = STATES.AUTO_PLAYING;
      this.stateChanged.fire(this.state);
      return this.handleTick();
    },
    
    pause: function(){
      if(this.state != STATES.AUTO_PLAYING){
        return false;
      }
      this.state = STATES.PAUSED;
      this.stateChanged.fire(this.state);
      if (this.autoPlayTimer) clearTimeout(this.autoPlayTimer);
      this.autoPlayTimer = null;
    },
    
    handleTick: function(ev){
      if(this.state != STATES.AUTO_PLAYING){
        return false;
      }
      this.startTimer();
      return this.next();
    },
    
    startTimer: function(){
      this.autoPlayTimer = window.setTimeout('YAHOO.Hollow.Widget.SlideshowCallbackHandler.advance("' + this.key + '")', this.autoPlayDuration);
    }
  
  };
  
  YAHOO.Hollow.Widget.SlideshowController = function(show){
    this.show = show;
    this.show.slideChanged.subscribe(this.handleSlideChanged, this, true);
    this.show.stateChanged.subscribe(this.handleStateChanged, this, true);
  };

  YAHOO.Hollow.Widget.SlideshowController.prototype = {
    handleSlideChanged: function(ev, newIndex){
      //Override Me
      return true;
    },
    
    handleStateChanged: function(ev){
      //Override Me
      return true;
    },
    
    handleShow: function(ev, newIndex){
      this.show.pause();
      this.show.show(newIndex);
    },
    
    handlePlay: function(ev){
      this.show.play();
      this.show.next();
    },
    
    handlePause: function(ev){
      this.show.pause();
      this.show.next();
    },
    
    handlePlayPause: function(ev){
      (this.show.state == STATES.PAUSED) ? this.show.play() : this.show.pause();
    },
    
    handleNext: function(ev){
      this.show.pause();
      this.show.next();
    },
    
    handlePrevious: function(ev){
      this.show.pause();
      this.show.previous();
    }
  }
  
  YAHOO.Hollow.Widget.SimpleSlideshowController = function(container, show){
    YAHOO.Hollow.Widget.SimpleSlideshowController.superclass.constructor.call(this, show);
    this.container = YAHOO.util.Dom.get(container);
    this.buttons = {};
    this.buttons = {
      next: YAHOO.util.Dom.getElementsByClassName(BUTTON_CLASS_NAMES.NEXT, null, this.container)[0],
      previous: YAHOO.util.Dom.getElementsByClassName(BUTTON_CLASS_NAMES.PREVIOUS, null, this.container)[0],
      playPause: YAHOO.util.Dom.getElementsByClassName(BUTTON_CLASS_NAMES.PLAY_PAUSE, null, this.container)[0],
      slides: YAHOO.util.Dom.getElementsByClassName(BUTTON_CLASS_NAMES.SHOW, null, this.container)
    }
    
    YAHOO.util.Event.addListener(this.buttons.next, "click", this.handleNext, this, true);
    YAHOO.util.Event.addListener(this.buttons.previous, "click", this.handlePrevious, this, true);
    YAHOO.util.Event.addListener(this.buttons.playPause, "click", this.handlePlayPause, this, true);
    for(var i=0;i<this.buttons.slides.length;i++){
      YAHOO.util.Event.addListener(this.buttons.slides[i], "click", this.handleShow, i, this); 
    }
    
    this.updatePlayPause();
    this.updateShow(this.show.currentIndex);
  };
  
  YAHOO.lang.extend(YAHOO.Hollow.Widget.SimpleSlideshowController, YAHOO.Hollow.Widget.SlideshowController);
  
  var proto = YAHOO.Hollow.Widget.SimpleSlideshowController.prototype;
  
  proto.handleSlideChanged = function(ev, newIndex) { 
    if(this.buttons.slides.length < newIndex || newIndex < 0){
      return false;
    }
    this.updateShow(newIndex);
    //YAHOO.Hollow.Widget.SimpleSlideshowController.superclass.handleSlideChanged.call(this);
  };
  
  proto.handleStateChanged = function(ev) { 
    YAHOO.Hollow.Widget.SimpleSlideshowController.superclass.handleStateChanged.call(this);
    this.updatePlayPause();    
  };
  
  proto.handlePlayPause = function(ev) {
    YAHOO.Hollow.Widget.SimpleSlideshowController.superclass.handlePlayPause.call(this);
    this.updatePlayPause();    
  };
  
  proto.updatePlayPause = function(){
    if(STATES.PAUSED == this.show.state){
      YAHOO.util.Dom.removeClass(this.buttons.playPause, STATE_CLASS_NAMES.AUTO_PLAYING);
      YAHOO.util.Dom.addClass(this.buttons.playPause, STATE_CLASS_NAMES.PAUSED);
    } 
    else if(STATES.AUTO_PLAYING == this.show.state){
      YAHOO.util.Dom.removeClass(this.buttons.playPause, STATE_CLASS_NAMES.PAUSED);
      YAHOO.util.Dom.addClass(this.buttons.playPause, STATE_CLASS_NAMES.AUTO_PLAYING);
    }
  };
  
  proto.updateShow = function(newIndex){
    for(var i=0;i < this.buttons.slides.length;i++){
      YAHOO.util.Dom.removeClass(this.buttons.slides[i], BUTTON_CLASS_NAMES.SELECTED);
      if(newIndex == i){
        YAHOO.util.Dom.addClass(this.buttons.slides[i], BUTTON_CLASS_NAMES.SELECTED);
      }
    }
  };
  
  YAHOO.Hollow.Widget.SlideshowCallbackHandler = {
    shows: {},
    
    register: function(show, key){
      if(this.shows[key]){
        throw ("Show already registered with key: " + key);
      }
      this.shows[key] = show;
    },
    
    remove: function(key){
      this.shows[key] = null;
    },
    
    advance: function(key){
      this.shows[key].handleTick();
    }
  };

  YAHOO.Hollow.Widget.SlideshowFactory = {
  
    buildSlideshowFromList: function(listContainer, cfg){
      var cfg = (null == cfg) ? {} : cfg;
      var container = YAHOO.util.Dom.get(listContainer);
      var slides = YAHOO.util.Dom.getChildrenBy(container, function(el){return el.tagName == "LI"});
      if (!slides || slides.length <= 0) {
        throw ("No list items in: " + listContainer);
      }
      var currentIndex = -1;
      for (var i = 0; i < slides.length; i++) {
        if (YAHOO.util.Dom.hasClass(slides[i], SELECTED_CLASS_NAME)) {
          currentIndex = i;
          break;
        }
      }
      if (currentIndex < 0) {
        currentIndex = 0;
        YAHOO.util.Dom.addClass(slides[0], SELECTED_CLASS_NAME);
      }
      cfg.currentIndex = currentIndex;
      return new YAHOO.Hollow.Widget.Slideshow(container, slides, cfg);
    },
  
    buildSlideshowByClassName: function(container, className){
      return false;
    },
    
    buildSlideshow: function(slides){
      return false;
    }
  };  
})();