//=====================================================================||
//              NOP Design / Cyberitas Slider Class                    ||
//                                                                     ||
// For more information on the Cyberitas Dynamic Toolkit, or NOP Design||
// systems, please visit us on the WWW at http://www.cyberitas.com     ||
//                                                                     ||
// Slider Module,     v. 1.0                                           ||
// Last Modified:     12/2006                                          ||
// Last Editor:       Scott Moore                                      ||
//                                                                     ||
//=====================================================================||

//---------------------------------------------------------------------||
// CLASS:       CyberSlider  (Contructor)                              ||
// PARAMETERS:  strContainerId, ID of Div to place this slider control ||
//              bIsVertical, true for an up down control, false for a  ||
//                left/right orientation.                              ||
//              iLowBound, Minumum number control can be set to        ||
//              iHighBound, Maximum number control can be set to       ||
//              iStartAt, Where to "default" the control to            ||
//              strBgImage, Background "track" image                   ||
//              iBgWidth, Width of background                          ||
//              iBgHeight, Height of background                        ||
//              strAdditionalStyleCommands, additional BG CSS tags     ||
//              strFgImage, Foreground pointer image                   ||
//              iFgWidth, Foreground width                             ||                      
//              iFgHeight, Foreground height                           ||
//              onMoveCompleteCb, Callback function on move complete   ||
//              onMoveCb, Callback function on pointer move            ||
// RETURNS:     Instantiated CyberSlider object.                       ||
// PURPOSE:     Creates a slider control that allows click or drag     ||
//              to set a document range.                               ||
// SUPPORTS:    GetValue, SetValue methods                             ||
//---------------------------------------------------------------------||
function CyberSlider( strContainerId, bIsVertical, iLowBound, iHighBound, iStartAt, 
                      strBgImage, iBgWidth, iBgHeight, strAdditionalStyleCommands, 
                      strFgImage, iFgWidth, iFgHeight,
                      onMoveCompleteCb, onMoveCb )
{
   this.pContainer   = document.getElementById(strContainerId);
   if( !this.pContainer ) {
      throw( new TypeError("Container ID must exist, could not create slider object") );
   }

   this.pContainer.style.float = "left";
   this.pContainer.style.margin = "0";
   this.pContainer.style.width = iBgWidth;
   this.pContainer.style.height = iBgHeight;

   var strPointerId = strContainerId+'_pointer';
   var strTrackId = strContainerId+'_track';

   var strContents = '<div id="'+strTrackId+'" style="height:'+iBgHeight+'px;width:'+iBgWidth+'px;background:url('+strBgImage+');position:relative;'+strAdditionalStyleCommands+'">' +
                     '   <div id="'+strPointerId+'" style="background:url('+strFgImage+');width:'+iFgWidth+'px; height:'+iFgHeight+'px;position:relative;"></div>' + 
                     '</div>';
   this.pContainer.innerHTML = strContents;

   this.pTrack = document.getElementById(strTrackId);
   if( !this.pTrack ) {
      throw( new TypeError("Could not create new slider track.") );
   }

   this.pTrack.strContainerId = strContainerId;   
   this.pTrack.bIsVertical    = bIsVertical;
   this.pTrack.iLowBound      = iLowBound;
   this.pTrack.iHighBound     = iHighBound;
   this.pTrack.iStartAt       = iStartAt;
   this.pTrack.strBgImage     = strBgImage;
   this.pTrack.iBgWidth       = iBgWidth;
   this.pTrack.iBgHeight      = iBgHeight;
   this.pTrack.strFgImage     = strFgImage;
   this.pTrack.iFgWidth       = iFgWidth;
   this.pTrack.iFgHeight      = iFgHeight;
   this.pTrack.onMoveComplete = onMoveCompleteCb;
   this.pTrack.onMove         = onMoveCb;
   this.pTrack.pMyself        = this;
   this.pTrack.iDistance      = (bIsVertical ? (iBgHeight-iFgHeight) : (iBgWidth-iFgWidth));
   this.pTrack.xMax           = 0;
   this.pTrack.yMax           = 0;
   this.pTrack.xMin           = 0;
   this.pTrack.yMin           = 0;
   this.pTrack.bInDrag        = false;
   this.pTrack.iNumElements   = iHighBound - iLowBound;
   this.pTrack.fValue         = iStartAt;
   this.pTrack.iEffectiveBound= 0;
   
   // Slider-display scale [value-change per pixel of movement].
   this.pTrack.scale = ((this.pTrack.iHighBound - this.pTrack.iLowBound) / this.pTrack.iDistance);
   if (this.pTrack.bIsVertical) {
      // Invert scale for vertical sliders. "Higher is more."
      this.pTrack.iEffectiveBound = iHighBound;
      this.pTrack.xMax = 0
      this.pTrack.yMax = this.pTrack.iDistance;
      this.pTrack.scale = -this.pTrack.scale;
   } else {
      this.pTrack.iEffectiveBound = iLowBound;
      this.pTrack.xMax = this.pTrack.iDistance;
      this.pTrack.yMax = 0;
   }
   

   this.pTrack.pPointer = document.getElementById(strPointerId);
   if( !this.pTrack.pPointer ) {
      throw( new TypeError("Could not create new slider pointer.") );
   }

   this.pTrack.pPointer.pTrack = this.pTrack;

   this.pTrack.pPointer.startOffsetX = 0;
   this.pTrack.pPointer.startOffsetY = 0;

   this.pTrack.pPointer.onmousedown = cyberSliderHandleOnMouseDown;
   this.pTrack.onclick = cyberSliderHandleTrackOnClick;


   //---------------------------------------------------------------------||
   // FUNCTION:    SetValue                                               ||
   // PARAMETERS:  Value to set pointer to                                ||
   // RETURNS:     N/A                                                    ||
   // PURPOSE:     Sets the slider pointer to fValue                      ||
   //---------------------------------------------------------------------||
   this.SetValue = function(fValue) {
      if( fValue > this.pTrack.iHighBound ) fValue = this.pTrack.iHighBound;
      if( fValue < this.pTrack.iLowBound ) fValue = this.pTrack.iLowBound;
      var sliderPos = (fValue - this.pTrack.iEffectiveBound) / this.pTrack.scale;

      if (this.pTrack.bIsVertical) {
         this.getSetObjectTop(this.pTrack.pPointer, Math.round(sliderPos));
      } else {
         this.getSetObjectLeft(this.pTrack.pPointer, Math.round(sliderPos));
      }
   };

   //---------------------------------------------------------------------||
   // FUNCTION:    GetValue                                               ||
   // PARAMETERS:  N/A                                                    ||
   // RETURNS:     Value pointer is currently pointing to                 ||
   // PURPOSE:     Reads the current value of the slider                  ||
   //---------------------------------------------------------------------||
   this.GetValue = function() {
      return this.pTrack.fValue;
   };

   //Private Members
   this.getSetObjectLeft = function(objElement, pos)
   {
   	if (objElement.style && (typeof(objElement.style.left) == 'string')) {
   		if (typeof(pos) == 'number') {
            objElement.style.left = pos + 'px';
   		} else {
   			pos = parseInt(objElement.style.left);
   			if (isNaN(pos)) pos = 0;
   		}
   	}
   	else if (objElement.style && objElement.style.pixelLeft) {
   		if (typeof(pos) == 'number') objElement.style.pixelLeft = pos;
   		else pos = objElement.style.pixelLeft;
   	}
   	return pos;
   }

   this.findPosY = function(obj)
   {
      var curtop = 0;
      if (document.getElementById || document.all) {
         if( !obj.offsetParent ){
            curtop += obj.offsetTop;
         }
         while (obj.offsetParent) {
            curtop += obj.offsetTop;
            obj = obj.offsetParent;
         }
      } else if (document.layers)
         curtop += obj.y;
   
      return curtop;
   }

   this.findPosX = function(obj)
   {
      var curleft = 0;
      if (document.getElementById || document.all) {
         while (obj.offsetParent) {
            curleft += obj.offsetLeft;
            obj = obj.offsetParent;
         }
      } else if (document.layers)
         curleft += obj.x;
   
      return curleft;
   }


   this.getSetObjectTop = function(objElement, pos)
   {
   	if (objElement.style && (typeof(objElement.style.top) == 'string')) {
   		if (typeof(pos) == 'number') {
            objElement.style.top = pos + 'px';
         } else {
   			pos = parseInt(objElement.style.top);
   			if (isNaN(pos)) pos = 0;
   		}
   	} else if (objElement.style && objElement.style.pixelTop) {
   		if (typeof(pos) == 'number') objElement.style.pixelTop = pos;
   		else pos = objElement.style.pixelTop;
   	}
   	return pos;
   }

   this.HandleTrackOnClick = function(objEvent) {
      var iPosX = 0;
      var iPosY = 0;
      if ( objEvent.pageX ) {
         iPosX = objEvent.pageX;
      } else {
         if ( objEvent.clientX ) {
            iPosX = objEvent.clientX + (document.body.scrollLeft?document.body.scrollLeft:0);
         }
      }
      if ( objEvent.pageY ) {
         iPosY = objEvent.pageY;
      } else {
         if ( objEvent.clientY ) {
            iPosY = objEvent.clientY + (document.body.scrollTop?document.body.scrollTop:0);
         }
      }
      var x = iPosX - this.findPosX(this.pTrack);
      var y = iPosY - this.findPosY(this.pTrack);

      if (x > this.pTrack.xMax) x = this.pTrack.xMax;
      if (x < this.pTrack.xMin) x = this.pTrack.xMin;
      if (y > this.pTrack.yMax) y = this.pTrack.yMax;
      if (y < this.pTrack.yMin) y = this.pTrack.yMin;
      this.getSetObjectLeft(this.pTrack.pPointer, x);
      this.getSetObjectTop(this.pTrack.pPointer, y);

      var sliderVal = x + y;
      var sliderPos = (this.pTrack.iDistance / this.pTrack.iNumElements ) * Math.round(this.pTrack.iNumElements * sliderVal / this.pTrack.iDistance);
      var v = Math.round( (sliderPos * this.pTrack.scale + this.pTrack.iEffectiveBound) );

      this.pTrack.fValue = v;
      if( this.pTrack.onMoveComplete ) {
         this.pTrack.onMoveComplete( this );
      }
   }

   this.HandleOnMouseDown = function(objEvent) {  
      this.pTrack.pPointer.startOffsetX = this.getSetObjectLeft(this.pTrack.pPointer) - objEvent.screenX;
   	this.pTrack.pPointer.startOffsetY = this.getSetObjectTop(this.pTrack.pPointer) - objEvent.screenY;
   	this.pTrack.bInDrag = true;

   	document.onmousemove = cyberSliderHandleOnMouseMove;
   	document.onmouseup = cyberSliderHandleOnMouseUp;

   	return false
   };

   this.HandleOnMouseMove = function(objEvent) {  
   	if (this.pTrack.bInDrag) {
   		var x = this.pTrack.pPointer.startOffsetX + objEvent.screenX;
   		var y = this.pTrack.pPointer.startOffsetY + objEvent.screenY;
   		if (x > this.pTrack.xMax) x = this.pTrack.xMax;
   		if (x < this.pTrack.xMin) x = this.pTrack.xMin;
   		if (y > this.pTrack.yMax) y = this.pTrack.yMax;
   		if (y < this.pTrack.yMin) y = this.pTrack.yMin;
   		this.getSetObjectLeft(this.pTrack.pPointer, x);
   		this.getSetObjectTop(this.pTrack.pPointer, y);

         var sliderVal = x + y;
   		var sliderPos = (this.pTrack.iDistance / this.pTrack.iNumElements ) * Math.round(this.pTrack.iNumElements * sliderVal / this.pTrack.iDistance);
         var v = Math.round( (sliderPos * this.pTrack.scale + this.pTrack.iEffectiveBound) );
         this.pTrack.fValue = v;
         if( this.pTrack.onMove ) {
            this.pTrack.onMove( this );
         }
   
   		return false;
   	}
   	return;
   }

   this.HandleOnMouseUp = function(objEvent) {  

   	if (this.pTrack.bInDrag) {

   		var v = (this.pTrack.fValue) ? this.pTrack.fValue : 0;
   		var pos = (v - this.pTrack.iEffectiveBound)/(this.pTrack.scale);

   		if (this.pTrack.yMax == 0) {
   			pos = (pos > this.pTrack.xMax) ? this.pTrack.xMax : pos;
   			pos = (pos < 0) ? 0 : pos;
   			this.getSetObjectLeft(this.pTrack.pPointer, pos);
   		}
   		if (this.pTrack.xMax == 0) {
   			pos = (pos > this.pTrack.yMax) ? this.pTrack.yMax : pos;
   			pos = (pos < 0) ? 0 : pos;
   			this.getSetObjectTop(this.pTrack.pPointer, pos);
   		}
   		if (document.removeEventListener) {
   			document.removeEventListener('mousemove', cyberSliderHandleOnMouseMove, false);
   			document.removeEventListener('mouseup', cyberSliderHandleOnMouseUp, false);
   		} else if (document.detachEvent) {
   			document.detachEvent('onmousemove', cyberSliderHandleOnMouseMove);
   			document.detachEvent('onmouseup', cyberSliderHandleOnMouseUp);
   		}
   	}
   	this.pTrack.bInDrag = false;

      if( this.pTrack.onMoveComplete ) {
         this.pTrack.onMoveComplete( this );
      }

   }

   //Everything is almost done, now set the options
   this.SetValue( iStartAt );

} //END CyberSlider object

