/**
 * This class manages an absolutely-positioned rectangle in the Gigapan Explorer
 * application.  It has <code>Stack</code> widgets as children.
 * <br><br>
 * Note that the scrollbars on the web browser window
 * that would appear due to the <code>plate</code> screen element (on all but huge display 
 * screens, the 
 * <code>plate</code> screen element is much bigger than the
 * <code>console</code> or its containing <code>mainBody</code> element) are eliminated by the
 * css property of <code>hidden</code> assigned to the <code>overflow</code> property of the
 * <code>mainBody</code> css class.  For debugging purposes, the <code>plate</code> shows
 * a unique leopard-skin background image and a red background property if the application 
 * is set to debug mode (see <code>self.gloScope.booDebugMode</code>).
 * <br>
 * <br><br>
 * <a href="mailto:ehudsons@andrew.cmu.edu">Ellen Hudson-Snyder</a>, 
 * <a href="mailto:evedar@andrew.cmu.edu">Elvin Vedar</a>,
 * <a href="mailto:cbalz@andrew.cmu.edu">Christopher M. Balz</a>.
 * <br><br>CVS Version Info:<br>
 *  $Id: Plate.js,v 1.117 2005/12/27 01:05:21 cbalz Exp $  
 * <br><br>
 * @inherits-from <code>AbstractWidget</code>
 * @gets-aspect      <code>GrabAndDrag</code>  This aspect enables an element to be draggable on the screen 
 *                                             by the user.
 * @listens-to-event <code>onmoveup</code> from the <code>NavigationPad</code> custom JavaScript object.
 * @listens-to-event <code>onmoveright</code> from the <code>NavigationPad</code> custom JavaScript object.
 * @listens-to-event <code>onmoveleft</code> from the <code>NavigationPad</code> custom JavaScript object.
 * @listens-to-event <code>onmovedown</code> from the <code>NavigationPad</code> custom JavaScript object.
 * @listens-to-event <code>onmovecenter</code> from the <code>NavigationPad</code> custom JavaScript object.
 * @listens-to-event <code>onzoomin</code> from the <code>ZoomPad</code> custom JavaScript object.
 * @listens-to-event <code>onzoomout</code> from the <code>ZoomPad</code> custom JavaScript object.
 * @listens-to-event <code>onbackwardslow</code> from the <code>LayerPad</code> custom Javascript object.
 * @listens-to-event <code>onbackwardmedium</code> from the <code>LayerPad</code> custom Javascript object.
 * @listens-to-event <code>onbackwardfast</code> from the <code>LayerPad</code> custom Javascript object.
 * @listens-to-event <code>onforwardslow</code> from the <code>LayerPad</code> custom Javascript object.
 * @listens-to-event <code>onforwardmedium</code> from the <code>LayerPad</code> custom Javascript object.
 * @listens-to-event <code>onforwardfast</code> from the <code>LayerPad</code> custom Javascript object.
 * @listens-to-event <code>onresize</code> from the <code>Console</code> custom JavaScript object.
 * @listens-to-event <code>ondblclick</code> from the <code>Plate</code> custom JavaScript object.
 * @object-prop <code>Gigapan</code> <code>objController</code> The parent of the object made from this class, 
 *                                   which is the application controller.
 * @object-prop <code>PanoramaProtocol</code> <code>objPanoramProtocol</code> The object representing the protocol 
 *                                            used to communicate information about the server image set and the 
 *                                            applicable graphical user interface controls between the client and
 *                                            the server.
 * @object-prop <code>ServerImageSet</code> <code>objServerImageSet</code> The object representing the set of
 *                                          images on the server, with methods to track the <code>plate</code>'s
 *                                          position on the server image set.
 * @object-prop <code>FastLinkedList</code> <code>objStackList</code> A linked list of <code>Stack</code> objects 
 *                                          on the <code>Plate</code> object.
 * @object-prop <code>Console</code> <code>wgtConsole</code> The <code>Console</code> object.
 * @object-prop <code>number</code> <code>intPresentationLeftPx</code> The internal representation of the current 
 *                                  <code>left</code> style property of the <code>plate</code> screen element.
 * @object-prop <code>number</code> <code>intPresentationTopPx</code> The internal representation of the current 
 *                                  <code>top</code> style property of the <code>plate</code> screen element.
 * @object-prop <code>number</code> <code>intPresentationLeftStartPx</code> The <code>left</code> pixel value where
 *                                  the <code>Plate</code> was before its latest image load.  This is presentation-
 *                                  specific data, unrelated to the image set on the server.
 * @object-prop <code>number</code> <code>intPresentationTopStartPx</code>  The <code>top</code> pixel value 
 *                                  where the <code>Plate</code> was before its latest image load.  
 *                                  This is presentation-specific data, unrelated to the image set on the server.
 * @object-prop <code>number</code> <code>intPlateHeightPx</code>  The height of the <code>plate</code> screen 
 *                                  element. 
 * @object-prop <code>number</code> <code>intPlateWidthPx</code>  The width of the <code>plate</code> screen 
 *                                  element.  
 * @object-prop <code>number</code> <code>intPresentationLeftEndPx</code>  The <code>right</code> pixel value where
 *                                  the <code>Plate</code> ends before image load.
 * @object-prop <code>number</code> <code>intPresentationTopEndPx</code>  The <code>right</code> pixel value where 
 *                                  the <code>Plate</code> ends before image load.
 * @object-prop <code>number</code> <code>intStackHeightPx</code> The height of each <code>Stack</code> object in 
 *                                  <code>objStackList</code>.  
 *                                  This variable is determined by the information in the 'PanoramaProtocol'-  
 *                                  -conformant xml document file that
 *                                  is read upon the initialization of the <code>Plate</code> object.
 * @object-prop <code>number</code> <code>intStackWidthPx</code> The width of each <code>Stack</code> object in 
 *                                  <code>objStackList</code>.  
 *                                  This variable is determined by the information in the 'PanoramaProtocol'-  
 *                                  -conformant xml document file that
 *                                  is read upon the initialization of the <code>Plate</code> object.
 * @object-prop <code>number</code> <code>intNumStacksHigh</code>  The number of <code>Stack</code> objects in a 
 *                                  column on the <code>Plate</code>.
 * @object-prop <code>number</code> <code>intNumStacksWide</code>  The number of <code>Stack</code> objects in a 
 *                                  row on the <code>Plate</code>.
 * @object-prop <code>number</code> <code>intDistanceMovedLeftPx</code>    The number of pixels moved at the last
 *                                  image load.  This value serves as the link between 
 *                                  presentation-specific positioning and the application data of the image set on 
 *                                  the server.
 *                                  This is presentation-specific data, unrelated to the image set on the server.
 * @object-prop <code>number</code> <code>intDistanceMovedTopPx</code> The number of pixels moved at the last 
 *                                  image load.  This value serves as the link between 
 *                                  presentation-specific positioning and the application data of the image set 
 *                                  on the server.
 *                                  This is presentation-specific data, unrelated to the image set on the server.
 * @object-prop <code>number</code> <code>intMoveUnits</code> The number of pixels that the <code>plate</code> 
 *                                  dom object is moved on the screen
 *                                  each time it moves according to a regular navigation pad button click command.
 * @object-prop <code>number</code> <code>intZoomIndex</code>        The current zoom level.    
 * @object-prop <code>number</code> <code>intZoomIndexMin</code>     The minimum zoom level.
 * @object-prop <code>number</code> <code>intZoomIndexMax</code>     The maximum zoom level.
 * @object-prop <code>boolean</code> <code>booZoomUpLock</code>  A boolean lock used to control disabling the
 *                                                               'down' button if the plate cannot be moved up.
 * @object-prop <code>boolean</code> <code>booZoomDownLock</code>  A boolean lock used to control disabling the
 *                                                                'up' button if the plate cannot be moved down.
 * @object-prop <code>boolean</code> <code>booZoomLeftLock</code>  A boolean lock used to control disabling the
 *                                                               'right' button if the plate cannot be moved left.
 * @object-prop <code>boolean</code> <code>booZoomUpLock</code>  A boolean lock used to control disabling the
 *                                                               'left' button if the plate cannot be moved right. 
 * @author Team GigaToasted (Fall-2005-CMU-NASA/Google-Practicum Subteam) 
 * @version 1.0
 * <br><br>
 */ 


