/*
  GSV 1.0, by Michal Migurski <mike-gsv@teczno.com>
  $Id: gsv.js,v 1.6 2005/06/28 03:30:49 migurski Exp $

  Description:
    Generates a draggable and zoomable viewer for images that would be
    otherwise too-large for a browser window, e.g. maps or hi-res
    document scans. Images must be pre-cut into tiles by PowersOfTwo
    Python library.
   	
  Usage:
    For an HTML construct such as this:

        <div class="imageViewer">
            <div class="well"> </div>
            <div class="surface"> </div>
            <p class="status"> </p>
        </div>

    ...pass the DOM node for the top-level DIV, a directory name where
    tile images can be found, and an integer describing the height of
    each image tile to prepareViewer():

        prepareViewer(element, 'tiles', 256);
        
    It is expected that the visual behavior of these nodes is determined
    by a set of CSS rules.
    
    The "well" node is where generated IMG elements are appended. It
    should have the CSS rule "overflow: hidden", to occlude image tiles
    that have scrolled out of view.
    
    The "surface" node is the transparent mouse-responsive layer of the
    image viewer, and should match the well in size.
    
    The "status" node is generally set to "display: none", but can be
    shown when diagnostic information is desired. It's controlled by the
    displayStatus() function here.

  License:
    Copyright (c) 2005 Michal Migurski <mike-gsv@teczno.com>
    
    Redistribution and use in source form, with or without modification,
    are permitted provided that the following conditions are met:
    1. Redistributions of source code must retain the above copyright
       notice, this list of conditions and the following disclaimer.
    2. The name of the author may not be used to endorse or promote products
       derived from this software without specific prior written permission.
    
    THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
    OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
    IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
    NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
    THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/   

// constants and vars used for GI grid ref functionality
var sStatus ='';
var LeftOffset;
var TopOffset;
var gridSize;
var startGridX = 200;
var startGridY = 1000;
var gridOffsetX = 0;
var gridOffsetY = 0;
var viewerWidth = 780;
var viewerHeight = 480;
var zeroOffsetX;
var zeroOffsetY;
var topRightX;
var topRightY;
var bottomLeftX;
var bottomLeftY;
var bottomRightX;
var bottomRightY;
var zoomLevel = 1;
var markerSize;
var sMarkers = "";
var markersOn = 0;
var keyOn = 0;
var keyLayer = 1;
var prevZoomLevel = 1;

function fn_toggle_layer(){
  var layerToggleText ='';
  
  if(tileDir == '/gi-tool-files/images/tiles/access'){
    tileDir ='/gi-tool-files/images/tiles/typologies';
    keyLayer = 1;
    layerToggleText = 'Show Access layer';
  } else {
    tileDir = '/gi-tool-files/images/tiles/access';
    layerToggleText = 'Show Typology layer';
    keyLayer = 2;
    //alert(keyLayer);
  }
  
  $("#layerToggle").html(layerToggleText);
  
  for(var i = 0; i < document.body.imageViewers.length; i += 1) {
      var imageViewer = document.body.imageViewers[i];
  }
  
  positionTiles(imageViewer, imageViewer.start);
  fn_update_key_content();
}

function fn_toggle_markers(){
  if (markersOn == 0){
    $("#markerToggle").html('Getting Markers...').animate({opacity: 1.0}, 1).fadeIn('slow', function() {
          addMarkers();
        });
  
    
    markersOn = 1;
  } else {
    hideMarkers();

    markersOn = 0;
  }
}

function fn_toggle_key(){

  var keyLayerHTML = '';
  
  if(keyLayer==2){
    keyLayerHTML = '<img src="/gi-tool-files/images/key-access.gif" alt="" />';
  }
  
  if(keyLayer==1){
    keyLayerHTML = '<img src="/gi-tool-files/images/key-typology.gif" alt="" />';
  }
  
  if(keyOn == 0){
    //alert('show');
    fn_update_key_content();
    $('#keyLayer').show();
    keyOn = 1;
    //$('#keyToggle').html('Hide Key');

  } else {
    //fn_hide_key();
  }
  
}

function fn_hide_key(){
  //$('#keyLayer').hide();
  //keyOn = 0;
  //$('#keyToggle').html('Show Key');
}

function fn_update_key_content(){
  var keyLayerHTML = '';
  
  if(keyLayer==2){
    keyLayerHTML = '<img src="/gi-tool-files/images/key-access.gif" alt="" />';
  }
  
  if(keyLayer==1){
    keyLayerHTML = '<img src="/gi-tool-files/images/key-typology.gif" alt="" />';
  }
  
  $('#keyLayer .content').html(keyLayerHTML);
}

function giEvent(str){
  
  for(var i = 0; i < document.body.imageViewers.length; i += 1) {
      var imageViewer = document.body.imageViewers[i];
  }
  
  var dim = imageViewer.dimensions;
  
  // For grid ref vars;
  zoomLevel = dim.zoomLevel;
  
  updateScaleVars();
  
  // used for grid reference calculations
  zeroOffsetX = 0 - (dim.x + LeftOffset);
  zeroOffsetY = 0 - (dim.y + TopOffset);
  
  updateGridRefRange();
  
  if (str == 'endPositionTiles'){
    hideMarkers();
  }
  
  if (zoomLevel <= 2) {
    $("#oppList").html('<p>Opportunites are not dislayed at this zoom level - to view opportunities zoom in using the "+" at the top right of the map and move the map around by clicking and dragging with your mouse</p>');
  }
  
  if (str=='releaseViewer' || prevZoomLevel != zoomLevel){
    getOpportunities();
  }
  updateScale(zoomLevel);
  sStatus += "zoomLevel:" + zoomLevel;
  prevZoomLevel = zoomLevel;
  sStatus += str;
  showMyStatus();
}

function updateScale(zoomLevel){
  var img = '';
  if (zoomLevel > 1) {
    img = '<img src="/gi-tool-files/images/scale-zoom-' + zoomLevel + '.gif" alt="" />';
  }
  $("#scale").html(img);
}

function getOpportunities(){
  if (zoomLevel >= 3){
    query = 'topLeft=' + gridOffsetX + gridOffsetY + '&' +
            'topRight=' + topRightX + topRightY + '&' +
            'bottomLeft=' + bottomLeftX + bottomLeftY + '&' +
            'bottomRight=' + bottomRightX + bottomRightY;
    
    //alert("/gi-tool-files/opportunities.php?" + query);   
    
        
    $("#oppList").load("/gi-tool-files/opportunities.php?" + query,displayMarkerToggle);

   
  }
}

function displayMarkerToggle(){
  if($("#oppList").html() != '' && zoomLevel > 2){
    $("#markerToggle").css("display","block");
    $("img").pngfix();
  } else {
    $("#markerToggle").css("display","none");
  }
}

function addMarkers(){
  //updateGridRefRange();
  //getOpportunities();
  
  sMarkers = "";
  
  
  var links = $("#oppList li");
  
  var i = 0;
  
  links.each(
    function(){
      //alert($(this).attr("class"));
      i++;
      addMarker($(this).attr("class"), i, $(this).find("a")[0].href);
    }
  );
  
  $("#markerToggle").html('Hide Markers');

}

function hideMarkers(){
    $("#markerPlaceholder").html("");
    $("#markerToggle").html('Show Opportunity markers');
}

function addMarker(ref, i, href){
  var gridRef = ref.substring(9, 16);
  var gridRefEastings = gridRef.substring(0,3);
  var gridRefNorthings = gridRef.substring(3,6);
  //sStatus += gridRef + ' ' + gridRefEastings + ' ' + gridRefNorthings;
  
  // convert eastings to pixel x in context of viewer
  pixelX = ((gridRefEastings - gridOffsetX)/100) * gridSize;
  
  //sStatus += 'gridRefEastings: ' + gridRefEastings + ' - gridOffsetX: ' + gridOffsetX + ' /100= ' + ((gridRefEastings - gridOffsetX)/100);
  //sStatus += 'pixelX: ' + pixelX;
  
  pixelY = ((gridOffsetY - gridRefNorthings)/100) * gridSize;
  
  //sStatus += 'pixelY: ' + pixelY;
  
  var markerX = pixelX - (markerSize/2);
  var markerY = pixelY - (markerSize/2);
  
  sMarkers += '<div id="marker-' + href + '" class="marker" style="top:' + markerY + 'px;left:' + markerX + 'px;">' +
            '<a href="' + href + '">' +
            ' <img src="/gi-tool-files/images/marker-zoom-' + zoomLevel + '.png" alt="marker ' + ref + '"/>' +
            '</a>' +
            '</div>';
            
  $("#markerPlaceholder").html(sMarkers);
  
  $("#markerPlaceholder img").pngfix();
  
  //showMyStatus();
}

function fn_load_popup(id){
  $("#infoContent").load("/gi-tool-files/opportunity_info.php?id=" + id);
  $("#infoPopup").css("display","block");
  fn_hide_key();
}

function fn_close_popup(){
  $("#infoPopup").css("display","none");
}

function hide(element){
  $(element).css("display","none");
}

// update costants used for different scales
function updateScaleVars(){
    
    if (zoomLevel == 6){
        LeftOffset = 1024;
        TopOffset = 3072;
        gridSize = 2048;
        markerSize = 100;
    }
    
    if (zoomLevel == 5){
       LeftOffset = 512;
       TopOffset = 1536;
       gridSize = 1024;
       markerSize = 50;
    }
    
    if (zoomLevel == 4){
       LeftOffset = 256;
       TopOffset = 768;
       gridSize = 512;
       markerSize = 25;
    }
    
    if (zoomLevel == 3){
       LeftOffset = 128;
       TopOffset = 384;
       gridSize = 256;
       markerSize = 12;
    }
    
    if (zoomLevel == 2){
       LeftOffset = 64;
       TopOffset = 192;
       gridSize = 128;
    } 
    
    if (zoomLevel == 1){
       LeftOffset = 32;
       TopOffset = 96;
       gridSize = 64;
    } 
  
}

// sets vars for the grid refs of the four corners of the viewer
function updateGridRefRange(){
  sStatus = 'LeftOffSet:' + LeftOffset + ' ';
  sStatus += 'offset from top left:' + zeroOffsetX + ':' + zeroOffsetY;
  
  // grid refs of top left of viewer
  gridOffsetX = Math.round(startGridX + (zeroOffsetX/gridSize)*100);
  gridOffsetY = Math.round(startGridY - (zeroOffsetY/gridSize)*100); 

  sStatus += ' topLeft:' + gridOffsetX + ' : ' + gridOffsetY;
  
  // grid refs of top right of viewer
  topRightX = Math.round(gridOffsetX + (viewerWidth/gridSize)*100);
  topRightY = gridOffsetY;
  
  sStatus += ' topRight:' + topRightX + ' : ' + topRightY;
  
  // grid refs of bottom left of viewer
  bottomLeftX = gridOffsetX;
  bottomLeftY = Math.round(gridOffsetY - (viewerHeight/gridSize)*100);
  
  sStatus += ' bottomLeft:' + bottomLeftX + ' : ' + bottomLeftY;
  
  // grid refs of bottom right of viewer
  bottomRightX = topRightX;
  bottomRightY = bottomLeftY;
  
  sStatus += ' bottomRight:' + bottomRightX + ' : ' + bottomRightY;
  
  //getOpportunities();
  
  //showMyStatus();
}

// show secondary status div for debugging.
function showMyStatus(){
  document.getElementById("myStatus").innerHTML = sStatus;
}

function showFeedbackForm(){
  $("#feedbackForm").css("display","block");
}

function hideFeedbackForm(){
  $("#feedbackForm").css("display","none");
}


/// start GSV functions - modified by Olivewood to add hooks ///

function getEvent(event)
{
    if(event == undefined) {
        return window.event;
    }
    
    return event;
}

function prepareViewer(imageViewer, tileDir, tileSize)
{
    for(var child = imageViewer.firstChild; child; child = child.nextSibling) {
        if(child.className == 'surface') {
            imageViewer.activeSurface = child;
            child.imageViewer = imageViewer;
        
        } else if(child.className == 'well') {
            imageViewer.tileWell = child;
            child.imageViewer = imageViewer;
        
        } else if(child.className == 'status') {
            imageViewer.status = child;
            child.imageViewer = imageViewer;
        
        }
    }
    
    var width = imageViewer.offsetWidth;
    var height = imageViewer.offsetHeight;
    var zoomLevel = -1; // guaranteed at least one increment below, so start at less-than-zero
    var fullSize = tileSize * Math.pow(2, zoomLevel); // full pixel size of the image at this zoom level
    do {
        zoomLevel += 1;
        fullSize *= 2;
    } while(fullSize < Math.max(width, height));

    var center = {'x': ((fullSize - width) / -2), 'y': ((fullSize - height) / -2)}; // top-left pixel of viewer, if it were to be centered in the view window

    imageViewer.style.width = width+'px';
    imageViewer.style.height = height+'px';
    
    var top = 0;
    var left = 0;
    for(var node = imageViewer; node; node = node.offsetParent) {
        top += node.offsetTop;
        left += node.offsetLeft;
    }

    imageViewer.dimensions = {

         // width and height of the viewer in pixels
         'width': width, 'height': height,

         // position of the viewer in the document, from the upper-left corner
         'top': top, 'left': left,

         // location and height of each tile; they're always square
         'tileDir': tileDir, 'tileSize': tileSize,

         // zero or higher; big number == big image, lots of tiles
         'zoomLevel': zoomLevel,

         // initial viewer position
         // defined as window-relative x,y coordinate of upper-left hand corner of complete image
         // usually negative. constant until zoomLevel changes
         'x': center.x, 'y': center.y

         };

    imageViewer.start = {'x': 0, 'y': 0}; // this is reset each time that the mouse is pressed anew
    imageViewer.pressed = false;

    if(document.body.imageViewers == undefined) {
        document.body.imageViewers = [imageViewer];
        document.body.onmouseup = releaseViewer;

    } else {
        document.body.imageViewers.push(imageViewer);
    
    }

    prepareTiles(imageViewer);
    //updateScaleVars();
    //updateGridRefRange();
    giEvent('endPrepareView');
    $("img").pngfix();
}


function prepareTiles(imageViewer)
{
    var activeSurface = imageViewer.activeSurface;
    var tileWell = imageViewer.tileWell;
    var dim = imageViewer.dimensions;

    imageViewer.tiles = [];
    
    var rows = Math.ceil(dim.height / dim.tileSize) + 1;
    var cols = Math.ceil(dim.width / dim.tileSize) + 1;
    
    displayStatus(imageViewer, 'rows: '+rows+', cols: '+cols);
    
    for(var c = 0; c < cols; c += 1) {
        var tileCol = [];
    
        for(var r = 0; r < rows; r += 1) {

            var tile = {'c': c, 'r': r, 'img': document.createElement('img'), 'imageViewer': imageViewer};

            tile.img.className = 'tile';
            tile.img.style.width = dim.tileSize+'px';
            tile.img.style.height = dim.tileSize+'px';
            setTileImage(tile, true);
            
            tileWell.appendChild(tile.img);
            tileCol.push(tile);
        }
        
        imageViewer.tiles.push(tileCol);
    }
    
    activeSurface.onmousedown = pressViewer;
    positionTiles(imageViewer, {'x': 0, 'y': 0}); // x, y should match imageViewer.start x, y
    //giEvent('endPrepareTiles', imageViewer);
}

function positionTiles(imageViewer, mouse)
{
    var tiles = imageViewer.tiles;
    var dim = imageViewer.dimensions;
    var start = imageViewer.start;
    
    var statusTextLines = [];
    statusTextLines.push('imageViewer.dimensions x,y: '+dim.x+','+dim.y);
    


    
    for(var c = 0; c < tiles.length; c += 1) {
        for(var r = 0; r < tiles[c].length; r += 1) {

            var tile = tiles[c][r];
            
            // wrappedAround will become true if any tile has to be wrapped around
            var wrappedAround = false;
            
            tile.x = (tile.c * dim.tileSize) + dim.x + (mouse.x - start.x);
            tile.y = (tile.r * dim.tileSize) + dim.y + (mouse.y - start.y);
            
            if(tile.x > dim.width) {
                // tile is too far to the right
                // shift it to the far-left until it's within the viewer window
                do {
                    tile.c -= tiles.length;
                    tile.x = (tile.c * dim.tileSize) + dim.x + (mouse.x - start.x);
                    wrappedAround = true;

                } while(tile.x > dim.width);

            } else {
                // tile may be too far to the right
                // if it is, shift it to the far-right until it's within the viewer window
                while(tile.x < (-1 * dim.tileSize)) {
                    tile.c += tiles.length;
                    tile.x = (tile.c * dim.tileSize) + dim.x + (mouse.x - start.x);
                    wrappedAround = true;

                }
            }
            
            if(tile.y > dim.height) {
                // tile is too far down
                // shift it to the very top until it's within the viewer window
                do {
                    tile.r -= tiles[c].length;
                    tile.y = (tile.r * dim.tileSize) + dim.y + (mouse.y - start.y);
                    wrappedAround = true;

                } while(tile.y > dim.height);

            } else {
                // tile may be too far up
                // if it is, shift it to the very bottom until it's within the viewer window
                while(tile.y < (-1 * dim.tileSize)) {
                    tile.r += tiles[c].length;
                    tile.y = (tile.r * dim.tileSize) + dim.y + (mouse.y - start.y);
                    wrappedAround = true;

                }
            }

            statusTextLines.push('tile '+r+','+c+' at '+tile.c+','+tile.r);
            
            // set the tile image once to *maybe* null, then again to
            // definitely the correct tile. this removes the wraparound
            // artifacts seen over slower connections.
            setTileImage(tile, wrappedAround);
            setTileImage(tile, false);

            tile.img.style.top = tile.y+'px';
            tile.img.style.left = tile.x+'px';
        }
    }
    
    //displayStatus(imageViewer, statusTextLines.join('<br>'));
    giEvent('endPositionTiles');
}

function setTileImage(tile, nullOverride)
{
    var dim = tile.imageViewer.dimensions;

    // request a particular image slice
    var src = tileDir+'/tile-'+dim.zoomLevel+'-'+tile.c+'-'+tile.r+'.jpg';

    // has the image been scrolled too far in any particular direction?
    var left = tile.c < 0;
    var high = tile.r < 0;
    var right = tile.c >= Math.pow(2, tile.imageViewer.dimensions.zoomLevel);
    var low = tile.r >= Math.pow(2, tile.imageViewer.dimensions.zoomLevel);
    var outside = high || left || low || right;

         if(nullOverride)     { src = '/gi-tool-files/images/null/none.png';          }

    // note this "outside" clause overrides all those below
    // RH - was breaking IE6 for some reason, hence hack below
    else if(outside)          { src = tileDir+'/tile-'+dim.zoomLevel+'-'+tile.c+'-'+tile.r+'.jpg';         }

    else if(high && left)     { src = '/gi-tool-files/images/null/top-left.png';      }
    else if(low  && left)     { src = '/gi-tool-files/images/null/bottom-left.png';   }
    else if(high && right)    { src = '/gi-tool-files/images/null/top-right.png';     }
    else if(low  && right)    { src = '/gi-tool-files/images/null/bottom-right.png';  }
    else if(high)             { src = '/gi-tool-files/images/null/top.png';           }
    else if(right)            { src = '/gi-tool-files/images/null/right.png';         }
    else if(low)              { src = '/gi-tool-files/images/null/bottom.png';        }
    else if(left)             { src = '/gi-tool-files/images/null/left.png';          }

    tile.img.src = src;
}

function moveViewer(event)
{
    var imageViewer = this.imageViewer;
    var ev = getEvent(event);
    var mouse = localizeCoordinates(imageViewer, {'x': ev.clientX, 'y': ev.clientY});

    //displayStatus(imageViewer, 'mouse at: '+mouse.x+', '+mouse.y+', '+(imageViewer.tiles.length * imageViewer.tiles[0].length)+' tiles to process');
    positionTiles(imageViewer, {'x': mouse.x, 'y': mouse.y});
    
}

function localizeCoordinates(imageViewer, client)
{
    var local = {'x': client.x, 'y': client.y};

    for(var node = imageViewer; node; node = node.offsetParent) {
        local.x -= node.offsetLeft;
        local.y -= node.offsetTop;
    }
    
    return local;
}

function pressViewer(event)
{
    var imageViewer = this.imageViewer;
    var dim = imageViewer.dimensions;
    var ev = getEvent(event);
    var mouse = localizeCoordinates(imageViewer, {'x': ev.clientX, 'y': ev.clientY});

    imageViewer.pressed = true;
    imageViewer.tileWell.style.cursor = imageViewer.activeSurface.style.cursor = 'move';
    
    imageViewer.start = {'x': mouse.x, 'y': mouse.y};
    this.onmousemove = moveViewer;

    displayStatus(imageViewer, 'mouse pressed at '+mouse.x+','+mouse.y);
    
    hideMarkers();
}

function releaseViewer(event)
{
    var ev = getEvent(event);
    
    for(var i = 0; i < document.body.imageViewers.length; i += 1) {
        var imageViewer = document.body.imageViewers[i];
        var mouse = localizeCoordinates(imageViewer, {'x': ev.clientX, 'y': ev.clientY});
        var dim = imageViewer.dimensions;
        

        

        if(imageViewer.pressed) {
            imageViewer.activeSurface.onmousemove = null;
            imageViewer.tileWell.style.cursor = imageViewer.activeSurface.style.cursor = 'pointer';
            imageViewer.pressed = false;

            dim.x += (mouse.x - imageViewer.start.x);
            dim.y += (mouse.y - imageViewer.start.y);
            //alert(mouse.x + ' ' + mouse.y);
             giEvent('releaseViewer');
        }
        

        displayStatus(imageViewer, 'mouse dragged from '+imageViewer.start.x+', '+imageViewer.start.y+' to '+mouse.x+','+mouse.y+'. image: '+dim.x+','+dim.y);
    }
}

function displayStatus(imageViewer, message)
{
    imageViewer.status.innerHTML = message;
}

function dumpInfo(imageViewer)
{
    var dim = imageViewer.dimensions;
    var tiles = imageViewer.tiles;

    var statusTextLines = ['imageViewer '+(i + 1), 'current window position: '+dim.x+','+dim.y+'.', '----'];

    for(var c = 0; c < tiles.length; c += 1) {
        for(var r = 0; r < tiles[c].length; r += 1) {
            statusTextLines.push('image ('+c+','+r+') has tile ('+dim.zoomLevel+','+tiles[c][r].c+','+tiles[c][r].r+')');
        }
    }
    
    alert(statusTextLines.join("\n"));
}

function dumpAllInfo()
{
    for(var i = 0; i < document.body.imageViewers.length; i += 1) {
        dumpInfo(document.body.imageViewers[i]);
    }
}

function zoomImage(imageViewer, mouse, direction)
{
    var dim = imageViewer.dimensions;
    
    if(mouse == undefined) {
        var mouse = {'x': dim.width / 2, 'y': dim.height / 2};
    }

    var pos = {'before': {'x': 0, 'y': 0}};

    // pixel position within the image is a function of the
    // upper-left-hand corner of the viewe in the page (pos.before),
    // the click position (event), and the image position within
    // the viewer (dim).
    pos.before.x = (mouse.x - pos.before.x) - dim.x;
    pos.before.y = (mouse.y - pos.before.y) - dim.y;
    pos.before.width = pos.before.height = Math.pow(2, dim.zoomLevel) * dim.tileSize;
    
    var statusMessage = ['at current zoom level, image is '+pos.before.width+' pixels wide',
                         '...mouse position is now '+pos.before.x+','+pos.before.y+' in the full image at zoom '+dim.zoomLevel,
                         '...with the corner at '+dim.x+','+dim.y];
                         
    
    //alert(direction);
    // Rick Hurst - limit zoomlevel
    if(((dim.zoomLevel == zoomLimit) && (direction == 1)) || ((dim.zoomLevel == 2) && (direction == -1))  ){
    	//alert('going out of range');
    	statusMessage.push('zoom range limit reached');
    	
   
    	
    	
    } else {

		if(dim.zoomLevel + direction >= 0) {
			pos.after = {'width': (pos.before.width * Math.pow(2, direction)), 'height': (pos.before.height * Math.pow(2, direction))};
			statusMessage.push('at zoom level '+(dim.zoomLevel + direction)+', image is '+pos.after.width+' pixels wide');
	
			pos.after.x = pos.before.x * Math.pow(2, direction);
			pos.after.y = pos.before.y * Math.pow(2, direction);
			statusMessage.push('...so the current mouse position would be '+pos.after.x+','+pos.after.y);
	
			pos.after.left = mouse.x - pos.after.x;
			pos.after.top = mouse.y - pos.after.y;
			statusMessage.push('...with the corner at '+pos.after.left+','+pos.after.top);
			
			dim.x = pos.after.left;
			dim.y = pos.after.top;
			dim.zoomLevel += direction;
			
			imageViewer.start = mouse;
			positionTiles(imageViewer, mouse);
		}
    
    }


    //displayStatus(imageViewer, statusMessage.join('<br>'));
}

function zoomImageUp(imageViewer, mouse)
{
    zoomImage(imageViewer, mouse, 1);
}

function zoomImageDown(imageViewer, mouse)
{
    zoomImage(imageViewer, mouse, -1);
}

