var Rotator = Class.create();

Rotator.prototype = {
  /**
   * @constructor  Create the spinner using an input, an up button, and a down button
   *
   * @param string/Element  inputElement
   * @param string/Element  upElement
   * @param string/Element  downElement
   * @param object          options
   * Available Options:
   *   interval     The amount to increment (default=1)
   *   round        The number of decimal points to which to round (default=0)
   *   min          The lowest allowed value, false for no min (default=false)
   *   max          The highest allowed value, false for no max (default=false)
   *   prefix       String to prepend when updating (default='')
   *   suffix       String to append when updating (default='')
   *   data         An array giving a list of items through which to iterate (default=false)
   *   onIncrement  Function to call after incrementing
   *   onDecrement  Function to call after decrementing
   *   afterUpdate  Function to call after update of the value
   *   onStop       Function to call on click or mouseup
   * @return void
   */
  initialize: function(element, list, options) {
    // store the elements
    this.element = $(element);
    this.list = this.buildList(list);
    this.layer1 = null;
    this.layer2 = null;
    this.img_index = -1;
    this.top_layer = null;
    // store the options
    this.options = Object.extend({
    	level: 1000,
    	auto_play: true,
      play_stop: false,
      speed: 3,
      onItemStart: Prototype.emptyFunction,      
      onItemFinish: Prototype.emptyFunction,      
      onListStart: Prototype.emptyFunction,      
      onListFinish: Prototype.emptyFunction      
    }, options);
    // set initial values
    //this.reset();
    // build our update function
    if (this.list)
    {
	    this.buildAnimation();
	    // define the rate of increasing speed
	    /*if (Prototype.Browser.IE) {
	      this.speedHash = {5: 300, 10: 175, 20: 90, 30: 17};
	    } else {
	      this.speedHash = {5: 250, 10: 85, 20: 35, 30: 10};
	    }*/
	    // attach listeners
	    this.observe();
    }
  },
  buildList: function(list)
  {
    var items = null;
  	if($(list))
  	{
  		list = $(list);
  		if(list.tagName.toLowerCase() == 'ul')
  		{
        var childs = list.childElements()
        items = new Array();
        childs.each(function(item){
        	items[items.length] = item.innerHTML;
        })	
  		}
  	}
    return items;
  },
  /**
   * Helper function to define the update function
   *
   * @return void
   */
  buildAnimation: function()
  {
    // do we have a data list?
    this.layer1 = $(document.createElement('div'));
    this.layer1.setStyle({'position': 'absolute', 'zIndex': this.getLevel(1), 'height': '100%', 'width': '100%'});
    this.layer2 = $(document.createElement('div'));
    this.layer2.setStyle({'position': 'absolute', 'zIndex': this.getLevel(0), 'height': '100%', 'width': '100%'});
    this.element.appendChild(this.layer1);
    this.element.appendChild(this.layer2);
    this.loadImages()
    this.top_layer = this.layer1;
  },
  loadImages: function()
  {
 		this.loadImage(this.layer1);
    this.loadImage(this.layer2);
  },
  loadImage: function(layer)
  {
    var index = (this.img_index < (this.list.length - 1))?this.img_index + 1:0;
  	var img = new Image();
	  img.src = this.list[index];
	  layer.innerHTML = "";
	  layer.appendChild(img);
    this.img_index = index;
  },
  fade: function() {
  	window.clearTimeout(this.timeout);
  	//this.top_layer.hide();
  	//this.swapLayers();
    this.top_layer.fade({afterFinish: this.swapLayers.bind(this)});
  },
  swapLayers: function(){
  	if(this.top_layer == this.layer1)
  	{
  		this.layer2.setStyle({'zIndex': this.getLevel(1)})
  		this.top_layer = this.layer2;
      this.loadImage(this.layer1);
      this.layer1.setStyle({'zIndex': this.getLevel(0)}).show();
  	}
  	else
  	{
      this.layer1.setStyle({'zIndex': this.getLevel(1)})
      this.top_layer = this.layer1;
      this.loadImage(this.layer2);
      this.layer2.setStyle({'zIndex': this.getLevel(0)}).show();
  	}
  	this.observe();
  },
  observe: function() {
    this.timeout = window.setTimeout(this.fade.bind(this), this.getSpeed())
  },
  /**
   * Start incrementing or decrementing based on a pressed key
   *
   * @event keydown on this.inputElement
   * @param object evt
   * @return void
   */
  keyStart: function(evt) {
    if (this.running == false) {
      if (evt.keyCode == Event.KEY_UP) {
        this.running = 'key';
        this.increment();
      } else if (evt.keyCode == Event.KEY_DOWN) {
        this.running = 'key';
        this.decrement();
      }
    }
  },
  /**
   * Start incrementing or decrementing based on a mousedown action
   *
   * @param boolean multiplier  If multipler is 1, increment
   * @return void
   */  
  clickStart: function(multiplier) {
    this.running = 'mouse';
    if (multiplier == 1) {
      this.increment();
    } else {
      this.decrement();
    }
  },
  /**
   * Set to resting state
   *
   * return @void
   */
  reset: function() {
    // blur the up/down buttons if we got started by clicking
    if (this.running == 'mouse') {
      this.upElement.blur();
      this.downElement.blur();      
    }
    this.running = false;
    this.iterations = 0;
  },
  /**
   * Reset and clear timeout
   *
   * @return void
   */
  stop: function() {
    this.reset();
    window.clearTimeout(this.timeout);
    this.options.onStop(this);
  },
  /**
   * Increment the value
   *
   * @return void
   */
  increment: function() {
    this.updateValue(1);
    this.timeout = window.setTimeout(this.increment.bind(this), this.getSpeed());
    this.options.onIncrement(this);
  },
  /**
   * Decrement the value
   *
   * @return void
   */  
  decrement: function() {
    this.updateValue(-1);
    this.timeout = window.setTimeout(this.decrement.bind(this), this.getSpeed());
    this.options.onDecrement(this);
  },
  /**
   * Get the delay for the next timeout
   * Overwrite this function for custom speed schemes
   *
   * @return integer
   */  
  getLevel: function(n) {
    return this.options.level + n;
  }, 
  getSpeed: function() {
    return this.options.speed * 1000;
  } 
};