// Set the prototype chain for efficient inheritance:
Plate.prototype = new AbstractWidget();


/**
 * Create a <code>Plate</code> object.
 * @param pObjParent <code>Object</code>  The parent, if any, of this object.
 * @param pWgtConsole <code>Console</code>  The console object of this application.
 */
function Plate(pObjParent, pWgtConsole) {
    this.superC("plate", pObjParent); // Complete the inheritance.    

    // Properties:
    this.objController = pObjParent;
    this.wgtConsole = pWgtConsole;
    this.strAnchorWrapperId = this.strId + "_anchor"; // Value unused; should be deleted
    this.objPanoramaProtocol = null;  
    this.objServerImageSet = null;  
    this.objStackList = new FastLinkedList();
    // Presentation Data:
    this.intPresentationLeftPx = null;
    this.intPresentationTopPx = null;
    this.intPresentationLeftStartPx = null; 
    this.intPresentationTopStartPx = null;
    this.intPresentationTopEndPx = null;
    this.intPresentationLeftEndPx = null;
    this.intDistanceMovedLeftPx = null;
    this.intDistanceMovedTopPx = null; 
    // Calculated plate data from Panorama data:
    this.intPlateHeightPx = null;
    this.intPlateWidthPx = null;
    this.intNumStacksHigh = null;
    this.intNumStacksWide = null;
    // intStackHeight and intStackWidth somehow managed
    // to get deleted, but are used in the code.
    // They should be declared here and tested.
    // Movement and Zoom information:
    this.intMoveUnits = 25;
    this.intZoomIndex = 0;
    this.intZoomIndexMin = 0;
    this.intZoomIndexMax = 2;
    this.booZoomUpLock = false;
    this.booZoomDownLock = false;
    this.booZoomLeftLock = false;
    this.booZoomRightLock = false;
    // Methods:
    this.init = Plate_init;
    this.initImageLayers = Plate_initImageLayers;
    this.redrawPlate = Plate_redrawPlate;
    this.getHtml = Plate_getHtml;
    this.receiveEvent = Plate_receiveEvent;
    this.movePlateRight = Plate_movePlateRight;
    this.movePlateUp = Plate_movePlateUp;
    this.movePlateLeft = Plate_movePlateLeft;
    this.movePlateDown = Plate_movePlateDown;
    this.reload = Plate_reload;
    this.resizePlate = Plate_resizePlate;
    this.center = Plate_center;
    this.sizePlateToImageLayers = Plate_sizePlateToImageLayers;
    this.zoom = Plate_zoom;
    this.browseLayerForwardFast = Plate_browseLayerForwardFast;
    this.browseLayerForwardMedium = Plate_browseLayerForwardMedium;
    this.browseLayerForwardSlow = Plate_browseLayerForwardSlow;
    this.browseLayerBackwardFast = Plate_browseLayerBackwardFast;
    this.browseLayerBackwardMedium = Plate_browseLayerBackwardMedium;
    this.browseLayerBackwardSlow = Plate_browseLayerBackwardSlow;
    this.buildStackList = Plate_buildStackList;
    this.buildStackListHtml = Plate_buildStackListHtml;
    this.calcDistanceMoved = Plate_calcDistanceMoved;
    this.load = Plate_load;
    this.reloadBrowseLayerLabels = Plate_reloadBrowseLayerLabels;
    this.reloadZoomButtonState = Plate_reloadZoomButtonState;
    this.enableNavigationButtonState = Plate_enableNavigationButtonState;
    this.findPlateZoomPoint = Plate_findPlateZoomPoint;
    this.ondblclick = Plate_ondblclick;
    // Register events:
    self.gloScope.registerEvent(this.strId, this, "navigationPad", "onmoveup");
    self.gloScope.registerEvent(this.strId, this, "navigationPad", "onmovedown");
    self.gloScope.registerEvent(this.strId, this, "navigationPad", "onmoveleft");
    self.gloScope.registerEvent(this.strId, this, "navigationPad", "onmoveright");
    self.gloScope.registerEvent(this.strId, this, "navigationPad", "onmovecenter");
    self.gloScope.registerEvent(this.strId, this, "zoomPad", "onzoomin");
    self.gloScope.registerEvent(this.strId, this, "zoomPad", "onzoomout");
    self.gloScope.registerEvent(this.strId, this, "layerpad", "onbackwardslow");
    self.gloScope.registerEvent(this.strId, this, "layerpad", "onbackwardmedium");
    self.gloScope.registerEvent(this.strId, this, "layerpad", "onbackwardfast");
    self.gloScope.registerEvent(this.strId, this, "layerpad", "onforwardslow");
    self.gloScope.registerEvent(this.strId, this, "layerpad", "onforwardmedium");
    self.gloScope.registerEvent(this.strId, this, "layerpad", "onforwardfast");
    self.gloScope.registerEvent(this.strId, this, "console", "onresize");
    self.gloScope.registerEvent(this.strId, this, "plate", "ondblclick");
}


