// 2/5/11 - complete kluge to get a random image be the target. This thing needs 
//    a major cleanup/rewrite, which I started a few years ago.
// 12/15/08 - complete rewrite, put it com.YourFriendPaul.imgScramOrig namespace
//  Also started more generic rewrite with pbScrambler, nowhere near done.
//
// 11/17/03 - removed non-standard posLeft and posTop to make it work in Mozilla
// Image scrambler script 8/19/03
//

// create the main namespace for everything
if( typeof com == "undefined" || !com ){
   var com = {};
   com.YourFriendPaul = {};
} else if( typeof com.YourFriendPaul == "undefined" || !com.YourFriendPaul ){
   com.YourFriendPaul = {};
}


com.YourFriendPaul.addNamespace = function(){
   var args = arguments;
   var root = null;	// returns null if nothing is done
   var nameParts, B, nameStart, iArg;
   
   for( iArg=0; iArg<args.length; iArg++ ){
   
      nameParts = args[ iArg ].split(".");
      root = com.YourFriendPaul;
      // skip over com.YourFriendPaul if it is there
      nameStart = ( nameParts[ 0 ] == "com" && nameParts[ 1 ] == "YourFriendPaul" ) ? 2 : 0;
      for( B=nameStart; B<nameParts.length; B++ ){
         // if root[ nameParts[B] ] is defined and not null, don't change it, else make it an object
         root[ nameParts[B] ] = root[ nameParts[B] ] || {};
         root = root[nameParts[B]];
      }
   }
   return root;
};

if( typeof com.YourFriendPaul.imgScramOrig != "undefined" ){ 
   alert( "Namespace com.YourFriendPaul.imgScramOrig is already defined" );
   throw new Error( "Namespace com.YourFriendPaul.imgScramOrig is already defined" );
}
else { com.YourFriendPaul.addNamespace( "imgScramOrig" ); }



/************************************************************/
/************************************************************/
/************************************************************/
/************************************************************/

//var imgScramOrig = {};
com.YourFriendPaul.imgScramOrig.gDataTable = null;			// storage for data, is [row][col] format

/************************************************************/
/************************************************************/
com.YourFriendPaul.imgScramOrig.xyMovement = ( function(){
   
   var imgScramOrig = com.YourFriendPaul.imgScramOrig;
   // movement is based on final cell, not current selections
   var MovementArray = null;

   // lots of code specific to this html page and its layout here...
   function moveXY( posNum ){
   
   	var elem = imgScramOrig.ui.getImgElem( posNum );
   
      var moveSize = 10;
      var newLeft = 0;
      var newTop = 0;
      var newStart = 0;
      
      if( MovementArray[ posNum ].currentXoffset != MovementArray[ posNum ].finalXoffset ){
      
         newStart = ( MovementArray[ posNum ].finalXoffset - MovementArray[ posNum ].currentXoffset ) / 
               3 + MovementArray[ posNum ].currentXoffset;
         newLeft = _nextOffset( newStart, MovementArray[ posNum ].minOffset, MovementArray[ posNum ].maxOffset, moveSize );
         MovementArray[ posNum ].currentXoffset = newLeft;
         elem.style.left = newLeft + "px"; 
      
      }
      
      if( MovementArray[ posNum ].currentYoffset != MovementArray[ posNum ].finalYoffset ){
      
         newStart = ( MovementArray[ posNum ].finalYoffset - MovementArray[ posNum ].currentYoffset ) / 3 + MovementArray[ posNum ].currentYoffset;
         newTop = _nextOffset( newStart, MovementArray[ posNum ].minOffset, MovementArray[ posNum ].maxOffset, moveSize );
         MovementArray[ posNum ].currentYoffset = newTop;
         elem.style.top = newTop + "px";
      }
      
   }

   /************************************************************/
   // new int that is +/- Amt from Start.  i.e. 1+/-20 would return -19 to 21 inclusive.
   function _nextOffset( currVal, minOff, maxOff, maxMove ){
   
   	var offset = Math.floor( Math.random() * ( maxMove + 1 ) );
      if ( offset !== 0 ){
         var sign = Math.floor( Math.random() * 2 );
         offset = offset * ( sign ? 1 : -1 );
      }
      offset = offset + currVal;
      offset = (offset > maxOff) ? maxOff : (offset < minOff) ? minOff : offset;
   
      return offset;
   }

   // this stays with a given element id
   function _movingObj( xoffset, yoffset ){
   
      this.finalXoffset = xoffset;
      this.finalYoffset = yoffset;
      this.currentXoffset = 0;
      this.currentYoffset = 0;
      this.minOffset = -20;
      this.maxOffset = 20;

      this.resetOffsets = function(){ this.currentXoffset = 0; this.currentYoffset = 0; }
      this.inFinalOffsetPosition = function(){
      
         return( this.currentXoffset == this.finalXoffset && this.currentYoffset == this.finalYoffset );
      }
   }
   
   function createMovementArray(){
   
      var finalLeft = Array( 20, -20, -20, 20 );
      var finalTop = Array( 20, 20, -20, -20 );
      var iCount = 0;
   
      var numObjs = imgScramOrig.gDataTable.getNumPositions();
      MovementArray = new Array();
   
      for( iCount = 0; iCount < numObjs; iCount++ ){
      
         MovementArray[ iCount ] = new _movingObj( finalLeft[ iCount ], finalTop[ iCount ] );
      }
   }
   
   function resetOffsets( objNum ){
      MovementArray[ objNum ].resetOffsets();
   }
   
   function inFinalOffsetPosition( objNum ){
      return MovementArray[ objNum ].inFinalOffsetPosition();
   }
   
   return { 
      moveXY: moveXY, 
      createMovementArray: createMovementArray, 
      resetOffsets: resetOffsets,
      inFinalOffsetPosition: inFinalOffsetPosition
   }
})();

