/*********************************************************************************
 Copyright (c) 2002-2003 Armin Burger
 
 Permission is hereby granted, free of charge, to any person obtaining 
 a copy of this software and associated documentation files (the "Software"), 
 to deal in the Software without restriction, including without limitation 
 the rights to use, copy, modify, merge, publish, distribute, sublicense, 
 and/or sell copies of the Software, and to permit persons to whom the Software 
 is furnished to do so, subject to the following conditions:
 
 The above copyright notice and this permission notice shall be included 
 in all copies or substantial portions of the Software.
 
 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 
 FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHOR OR 
 COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 
 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 
 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
**********************************************************************************/

// ================== FUNCTIONS FOR ZOOM AND PAN  =====================//
// will only work with modern browsers, NOT with 4.x versions          //
// Successfully tested with Mozilla 1.0+, Firefox, IE 5.5+, Opera 6+, Konqueror 3//

  
/*
 * GLOBAL VARIABLES
 ******************************************************/
var mouseDrag = false;    // TRUE when mouse is pressed
var maction;

var rightMouseButton = false;

var downX, downY;
var upX, upY;
var moveX, moveY;

//var offsX = 0; 	// horizontal image offset
//var offsY = 0;    // vertical image offset

var rBoxMinW = 8;   // Minimal width until to show refBox; below threshold switches to refCross
var rOffs = 13;     // Offset of refCross Image, adapt to Image size and refbox border

if (document.all) {
    var zBorder = 0;
} else {
    var zBorder = 4;
}

var refmapClick = false;
var mapcL, mapcT, mapcL, mapcR;
var mapElem; 

var isIE = (document.all) ? true : false;

var iquery_timer;



/*
 * DEFINE MOUSE ACTIONS, CALLED AS 'ONLOAD' SCRIPT
 ******************************************************/
// FOR MOUSE OVER MAP
function startUp() {
    refmapClick = false;
    
    // ENABLES ACTIONS FOR KEYBOARD KEYS
    // comment out if not wanted
    if (document.all) document.onkeydown = kp;
    document.onkeypress = kp;
    
    mapElem = $('map');
    if (mapElem) {
        mapElem.onmousedown = doMouseDown; 
        mapElem.onmouseup   = doMouseUp;
        mapElem.onmousemove = doMouseMove; 
                
        // ENABLES ACTIONS FOR MOUSE WHEEL
        if (isIE) {
            mapElem.onmousewheel = omw;
        } else {
            mapElem.addEventListener('DOMMouseScroll', omw, false);
        }
        mapElem.oncontextmenu = disableContextMenu;
        
        setCursorMinMax('map');
        //scaleMouseOut();
    }
    
}



// FOR MOUSE OVER REFERENCE MAP
function startUpRef() {
    clearTimeout(iquery_timer);  // necessary for iquery mode
    refmapClick = true;
    refElem = $('refmap');
    if (refElem) {
        refElem.onmousedown = doMouseDown; 
        refElem.onmouseup   = doMouseUp;
        refElem.onmousemove = doMouseMove;   
    
        // ENABLES ACTIONS FOR MOUSE WHEEL ON MAP
        if (isIE) {
            refElem.onmousewheel = omw;
        } else {
            refElem.addEventListener('DOMMouseScroll', omw, false);
        }
        
        setCursorMinMax('refmap');
    }
}


// MIN AND MAX VALUES FOR MOUSE
function setCursorMinMax(elem) {
    // MAP
    if (elem == 'map') {
        mapcL = rawLeft('mapFrame') + rawLeft('map');
        mapcT = rawTop('mapFrame') + rawTop('map');
        mapcR = mapcL + mapW;
        mapcB = mapcT + mapH;
    // REFERENCE MAP
    } else {
        mapcL = rawLeft('refmap');
        mapcT = rawTop('refmap');
        mapcR = mapcL + refW;
        mapcB = mapcT + refH;
    }
    
    offsX = mapcL + 1; 		// horizontal image offset
    offsY = mapcT + 1; 
}