/**
 * This method initializes attributes in the <code>Plate</code>.  This function uses a multiplier to
 * determine the number of stacks on a <code>plate</code>.  This multiplier should not exceed 15 to 20,
 * depending on the performance of the machine running the application.
 * @param pObjPanoramaProtocol <code>PanoramaProtocol</code>  An object representing the protocol 
 *                             used to communicate information about the server image set and the 
 *                             applicable graphical user interface controls between the client and
 *                             the server.
 * @param pIntCompositeImageLayerHeight <code>number</code>  An integer representing the number
 *                             of <code>stacks</code> on the <code>Plate</code> in the vertical direction.
 * @param pIntCompositeImageLayerWidth <code>number</code>  An integer representing the number
 *                             of <code>stacks</code> on the <code>Plate</code> in the horizontal direction.
 */
function Plate_init(pObjPanoramaProtocol, pIntCompositeImageLayerHeight, pIntCompositeImageLayerWidth) {
    this.objPanoramaProtocol = pObjPanoramaProtocol; 
    this.objServerImageSet = this.objController.objServerImageSet;   
    this.intStackHeightPx = parseInt(pObjPanoramaProtocol.getTileHeight(this.intZoomIndex));
    this.intStackWidthPx = parseInt(pObjPanoramaProtocol.getTileWidth(this.intZoomIndex));
    this.intZoomIndexMin = parseInt(pObjPanoramaProtocol.getMinDetailLevel());
    this.intZoomIndexMax = parseInt(pObjPanoramaProtocol.getMaxDetailLevel());
    this.intNumStacksHigh = pIntCompositeImageLayerHeight;
    this.intNumStacksWide = pIntCompositeImageLayerWidth;
    this.intPlateHeightPx = (this.intStackHeightPx * this.intNumStacksHigh);
    this.intPlateWidthPx = (this.intStackWidthPx * this.intNumStacksWide); 
    // Build the stack list:
    this.buildStackList();
}


/**
 * This method resets the positioning of the <code>plate</code> dom object on the screen
 * so that the user may continue with two-dimensional navigation,
 * requests new images from the server, 
 */
function Plate_initImageLayers() {    
    this.sizePlateToImageLayers();
    this.center( this.wgtConsole.getHeightWidth()[1], this.wgtConsole.getHeightWidth()[0] );
    this.load( this.objServerImageSet.requestImages() );
}


/**
 * This method centers the <code>plate</code> document object model object
 * on the screen.<br><br>
 * This method caches the <code>top</code> and <code>left</code> start (pre-centering) pixel values.  
 * @param pIntConsoleWidth  <code>number</code> The total width of the console widget.
 * @param pIntConsoleHeight  <code>number</code> The total height of the console widget.
 */
function Plate_center(pIntConsoleWidth, pIntConsoleHeight) {
    var objStyle = this.getDomRef().style,
        intTopEdgeOfWindowSill = this.wgtConsole.getWindowSillHeight() + 
        (2*this.wgtConsole.getWindowSillBorderWidths()[0]) +
        (this.wgtConsole.getBorderWidths()[1]);

    this.intPresentationTopPx = Math.floor(( (this.intPlateHeightPx/2) * (-1) ) + 
                                             ( (pIntConsoleHeight - intTopEdgeOfWindowSill) / 2 )); // Center the Plate.
    this.intPresentationLeftPx = Math.floor(( (this.intPlateWidthPx/2) * (-1) ) + ( pIntConsoleWidth / 2 )); // Center the Plate.
    this.intPresentationLeftStartPx = this.intPresentationLeftPx; 
    this.intPresentationTopStartPx = this.intPresentationTopPx;
    objStyle.top = this.intPresentationTopPx + "px";
    objStyle.left = this.intPresentationLeftPx + "px";
}


/**
 * This method resets the positioning of the <code>plate</code> dom object on the screen
 */
function Plate_redrawPlate() {
	// here we need to draw the html for the new stacks on the plate
        this.objController.objStringBuffer = new StringBuffer();
        this.buildStackListHtml(this.objController.objStringBuffer);
	this.getDomRef().innerHTML = this.objController.objStringBuffer.toString();  
}


/**
 * This method receives any events that this object listens to and 
 * routes them to the proper methods. 
 * @param pStrEventSourceElementId <code>string</code> The i.d. of the document object model from which the event
 *                                 sprang.
 * @param pStrEventType  <code>string</code> The event type of the object (e.g., 'onclick', etc).
 * @param pObjEvent  <code>Object</code> The event object itself.
 */
function Plate_receiveEvent(pStrEventSourceElementId, pStrEventType, pObjEvent) { 
    switch (pStrEventSourceElementId) { 
    case "plate" :
        switch (pStrEventType) {
        case "ondblclick" :
            this.ondblclick(pObjEvent);
            break;
        }
        break;
    case "navigationPad" :
        switch (pStrEventType) {
        case "onmoveup" :
            this.movePlateUp(this.intMoveUnits);
            break;
        case "onmoveright" : 
            this.movePlateRight(this.intMoveUnits);
            break;
        case "onmoveleft" :
            this.movePlateLeft(this.intMoveUnits);
            break;
        case "onmovedown" :
            this.movePlateDown(this.intMoveUnits);
            break;
        case "onmovecenter" :
            this.movePlateCenter();
            break;
        }
        break;
    case "zoomPad" : 
        switch (pStrEventType) {
        case "onzoomin" : 
            this.zoom("in");
            break;
        case "onzoomout" :
            this.zoom("out");
            break;
        }
        break;
    case "layerpad" : 
        switch (pStrEventType) {
        case "onforwardslow" : 
            this.browseLayerForwardSlow();
            break;
        case "onforwardmedium" : 
            this.browseLayerForwardMedium();
            break;
        case "onforwardfast" : 
            this.browseLayerForwardFast();
            break;
        case "onbackwardslow" : 
            this.browseLayerBackwardSlow();
            break;
        case "onbackwardmedium" : 
            this.browseLayerBackwardMedium();
            break;
        case "onbackwardfast" : 
            this.browseLayerBackwardFast();
            break;
        }
        break; 
    }
}


