  function Point( x, y ) {
    this.x = x;
    this.y = y;
    this.toString = Function( "return \"[\" + this.x + \",\" + this.y + \"]\"" );
  }

  var oldScroll = new Point( -1, -1 );
  var mapOffset = new Point( 0, 0 );
  var downPoint = new Point( -1, -1 );
  
  function normalizeBox( p1, p2 ) {
    var upLeft = new Point( Math.min( p1.x, p2.x ), Math.min( p1.y, p2.y ) );
    var downRight = new Point( Math.max( p1.x, p2.x ), Math.max( p1.y, p2.y ) );
    
    p1.x = upLeft.x;
    p1.y = upLeft.y;
    p2.x = downRight.x;
    p2.y = downRight.y;
  }
  
  function boxCommand( p1, p2 ) {
    var upLeft = p1;
    var downRight = p2;
    normalizeBox( upLeft, downRight );
  
    with( document.mapCommand ) {
      clickX.value = upLeft.x;
      clickY.value = upLeft.y;
      coordX.value = downRight.x;
      coordY.value = downRight.y;
      
      submit();
    }
    
    return false;
  }

  function calcMapOffsets() {
    var obj;
    obj = document.mapImage;
    
    if( oldScroll.x == document.body.scrollLeft && oldScroll.y == document.body.scrollTop ) {
      return;
    }
    
    oldScroll.x = document.body.scrollLeft;
    oldScroll.y = document.body.scrollTop;
    
    mapOffset.x = -document.body.scrollLeft - document.body.clientLeft;
    mapOffset.y = -document.body.scrollTop - document.body.clientTop;
    
    do {
      mapOffset.x += obj.offsetLeft + obj.clientLeft;
      mapOffset.y += obj.offsetTop + obj.clientTop;
      obj = obj.offsetParent;
    } while( obj );
  }

  function inMap( clientPoint ) {
    var mapPoint = toMapPoint( clientPoint );
    
    return mapPoint.x >= 0 && mapPoint.x < document.mapImage.width && mapPoint.y >= 0 && mapPoint.y < document.mapImage.height;
  }
  
  function toMapPoint( clientPoint ) {
    calcMapOffsets();
    
    return new Point( clientPoint.x - mapOffset.x, clientPoint.y - mapOffset.y );
  }
  
  function fromMapPoint( mapPoint ) {
    calcMapOffsets();
    
    return new Point( mapPoint.x + mapOffset.x + document.body.scrollLeft, mapPoint.y + mapOffset.y + document.body.scrollTop );
  }
  
  function clipToMap( mapPoint ) {
    if( mapPoint.x < 0 ) {
      mapPoint.x = 0;
    } else if( mapPoint.x >= document.mapImage.width ) {
      mapPoint.x = document.mapImage.width - 1;
    }
    
    if( mapPoint.y < 0 ) {
      mapPoint.y = 0;
    } else if( mapPoint.y >= document.mapImage.height ) {
      mapPoint.y = document.mapImage.height - 1;
    }
    
    return mapPoint;
  }
  
  function setBoxVisible( visible ) {
    var visStyle = (visible) ? "visible" : "hidden";
    
    document.all.box_top.style.visibility = visStyle;
    document.all.box_left.style.visibility = visStyle;
    document.all.box_right.style.visibility = visStyle;
    document.all.box_bottom.style.visibility = visStyle;
  }
  
  function setBoxPosition( mapUpLeft, mapDownRight ) {
    var clientUpLeft = fromMapPoint( mapUpLeft );
    var clientDownRight = fromMapPoint( mapDownRight );
    
    normalizeBox( clientUpLeft, clientDownRight );
    
    document.all.box_top.style.pixelLeft = clientUpLeft.x;
    document.all.box_top.style.pixelTop = clientUpLeft.y;
    document.all.box_top.style.pixelWidth = clientDownRight.x - clientUpLeft.x;
    document.all.box_left.style.pixelLeft = clientUpLeft.x;
    document.all.box_left.style.pixelTop = clientUpLeft.y;
    document.all.box_left.style.pixelHeight = Math.max( 1, clientDownRight.y - clientUpLeft.y );
    document.all.box_right.style.pixelLeft = clientDownRight.x;
    document.all.box_right.style.pixelTop = clientUpLeft.y;
    document.all.box_right.style.pixelHeight = Math.max( 1, clientDownRight.y - clientUpLeft.y );
    document.all.box_bottom.style.pixelLeft = clientUpLeft.x;
    document.all.box_bottom.style.pixelTop = clientDownRight.y;
    document.all.box_bottom.style.pixelWidth = clientDownRight.x - clientUpLeft.x;
  }
  
  function mouseDown( clientX, clientY ) {
    if( document.mapCommand.command.value != "zoomin" && document.mapCommand.command.value != "identify" ) {
      return;
    }
  
    var clientPoint = new Point( clientX - 2, clientY - 2 );
    
    if( !inMap( clientPoint ) ) {
      return;
    }

    downPoint = toMapPoint( clientPoint );
    
    setBoxPosition( downPoint, downPoint );
    setBoxVisible( true );
  }
  
  function mouseMove( clientX, clientY ) {
    if( downPoint.x < 0 || downPoint.y < 0 ) {
      return;
    }
    
    var mapPoint = clipToMap( toMapPoint( new Point( clientX - 2, clientY - 2 ) ) );
      
    setBoxPosition( downPoint, mapPoint );
  }

  function mouseUp( clientX, clientY ) {
    var clientPoint = new Point( clientX - 2, clientY - 2 );
    var mapPoint = clipToMap( toMapPoint( clientPoint ) );
    
    if( document.mapCommand.command.value != "zoomin" && document.mapCommand.command.value != "identify" ) {
      if( !inMap( clientPoint ) ) {
        return;
      }
      
      mapClick( mapPoint.x, mapPoint.y );
      if( document.mapCommand.command.value != "getcoord" ) {
        document.mapImage.style.cursor = "wait";
      }
      return;          
    }
    
    if( downPoint.x < 0 || downPoint.y < 0 ) {
      return;
    }
    
    if( Math.abs( mapPoint.x - downPoint.x ) <= 3 && Math.abs( mapPoint.y - downPoint.y ) <= 3 ) {
      boxCommand( downPoint, downPoint );
    } else {
      boxCommand( downPoint, mapPoint );
    }
    
    downPoint = new Point( -1, -1 );
    document.mapImage.style.cursor = "wait";
  }
