//

Event.observe(window, 'load', function() {
  // if this exists we should init a Ticker on it
  if($('productTicker') && $('tickerid')){
     var ticker = new Ticker($('productTicker'), $('tickerid').value, 4);
  }
});

var Ticker = Class.create();
Ticker.prototype = {
   initialize: function(el, id, slots) {
      this.page = id;
      this.productEl = el;
      this.index = 0;
      this.slots = slots;
      this.products = [];
      this.moving = false;
      this.startIndex = 0;
      this.finishIndex = 0;
      this.startX = 0;
      this.finishX = 0;
      this.moveInc = 0;
      this.spacing = 0;
      this.clickable = false;
      this.right = $(document.createElement('DIV'));
      this.left = $(document.createElement('DIV'));
      this.content = $(document.createElement('DIV'));
      this.container = $(document.createElement('DIV'));
      this.setup();
      this.request();
   },
   setup: function(){
      // apply styles and attach to the DOM
      this.right.addClassName('tickerRight');
      this.left.addClassName('tickerLeft');
      this.content.addClassName('tickerContent');
      this.container.addClassName('tickerContainer');
      this.productEl.appendChild(this.left);
      this.productEl.appendChild(this.container);
      this.productEl.appendChild(this.right);
      this.container.appendChild(this.content);
      this.left.style.height = this.content.style.height = this.right.style.height = this.container.style.height = this.productEl.getHeight() + 'px';
      this.left.style.left = '0px';
      this.container.style.left = this.left.getWidth() + 'px';
      this.container.style.width = this.contentWidth() + 'px';
      this.right.style.left = (this.left.getWidth() + this.contentWidth()) + 'px';
   },
   request: function(){
      // request products
      new Ajax.Request('/ticker?id=' + this.page,{
         method:'get',
         onSuccess: function(res){
            var response = res.responseText.evalJSON();
            if(response.success){
               this.parseContent(response.products);
            }
         }.bind(this),
         onFailure: function(){
            // down the road, not across the street
         }.bind(this)
     });

   },
   contentWidth: function(){
      return this.productEl.getWidth() - this.left.getWidth() - this.right.getWidth();
   },
   
   parseContent: function(txt) {
      // attach our response to the DOM
      this.content.update(txt);
      var width = 0;
      var contW = this.contentWidth();
      var tempProducts = [];
      // Add products twice
      var len = this.content.childNodes.length;
      for(var i = 0; i < len; i++){
         var node = $(this.content.childNodes[i]).cloneNode(true);
         if(node.tagName == 'DIV')
            this.content.appendChild(node);
      }
      // spin through, looking for product divs, ignore text nodes. work out how wide we are.
      for(var i = 0; i < this.content.childNodes.length; i++){
         var node = $(this.content.childNodes[i]);
         if(node.tagName == 'DIV'){
            var nodeWidth = node.getWidth();
            this.spacing = Math.floor(((contW - (nodeWidth * this.slots)) / this.slots) / 2);
            node.style.left = '0px';
            node.style.position = 'absolute';
            this.products.push(node);
            width += node.getWidth() + this.spacing + this.spacing;
         }
      }
      // now that we're in the know, set the product container width.
      this.content.style.width = width + 'px';
      
      // position our products within the container
      for(var i = 0; i < this.products.length; i++){
         this.products[i].style.left = (i * (this.nodeWidth() + this.spacing * 2)) + this.spacing + 'px';
      }
      
      // if our ticker is full, we can enable the spinny buttons
      // we're doubled up on products to help with the scrolling animation so / 2
      if(this.products.length / 2 >= this.slots){
         this.clickable = true;
      }
      
      if(this.clickable){
         // this is a good time to enable our buttons
         Event.observe(this.right, 'click', this.moveRight.bind(this));
         Event.observe(this.left, 'click', this.moveLeft.bind(this));
         Event.observe(this.right, 'mouseover', this.mouseOverR.bind(this));
         Event.observe(this.left, 'mouseover', this.mouseOverL.bind(this));
         Event.observe(this.right, 'mouseout', this.mouseOutR.bind(this));
         Event.observe(this.left, 'mouseout', this.mouseOutL.bind(this));
      } else {
         // if we arn't clickable we should remove our doubled up products
         for(var i = this.products.length -1; i >= this.products.length / 2; i--)
            this.products[i].parentNode.removeChild(this.products[i]);
      }
   },
   slotWidth: function(){
      if(this.products.length > 0){
         return this.spacing + this.products[0].getWidth() + this.spacing;
      }
      return 0;
   },
   nodeWidth: function(){
      if(this.products.length > 0){
         return this.products[0].getWidth();
      }
      return 0;
   },
   mouseOverR: function(e){
      var tar = $(e.target || e.srcElement);
      tar.addClassName('tickerRightOver');
   },
   mouseOutR: function(e){
      var tar = $(e.target || e.srcElement);
      tar.removeClassName('tickerRightOver');
   },
   mouseOverL: function(e){
      var tar = $(e.target || e.srcElement);
      tar.addClassName('tickerLeftOver');
   },
   mouseOutL: function(e){
      var tar = $(e.target || e.srcElement);
      tar.removeClassName('tickerLeftOver');
   },
   moveLeft: function(e){
      // we would implode if we were to move while moving
      if(!this.moving){
         this.move(-1);
      }
   },
   moveRight: function(e){
      // we would implode if we were to move while moving
      if(!this.moving){
         this.move(1);
      }
   },
   move: function(amount){
      // because we are doubled up on products we can use some trickery to animate without
      // having to move or copy/paste product DOM nodes
      var newIndex = this.index + amount;
      if(newIndex < 0){
         // we've reached an edge, reset the product container's position
         // to somewhere more friendly
         newIndex = this.products.length / 2 - 1;
         this.startX = -((this.products.length / 2) * this.slotWidth());
         this.content.style.left = this.startX + 'px';
      } else if(newIndex > this.products.length / 2) {
         // we've reached the other edge, reset the product container's position
         // to somewhere more friendly
         newIndex = 1;
         this.startX = 0;
         this.content.style.left = this.startX + 'px';
      } else {
         // we don't have to move anything, use our current position
         this.startX = parseInt(this.content.getStyle('left'));
      }
      
      this.finishX = this.startX - this.slotWidth() * amount; 
      this.index = newIndex;
      // for 10 frames of animation, work out how far we have to move each frame
      this.moveInc = Math.abs((this.finishX - this.startX) / 10);
      // buckle up
      this.moving = true;
      // wheee
      this.moveCycle();
   },
   moveCycle: function(){
      // This moves the product container
      // if we arn't finished moving, it sets a timeout to run again
   
      var currentX = parseInt(this.content.getStyle('left'));
      
      // work out our direction
      if(this.startX < this.finishX){
         currentX += this.moveInc;
         // have we gone too far?
         if(currentX > this.finishX){
            currentX = this.finishX;
         }
      } else {
         currentX -= this.moveInc;
         // have we gone too far?
         if(currentX < this.finishX){
            currentX = this.finishX;
         }
      }
      
      // styles enjoy round numbers
      currentX = Math.round(currentX);
      
      // move
      this.content.style.left = currentX + 'px';
      
      // enabled button input so we can move again
      // or run again if we havn't finished
      if(currentX == this.finishX)
         this.moving = false; 
      else
         window.setTimeout(this.moveCycle.bind(this), 30);
   }
};