/**
 * This method sizes the <code>plate</code> document object model object
 * to the height and width of the actual image layer tiles (held by <code>Stack</code>
 * and <code>ImageLayer</code> objects). <br>
 */
function Plate_sizePlateToImageLayers() {
    var objStyle = this.getDomRef().style;
          
    this.intPlateHeightPx = (this.intNumStacksHigh * this.intStackHeightPx);
    this.intPlateWidthPx  = (this.intNumStacksWide *  this.intStackWidthPx);        

    objStyle.height = this.intPlateHeightPx + "px";
    objStyle.width  = this.intPlateWidthPx  + "px";        
    if (!self.gloScope.booDebugMode) {
        objStyle.backgroundColor = "transparent";
        objStyle.backgroundImage = "";
    }
}


/**
 * This method sizes the <code>plate</code> document object model object
 * to the smaller of the: height and width of the actual image layer tiles; or the configured
 * height and width values; and rebuilds and redraws the plate.
 * @param pIntCompositeImageLayerHeight <code>number</code> The determined height of the image set
 *											to be loaded on this plate.
 * @param pIntCompositeImageLayerWidth  <code>number</code> The determined width of the image set
 *											to be loaded on this plate.
 */
function Plate_resizePlate(pIntCompositeImageLayerHeight, pIntCompositeImageLayerWidth) {

    this.intNumStacksHigh = pIntCompositeImageLayerHeight; 
    this.intNumStacksWide = pIntCompositeImageLayerWidth;
    // Do not clear the stack list, for it is bad for performance.
    // this.objStackList.objHead = null;
    // Build a new stack list with the new parameters
    this.buildStackList();
    // Set the plate size to the image set size
    this.sizePlateToImageLayers();
    // Redraw the plate
    this.redrawPlate();
}


/**
 * This method resets the <code>Stack</code> widgets on a given plate to display the next 
 * set of images from the server.  Assumes the length of the <code>objStackList</code>
 * and the URL list in the <code>PlatefulResponse</code> are the same.
 * @param pObjPlateUpdateResponse <code>PlateUpdateResponse</code>  A properly set object
 *                                representing the <code>ServerImageSet</code> object's 
 *                                response to the <code>Plate</code> object's request for a reload.
 */
function Plate_reload(pObjPlateUpdateResponse) {                              
    var objUrlList = pObjPlateUpdateResponse.objNewImagesList, objStackList = this.objStackList, 
        objImageLayer = null, objUrlListNode = null, objStackListNode = null, intCounter=0,
        intMaxNumNodes;
    intMaxNumNodes = this.intNumStacksHigh * this.intNumStacksWide;
    objUrlListNode = objUrlList.objHead;
    objStackListNode = objStackList.objHead;

    while (intCounter < intMaxNumNodes) { // objUrlListNode != null && objStackListNode != null) {
        // Set the ImageLayer source
        objImageLayer = objStackListNode.anyData.getImageLayer();
        objImageLayer.setImageSrc(objUrlListNode.anyData);  
        objImageLayer.loadImage();
        // Iterate down the list
        objStackListNode = objStackListNode.objNext;
        objUrlListNode = objUrlListNode.objNext;
        
        intCounter++;
    }
}


/**
 * This method loads the src properties in the <code>ImageLayer</code> widgets to display the initial 
 * set of images from the server.
 * @param pObjPlateUpdateResponse <code>PlateUpdateResponse</code>  A properly set object
 *                                representing the <code>ServerImageSet</code> object's 
 *                                response to the <code>Plate</code> object's request for a reload.
 */
function Plate_load(pObjPlateUpdateResponse) {
    this.reload( pObjPlateUpdateResponse);
}


/**
 * This method moves the <code>plate</code> element <code>intMoveUnits</code> pixels to the left.  This occurs when
 * the user clicks the 'right' arrow.  If the <code>plate</code> is reloaded new images appear on the right side of
 * the screen.
 * @param pIntMoveUnitsPx  <code>number</code> number of units to move the plate
 */
function Plate_movePlateLeft(pIntMoveUnitsPx) {
    var objStyle = this.getDomRef().style, intConsoleWidth = this.wgtConsole.getHeightWidth()[1];

    if (this.booZoomLeftLock) {
        self.Environment.handleEvent(this.strId, 'ondisablerightbutton', null);
        return;
    }

    if (!this.booZoomRightLock) {
        self.Environment.handleEvent(this.strId, 'onenableleftbutton', null);
    }
    this.intPresentationLeftPx = this.intPresentationLeftPx - pIntMoveUnitsPx;
    if ( (this.intPresentationLeftPx + this.intPlateWidthPx - intConsoleWidth) < (this.wgtConsole.getBorderWidths()[3]) ) {

        var  objPlateUpdateRequest, objPlateUpdateResponse;

        this.intPresentationLeftEndPx = this.intPresentationLeftPx;
        this.intPresentationTopEndPx = this.intPresentationTopPx;
        this.calcDistanceMoved();
        objPlateUpdateRequest = new PlateUpdateRequest( true, this.intDistanceMovedLeftPx, null );
        objPlateUpdateResponse = this.objServerImageSet.getReloadData( objPlateUpdateRequest ); 
        
        if( objPlateUpdateResponse.booHasNewImages ) {
            this.intPresentationLeftPx += (this.intDistanceMovedLeftPx * -1)- objPlateUpdateResponse.intXOffsetPx
            				+ objPlateUpdateResponse.intAdjustmentPx;
            this.reload( objPlateUpdateResponse );
            this.intPresentationLeftStartPx = this.intPresentationLeftPx;
        } else { 
            //Disable the button
            self.Environment.handleEvent(this.strId, 'ondisablerightbutton', null);
            this.intPresentationLeftPx = this.intPresentationLeftPx + pIntMoveUnitsPx; // Undo changes. 
        }  
    } 

    if ( isNaN(this.intPresentationLeftPx) ) { // Workaround for weird IE 6 bug.
        this.intPresentationLeftPx = parseInt(objStyle.left);
        return;
    }

    if (this.booZoomRightLock && this.intPresentationLeftPx < (this.wgtConsole.getBorderWidths()[2]) ) {
        this.booZoomRightLock = false;
    }    

    objStyle.left = this.intPresentationLeftPx + "px";
}


