function Ring3D(id, radius, speed) {
  this.id = id;
  this.speed = speed || 1000;
  this.radius = radius || 300;
  this.currentIndex = 0;
};

Ring3D.prototype.scale = function() {
  var ind = this.currentIndex;
  var items = this.getItems();
  var low = ind - 6;
  var high = ind + 6;
  var Cos = Math.cos;
  var Sin = Math.sin;
  var Round = Math.round;
  var radius = this.radius;
  for(var i=0, style, l = items.length; i < l; i++) {
    style = items[i].style;
    if(i > low && i < high) {
      rad = (i-ind)/4;
      cos = Cos(rad);
      var sin = Sin(rad);
      var widthZ = Round(cos*100);
      style.left = Round(sin*radius)-widthZ+'px';
      style.top = -widthZ/2+'px';
      style.width = widthZ+'px';
      style.height = widthZ+'px';
      style.display = 'block';
      set_opacity(items[i], widthZ);
      style.zIndex = widthZ;
    }
    else style.display = 'none';
  }
};

Ring3D.prototype.shiftTo = function(indx) {
  this.currentIndex = indx;
  this.scale();
};

Ring3D.prototype.getItems = function() {
  return this.getWrapper().childNodes;
};

Ring3D.prototype.getWrapper = function() {
  return get_by_id(this.id);
};



function Scroller3d(id, radius, speed, callBack) {
  this.ring = new Ring3D(id, radius, speed, radius);
  this.animator = new Animator();
  this.callBack = callBack || null;
  var wrpr = this.ring.getWrapper();
  wrpr.oncontrolselect = preventDefault;
  addEvent(wrpr,'mousedown',preventDefault,false);
  this.addEvent(wrpr,'click', 'click');
};

Scroller3d.prototype = new ObjectEvents();

Scroller3d.prototype.getItem = function(e) {
  for(var el = get_srcEl(e);
      el && typeof el.itemIndex == 'undefined';
      el = el.parentNode);
  return el;
};

Scroller3d.prototype.getCurrentItem = function() {
  return this.ring.getItems()[Math.round(this.ring.currentIndex)];
};


Scroller3d.prototype.draw = function(indx) {//<-- This is a bad hack. Figure out a better way to do this.
  if(indx != 0)
  this.scrollBy(indx);
  else {
    this.ring.shiftTo(indx);
    this.callBack(this.getCurrentItem());
  }
};

Scroller3d.prototype.scrollBy = function(indx) {
  var curIndx = this.ring.currentIndex;
  var finalPos = curIndx + indx;
  if(finalPos < 0) {
    finalPos = 0;
    indx = 0 - curIndx;
  }
  else if (finalPos > this.ring.getItems().length -1) {
    finalPos = this.ring.getItems().length -1;
    indx = finalPos - curIndx;
  };

  if(indx != 0) {
    this.stopScrolling();
    var me = this;
    var shiftWrapper = function(val) {
      val = curIndx + val/100*indx;
      me.ring.shiftTo(val);
      me.isNotScrolling = val == curIndx + indx;
    };

    var onEnd = function() {
      me.callBack(me.getCurrentItem());
    };

    this.animator.start(shiftWrapper, 0, 100, 'out', this.speed ,onEnd);
  }
};

Scroller3d.prototype.stopScrolling = function() {
    this.animator.stop();
};

Scroller3d.prototype.click = function(e) {
  if(this.wasMoved) return;
  var item = this.getItem(e);
  if(item) {
    preventDefault(e);
    this.scrollBy(item.itemIndex - this.ring.currentIndex);
  }
};