/************************************************************/
/************************************************************/
com.YourFriendPaul.imgScramOrig.ui = {};


com.YourFriendPaul.imgScramOrig.ui.setEventHandlers = function(){
   
   var elem = document.getElementById( "hiddenStopStart" );
   elem.onclick=function(){ com.YourFriendPaul.imgScramOrig.ui.startStopMotion(this); }
}


com.YourFriendPaul.imgScramOrig.ui.startStopMotion = function( elem ){

   com.YourFriendPaul.imgScramOrig.main.startStopMotion();
}

com.YourFriendPaul.imgScramOrig.ui.modifyImgElemSrc = function( posNum, newSource ){

   this.getImgElem( posNum ).src = newSource;
}

com.YourFriendPaul.imgScramOrig.ui.getImgElem = function( posNum ){

   var idName = this.getImageId( posNum );
   return document.getElementById( idName );
}

com.YourFriendPaul.imgScramOrig.ui.getImgElemSrcName = function( posNum ){

   return this.getImgElem( posNum ).src;
}

// The base for the elementId names: picId0, picId1, picId2, etc.
com.YourFriendPaul.imgScramOrig.ui.getImageId = function( imgNum ){
	return "picId" + imgNum;
}

/************************************************************/
/************************************************************/

/************************************************************/
// All images are accessed through this object
// This is specific to the images being used
/************************************************************/
com.YourFriendPaul.imgScramOrig.ui.CPicture = function(){

   var imgScramOrig = com.YourFriendPaul.imgScramOrig;
   // One entry for every picture series; determines stack height
   var namePrefixText = [ "PN", "PS", "PY", "PBm2" ];
   // One entry for each position in the table; depends on physical layout
   var imgOrderText = [ "1x1", "1x2", "2x2", "2x1" ];
   var imgNameSeparator = "_";
   var imgNameExtension = ".jpg";
   var imagePath = "image/";
   
   // images will live here
   this.images = [];
         
   this.getNumPositions = function(){ return imgOrderText.length; }
   this.getStackHeight = function(){ return namePrefixText.length; }
   // returns array of all images for given position
   this.imagesAtPosition = function( posn ){ return this.images[ posn ]; }
   
   this.getImage = function( orderNum, stackNum ){ 
      return this.images[ orderNum ][ stackNum ]; 
   }
   
   this.preloadImages = function(){
   
      var posArray = null;
      var order, pref;
      // cycle through each position in the total image
      for ( order=0; order < this.getNumPositions(); order++ ){
      
         this.images[ order ] = new Array();
         posArray = this.images[ order ];
         
         // load every picture for the position
         for ( pref=0; pref < this.getStackHeight(); pref++ ){
   
            // make Image object and build each name from its component parts
            posArray[ pref ] = 
                  this._newImage( imagePath + namePrefixText[ pref ] + 
                  imgNameSeparator + imgOrderText[ order ] + 
                  imgNameExtension );	// path + name
         }
      }
   }
   
   // execute the building process and load the images
   this.preloadImages();
}

