/*********************************
   utils.js for Nintendo.com
   js code for Nintendo.com redesign prototype
   code by Chad Lindstrom (chad.lindstrom(AT)blastradius.com)
*********************************/

var shifterDebug = 1; // toggle debug output
var debugStr = "";
var animEnabled = true;

var ua = navigator.userAgent.toLowerCase();
var isGecho = (ua.match('gecho') != -1 );

/* object creation */
function Shifter(w, h, ID, targetID, controlsID, itemPrefix, numItems, visibleItems, isLooping, orientation ){

   this.width        = w;
   this.height       = h;

   this.targetID     = targetID;
   this.controlsID   = controlsID;

   this.numItems     = numItems;
   var numStates     = Math.ceil(numItems/visibleItems);

   this.statesArr    = new Array(numStates); //how to store state information ... not sure if needed
   this.itemPrefix   = itemPrefix;           //prefix for individual items
   this.currState    = 0;                    //same as array indexing
   this.looping      = isLooping;
   this.lastState    = this.statesArr.length - 1;
   this.firstState   = 0;
   this.visibleItems = visibleItems;
   this.orientation  = orientation; // 0 == landscape/horiz, 1 == portrait/vert

   //BEGIN CONSTANTS
   this.speedStart   = 22;    //trans speed at start
   this.speedEnd     = 16;     //trans speed at end
   this.speedMid     = 26;    //trans speed in mid
   this.goPrevious   = -1;    //flag for previous shifting
   this.goNext       = 1;     //flag for next shifting
   this.landscape    = 0;     //flag for landscape orientation
   this.portrait     = 1;     //flag for portrait orientation
   this.speedMean    = 30;     //default interval duration
   this.btnClass     = "shiftBtn";
   //END CONSTANTS


   this.init();
}

/* initialize the shifter and controls */
Shifter.prototype.init = function(){

   var _controlsElm  = getElm(this.controlsID);
   var _targetElm    = getElm(this.targetID);

   this.prevBtn            = createElm("DIV",this.controlsID + "_prevBtn",_controlsElm );
   this.prevBtn.className  = this.btnClass + " prevBtn";
   this.prevBtn.shifter    = this;
   addListener(this.prevBtn,"mousedown",this.shiftPrevious );

   //create state buttons and add event listeners
   this.stateBtns = createElm("DIV",this.controlsID + "_shiftButtons",_controlsElm );
   this.stateBtns.className = "shiftButtons";

   var stateBtnSize = 0;

   this.stateBtnsArray = new Array( this.statesArr.length );
   for( var i = this.firstState; i <= this.lastState; i++ ){
      var thisId = this.controlsID + "_shiftBtn_"+i;
      var tmpElem = createElm("DIV",thisId,this.stateBtns);
      var tmpClass = "shiftBtn" + i + "_" + ((this.currState == i) ? "sel" : "unsel");
      tmpElem.className = this.btnClass + " " + tmpClass;
      tmpElem.resultingState  = i;
      tmpElem.myId            = thisId;
      tmpElem.shifter         = this;

      addListener(tmpElem,"mousedown",this.doShift ); //not sure if this will work, ask Byron if problems?
      this.stateBtnsArray[i] = tmpElem;

      if(stateBtnSize==0){
         if(this.orientation == this.landscape){
            stateBtnSize = tmpElem.offsetWidth;
         } else {
            stateBtnSize = tmpElem.offsetHeight;
         }
      }
   }

   //add arrows and events
   this.nextBtn            = createElm("DIV",this.controlsID + "_nextBtn",_controlsElm );
   this.nextBtn.className  = this.btnClass + " nextBtn";
   this.nextBtn.shifter    = this;
   addListener(this.nextBtn,"mousedown",this.shiftNext);

   _targetElm.style.position  = "absolute";

   // positioning takes place now
   var totalSpace = (this.orientation == this.landscape) ? _controlsElm.offsetWidth : _controlsElm.offsetHeight;
   var btnPadding = 0;
   var spacing = Math.floor( (totalSpace - ( (this.statesArr.length) * (stateBtnSize+btnPadding) )) / 2 ) + btnPadding;

   this.stateBtns.style.position = "absolute";
   if(this.orientation == this.landscape){
      this.stateBtns.style.left  = spacing + "px";
   } else {
      this.stateBtns.style.top  = spacing + "px";
   }

   if(this.statesArr.length == 1){
      var controlsWidth = _controlsElm.offsetWidth;
      _controlsElm.style.display = "none";

      if( this.orientation == this.portrait ){
      
          var width = _targetElm.parentNode.style.width;
          if( isNaN( parseInt(width) ) == true || width == null ){      
              width = _targetElm.parentNode.offsetWidth;
          }
          var hackSpace = width + controlsWidth + 5;
          _targetElm.parentNode.style.width = hackSpace + "px";
      }
   }
   window.isAnimating = false;
}