function checkCursorPosition(cX, cY) {
    if (cX >= mapcL && cX <= mapcR && cY >= mapcT && cY <= mapcB) {
        return true;
    } else {
        return false;
    }
}



/*
 * FUNCTIONS TO GET MOUSE POSITIONS
 ******************************************************/
// For MouseDown
function getDownXY(e) {
    if (document.all) {
		eX = event.clientX;
        eY = event.clientY;
	} else {
		eX = e.pageX;
		eY = e.pageY;
	}
	// subtract offsets
        
    downX = eX - offsX;
    downY = eY - offsY;
    
    mapElem.onmouseup   = doMouseUp;
    mapElem.onmousemove = doMouseMove;
    mapElem.ondblclick  = doMouseDblClick;  // used for measure area, comment out if area measurement not wanted

    //alert (downX + ' - ' + downY);

    return false;	
}


// For MouseUp
function getUpXY(e) {
    if (document.all) {
        eX = event.clientX;
        eY = event.clientY;
    } else {
        eX = e.pageX;
        eY = e.pageY;
    }
    // subtract offsets from left and top and don't go outside of map
    
    if (!refmapClick) {
        upX = Math.min(eX - offsX, mapW);
        upY = Math.min(eY - offsY, mapH);
    } else {
        upX = eX - offsX;
        upY = eY - offsY;
    }

    return false;
}


// For MouseMove
function getMoveXY(e) {
    if (document.all) {
        moveX = event.clientX;
        moveY = event.clientY;
    } else {
        moveX = e.pageX;
        moveY = e.pageY;
    }
    // subtract offsets from left and top
    /*moveX = Math.min(moveX - offsX, mapW);
    moveY = Math.min(moveY - offsY, mapH); */
    moveX = moveX - offsX;
    moveY = moveY - offsY;             
}


/*
 * BASIC MOUSE FUNCTIONS: DOWN, UP, MOVE
 ******************************************************/

function doMouseDown(e) {
    e = (e)?e:((event)?event:null);
    
    if (enableRightMousePan) {
        if (e.button == 2) {
            rightMouseButton = true;
            setCursor(true);
        } else {
            rightMouseButton = false;
        }
    }

    // ENABLES ACTIONS FOR KEYBOARD KEYS
    // comment out if not wanted
    if (document.all) document.onkeydown = kp;
    document.onkeypress = kp;
    
    mouseDrag = true;
    getDownXY(e);
    
    if (refmapClick) {
        if (downX < 1 || downY < 1 || downX > refW || downY > refH) {        // Don't go ouside of map
            return false;
        } else {
            moveRefBox('shift');
        }
    }

    return false;
}


function doMouseUp(e) {
    e = (e)?e:((event)?event:null);
    //alert (rightMouseButton);
    
    mouseDrag = false;
    getUpXY(e);

    var varform = $("varform");

    // Click in main map
    if (!refmapClick) {

        maction = varform.maction.value;

        if (rightMouseButton) {
            maction = 'pan';
        }
        
        if (maction == 'measure') {
            //alert(upX + ' - ' + upY);
            measureDrawSymbols(e, upX, upY, 0);

        } else if (maction == 'pan'){
            var diffX = upX - downX;
            var diffY = upY - downY;
            // pan with click
            if (diffX == 0 && diffY == 0) {
                var newX = upX;
                var newY = upY;
            // pan with drag
            } else {
                var newX = (mapW / 2) - diffX ;
                var newY = (mapH / 2) - diffY;
            }
            
            zoombox_apply(newX, newY, newX, newY);
            
            //Reset after right-mouse pan
            maction = varform.maction.value;
            rightMouseButton = false;
        
        } else if (maction == 'click'){
            zoombox_apply(downX, downY, downX, downY);
                
        } else if (maction == 'move'){
            // do nothing
            return false;

        } else {
            zoombox_apply(Math.min(downX,upX), Math.min(downY,upY), Math.max(downX,upX), Math.max(downY,upY));
        }

    // Click in reference map
    } else {
        if (upX < 1 || upY < 1 || upX > refW || upY > refH) {   // Don't go ouside of map
            return false;
        } else {
            //alert(upX +', '+ upY +', '+ upX +', '+ upY);
            zoombox_apply(upX, upY, upX, upY);
        }
    }
    
    return false;    
}