com.YourFriendPaul.imgScramOrig.ui.CPicture.prototype._newImage = function( imgSrc ) {

   var tempImg = new Image();
   tempImg.src = imgSrc;
   return tempImg;
}


/************************************************************/
/************************************************************/
/************************************************************/
/************************************************************/
com.YourFriendPaul.imgScramOrig.main = ( function(){

   var imgScramOrig = com.YourFriendPaul.imgScramOrig;
   /************************************************************/
   // This is the main looping function
   // assumes final correct pic for each location is in array element 0
   var timeoutID = null;
   var SortTimeout = 200;					// How often to change picture, in msec.
   var imageMoving = false;

   function sortPics(){
   
      var PositionsIncorrect = 0;
      var OrdersIncorrect = 0;
      var _self = this;
   
      // randomize column pictures if not final correct pic & row
      OrdersIncorrect = imgScramOrig.orderAtLocation.randomizeStackPics();
   
      // sort the columns within the rows
      PositionsIncorrect = imgScramOrig.positions.sortRows( true );
      
      imageMoving = true;

      if ( PositionsIncorrect || OrdersIncorrect ){
         timeoutID = setTimeout( function(){ _self.sortPics(); }, SortTimeout );
      } else {
         timeoutID = setTimeout( function(){ _self.resetLoop();}, 500);
      }
   }
   
   // Start a new scrambling of the images
   function resetLoop(){
   
      var _self = this;
      imgScramOrig.positions.scramblePics();					// Create initial random order
      timeoutID = setTimeout(  function(){ _self.sortPics(); }, SortTimeout );		// Begin sorting process
      imageMoving = true;
   }
   
   function stopTimers(){
   
      if( timeoutID !== null ){
         clearTimeout( timeoutID );
         imageMoving = false;
         timeoutID = null;
      }
   }
   
   function startStopMotion(){
      if ( imageMoving === true ){
         stopTimers();
         imageMoving = false;
      } else {
         imageMoving = true;
         this.sortPics();
      }
   }
   
   /************************************************************/
   // Puts Image objects in the global gDataTable
   function preloadImages(){
   
      imgScramOrig.gDataTable = new imgScramOrig.ui.CPicture();
   }
   

   /************************************************************/
   /************************************************************/
   // Randomizes the visible pictures -- used with picId0 - picId3
   // Doesn't store info in tables, this is just a temp move until all arrays are built
   // Only called at initial load
   function randomizeVisiblePics()
   {
      // It has to be the same number as the global table or this 
      // whole thing doesn't work. Images not loaded, so can't use table's values.
      var numPics = 4;
      var i;
      
   	var tImg = new Array();	// temp image storage
      
      // Store pic names temporarily
      for ( i=0; i<numPics; i++ ){
         tImg[ i ] = imgScramOrig.ui.getImgElemSrcName( i );
      }
      
      // Determine new order
      var newOrder = imgScramOrig.util.buildRandomArray( numPics );
      
   	for ( i=0; i<numPics; i++ ){				// Place pics in new order
      	imgScramOrig.ui.modifyImgElemSrc( i, tImg[ newOrder[ i ] ] );
      }
   }
   
   function init(){
   
   	if ( ! document.images ){ return; }
   
      // shuffle the existing pictures without loading any others
      randomizeVisiblePics();
      
      // Download all images into arrays
      preloadImages();
      
      imgScramOrig.xyMovement.createMovementArray();
      
      // just test the new shuffle system, not used yet.
      // pbScrambler.testIt();
      
      // put in the hidden stop/start button
      imgScramOrig.ui.setEventHandlers();
   
      // Do initial scramble and start the loop
      imgScramOrig.main.resetLoop();
   }
   
   return{
      resetLoop: resetLoop,
      stopTimers: stopTimers,
      sortPics: sortPics,
      startStopMotion: startStopMotion,
      init: init
   }
   
})(); // end imgScramOrig.main

/************************************************************/
/************************************************************/