/**
 * This method moves the <code>plate</code> element <code>intMoveUnits</code> pixels to the right. This occurs when
 * the user clicks the 'left' arrow.  If the <code>Plate</code> is reloaded new images appear on the left side of 
 * the screen.
 * @param pIntMoveUnitsPx  <code>number</code> number of units to move the plate
 */
function Plate_movePlateRight(pIntMoveUnitsPx) {
    var objStyle = this.getDomRef().style, intConsoleWidth = this.wgtConsole.getHeightWidth()[1];

    if (this.booZoomRightLock) {
        self.Environment.handleEvent(this.strId, 'ondisableleftbutton', null);
        return;
    }

    if (!this.booZoomLeftLock) {
        self.Environment.handleEvent(this.strId, 'onenablerightbutton', null);
    }
    this.intPresentationLeftPx = this.intPresentationLeftPx + pIntMoveUnitsPx; 
    if (this.intPresentationLeftPx > (this.wgtConsole.getBorderWidths()[2]) ) {

        var  objPlateUpdateRequest, objPlateUpdateResponse;

        this.intPresentationLeftEndPx = this.intPresentationLeftPx;
        this.intPresentationTopEndPx = this.intPresentationTopPx;
        this.calcDistanceMoved();
        
        objPlateUpdateRequest = new PlateUpdateRequest( true, this.intDistanceMovedLeftPx, null );
        objPlateUpdateResponse = this.objServerImageSet.getReloadData( objPlateUpdateRequest );
        
        
        if( objPlateUpdateResponse.booHasNewImages ) {
            this.intPresentationLeftPx += (this.intDistanceMovedLeftPx * -1) - objPlateUpdateResponse.intXOffsetPx
            				+ objPlateUpdateResponse.intAdjustmentPx;
            this.reload( objPlateUpdateResponse );
            this.intPresentationLeftStartPx = this.intPresentationLeftPx;
        } else { 
            //Disable the button
            self.Environment.handleEvent(this.strId, 'ondisableleftbutton', null);
            this.intPresentationLeftPx = this.intPresentationLeftPx - pIntMoveUnitsPx; // Undo changes. 
        } 
    } 

    if ( isNaN(this.intPresentationLeftPx) ) { // Workaround for weird IE 6 bug.
        this.intPresentationLeftPx = parseInt(objStyle.left);
        return;
    }

    if ( this.booZoomLeftLock && 
         (this.intPresentationLeftPx + this.intPlateWidthPx - intConsoleWidth) > (this.wgtConsole.getBorderWidths()[3]) ) {
        this.booZoomLeftLock = false;
    }    

    objStyle.left = this.intPresentationLeftPx + "px";    
}


/**
 * This method moves the <code>plate</code> element <code>intMoveUnits</code> pixels up.  This occurs when
 * the user clicks the 'down' arrow.  If the <code>plate</code> is reloaded, new images appear on the bottom.
 * @param pIntMoveUnitsPx  <code>number</code> number of units to move the plate
 */
function Plate_movePlateUp(pIntMoveUnitsPx) {
    var objStyle = this.getDomRef().style, intConsoleHeight = this.wgtConsole.getHeightWidth()[0],
        intTopEdgeOfWindowSill = this.wgtConsole.getWindowSillHeight() + 
                                 (2*this.wgtConsole.getWindowSillBorderWidths()[0]) -
                                 (this.wgtConsole.getBorderWidths()[1]*2);
     
    if (this.booZoomUpLock) {
        self.Environment.handleEvent(this.strId, 'ondisabledownbutton', null);
        return;
    } 

    if (!this.booZoomDownLock) {
        self.Environment.handleEvent(this.strId, 'onenableupbutton', null);
    }

    this.intPresentationTopPx = this.intPresentationTopPx - pIntMoveUnitsPx;
    if ( (this.intPresentationTopPx + this.intPlateHeightPx) < (intConsoleHeight - intTopEdgeOfWindowSill) ) {       
        
        var  objPlateUpdateRequest, objPlateUpdateResponse;

        this.intPresentationLeftEndPx = this.intPresentationLeftPx;
        this.intPresentationTopEndPx = this.intPresentationTopPx;
        this.calcDistanceMoved();
        objPlateUpdateRequest = new PlateUpdateRequest( true, null, this.intDistanceMovedTopPx );
        objPlateUpdateResponse = this.objServerImageSet.getReloadData( objPlateUpdateRequest ); 
        
        if( objPlateUpdateResponse.booHasNewImages ) {   
            this.intPresentationTopPx += (this.intDistanceMovedTopPx * -1) - objPlateUpdateResponse.intYOffsetPx 
				+ objPlateUpdateResponse.intAdjustmentPx;
            this.reload( objPlateUpdateResponse );
            this.intPresentationTopStartPx = this.intPresentationTopPx;
        } else { 
            //Disable the button
            self.Environment.handleEvent(this.strId, 'ondisabledownbutton', null);
            this.intPresentationTopPx = this.intPresentationTopPx + pIntMoveUnitsPx;
        }
    } 

    if ( isNaN(this.intPresentationTopPx) ) { // Workaround for weird IE 6 bug.
        this.intPresentationTopPx = parseInt(objStyle.top);
        return;
    }

    if ( this.booZoomDownLock && this.intPresentationTopPx < (this.wgtConsole.getBorderWidths()[0]) ) {       
        this.booZoomDownLock = false;
    }

    objStyle.top = this.intPresentationTopPx + "px";
}


/**
 * This method moves the <code>plate</code> element <code>intMoveUnits</code> pixels down. This occurs when
 * the user clicks the 'up' arrow.  If the <code>plate</code> is reloaded, new images appear on the top.
 * @param pIntMoveUnitsPx  <code>number</code> number of units to move the plate
 */