//Global pointer to current moving pointer
var g_pCurrentMovingPointer = null;

//Friend function, do not call directly
function cyberSliderHandleOnMouseDown( objEvent )
{
   if (!objEvent) objEvent = window.event;
   var pPointer = (objEvent.target) ? objEvent.target : objEvent.srcElement;
   
   if( pPointer && pPointer.pTrack ) {
      g_pCurrentMovingPointer = pPointer;
      return pPointer.pTrack.pMyself.HandleOnMouseDown( objEvent );
   }
}

//Friend function, do not call directly
function cyberSliderHandleOnMouseMove( objEvent )
{
   if (!objEvent) objEvent = window.event;
   var pPointer = g_pCurrentMovingPointer;
   if( pPointer && pPointer.pTrack ) {
      return pPointer.pTrack.pMyself.HandleOnMouseMove( objEvent );
   }
}

//Friend function, do not call directly
function cyberSliderHandleOnMouseUp( objEvent )
{
   if (!objEvent) objEvent = window.event;
   var pPointer = g_pCurrentMovingPointer;
   if( pPointer && pPointer.pTrack ) {
      return pPointer.pTrack.pMyself.HandleOnMouseUp( objEvent );
   }
}

//Friend function, do not call directly
function cyberSliderHandleTrackOnClick( objEvent )
{
   if (!objEvent) objEvent = window.event;
   var pTrack = (objEvent.target) ? objEvent.target : objEvent.srcElement;
   if( pTrack && pTrack.pMyself ) {
      return pTrack.pMyself.HandleTrackOnClick( objEvent );
   }
}