com.YourFriendPaul.imgScramOrig.positions = ( function(){

   var imgScramOrig = com.YourFriendPaul.imgScramOrig;
   // storage for current row used at position number
   var _CurrentPositionOrder = new Array();
   
   // assumes final correct pic for each location is in array element 0
   // AllowBadMove lets higher correct positions be changed during a swap
   function sortRows( AllowBadMove ){

      var numPics = imgScramOrig.gDataTable.getNumPositions();
      var PositionsIncorrect = 0;
      
   	for (var i=0; i<numPics; i++ ){
      
         if ( !_isPositionCorrect( i ) ){
         
         	PositionsIncorrect++;
            // go thru loop at least once
            var Swappee = i;
            
            // pick a different image to swap with
            while ( Swappee == i ){
            
               Swappee = Math.floor( Math.random() * ( numPics - i ) ) + i;
            }
            
         	if ( !_isPositionCorrect( Swappee ) || AllowBadMove ){ 
   
               _swapPicsPositions( i, Swappee );
               break;
            }
         } else {
   
            if( !imgScramOrig.xyMovement.inFinalOffsetPosition( i ) ){
            
               imgScramOrig.xyMovement.moveXY( i );
               PositionsIncorrect++;	// not exactly, but don't want to stop
            }
   
         }
      }
      
      return ( PositionsIncorrect );
   }
   
   //
   // Put random pics in the table images.
   // 
   function scramblePics()
   {
      var i;
      var Table = imgScramOrig.gDataTable;
      var numPositions = Table.getNumPositions();	// 4 locations to display
      var rowOrder = null;
      
      // Determine table position order for placement
      rowOrder = imgScramOrig.util.buildRandomArray( numPositions );
      //alert( RowOrder );
      var Tm = new Image();
      
      // randomize which image in the stack we stop on
      imgScramOrig.orderAtLocation.setRandomFinalStackNum();
      
   	// for each position
      for ( i=0; i<numPositions; i++ ){
      
      	// get a random picture from the correct position
         Tm.src = Table.imagesAtPosition( rowOrder[ i ] )[ Math.floor( Math.random() * ( Table.getStackHeight() ) ) ].src;
         // start image in center XY of position
         imgScramOrig.xyMovement.resetOffsets( i );
         _placeImage( i, rowOrder[ i ], Tm.src );
      }
   }
   
   function getCurrentPositionOrder( posNum ){
   
      return _CurrentPositionOrder[ posNum ];
   }
   
   function _isPositionCorrect( posNum ){
   
   	return ( posNum == _CurrentPositionOrder[ posNum ] ) ? true : false;
   }
   
   // where to place it, which image array# used, source 
   function _placeImage( posNum, RowUsed, srcName ){
   
      imgScramOrig.ui.modifyImgElemSrc( posNum, srcName );
   
      // Update Current Row info
      _CurrentPositionOrder[ posNum ] = RowUsed;
   // if( iCount++ < 10 ) alert( posNum + " " + srcName );
      imgScramOrig.xyMovement.moveXY( posNum );
      
   }
   
   function _swapPicsPositions( SwapperNum, SwappeeNum ){
   
      var curElemSrcName = imgScramOrig.ui.getImgElemSrcName( SwapperNum );
      var posCurr = _CurrentPositionOrder[ SwapperNum ];		// temp save current Swapper row info
      _placeImage( SwapperNum, _CurrentPositionOrder[ SwappeeNum ], imgScramOrig.ui.getImgElemSrcName( SwappeeNum ) );
      _placeImage( SwappeeNum, posCurr, curElemSrcName );
   }
   
   return{
      scramblePics : scramblePics,
      sortRows : sortRows,
      getCurrentPositionOrder: getCurrentPositionOrder
   }
   
})();

/************************************************************/
/************************************************************/

   /************************************************************/