function Plate_movePlateDown(pIntMoveUnitsPx) {    
    var objStyle = this.getDomRef().style, intConsoleHeight = this.wgtConsole.getHeightWidth()[0],
        intTopEdgeOfWindowSill = this.wgtConsole.getWindowSillHeight() + 
                                 (2*this.wgtConsole.getWindowSillBorderWidths()[0]) -
                                 (this.wgtConsole.getBorderWidths()[1]);

    if (this.booZoomDownLock) {
        self.Environment.handleEvent(this.strId, 'ondisableupbutton', null);
        return;
    } 

    if (!this.booZoomUpLock) {
        self.Environment.handleEvent(this.strId, 'onenabledownbutton', null);
    }

    this.intPresentationTopPx = this.intPresentationTopPx + pIntMoveUnitsPx; 
    if (this.intPresentationTopPx > (this.wgtConsole.getBorderWidths()[0]) ) {
		var  objPlateUpdateRequest, objPlateUpdateResponse;

        this.intPresentationLeftEndPx = this.intPresentationLeftPx;
        this.intPresentationTopEndPx = this.intPresentationTopPx;
        this.calcDistanceMoved();
        
        objPlateUpdateRequest = new PlateUpdateRequest( true, null, this.intDistanceMovedTopPx );
        objPlateUpdateResponse = this.objServerImageSet.getReloadData( objPlateUpdateRequest ); 
		if( objPlateUpdateResponse.booHasNewImages ) {  
			this.intPresentationTopPx += (this.intDistanceMovedTopPx * -1)- objPlateUpdateResponse.intYOffsetPx
							+ objPlateUpdateResponse.intAdjustmentPx;
            this.reload( objPlateUpdateResponse );
            this.intPresentationTopStartPx = this.intPresentationTopPx;
        } else { 
            //Disable the button
            self.Environment.handleEvent(this.strId, 'ondisableupbutton', null);
            this.intPresentationTopPx = this.intPresentationTopPx - pIntMoveUnitsPx;
        }
    } 

    if ( isNaN(this.intPresentationTopPx) ) { // Workaround for weird IE 6 bug.
        this.intPresentationTopPx = parseInt(objStyle.top);
        return;
    }

    if ( this.booZoomUpLock && (this.intPresentationTopPx + this.intPlateHeightPx) > (intConsoleHeight - intTopEdgeOfWindowSill) ) {       
        this.booZoomUpLock = false;
    }

    objStyle.top = this.intPresentationTopPx + "px";
}


/**
 * This method moves the <code>plate</code> up or down one zoom level by making the appropriate calls to
 * calculate the zoom point, make the zoom request to the ServerImageSet, and reload the plate with
 * new images.
 * @param pStrDirection  <code>string</code> Direction of movement through zoom levels
 */
function Plate_zoom( pStrDirection ) {
	if( pStrDirection == "in" ) {
		this.intZoomIndex++;
	} else if (pStrDirection == "out" ) {
		this.intZoomIndex--;
	} else {
		alert("Plate_zoom: direction is wrong: " + pStrDirection );
	}
    this.reloadZoomButtonState();
    this.enableNavigationButtonState();
    
    var objPlateZoomRequest = new PlateZoomRequest( this.intZoomIndex, null, null, pStrDirection ),
		objPlateUpdateResponse, 
		intTopEdgeOfWindowSill = this.wgtConsole.getWindowSillHeight() + 
			(2*this.wgtConsole.getWindowSillBorderWidths()[0]) +
			(this.wgtConsole.getBorderWidths()[1]),
		intConsoleWidth = intViewableAreaWidth = this.wgtConsole.getHeightWidth()[1],
        intConsoleHeight = this.wgtConsole.getHeightWidth()[0],
		intViewableAreaHeight = intConsoleHeight - intTopEdgeOfWindowSill,
		objStyle = this.getDomRef().style;
		
    // Find the x, y of the center of the console
    this.findPlateZoomPoint( objPlateZoomRequest );
    // Call the zoom method
    objPlateUpdateResponse = this.objServerImageSet.zoom( objPlateZoomRequest );
    // Resize the plate
    this.resizePlate(
		objPlateUpdateResponse.intNumRowsInCompositeImage, 
		objPlateUpdateResponse.intNumColsInCompositeImage);
	// The objServerImageSet.intPlateZoomPointDistanceXPx value is the distance from the zoom point
	// to the image tile on the top left corner of the plate.  The zoom point is approximately centered
	// on the plate.
	this.intPresentationLeftPx = (intViewableAreaWidth/2) - this.objServerImageSet.intPlateZoomPointDistanceXPx;
	this.intPresentationTopPx = (intViewableAreaHeight/2) - this.objServerImageSet.intPlateZoomPointDistanceYPx; 
	this.intPresentationLeftStartPx = this.intPresentationLeftPx; 
    this.intPresentationTopStartPx = this.intPresentationTopPx;
    objStyle.top = this.intPresentationTopPx + "px";
    objStyle.left = this.intPresentationLeftPx + "px";
    
    /*-
     * Check if need to lock certain navigation directions due to zooming such that 
     * a corner or edge of the 'plate' is showing.  If so, lock movement so that
     * 'plate' cannot be moved further in those directions.  Note that the 'left' button lets the user 
     * 'fly' left by moving the 'plate' right, and so forth for the other directions.
     */
    if ( (this.intPresentationTopPx + this.intPlateHeightPx) < (intConsoleHeight - intTopEdgeOfWindowSill) ) {       
        self.Environment.handleEvent(this.strId, 'ondisabledownbutton', null);
        this.booZoomUpLock = true;
    } else {
		this.booZoomUpLock = false;
		self.Environment.handleEvent(this.strId, 'onenableupbutton', null);
    }

    if (this.intPresentationTopPx > (this.wgtConsole.getBorderWidths()[0]) ) {
        self.Environment.handleEvent(this.strId, 'ondisableupbutton', null);
        this.booZoomDownLock = true;
    } else {
		this.booZoomDownLock = false;
		self.Environment.handleEvent(this.strId, 'onenabledownbutton', null);
    }


    if ( (this.intPresentationLeftPx + this.intPlateWidthPx - intConsoleWidth) < (this.wgtConsole.getBorderWidths()[3]) ) {
        self.Environment.handleEvent(this.strId, 'ondisablerightbutton', null);        
        this.booZoomLeftLock = true;
    } else {
		this.booZoomLeftLock = false;
		self.Environment.handleEvent(this.strId, 'onenablerightbutton', null);
    }


    if (this.intPresentationLeftPx > (this.wgtConsole.getBorderWidths()[2]) ) {
        self.Environment.handleEvent(this.strId, 'ondisableleftbutton', null);
        this.booZoomRightLock = true;
    } else {
		this.booZoomRightLock = false;
		self.Environment.handleEvent(this.strId, 'onenableleftbutton', null);
    }
    

    this.reload( objPlateUpdateResponse );
}


