//<![CDATA[
//Raj Kaimal
//Simple implementation of a zoom area for Google Maps
//http://weblogs.asp.net/rajbk/
//Free source code!

var mapx1, mapx2, mapy1, mapy2, maparea;
var zoomx1, zoomy1, zoomx2, zoomx2, zoomarea;
var mapwidth, mapheight;
var mousex, mousey;
var zoomLayer;
var startTracking = false;
var gpstart, gpend;
var multiplier;

var ZOOMAREA_KEYCODE = 90; // shift+'z' key zooms an area when the mouse is moved (not dragged).

var zoomLevelAreas = new Array(
 0.000044782205316291115,
 0.00017912880077214252,
 0.0007165152014842625,
 0.0028660594751396392,
 0.01146422704873143,
 0.04585681809304249,
 0.18342716717851734,
 0.7337069855714002,
 2.9348010091822907,
 11.738430973389503,
 46.94408531995497,
 187.64344725577126,
 748.5823131256056,
 2961.473356669126,
 11242.849261491675,
 36095.54334444813,
 86649.85238489839,
 177134.48041308092
);

function getObjectTop(refobj) {
 var y = refobj.offsetTop;
 var obj = refobj.offsetParent;
  while (obj != null) {
    y += obj.offsetTop;
    obj = obj.offsetParent;
  }
 return y;
}

function getObjectLeft(refobj) {
 var x = refobj.offsetLeft;
 var obj = refobj.offsetParent;
  while (obj != null) {
    x += obj.offsetLeft;
    obj = obj.offsetParent;
  }
 return x;
}

function xInBounds(x) {
 if ((x < mapx2) && (x > mapx1))
  return true;
 return false;
}

function yInBounds(y) {
 if ((y < mapy2) && (y > mapy1))
  return true;
 return false;
}

//simple method to get next zoomlevel
//could be made smarter - binary search with closest match?
function getNextZoomLevel(maparea) {
 var i = 0;
 while (zoomLevelAreas[i] < maparea)
  i++;
  
 return i;
}

function getLatLonFromPixel(x, y) {
 var origin =  map.getCurrentMapType().getBitmapCoordinate(map.getBoundsLatLng().maxY, map.getBoundsLatLng().minX, map.getZoomLevel());
 return map.getCurrentMapType().getLatLng(origin.x + x, origin.y + y, map.getZoomLevel()); 
}

function setValidZoomArea(e) {
 mousex = e.clientX;
 mousey = e.clientY;

 if (mousex > mapx2) mousex = mapx2; 
 if (mousex < mapx1) mousex = mapx1;
 if (mousey < mapy1) mousey = mapy1;
 if (mousey > mapy2) mousey = mapy2;
}

function mouseMoveHandler(e){
 if (!e) e = window.event;

 mousex = e.clientX;
 mousey = e.clientY;

 setValidZoomArea(e)

 if (!startTracking)
  return;

 w = parseFloat(mousex) - parseFloat(zoomx1);
 h = parseFloat(mousey) - parseFloat(zoomy1);
 
 if (w < 0) {
  w = Math.abs(w);
  zoomLayer.style.left = mousex;
 }  
 zoomLayer.style.width = w;

 if (h < 0) {
  h = Math.abs(h);
  zoomLayer.style.top = mousey;
 }
 zoomLayer.style.height = h;
}

function keyDownHandler(e){
 if (!e) var e = window.event;
 if ((startTracking == false) && (e.shiftKey) &&(e.keyCode == ZOOMAREA_KEYCODE)){
  zoomx1 = mousex;
  zoomy1 = mousey;
 if ((xInBounds(zoomx1)) && (yInBounds(zoomy1))) {
  startTracking = true;
  gpstart = getLatLonFromPixel(zoomx1 - mapx1, zoomy1 - mapy1); 
 
  zoomLayer.style.visibility = "visible";
  zoomLayer.style.left = zoomx1;
  zoomLayer.style.top = zoomy1;
  zoomLayer.style.width = 0;
  zoomLayer.style.height = 0;
  document.body.style.cursor = "crosshair";
  }
 }
}