com.YourFriendPaul.imgScramOrig.orderAtLocation = ( function(){

   // determines which of the completed images will be the final picture
   // the target image when it's all sorted out
   function _finalStackNum( amaxPos ){
      
      this.target = 0;
      maxPos = amaxPos;
   }
   
   _finalStackNum.maxPos = 0;

   _finalStackNum.prototype.get = function(){ 
      return this.target; 
   }
   
   _finalStackNum.prototype.set = function( num ){ 
      this.target = num; 
   }
   
   _finalStackNum.prototype.setRandom = function(){
   
     this.target = Math.floor( Math.random() * maxPos );
     //alert ( "New target: " + maxPos + ", " + this.target );
   }
   
   var imgScramOrig = com.YourFriendPaul.imgScramOrig;
   // Use this if I rewrite: imgScramOrig.gDataTable.getNumPositions()
   var FinalStackNum = new _finalStackNum( 4 );

   var maxImagesPerLoc = 4;

   var FinalStackNum1;

   function setFinalImageNum(){
   
      FinalStackNum1 = Math.floor( Math.random() * maxImagesPerLoc );
      //alert ( "New target: " + FinalStackNum1 );
   }
   
   // set a random first image
   //FinalStackNum.setRandom();
   setFinalImageNum();
   

   function swapWithinPosition( i ){
   
      var posCurr = imgScramOrig.positions.getCurrentPositionOrder( i );
      var imgNum = Math.floor( Math.random() * imgScramOrig.gDataTable.getStackHeight() );
      imgScramOrig.ui.modifyImgElemSrc( i, imgScramOrig.gDataTable.imagesAtPosition( posCurr )[ imgNum ].src );
   }

   // this changes which picture is in any location, but does not move or swap positions
   // it returns 0 if the right pictures are in the right places, independent of xy offset
   function randomizeStackPics()
   {
      var numPics = imgScramOrig.gDataTable.getNumPositions();
      var PosName = "";
      var PosCurr = 0;
      var OrdersIncorrect = 0;
      var imgNum = 0;
      var elem = null;
    //alert( "randomizeStackPics(): " + FinalStackNum1 );  
   	for ( var i=0; i<numPics; i++ ){
      
         // is it the final image in the series?
         if ( !_isImgStackPosCorrect ( i ) ){
         
            // If not the right image in the right box position, swap within position
            swapWithinPosition( i );
            OrdersIncorrect += 1;
         }
      }
   
      return OrdersIncorrect;
   }

   function _isImgStackPosCorrect( posNum ){
   
      var result = false;
   
      if ( imgScramOrig.ui.getImgElemSrcName( posNum ) == imgScramOrig.gDataTable.imagesAtPosition( posNum )[ FinalStackNum1 ].src ){ result = true; }
      return result;
   }
   
   return{
      swapWithinPosition : swapWithinPosition,
      //setRandomFinalStackNum: FinalStackNum.setRandom,
      setRandomFinalStackNum: setFinalImageNum,
      randomizeStackPics: randomizeStackPics
   }
   
})(); // end imgScramOrig.orderAtLocation

/************************************************************/
/************************************************************/

com.YourFriendPaul.imgScramOrig.util = ( function(){
   
   var    imgScramOrig = com.YourFriendPaul.imgScramOrig;

   /************************************************************/
   /************************************************************/
   // returns an array where each element will be from 0 to size with no duplicates
   function buildRandomArray( size ){
      
      var data = new Array( size );
      for ( var i=0; i<size; i++){		 	  // create data to be used
      		data[ i ] = i;
      }
   	shuffleArray( data );
      return data;
      
   }
   
   // =======================================================
   // Randomly order the items in the array
   // like a deck of cards, no duplicates allowed
   //
   function shuffleArray( array ){
   
   	var tempItem;
      var newItemPos;
      for ( var i=array.length; 1<i; i-- ){
      
         // includes 0 but not 1
         newItemPos = Math.floor( Math.random() * ( i ) );
         
         // swap elements if they are not the same
         if ( newItemPos != i ){
         
         	tempItem = array[ i-1 ];
            array[ i-1 ] = array[ newItemPos ];
            array[ newItemPos ] = tempItem;
         }
      }
   }

   return{
      buildRandomArray: buildRandomArray
   }
   
})(); // end com.YourFriendPaul.imgScramOrig.imgScramOrig.util




/************************************************************/
/************************************************************/
/************************************************************/
/************************************************************/
/************************************************************/
/************************************************************/