function doMouseMove(e) {
    e = (e)?e:((event)?event:null);
    
    getMoveXY(e);
    /* * Draw a zoombox when mouse is pressed and zoom-in or select function are active
       * move map layer when pan function is active
       * do nothing for all others                                                      */

    // Actions in MAIN MAP
    if (!refmapClick) {
    	var varform = $("varform");
        if (varform) {
            maction = varform.maction.value;
        }
        
        if (rightMouseButton) {
            maction = 'pan';
        }

        
        // Display coordinates of current cursor position
        displayCoordinates();        
        	
        
        switch (maction) {
            //# zoom-in, select
            case 'box':
                if (mouseDrag == true) { 
                    startZoomBox(e, moveX, moveY);
                } else if (varform.mode.value == 'nquery') {
                    try {
                        if (combinedSelectIquery) {
                            clearTimeout(iquery_timer);
                            iquery_timer = setTimeout("applyIquery(" + moveX + "," + moveY + ")", 300);
                        }
                    } catch(e) {
                        return false;
                    }
                }
                break;
    
            //# zoom-out, identify
            case 'click':
                hideLayer('zoombox');
                break;
    
            //# pan with drag
            case 'pan':
                hideLayer('zoombox');
                startPan(e, moveX, moveY);
                break;
    
            //# measure
            case 'measure':
                showLayer('measureLayer');
                redrawAll(moveX , moveY);                
                break;
                
            //# move
            case 'move':
                if (varform.mode.value == 'iquery') {    //# iquery
                    clearTimeout(iquery_timer);
                    iquery_timer = setTimeout("applyIquery(" + moveX + "," + moveY + ")", 300);
                }
                break;
        }
        
    // Actions in REFERENCE MAP
    } else {
        hideLayer('zoombox');
        if (mouseDrag) {
            moveRefBox('move');
        }
    }
    
    return false;    
}


// For DOUBLE CLICK 
// currently only used for measure function: end measure, calculate polygon area
function doMouseDblClick(e) {
    getUpXY(e);
    var varform = $("varform");
    maction = varform.maction.value;
    if (maction == 'measure') {
        measureDrawSymbols(e, upX, upY, 1);
    }
}  




/*
 * FUNCTIONS FOR ZOOM BOX && PAN MOVING MAP
 ******************************************************/

// DRAG ZOOM BOX (ZOOM IN, SELECT)
function startZoomBox(e, moveX, moveY) {
    if (mouseDrag == true) {
        if (checkCursorPosition(moveX + offsX, moveY + offsY)) {
            showLayer('zoombox');
            var boxL = Math.min(moveX, downX);
            var boxT = Math.min(moveY, downY);
            var boxW = Math.abs(moveX - downX);
            var boxH = Math.abs(moveY - downY);

            var theZoomBox = $("zoombox");            
            theZoomBox.style.left   = boxL+"px";
            theZoomBox.style.top    = boxT+"px";
            theZoomBox.style.width  = boxW+"px";
            theZoomBox.style.height = boxH+"px";
        }
    }
    return false;
}

// PAN
function startPan(e, moveX, moveY) {
    if (mouseDrag == true) {
        
        if (checkCursorPosition(moveX + offsX, moveY + offsY)) {
            var mapL = moveX - downX;
            var mapT = moveY - downY;
    
            var theMapImg = $("mapimg");
            var theMapImgL = $("mapimgLayer");
            
            var clipT = 0;
            var clipR = mapW;
            var clipB = mapH;
            var clipL = 0;
            
            theMapImgL.style.top  = mapT+"px";
            theMapImgL.style.left = mapL+"px";
            
            if (mapT > 0) {
                clipB = mapH - parseInt(theMapImgL.style.top);
            } else {
                clipT = -1 * parseInt(theMapImgL.style.top);     
            }
            
            if (mapL > 0) {
                clipR = mapW - parseInt(theMapImgL.style.left);
            } else {
                clipL = -1 * parseInt(theMapImgL.style.left);
            }
            
    
            var clipRect = 'rect(' + clipT + 'px ' 
                                   + clipR + 'px '
                                   + clipB + 'px ' 
                                   + clipL + 'px)'; 
            //window.status = clipRect;
            theMapImgL.style.clip = clipRect;

        }
    }
    return false;
}