/**
 * This method finds the distance from the top left corner of the plate to the zoom point
 * located at the center of the console.  This value is entered into the PlateZoomRequest
 * object which is then passed to the ServerImageSet to process the request.
 * @param pObjPlateZoomRequest <code>Object</code> The Zoom Request object.
 */
function Plate_findPlateZoomPoint( pObjPlateZoomRequest ) {
	var intTopEdgeOfWindowSill = this.wgtConsole.getWindowSillHeight() + 
        (2*this.wgtConsole.getWindowSillBorderWidths()[0]) +
        (this.wgtConsole.getBorderWidths()[1]);
        
	pObjPlateZoomRequest.intCenterXValuePx = ((-1)* this.intPresentationLeftPx +
		((this.wgtConsole.getHeightWidth()[1]) / 2 ));
	pObjPlateZoomRequest.intCenterYValuePx = ((-1)* this.intPresentationTopPx + 
		((this.wgtConsole.getHeightWidth()[0]) - intTopEdgeOfWindowSill) / 2 );
}


/**
 * This method changes the layer of the <code>plate</code> element so that you can see browse layers forward slow
 */
function Plate_browseLayerForwardSlow() {
    // The PlateUpdateRequest object should be used here
    this.objServerImageSet.browseLayerForwardSlow();
    this.reload(this.objServerImageSet.objPlateUpdateResponse);
}


/**
 * This method changes the layer of the <code>plate</code> element so that you can see browse layers forward medium
 */
function Plate_browseLayerForwardMedium() {
    // The PlateUpdateRequest object should be used here
    this.objServerImageSet.browseLayerForwardMedium();
    this.reload(this.objServerImageSet.objPlateUpdateResponse);
}


/**
 * This method changes the layer of the <code>plate</code> element so that you can see browse layers forward fast
 */
function Plate_browseLayerForwardFast() {
    // The PlateUpdateRequest object should be used here
    this.objServerImageSet.browseLayerForwardFast();
    this.reload(this.objServerImageSet.objPlateUpdateResponse);
}


/**
 * This method changes the layer of the <code>plate</code> element so that you can see browse layers backward slow
 */
function Plate_browseLayerBackwardSlow() {
    // The PlateUpdateRequest object should be used here
    this.objServerImageSet.browseLayerBackwardSlow();
    this.reload(this.objServerImageSet.objPlateUpdateResponse);
}


/**
 * This method changes the layer of the <code>plate</code> element so that you can see browse layers backward medium
 */
function Plate_browseLayerBackwardMedium() {
    // The PlateUpdateRequest object should be used here
    this.objServerImageSet.browseLayerBackwardMedium();
    this.reload(this.objServerImageSet.objPlateUpdateResponse);
}


/**
 * This method changes the layer of the <code>plate</code> element so that you can see browse layers backward fast
 */
function Plate_browseLayerBackwardFast() {
    // The PlateUpdateRequest object should be used here
    this.objServerImageSet.browseLayerBackwardFast();
    this.reload(this.objServerImageSet.objPlateUpdateResponse);
}


/**
 * This method calculates the <code>intDistanceMovedLeftPx</code> and <code>intDistanceMovedTopPx</code> values, in pixels.
 * This distance calculation allows for negative values; the sign determines the direction.
 */
function Plate_calcDistanceMoved() {
    
    this.intDistanceMovedLeftPx = this.intPresentationLeftEndPx - this.intPresentationLeftStartPx;
    this.intDistanceMovedTopPx = this.intPresentationTopEndPx - this.intPresentationTopStartPx;
}



/** 
 * This method creates a linked list of stack objects which fill the <code>plate</code>.
 *
 * We'll be making new dom objects, so we set the <code>domObj</code> properties 
 * of the <code>ImageLayer</code> widgets to <code>null</code> in order 
 * to force the widgets to refresh their dom object reference when new <code>src</code>
 * properties are entered for them.
 */
function Plate_buildStackList() {
    var intStackTop = 0, intStackLeft = 0, i = 0, j = 0, intStackListLen = 0;
    var objStack = null, intNumNewStacks = 0;
    var ht = this.intNumStacksHigh, wd = this.intNumStacksWide;
    var objNode = ( (this.objStackList.objHead != null) ? this.objStackList.objHead : null);

    if (objNode == null) { // Need a new list with all new objects (only happens once):
        for ( ; i < ht; i++) {
            j=0;
            intStackTop = 0;
            for ( ; j < wd; j++ ) {               
                objStack = new Stack(this, intStackTop, intStackLeft, this.intStackHeightPx, this.intStackWidthPx);
                this.objStackList.add( objStack );
                intStackTop += this.intStackHeightPx;
                // intStackListLen++; // This is for debugging
            }
            intStackLeft += this.intStackWidthPx;
        }
    } else { // Need a new list with some or all recycled objects:
        this.objStackList = null;
        this.objStackList = new FastLinkedList();
        for ( ; i < ht; i++) {
            j=0;
            intStackTop = 0;
            for ( ; j < wd; j++ ) {
                if (objNode) { 
                    objStack = objNode.anyData;
                    objStack.intLeftPx   = intStackTop;
                    objStack.intTopPx    = intStackLeft;
                    objStack.intHeightPx = this.intStackHeightPx;
                    objStack.intWidthPx  = this.intStackWidthPx;
                    objStack.wgtImageLayer.domObj = null; 
                    this.objStackList.add( objStack );
                    objNode = objNode.objNext;
                } else {
                    objStack = new Stack(this, intStackTop, intStackLeft, this.intStackHeightPx, this.intStackWidthPx);
                    this.objStackList.add( objStack );
                    // intNumNewStacks++; // This is for debugging                
                }
                intStackTop += this.intStackHeightPx;
                // intStackListLen++; // This is for debugging                
            }
            intStackLeft += this.intStackWidthPx;
        }
    }
}

 
/**
 * This method builds the <code>objStackList</code>'s html in <code>plate</code>.
 * @param <code>pObjStringBuffer</code>  String buffer to place the string
 */
function Plate_buildStackListHtml(pObjStringBuffer) {
    var i = 0, j = 0;
    var objStack = null;
    var objThisNode = new FastNode( null );
    var ht = this.intNumStacksHigh, wd = this.intNumStacksWide;
    var strStackListHtml = new String();

    // Go to the head of the list
    objThisNode = this.objStackList.objHead;

    for ( ; i < wd; i++) {
        j=0;
        for ( ; j < ht; j++ ) {
            objThisNode.anyData.getHtml(pObjStringBuffer); 
            objThisNode = objThisNode.objNext;          
        }
    }
}