/************************************************************/
/************************************************************/
// This is an array of objects that are also include arrays
// The desired final value is always 0, 1, 2 ... to the array limit
//
// pbScrambler is only started, it isn't working yet
//
var pbScrambler = {

   // Randomly order the items in the array
   // like a deck of cards, no duplicates allowed
   //
   shuffleArray : function( arr ){
   
   	var tempElement = 0;
      var newItemPos = 0;
      var elemNum = 0;
      
      for ( elemNum = arr.length; 1 < elemNum; elemNum-- ){
      
         // includes 0 but not 1
         newItemPos = Math.floor( Math.random() * ( elemNum ) );
         
         // swap elements if they are not the same
         if ( newItemPos != elemNum ){
         
         	tempElement = arr[ elemNum-1 ];
            arr[ elemNum-1 ] = arr[ newItemPos ];
            arr[ newItemPos ] = tempElement;
         }
      }
   },
   
   testItEinfo : function( elem ){
   
      var text = "id: " + elem.getId() + ", elems: " + elem.getCurrentOrder() + "\n frozen=" + elem.isFrozen() + ", target=" + elem.getTarget();
      return text;
   },
   
   testIt : function(){
   
      // Makes a place to hold a list of IDs; won't allow duplicates
      var uidList = new pbScrambler.pUniqueIdList();
      
      var p1Elem = new this.positionItem( 0, 4 );
      var added = uidList.addItem( p1Elem.getId() );
      var p2Elem = new this.positionItem( 1, 6 );
      added = uidList.addItem( p2Elem.getId() );
      //alert( p1Elem.getCurrentOrder() + "\nfrozen=" + p1Elem.isFrozen() );
      //alert( this.testItEinfo( p1Elem ) );
      
      p2Elem.freeze();
      
      alert( this.testItEinfo( p1Elem ) + "\n" + this.testItEinfo( p2Elem ) + "\n  id list: " + uidList );

      var p3Elem = new this.positionItem( 2, 8 );
      added = uidList.addItem( p3Elem.getId() );
      //alert( this.testItEinfo( p1Elem ) + "\n" + this.testItEinfo( p2Elem ) + "\n" + this.testItEinfo( p3Elem ) + "\n  id list: " + uidList );
      
      p1Elem.deleteElements();
      p2Elem.shuffle();
      //alert( this.testItEinfo( p1Elem ) + "\n" + this.testItEinfo( p2Elem ) + "\n" + this.testItEinfo( p3Elem ) + "\n  id list: " + uidList );

      p2Elem.thaw();
      p2Elem.shuffle();
      //alert( this.testItEinfo( p1Elem ) + "\n" + this.testItEinfo( p2Elem ) + "\n" + this.testItEinfo( p3Elem ) + "\n  id list: " + uidList );

      p1Elem.initOrder();
      p3Elem.setTarget( 2 );
      p3Elem.freezeOnTarget = true;
      p3Elem.shuffle();
      //alert( this.testItEinfo( p1Elem ) + "\n" + this.testItEinfo( p2Elem ) + "\n" + this.testItEinfo( p3Elem ) + "\n  id list: " + uidList );

      p3Elem.shuffle();
      //alert( this.testItEinfo( p1Elem ) + "\n" + this.testItEinfo( p2Elem ) + "\n" + this.testItEinfo( p3Elem ) + "\n  id list: " + uidList );

      p1Elem.shuffle();
      p1Elem.shuffle();
      p3Elem.shuffle();
      alert( this.testItEinfo( p1Elem ) + "\n" + this.testItEinfo( p2Elem ) + "\n" + this.testItEinfo( p3Elem ) + "\n  id list: " + uidList );
      
      var posHolder = new this.positionHolder();
      // number of posItems, size of posItem, this is for test
      posHolder.addItems( 4, 6 );
   }
};

   // positionHolder object
   // This holds all the position objects.
   // The desired final order is Always 0,1,2...
   pbScrambler.positionHolder = function(){
   
      // holds the positionItems added
      this.elemList = [];
      
      // list of IDs, won't allow duplicates
      // Future: can change order to make new prefered final order
      this.uidList = new pbScrambler.pUniqueIdList();	
   }
   
   pbScrambler.positionHolder.prototype = {
   
      addItems : function( qty, posItemSize ){
      
         var iCount=0;
         for( iCount=0; iCount< qty; iCount++ ){
         
            var newElem = new pbScrambler.positionItem( iCount, posItemSize ); // id, numElements
            var added = this.uidList.addItem( newElem.getId() );
            if( added ){ this.elemList.push( newElem ); }
         }
         alert( "\n  added uid list: " + this.uidList + 
                "\n   and elem list: " + this.elemList );
      
      },
      
      getCurrent : function( iNum ){ return elemList[ iNum ].getCurrentItem(); },
      
      // The desired final order is Always 0,1,2...
      isCorrectPosition : function( iNum ){
      
         return ( this.elemList[ iNum ].getId() == this.uidList[ iNum ] ) ? true : false;
      },
      
      length : function(){ return this.elemList.length; },
      
      toString : function(){
         alert( elemList + "\n" + elemList.toString() );return this.elemList.toString(); 
      }
      

   };
   