/*
 * FUNCTIONS FOR REFERENCE MAP RECTANGLE
 ******************************************************/
function setRefBox(boxL, boxT, boxW, boxH) {
    //showLayer('refbox');
    var rBox   = $("refbox");
    var sBox   = $("sliderbox");
    var rCross = $("refcross");
    
    if (rBox) {
        rBox.style.left   = boxL+"px";
        rBox.style.top    = boxT+"px";
        rBox.style.width  = boxW+"px"; //Math.max(4, boxW);
        rBox.style.height = boxH+"px"; //Math.max(4, boxH);
    }
    
    if (rCross) {
        if (boxW < rBoxMinW) {
            rBox.style.visibility = "hidden";
            rCross.style.visibility = "visible";
            setRefCross(rCross, boxL, boxT, boxW, boxH);
        } else {
            rCross.style.visibility = "hidden";
            rBox.style.visibility = "visible";
        }
    }
    
    if (sBox) {
        sBox.style.visibility = "hidden";
    }
}

// MOVE RECTANGLE WITH MOUSE PAN
function moveRefBox(moveAction) {
    var rBox   = $("refbox");
    var rCross = $("refcross");

    var boxL = parseInt(rBox.style.left);
    var boxT = parseInt(rBox.style.top);
    var boxW = parseInt(rBox.style.width);
    var boxH = parseInt(rBox.style.height);
    
    if (moveAction == 'shift') {
        var newX = downX; 
        var newY = downY;        
    } else {
        var newX = moveX; 
        var newY = moveY; 
    }
    
    boxLnew = newX - (boxW / 2) - 1; 
    boxTnew = newY - (boxH / 2) - 1;
    
    if (boxLnew < 0 || boxTnew < 0 || (boxLnew + boxW) > refW || (boxTnew + boxH) > refH) {
        return false;
    } else {
        rBox.style.left = boxLnew+"px";
        rBox.style.top  = boxTnew+"px";
        window.status = (boxLnew + boxW + ' - ' + refW);
        
        if (boxW < rBoxMinW) {
            setRefCross(rCross, boxLnew, boxTnew, boxW, boxH);
        }
    }
}


// Change position of reference cross
// => symbol used when refbox below threshold
function setRefCross(rCross, boxL, boxT, boxW, boxH) {	
    boxcX = parseInt(boxL) + parseInt((boxW / 2));
    boxcY = parseInt(boxT) + parseInt((boxH / 2));
    rCross.style.left = Math.round((boxcX - rOffs))+"px";
    rCross.style.top  = Math.round((boxcY - rOffs))+"px";    
}



// SET DIV LAYER VISIBLE - HIDDEN
function showLayer(elementID) {
    $(elementID).style.visibility = "visible";
}

function hideLayer(elementID) {
    $(elementID).style.visibility = "hidden";
}



/*******************************************************************
 * Resize map image while zooming with slider
 * called from sliderMove() in slider.js
 ********************************************/
function resizeMap(sizeFactor) {
    //alert(sizeFactor);
    var theMapImg = $('mapImg');
    var theMapLay = $('mapimgLayer');
    
    var oldW = mapW;
    var oldH = mapH;
    var newW = oldW * sizeFactor;
    var newH = oldH * sizeFactor;
    
    var newLeft = (oldW - newW) / 2;
    var newTop  = (oldH - newH) / 2;

    theMapImg.style.width  = newW+"px";
    theMapImg.style.height = newH+"px";
    theMapLay.style.left   = newLeft+"px"; 
    theMapLay.style.top    = newTop+"px";
    
    if (sizeFactor > 1) {
        var diffW = parseInt((newW - oldW) / 2);
        var diffH = parseInt((newH - oldH) / 2);
        clipT = diffH;
        clipR = diffW + oldW;
        clipB = diffH + oldH;
        clipL = diffW;

        var clipRect = 'rect(' + clipT + 'px ' 
                               + clipR + 'px '
                               + clipB + 'px ' 
                               + clipL + 'px)'; 
        //window.status = clipRect;
        theMapLay.style.clip = clipRect;
        
        theMapLay.style.width   = newW+"px";
        theMapLay.style.height  = newH+"px";
    } 
}