Shifter.prototype.shiftNext = function(e){
   if(window.isAnimating) return;
   if(!e) var e = window.event;
   var tg         = (e.target) ? e.target : e.srcElement;
   var _shifter   = tg.shifter;
   var nextState = ( _shifter.currState == _shifter.lastState ) ? _shifter.firstState : _shifter.currState + 1;
   return _shiftHelper(_shifter, nextState, _shifter.goNext, 0);
}
Shifter.prototype.shiftPrevious = function(e){
   if(window.isAnimating) return;
   if(!e) var e = window.event;
   var tg         = (e.target) ? e.target : e.srcElement;
   var _shifter   = tg.shifter;
   var nextState = ( _shifter.currState == _shifter.firstState ) ? _shifter.lastState : _shifter.currState - 1;
   return _shiftHelper(_shifter, nextState, _shifter.goPrevious, 0);
}
/* set the ball in motion */
Shifter.prototype.doShift = function(e){
   if(window.isAnimating) return;

   if(!e) var e = window.event;
   var tg               = (e.target) ? e.target : e.srcElement;
   var resultingState   = tg.resultingState;
   var _shifter         = tg.shifter;

   var direction = ( _shifter.currState > resultingState ) ? _shifter.goPrevious : _shifter.goNext;
   _shiftHelper(_shifter, resultingState, direction, 1);
}

/* this performs the magic by only replacing/removing items */
function _shiftHelper( _shifter, resultingState, direction, isStateBtn ){

   var offset              = ((_shifter.orientation == _shifter.portrait) ? _shifter.height : _shifter.width );
   var numTransitions      = ( (!isStateBtn && resultingState == _shifter.firstState && _shifter.currState == _shifter.lastState) || (!isStateBtn && resultingState == _shifter.lastState && _shifter.currState == _shifter.firstState) ) ? 1 : Math.abs( resultingState - _shifter.currState );

   var currTopItemIndex    = ((_shifter.currState) * _shifter.visibleItems) + 1;
   var currBtmItemIndex    = (_shifter.currState == _shifter.firstState) ? _shifter.visibleItems * (_shifter.lastState+1) : _shifter.currState * _shifter.visibleItems;

   if( direction == _shifter.goNext ) {

      slide(offset * numTransitions, direction, _shifter);

      //set globals for use later
      window.replaceIntervalItems = _shifter.visibleItems * numTransitions;
      window.replaceIntervalDirection = direction;
      window.replaceIntervalShifter = _shifter;
      window.replaceIntervalCurrTopItemIndex = currTopItemIndex;
      window.replaceIntervalCurrBtmItemIndex = currBtmItemIndex;
      window.replaceInterval = setInterval( "replaceNext()", 1 );
      window.correctionInterval = setInterval( "correctPos()", 1 );

   } else {
      replace(_shifter.visibleItems * numTransitions, direction, _shifter, currTopItemIndex, currBtmItemIndex);
      moveTo(
         getElm(_shifter.targetID),
         ( _shifter.orientation == _shifter.landscape ) ? -1 * offset * numTransitions : 0,
         ( _shifter.orientation == _shifter.portrait ) ? -1 * offset * numTransitions : 0,
         0 );
      slide(offset * numTransitions, direction, _shifter);
   }

   //now update the buttons
   var e1 = getElm(_shifter.stateBtnsArray[_shifter.currState].myId);
   var tmpClass = _shifter.btnClass + _shifter.currState + "_unsel";
   e1.className = _shifter.btnClass + " " + tmpClass;  //removes the activation

   _shifter.currState = resultingState;

   var e2 = getElm(_shifter.stateBtnsArray[_shifter.currState].myId);
   tmpClass = _shifter.btnClass + _shifter.currState + "_sel";
   e2.className = _shifter.btnClass + " " + tmpClass;  //adds the activation
}