/**
 * Return the HTML of the object managed by the <code>Plate</code> widget and its child widgets.    
 * @param <code>pObjStringBuffer</code>  Buffer to place all strings
 */
function Plate_getHtml(pObjStringBuffer) {
    pObjStringBuffer.append( [ "<div id='", this.strId, 
                               "' ondblclick='self.Environment.handleEvent(this.id,\"ondblclick\",event); return true;' >" ] );
    this.buildStackListHtml(pObjStringBuffer);
    pObjStringBuffer.append( [ "</div>" ] );
}


/**
 * Set up the layer names and disable the buttons if disabled
 */
function Plate_reloadBrowseLayerLabels() {
    if (this.objServerImageSet.strForwardFastLayerLevel == null) {
        self.Environment.handleEvent(this.strId, 'onsetforwardfasttext', "");
        self.Environment.handleEvent(this.strId, 'ondisableforwardfast', null);
    } else {
        self.Environment.handleEvent(this.strId, 'onsetforwardfasttext', this.objServerImageSet.strForwardFastLayerLevel);
        self.Environment.handleEvent(this.strId, 'onenableforwardfast', null);
    }

    if (this.objServerImageSet.strForwardMediumLayerLevel == null) {
        self.Environment.handleEvent(this.strId, 'onsetforwardmediumtext', "");
        self.Environment.handleEvent(this.strId, 'ondisableforwardmedium', null);
    } else {
        self.Environment.handleEvent(this.strId, 'onsetforwardmediumtext', this.objServerImageSet.strForwardMediumLayerLevel);
        self.Environment.handleEvent(this.strId, 'onenableforwardmedium', null);
    }

    if (this.objServerImageSet.strForwardSlowLayerLevel == null) {
        self.Environment.handleEvent(this.strId, 'onsetforwardslowtext', "");
        self.Environment.handleEvent(this.strId, 'ondisableforwardslow', null);
    } else {
        self.Environment.handleEvent(this.strId, 'onsetforwardslowtext', this.objServerImageSet.strForwardSlowLayerLevel);
        self.Environment.handleEvent(this.strId, 'onenableforwardslow', null);
    }

    if (this.objServerImageSet.strBackwardFastLayerLevel == null) {
        self.Environment.handleEvent(this.strId, 'onsetbackwardfasttext', "");
        self.Environment.handleEvent(this.strId, 'ondisablebackwardfast', null);
    } else {
        self.Environment.handleEvent(this.strId, 'onsetbackwardfasttext', this.objServerImageSet.strBackwardFastLayerLevel);
        self.Environment.handleEvent(this.strId, 'onenablebackwardfast', null);
    }

    if (this.objServerImageSet.strBackwardMediumLayerLevel == null) {
        self.Environment.handleEvent(this.strId, 'onsetbackwardmediumtext', "");
        self.Environment.handleEvent(this.strId, 'ondisablebackwardmedium', null);
    } else {
        self.Environment.handleEvent(this.strId, 'onsetbackwardmediumtext', this.objServerImageSet.strBackwardMediumLayerLevel);
        self.Environment.handleEvent(this.strId, 'onenablebackwardmedium', null);
    }

    if (this.objServerImageSet.strBackwardSlowLayerLevel == null) {
        self.Environment.handleEvent(this.strId, 'onsetbackwardslowtext', "");
        self.Environment.handleEvent(this.strId, 'ondisablebackwardslow', null);
    } else {
        self.Environment.handleEvent(this.strId, 'onsetbackwardslowtext', this.objServerImageSet.strBackwardSlowLayerLevel);
        self.Environment.handleEvent(this.strId, 'onenablebackwardslow', null);
    }

    if (this.objServerImageSet.strLayerLevelTitle == this.objServerImageSet.strLayerLevel) {
        self.Environment.handleEvent(this.strId, 'onsetcurrentlayertext', this.objServerImageSet.strLayerLevel);
    } else {
    self.Environment.handleEvent(this.strId, 'onsetcurrentlayertext', this.objServerImageSet.strLayerLevelTitle + " (" + this.objServerImageSet.strLayerLevel + ")");
    }
}


/**
 * Set up the zoom buttons if disabled or enabled
 */
function Plate_reloadZoomButtonState() {
    if (this.intZoomIndex == this.intZoomIndexMax) {
        self.Environment.handleEvent(this.strId, 'ondisablezoomin', null);
    } else {
        self.Environment.handleEvent(this.strId, 'onenablezoomin', null);
    }

    if (this.intZoomIndex == this.intZoomIndexMin) {
        self.Environment.handleEvent(this.strId, 'ondisablezoomout', null);
    } else {
        self.Environment.handleEvent(this.strId, 'onenablezoomout', null);
    }
}


/**
 * Enable all the navigation buttons
 */
function Plate_enableNavigationButtonState() {
    self.Environment.handleEvent(this.strId, 'onenabledownbutton', null);
    self.Environment.handleEvent(this.strId, 'onenableupbutton', null);
    self.Environment.handleEvent(this.strId, 'onenableleftbutton', null);
    self.Environment.handleEvent(this.strId, 'onenablerightbutton', null);
}


/**
 * Move the plate to center on a certain point
 * @param pObjEvent <code>Object</code> Event of the dblclick
 */
function Plate_ondblclick(pObjEvent) {
    var intX = pObjEvent.clientX, intY = pObjEvent.clientY;
    var intDistanceToMoveX = 0, intDistanceToMoveY = 0;
    var intConsoleHeight = this.wgtConsole.getHeightWidth()[0],
        intTopEdgeOfWindowSill = this.wgtConsole.getWindowSillHeight() + (2*this.wgtConsole.getWindowSillBorderWidths()[0]) +
        (this.wgtConsole.getBorderWidths()[1]);

    // Get the distance to move
    intDistanceToMoveX = intX - (this.wgtConsole.getHeightWidth()[1] / 2);
    intDistanceToMoveY = intY - ((intConsoleHeight-intTopEdgeOfWindowSill) / 2);

    if (intDistanceToMoveX < 0) {
        this.movePlateRight(-1 * intDistanceToMoveX);
    } else {
        this.movePlateLeft(intDistanceToMoveX);
    }

    if (intDistanceToMoveY < 0) {
        this.movePlateDown(-1 * intDistanceToMoveY);
    } else {
        this.movePlateUp(intDistanceToMoveY);
    }
}