function resizeRefBox(sizeFactor) { 
    var refZoomBox = $('refbox');
    var refSliderBox = $('refsliderbox');
    
    if (refSliderBox) {
        refSliderBox.style.visibility = "visible";
    }
    
    if (refZoomBox) {
        var refBoxBorderW = 1;  // adapt to border width in CSS

        var oldRefW = parseInt(refZoomBox.style.width);
        var oldRefH = parseInt(refZoomBox.style.height);
        var oldRefLeft = parseInt(refZoomBox.style.left);
        var oldRefTop = parseInt(refZoomBox.style.top);
        
        var newRefW = Math.round(oldRefW / sizeFactor);
        var newRefH = Math.round(oldRefH / sizeFactor);
        
        var newRefLeft = parseInt(oldRefLeft + ((oldRefW - newRefW) / 2) + refBoxBorderW);
        var newRefTop  = parseInt(oldRefTop + ((oldRefH - newRefH) / 2) + refBoxBorderW);
        
        refSliderBox.style.left   = newRefLeft+"px";
        refSliderBox.style.top    = newRefTop+"px";
        refSliderBox.style.width  = newRefW+"px";
        refSliderBox.style.height = newRefH+"px";
    }
}



/*
 * KEYBOARD FUNCTIONS
 * original script taken from http://ka-map.maptools.org/
 ******************************************************************/
function kp(e) {
    e = (e)?e:((event)?event:null);
    if(e) {
        var charCode=(e.charCode)?e.charCode:e.keyCode;
        //alert(charCode);
        var b=true;
        var nStep = 16;
        switch(charCode){
          case 63232://safari up arrow
          case 38://up arrow
            arrowpan('n');
            break;
          case 63233://safari down arrow
          case 40://down arrow
            arrowpan('s');
            break;
          case 63234://safari left arrow
          case 37:// left arrow
            arrowpan('w');
            break;
          case 63235://safari right arrow
          case 39://right arrow
            arrowpan('e');
            break;
          case 63276://safari pageup
          case 33://pageup
            gofwd();
            break;
          case 63277://safari pagedown
          case 34://pagedown
            goback();
            break;
          case 63273://safari home (left)
          case 36://home
            zoomfullext();
            break;
          case 63275://safari end (right)
          case 35://end
            slideBy(-viewportWidth/2,0);
            break;
          case 43:
            //if (!navigator.userAgent.match(/Opera|Konqueror/i))  
            zoompoint(2, '');
            break;
         case 45:
            zoompoint(-2, '');
            break;
          default:
            b=false;
        }
    }
}



/*
 * MOUSEWHEEL FUNCTIONS (zoom in/out)
 * only works with IE
 ******************************************************************/
function omw(e) {
    e = (e)?e:((event)?event:null);
    if(e) {
        var wD = e.wheelDelta ? e.wheelDelta : e.detail*-1;
        clearTimeout(resize_timer);
        if (wD < 0) {
            //zoompoint(2, '');
            resize_timer = setTimeout("zoompoint(2, '')",300);  
            return false;
        } else if (wD > 0) {
            //zoompoint(-2, '');
            resize_timer = setTimeout("zoompoint(-2, '')",300);  
            return false;
        }
    }
}



function disableContextMenu(e) {
    e = (e)?e:((event)?event:null);
    return false;
}




/* 
 * FUNCTIONS FOR COODINATE DIPLAY FUNCTIONS
 ***********************************************/