function replace(itemsToReplace, direction, _shifter, currTopItemIndex, currBtmItemIndex){
   currBtmItemIndex = (currBtmItemIndex <= _shifter.numItems) ? currBtmItemIndex: _shifter.numItems;
   //currTopItemIndex = (currTopItemIndex + itemsToReplace <= _shifter.numItems) ? currTopItemIndex: _shifter.numItems - itemsToReplace;
   
   if( direction == _shifter.goNext ){
      //take from top and put in bottom  ... do we ever really need to worry about index wrapping to negative?  we'll try our luck for now
      for( var i = 0; i < itemsToReplace; i++ ){
         var index = i + currTopItemIndex;
         if (index > _shifter.numItems) {
            index -= _shifter.numItems;
         }
         var tmpDiv = getElm( _shifter.itemPrefix + "" + index );
         var parent = tmpDiv.parentNode;
         parent.removeChild(tmpDiv);
         parent.appendChild(tmpDiv);
      }
   } else {
      for( var i = 0; i < itemsToReplace; i++ ){
         var index = currBtmItemIndex - i;
         if (index < 0) {
            index += _shifter.numItems;
         } 
         var tmpDiv = getElm( _shifter.itemPrefix + "" + index );
         var parent = tmpDiv.parentNode;
         parent.removeChild(tmpDiv);
         var tmpTop = getElm( _shifter.itemPrefix + "" + currTopItemIndex );
         parent.insertBefore(tmpDiv, tmpTop);
         tmpTop = tmpDiv;
         currTopItemIndex = index;
      }
   }
}
function slide(offset, direction, _shifter){
   window.shifterOffset       = offset;
   window.shifterDirection    = direction;
   window.shifter             = _shifter;
   window.shifterTargetElm    = getElm(_shifter.targetID)
   window.division            = Math.floor( offset / 4 );
   window.shifterMovement     = 0;
   window.shifterTimer        = setInterval("_animate()",_shifter.speedMean);
   window.isAnimating         = true;
}
function replaceNext(){
   if( !window.isAnimating ){
      clearInterval(window.replaceInterval);
      replace(
         window.replaceIntervalItems,
         window.replaceIntervalDirection,
         window.replaceIntervalShifter,
         window.replaceIntervalCurrTopItemIndex,
         window.replaceIntervalCurrBtmItemIndex);
   }
}
function correctPos(){
   if( !window.isAnimating ){
      clearInterval(window.correctionInterval);
      moveTo( window.shifterTargetElm , 0, 0, 0 );
   }
}

/* slide effect */
function _animate(){

   if(window.shifterMovement == window.shifterOffset) {
      clearInterval( window.shifterTimer );
      window.isAnimating = false;
   }

   var speed = ( window.shifterMovement < window.division ) ? window.shifter.speedStart : ( window.shifterMovement > window.shifterOffset - window.division ) ? window.shifter.speedEnd : window.shifter.speedMid;
   if( window.shifterDirection == -1 && isGecho ){ //speed hack for FF
      speed = speed * 1.5;
   }

   speed = ((window.shifterOffset - window.shifterMovement) < speed ) ? window.shifterOffset - window.shifterMovement : speed;
   window.shifterMovement += speed;

   var directionCorrection = -1;
   moveBy(
      window.shifterTargetElm,
      (window.shifter.orientation == window.shifter.landscape) ?  directionCorrection * window.shifterDirection * speed : 0,
      (window.shifter.orientation == window.shifter.portrait) ? directionCorrection * window.shifterDirection * speed : 0,
      0);
}