/************************************************************/
/************************************************************/
   // list of unique ids for each positionItem created 
   // Property is shared by all pbScrambler
   //
   // All this really is, is a list of numbers
   pbScrambler.pUniqueIdList = function(){
      this.itemList = [];
   };

   pbScrambler.pUniqueIdList.prototype = {
   
      // used to look for duplicate items
      isInList : function( newId ){
      
         var iCount = 0;
         
         if( this.itemList.length > 0 ){ 
            do {
               if( this.itemList[ iCount ] == newId ){
                  alert( "duplicate in pUniqueIdList: " + newId );
                  return true;
               }
            } while( ++iCount < this.itemList.length );
         }
         
         return false
      },
      
      clearList : function(){ this.itemList.length = 0; },
      
      getItem : function( iNum ){ return this.itemList[ iNum ]; },
      
      // true if added, false if not
      addItem : function( newId ){
         var bFound = this.isInList( newId );
         if( !bFound ){ this.itemList.push( newId ); }
         return !bFound;
      },
      toString : function(){ return this.itemList.toString(); }
   };

/************************************************************/
/************************************************************/
// These objects are moved in the position array.
// The element count cannot be changed after the object is created
// A positionItem is nothing more than a list of increasing ints,
// it can be scrambled, reset, or told to ignore a scramble 
// command (frozen state).
// The id variable is to identify a unique positionItem

// Use increasing id values so the final value will be increasing ints.


pbScrambler.positionItem = function( id, elemCount ){

   var currentOrder = [];
   this.getCurrentOrder = function(){ return currentOrder.slice(0); }	// return copy of array
   
   this.getCurrentItem = function(){ return currentOrder[ 0 ]; }
   //localPush = function( thing ){ currentOrder.push( thing ); }

   // only available to allow access to the scramble function
   this.pCurrentOrder = currentOrder;	// intended for internal use only
   this.deleteElements = function(){ currentOrder.length = 0; }

   var frozen = false;
   this.freeze = function(){ frozen = true; }
   this.thaw = function(){ frozen = false; }
   this.isFrozen = function(){ return frozen; }

   var target = 0;	// can change desired final value
   this.setTarget = function( num ){ if( num >= 0 &&  num < this.getNumElements() ){ target = num; } }
   this.getTarget = function(){ return target; }
   
   this.getId = function(){ return id; }
   this.getNumElements = function(){ return elemCount; }
   this.freezeOnTarget = false;

   this.createObj();	// build the object
}

pbScrambler.positionItem.prototype = {

   initOrder : function(){
   
      var iCount = 0;
      this.deleteElements();
      while( iCount < this.getNumElements() ){ this.pCurrentOrder.push( iCount++ ); }
   },
   
   shuffle : function(){ if( !this.isFrozen() ){
      //alert( "scramble item " + this.getId() );
      pbScrambler.shuffleArray( this.pCurrentOrder ) ;
      if( this.freezeOnTarget ){
         if( this.getTarget() == this.getCurrentOrder()[0] ){ this.freeze(); }
      }
   }},

   toString : function(){ return "ID " + this.getId() + ": " + this.getCurrentOrder().toString(); },

   // looks for duplicate IDs, do not call twice, not for use outside of object
   createObj : function(){
   
      this.initOrder();	// initialize array on object creation
      return true;
   }
   
} // end pbScrambler.positionItem.prototype

/************************************************************/
// this is info about the object, but movement depends on position
/************************************************************/
pbScrambler.sortableObj = function( finalOrderIn, maxItemsIn ){

   this.finalOrder = -1;
   this.currentItemUsed = -1;
   this.maxItems = 0;
}

// end pbScrambler
/************************************************************/
/************************************************************/