// GET MAP COORDINATES FOR MOUSE MOVE
function getCoords(mouseX, mouseY, convert2latlon) {
    var x_geo = minx_geo + ((mouseX/mapW) * xdelta_geo);
    var y_geo = maxy_geo - ((mouseY/mapH) * ydelta_geo);
    
    if (convert2latlon) {
        // Just for ETRS-LAEA projection: convert from LAEA to latlon coordinates
        var mpoint = laea2latlon(x_geo, y_geo);
    
    } else {
        // Display mouse position in MAP coordinates 
        var mpoint = new Object();
        mpoint.x = x_geo;
        mpoint.y = y_geo;
    }
    
    return  mpoint;
}




// DISPLAY MAP COORDINATES FOR MOUSE MOVE
function displayCoordinates() {
    var mpoint = getCoords(moveX, moveY, false);
    //var mpoint = getCoords(moveX, moveY, true);
    
    // Round values (function 'roundN()' in 'measure.js')
    var rfactor = 0;
    var px = isNaN(mpoint.x) ? '' : roundN(mpoint.x, rfactor);
    var py = isNaN(mpoint.y) ? '' : roundN(mpoint.y, rfactor);
    
    // Display in status bar
    /*
    var mapCoords = 'X: ' + px + '  Y: ' + py;
    window.status = mapCoords;
    */
    
    // Display in DIV over MAP 
    $('xcoord').innerHTML = 'X: ' + px; // + ' &deg;';
    $('ycoord').innerHTML = 'Y: ' + py; // + ' &deg;';
}



// Convert XY coordinates from ETRS-LAEA to lat/lon
function laea2latlon(X, Y) {
    var a   = 6378137;
    var f   = 1 / 298.257222101;
    var e2  = (2*f) - (f*f);
    var e   = Math.sqrt(e2);
    var ph0 = 52 / 180 * Math.PI ;
    var la0 = 10 / 180 * Math.PI;
    var X0  = 4321000.0;
    var Y0  = 3210000.0;
    
    
    var q0 = (1-e2) *  ((Math.sin(ph0) / (1 - (e2 * Math.pow(Math.sin(ph0), 2)))) - ((1/(2*e)) * Math.log((1 - (e * Math.sin(ph0))) / (1 + (e * Math.sin(ph0))))));    
    
    var qp = (1-e2) *  ( (1 / (1-e2)) - ((1/(2*e)) * Math.log((1-e)/(1+e)) ) ) ;
    
    var beta0 = Math.asin(q0/qp);
    
    var Rq = a * Math.sqrt(qp/2);
    
    var D  =  (a * Math.cos(ph0)) / (Math.sqrt(1 - (e2 * Math.pow(Math.sin(ph0), 2))) * (Rq * Math.cos(beta0))  );
    
    var p = Math.sqrt(Math.pow((X-X0)/D, 2) + Math.pow(D * (Y-Y0), 2));
    
    var C = 2 * Math.asin(p / (2*Rq));
    
    var beta_ = Math.asin((Math.cos(C) * Math.sin(beta0))  +  (((D * (Y-Y0)) * Math.sin(C) * Math.cos(beta0)) / p));
    
    
    // Latitude
    var lat1 = ((e2/3) + ((31*Math.pow(e2, 2)) / 180) + ((517*Math.pow(e2, 3)) / 5040)) * Math.sin(2*beta_);
    var lat2 = (((23*Math.pow(e2, 2)) / 360) + ((251*Math.pow(e2, 3)) / 3780)) * Math.sin(4*beta_);
    var lat3 = ((761*Math.pow(e2, 3)) / 45360) * Math.sin(6*beta_);
    var lat = (beta_ + lat1 + lat2 + lat3) * (180/Math.PI);
    
    
    //Longitude
    var lon = (la0 + Math.atan( ((X-X0) * Math.sin(C)) / ((D * p * Math.cos(beta0) * Math.cos(C)) - (D*D * (Y-Y0) * Math.sin(beta0) * Math.sin(C))))) * (180/Math.PI);  
    
    
    // Return Point
    var mpoint = new Object();
    mpoint.x = lon;
    mpoint.y = lat;
    
    return mpoint;
}