function keyUpHandler(e){
 startTracking = false;
 if (!e) e = window.event;
 if (e.keyCode != ZOOMAREA_KEYCODE)
  return;
  
 if(typeof(gpstart) == 'undefined')
  return;
 
 zoomLayer.style.visibility = "hidden";
 document.body.style.cursor = "default";
 zoomx2 = mousex;
 zoomy2 = mousey;
 gpend = getLatLonFromPixel(mousex - mapx1, mousey - mapy1); 
 zoomarea = Math.abs((gpend.x - gpstart.x) * (gpend.y - gpstart.y));
 
 if (zoomarea == 0)
  return;
 
 centerx = ((gpend.x + gpstart.x)/2);
 centery = ((gpend.y + gpstart.y)/2);
 
 var zoomLevel = getNextZoomLevel(zoomarea);
 
 if (zoomLevel < 0)
  zoomLevel = 0;
 map.centerAndZoom(new GPoint(centerx, centery), zoomLevel);
}

function initCoords() {
 var mapElement = document.getElementById("map");
 zoomLayer = document.getElementById("ZoomLayer");
 zoomLayer.style.visibility = "hidden";
 mapx1 = getObjectLeft(mapElement);
 mapy1 = getObjectTop(mapElement);
 mapwidth = parseFloat(mapElement.style.width);
 mapheight = parseFloat(mapElement.style.height);
 mapx2 = mapx1 + mapwidth;
 mapy2 = mapy1 + mapheight;
 maparea = mapwidth * mapheight;
}

// Below code supports mouse wheel zoom
// From Joaquin Cuenca Abela
// Hook the mouse wheel to zoom the map on Mozilla and Internet Explorer 6.0 browsers 

function exO(a){return Math.round(a)+"px"} 

GMap.prototype.applyZoom = function(a) 
{ 
        var b = this; 
        var c = Math.floor(Math.log(b.viewSize.width) * Math.LOG2E - 2); 
        var d = b.zoomLevel - a; 
        if (d > c) 
        { 
                d = c; 
        } 
        else if (d < -c) 
        { 
                d = -c; 
        } 


        var e = Math.pow(2, d); 
        b.div.style.zoom = e; 
        var f = b.viewSize.width * b.centerScreen.x; 
        var h = b.viewSize.height * b.centerScreen.y; 
        b.div.style.left = exO((this._savedOffset.x - f) * e + f); 
        b.div.style.top = exO((this._savedOffset.y - h) * e + h); 



} 

GMap.prototype.smoothZoomTo = function(newZoom) 
{ 
        var a = this; 

        if (a.div.style.zoom == undefined) 
        { 
                a.zoomTo(newZoom); 
                return; 
        } 


        a._currentZoom = parseInt(a.getZoomLevel()); 
        a._targetZoom = newZoom; 
        a._savedOffset={"x" : a.div.offsetLeft, "y" : a.div.offsetTop}; 
        a.hideOverlays(); 


        this._zoomInterval = setInterval(function() { 
                a._currentZoom += 0.3 * (a._targetZoom - a._currentZoom); 


                if (Math.abs(a._targetZoom - a._currentZoom) < 0.05) 
                { 
                        if (a._savedOffset) 
                        { 
                                a.div.style.left=exO(a._savedOffset.x); 
                                a.div.style.top=exO(a._savedOffset.y); 
                        } 
                        a.div.style.zoom = 1; 
                        a.showOverlays(); 
                        a.zoomTo(a._targetZoom); 
                        a._savedOffset = null; 
                        window.clearInterval(a._zoomInterval); 
                } 
                else 
                { 
                        a.applyZoom(a._currentZoom); 
                } 
        }, 50); 



} 


function zoom(oEvent, scr) 
{ 
        var new_zoom = map.getZoomLevel(); 
        if (scr >= 120) 
                new_zoom--; 
        else 
                new_zoom++; 

        map.smoothZoomTo(new_zoom); 
        if (oEvent.preventDefault) 
                oEvent.preventDefault(); 


} 

function hookMouseWheelHandlers(id) 
	{ 
        var d = document.getElementById(id); 
        if (d) 
        { 
                try 
                { 
                        if (document.body.addEventListener) 
                                d.addEventListener('DOMMouseScroll', function(oEvent) { 
				zoom(oEvent, oEvent.detail * -40); }, false); 
                        else 
                                d.onmousewheel = function() { zoom(event, event.wheelDelta); return false; } 
                } 
		catch (ex) {} 
        } 
} 

