/*
* DragZoomControl Class v1.1 
*  Copyright (c) 2005-2007, Andre Lewis, andre@earthcode.com
*
* Back Button functionality
*  Copyright (c)  2007, Richard Garland, papabear.newyork@gmail.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* 
*       http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This class lets you add a control to the map which will let the user
*  zoom by dragging a rectangle.
*  More info on original GZoom at http://earthcode.com
*
* Back Button functionality provides the user with a one click means to return the map state 
*  to its state prior to the DragZoom.  Sequential DragZooms are backed out in reverse order.
*/

/**
 * Constructor for DragZoomControl, which takes 3 option hashes and
 *  uses them to customize the control.
 * @param {opts_boxStyle} Named optional arguments:
 *   opts_boxStyle.opacity {Number} Opacity from 0-1
 *   opts_boxStyle.fillColor {String} Hex value of fill color
 *   opts_boxStyle.border {String} CSS-style declaration of border
 * @param {opts_other} Named optional arguments:
 *   opts_other.buttonHTML {String} The zoom button HTML in non-activated state
 *   opts_other.buttonStartingStyle {Object} A hash of css styles for the 
 *     zoom button which are common to both un-activated and activated state
 *   opts_other.buttonStyle {Object} A hash of css styles for the zoom button 
 *     which will be applied when the button is in un-activated state.
 *   opts_other.buttonZoomingHTML {String} HTML which is placed in the 
 *     zoom button when the button is activated. 
 *   opts_other.buttonZoomingStyle {Object} A hash of css styles for the 
 *    zoom button which will be applied when the button is activated.
 *   opts_other.overlayRemoveTime {Number} The number of milliseconds to wait before
 *     removing the rectangle indicating the zoomed-in area after the zoom has happened.
 *   opts_other.stickyZoomEnabled {Boolean} Whether or not the control stays in 
 *     "zoom mode" until turned off. When true, the user can zoom repeatedly, 
 *     until clicking on the zoom button again to turn zoom mode off.
 *   opts_other.backButtonEnabled {Boolean} enables Back Button functionality
 *   opts_other.backButtonHTML {String} The back button HTML
 *   opts_other.backButtonStyle {Object} A hash of css styles for the back button
 *     which will be applied when the button is created.  
 * @param {opts_callbacks} Named optional arguments:
 *   opts_callbacks.buttonclick {Function} Called when the DragZoom is activated 
 *     by clicking on the "zoom" button. 
 *   opts_callbacks.dragstart {Function} Called when user starts to drag a rectangle.
 *     Callback args are x,y -- the PIXEL values, relative to the upper-left-hand 
 *     corner of the map, where the user began dragging.
 *   opts_callbacks.dragging {Function} Called repeatedly while the user is dragging.
 *     Callback args are startX,startY, currentX,currentY -- the PIXEL values of the 
 *     start of the drag, and the current drag point, respectively.
 *   opts_callbacks.dragend {Function} Called when the user releases the mouse button 
 *     after dragging the rectangle. Callback args are: NW {GLatLng}, NE {GLatLng}, 
 *     SE {GLatLng}, SW {GLatLng}, NW {GPoint}, NE {GPoint}, SE {GPoint}, SW {GPoint}.
 *     The first 4 are the latitudes/longitudes; the last 4 are the pixel coords on the map.
 *   opts_callbacks.backbuttonclick {Function} Called when the back button is activated 
 *     after the map context is restored. Callback args: methodCall (boolean) set true if
 *     this backbuttonclick was to restore context set by the mathod call, else false.
 * Method
 *    this.saveMapContext(text) Call to push map context onto the backStack and set the button text 
 */ 
function DragZoomControl(opts_boxStyle, opts_other, opts_callbacks) {
  // Holds all information needed globally
  // Not all globals are initialized here
  this.globals = {
    draggingOn: false,
    cornerTopDiv: null,
    cornerRightDiv: null,
    cornerBottomDiv: null,
    cornerLeftDiv: null,
    mapPosition: null,
    outlineDiv: null,
    mapWidth: 0,
    mapHeight: 0,
    mapRatio: 0,
    startX: 0,
    startY: 0,
    borderCorrection: 0
  };

  //box style options
  this.globals.style = {
    opacity: .2,
    fillColor: "#000",
    border: "2px solid blue"
  };

  var style = this.globals.style;
  for (var s in opts_boxStyle) {
    style[s]=opts_boxStyle[s];
  }

  var borderStyleArray = style.border.split(' ');
  style.outlineWidth = parseInt(borderStyleArray[0].replace(/\D/g,''));
  style.outlineColor = borderStyleArray[2];
  style.alphaIE = 'alpha(opacity=' + (style.opacity * 100) + ')';
 
  // map context stack for back button
  this.globals.backStack = [];

  // Other options
  this.globals.options={
    buttonHTML: 'zoom ...',
    buttonStartingStyle: 
      {width: '52px', border: '1px solid black', padding: '2px'},
    buttonStyle: {background: '#FFF'},
    backButtonHTML: 'zoom back',
    backButtonStyle: {background: '#FFF', display: 'none'},
    buttonZoomingHTML: 'Drag a region on the map',
    buttonZoomingStyle: {background: '#FF0'},
    overlayRemoveTime: 6000,
    backButtonEnabled: false,
    stickyZoomEnabled: false
  };
  
  for (var s in opts_other) {
    this.globals.options[s] = opts_other[s]
  }

  // callbacks: buttonclick, dragstart, dragging, dragend, backbuttonclick 
  if (opts_callbacks == null) {
    opts_callbacks = {}
  }
  this.globals.callbacks = opts_callbacks;

}

DragZoomControl.prototype = new GControl();


/**
 * Back Button functionality: 
 * Method of this object called to save the map context before the zoom.
 * @param {text} text string for the back button
 */
DragZoomControl.prototype.saveMapContext = function(text) {
  if (this.globals.options.backButtonEnabled) {
    this.saveBackContext_(text,true);
    this.globals.backButtonDiv.style.display = 'block';
  } 
};


/**
 * Creates a new button to control gzoom and appends to the button container div.
 * @param {DOM Node} buttonContainerDiv created in main .initialize code
 */
DragZoomControl.prototype.initButton_ = function(buttonContainerDiv) {
  var G = this.globals;
  var buttonDiv = document.createElement('div');
  buttonDiv.innerHTML = G.options.buttonHTML;
  buttonDiv.id = 'gzoom-control';
  DragZoomUtil.style([buttonDiv], {cursor: 'pointer', zIndex:200});
  DragZoomUtil.style([buttonDiv], G.options.buttonStartingStyle);
  DragZoomUtil.style([buttonDiv], G.options.buttonStyle);
  buttonContainerDiv.appendChild(buttonDiv);
  return buttonDiv;
};

/**                       
 * Creates a second new button to control backup zoom and appends to the button container div.
 * @param {DOM Node} buttonContainerDiv created in main .initialize code
 */
DragZoomControl.prototype.initBackButton_ = function(buttonContainerDiv) {  //**BB** entire function
  var G = this.globals;
  var backButtonDiv = document.createElement('div');
  backButtonDiv.innerHTML = G.options.backButtonHTML;
  backButtonDiv.id = 'gzoom-back';
  DragZoomUtil.style([backButtonDiv], {cursor: 'pointer', zIndex:200});
  DragZoomUtil.style([backButtonDiv], G.options.buttonStartingStyle);
  DragZoomUtil.style([backButtonDiv], G.options.backButtonStyle);
  buttonContainerDiv.appendChild(backButtonDiv);
  return backButtonDiv;
};

/**
 * Sets button mode to zooming or otherwise, changes CSS & HTML.
 * @param {String} mode Either "zooming" or not.
 */
DragZoomControl.prototype.setButtonMode_ = function(mode){
  var G = this.globals;
  if (mode == 'zooming') {
    G.buttonDiv.innerHTML = G.options.buttonZoomingHTML;
    DragZoomUtil.style([G.buttonDiv], G.options.buttonStartingStyle);
    DragZoomUtil.style([G.buttonDiv], G.options.buttonZoomingStyle);
  } else {
    G.buttonDiv.innerHTML = G.options.buttonHTML;
    DragZoomUtil.style([G.buttonDiv], G.options.buttonStartingStyle);
    DragZoomUtil.style([G.buttonDiv], G.options.buttonStyle);
  }
};

/**
 * Is called by GMap2's addOverlay method. Creates the zoom control
 * divs and appends to the map div.
 * @param {GMap2} map The map that has had this DragZoomControl added to it.
 * @return {DOM Object} Div that holds the gzoomcontrol button
 */ 
DragZoomControl.prototype.initialize = function(map) {
  var G = this.globals;
  var me = this;
  var mapDiv = map.getContainer();
 
  // Create div for both buttons  
    var buttonContainerDiv = document.createElement("div"); 
    DragZoomUtil.style([buttonContainerDiv], {cursor: 'pointer', zIndex: 150});

  // create and init the zoom button
    //DOM:button
    var buttonDiv = this.initButton_(buttonContainerDiv);

  // create and init the back button        
    //DOM:button
    var backButtonDiv = this.initBackButton_(buttonContainerDiv);
  
  // Add the two buttons to the map           
    mapDiv.appendChild(buttonContainerDiv);
 
  //DOM:map covers
    var zoomDiv = document.createElement("div");
    zoomDiv.id ='gzoom-map-cover';
    zoomDiv.innerHTML ='<div id="gzoom-outline" style="position:absolute;display:none;"></div><div id="gzoom-cornerTopDiv" style="position:absolute;display:none;"></div><div id="gzoom-cornerLeftDiv" style="position:absolute;display:none;"></div><div id="gzoom-cornerRightDiv" style="position:absolute;display:none;"></div><div id="gzoom-cornerBottomDiv" style="position:absolute;display:none;"></div>';
    DragZoomUtil.style([zoomDiv], {position: 'absolute', display: 'none', overflow: 'hidden', cursor: 'crosshair', zIndex: 101});
    mapDiv.appendChild(zoomDiv);
  
  // add event listeners
    GEvent.addDomListener(buttonDiv, 'click', function(e) {
      me.buttonclick_(e);
    });
    GEvent.addDomListener(backButtonDiv, 'click', function(e) {
      me.backButtonclick_(e);
    });
    GEvent.addDomListener(zoomDiv, 'mousedown', function(e) {
      me.coverMousedown_(e);
    });
    GEvent.addDomListener(document, 'mousemove', function(e) {
      me.drag_(e);
    });
    GEvent.addDomListener(document, 'mouseup', function(e) {
      me.mouseup_(e);
    });
  
  // get globals
    G.mapPosition = DragZoomUtil.getElementPosition(mapDiv);
    G.outlineDiv = DragZoomUtil.gE("gzoom-outline");  
    G.buttonDiv = DragZoomUtil.gE("gzoom-control");
    G.backButtonDiv = DragZoomUtil.gE("gzoom-back");
    G.mapCover = DragZoomUtil.gE("gzoom-map-cover");
    G.cornerTopDiv = DragZoomUtil.gE("gzoom-cornerTopDiv");
    G.cornerRightDiv = DragZoomUtil.gE("gzoom-cornerRightDiv");
    G.cornerBottomDiv = DragZoomUtil.gE("gzoom-cornerBottomDiv");
    G.cornerLeftDiv = DragZoomUtil.gE("gzoom-cornerLeftDiv");
    G.map = map;
  
    G.borderCorrection = G.style.outlineWidth * 2;  
    this.setDimensions_();
  
  //styles
    this.initStyles_();
  return buttonContainerDiv;
};

/**
 * Required by GMaps API for controls. 
 * @return {GControlPosition} Default location for control
 */
DragZoomControl.prototype.getDefaultPosition = function() {
  return new GControlPosition(G_ANCHOR_TOP_LEFT, new GSize(3, 120));
};

/**
 * Function called when mousedown event is captured.
 * @param {Object} e 
 */
DragZoomControl.prototype.coverMousedown_ = function(e){
  var G = this.globals;
  var pos = this.getRelPos_(e);
  G.startX = pos.left;
  G.startY = pos.top;
  
  DragZoomUtil.style([G.mapCover], {background: 'transparent', opacity: 1, filter: 'alpha(opacity=100)'});
  DragZoomUtil.style([G.outlineDiv], {left: G.startX + 'px', top: G.startY + 'px', display: 'block', width: '1px', height: '1px'});
  G.draggingOn = true;

  G.cornerTopDiv.style.top = (G.startY - G.mapHeight) + 'px';
  G.cornerTopDiv.style.display ='block';
  G.cornerLeftDiv.style.left = (G.startX - G.mapWidth) +'px';
  G.cornerLeftDiv.style.top = G.startY + 'px';
  G.cornerLeftDiv.style.display = 'block';

  G.cornerRightDiv.style.left = G.startX + 'px';
  G.cornerRightDiv.style.top = G.startY + 'px';
  G.cornerRightDiv.style.display = 'block';
  G.cornerBottomDiv.style.left = G.startX + 'px';
  G.cornerBottomDiv.style.top = G.startY + 'px';
  G.cornerBottomDiv.style.width = '0px';
  G.cornerBottomDiv.style.display = 'block';

  // invoke the callback if provided
  if (G.callbacks.dragstart != null) {
    G.callbacks.dragstart(G.startX, G.startY);
  }

  return false;
};

/**z
 * Function called when drag event is captured
 * @param {Object} e 
 */
DragZoomControl.prototype.drag_ = function(e){
  var G = this.globals;

  document.onselectstart = function() {
    return false;
  };

  if(G.draggingOn) {
    var pos = this.getRelPos_(e);
    rect = this.getRectangle_(G.startX, G.startY, pos, G.mapRatio);

    if (rect.left) {
      addX = -rect.width;     
    } else { 
      addX = 0;
    }

    if (rect.top) {
      addY = -rect.height;
    } else {
      addY = 0;
    }

    DragZoomUtil.style([G.outlineDiv], {left: G.startX + addX + 'px', top: G.startY + addY + 'px', display: 'block', width: '1px', height: '1px'}); 
  
    G.outlineDiv.style.width = rect.width + "px";
    G.outlineDiv.style.height = rect.height + "px";

    G.cornerTopDiv.style.height = ((G.startY + addY) - (G.startY - G.mapHeight)) + 'px';
    G.cornerLeftDiv.style.top = (G.startY + addY) + 'px';
    G.cornerLeftDiv.style.width = ((G.startX + addX) - (G.startX - G.mapWidth)) + 'px';
    G.cornerRightDiv.style.top = G.cornerLeftDiv.style.top;
    G.cornerRightDiv.style.left = (G.startX + addX + rect.width + G.borderCorrection) + 'px';
    G.cornerBottomDiv.style.top = (G.startY + addY + rect.height + G.borderCorrection) + 'px';
    G.cornerBottomDiv.style.left = (G.startX - G.mapWidth + ((G.startX + addX) - (G.startX - G.mapWidth))) + 'px';
    G.cornerBottomDiv.style.width = (rect.width + G.borderCorrection) + 'px';
    
    // invoke callback if provided
    if (G.callbacks.dragging != null) {
      G.callbacks.dragging(G.startX, G.startY, rect.endX, rect.endY)
    }
    
    return false;
  }  
};

/** 
 * Function called when mouseup event is captured
 * @param {Event} e
 */
DragZoomControl.prototype.mouseup_ = function(e){
  var G = this.globals;
  if (G.draggingOn) {
    var pos = this.getRelPos_(e);
    G.draggingOn = false;
    
    var rect = this.getRectangle_(G.startX, G.startY, pos, G.mapRatio);

    if (rect.left) rect.endX = rect.startX - rect.width;
    if (rect.top) rect.endY = rect.startY - rect.height;
  
    this.resetDragZoom_();

    var nwpx = new GPoint(rect.startX, rect.startY);
    var nepx = new GPoint(rect.endX, rect.startY);
    var sepx = new GPoint(rect.endX, rect.endY);
    var swpx = new GPoint(rect.startX, rect.endY);
    var nw = G.map.fromContainerPixelToLatLng(nwpx); 
    var ne = G.map.fromContainerPixelToLatLng(nepx); 
    var se = G.map.fromContainerPixelToLatLng(sepx); 
    var sw = G.map.fromContainerPixelToLatLng(swpx); 

    var zoomAreaPoly = new GPolyline([nw, ne, se, sw, nw], G.style.outlineColor, G.style.outlineWidth + 1,.4);

    try{
      G.map.addOverlay(zoomAreaPoly);
      setTimeout (function() {G.map.removeOverlay(zoomAreaPoly)}, G.options.overlayRemoveTime);  
    }catch(e) {}

    polyBounds = zoomAreaPoly.getBounds();
    var ne = polyBounds.getNorthEast();
    var sw = polyBounds.getSouthWest();
    var se = new GLatLng(sw.lat(), ne.lng());
    var nw = new GLatLng(ne.lat(), sw.lng());
    zoomLevel = G.map.getBoundsZoomLevel(polyBounds);
    center = polyBounds.getCenter();
    G.map.setCenter(center, zoomLevel);

    // invoke callback if provided
    if (G.callbacks.dragend != null) {
      G.callbacks.dragend(nw, ne, se, sw, nwpx, nepx, sepx, swpx);
    }
    
    //re-init if sticky
    if (G.options.stickyZoomEnabled) {
      //GLog.write("stickyZoomEnabled, re-initting");
      this.initCover_();
      if (G.options.backButtonEnabled) this.saveBackContext_(G.options.backButtonHTML,false); // save the map context for back button
      G.backButtonDiv.style.display='none';
    }
  }
};

/**
 * Set the cover sizes according to the size of the map
 */
DragZoomControl.prototype.setDimensions_ = function() {
  var G = this.globals;
  var mapSize = G.map.getSize();
  G.mapWidth  = mapSize.width;
  G.mapHeight = mapSize.height;
  G.mapRatio  = G.mapHeight / G.mapWidth;
  DragZoomUtil.style([G.mapCover, G.cornerTopDiv, G.cornerRightDiv, G.cornerBottomDiv, G.cornerLeftDiv], 
    {width: G.mapWidth + 'px', height: G.mapHeight +'px'});
};

/**
 * Initializes styles based on global parameters
 */
DragZoomControl.prototype.initStyles_ = function(){
  var G = this.globals;
  DragZoomUtil.style([G.mapCover, G.cornerTopDiv, G.cornerRightDiv, G.cornerBottomDiv, G.cornerLeftDiv], 
    {filter: G.style.alphaIE, opacity: G.style.opacity, background:G.style.fillColor});
  G.outlineDiv.style.border = G.style.border;  
};

/**
 * Function called when the zoom button's click event is captured.
 */
DragZoomControl.prototype.buttonclick_ = function(){
  var G = this.globals; 
  G.backButtonDiv.style.display='none';
  if (G.mapCover.style.display == 'block') { // reset if clicked before dragging 
    this.resetDragZoom_();
    if (G.options.backButtonEnabled) {  
      this.restoreBackContext_();  // pop the backStack on a button reset
      if (G.backStack.length==0) G.backButtonDiv.style.display='none';
    }
  } else {
    this.initCover_();
    if ( G.options.backButtonEnabled ) this.saveBackContext_(G.options.backButtonHTML,false); // save the map context for back button
  }
};

/**
 * Back Button functionality: 
 * Function called when the back button's click event is captured.
 * calls the function to set the map context back to where it was before the zoom.
 */
DragZoomControl.prototype.backButtonclick_ = function(){
  var G = this.globals; 
  if (G.options.backButtonEnabled) {
    this.restoreBackContext_();
    // invoke the callback if provided
    if (G.callbacks['backbuttonclick'] != null) {
      G.callbacks.backbuttonclick(G.methodCall);
    }
  }
};

/** 
 * Back Button functionality: 
 * Saves the map context and pushes it on the backStack for later use by the back button
 */
DragZoomControl.prototype.saveBackContext_ = function(text,methodCall) {
  var G = this.globals;
  var backFrame = {};
  backFrame["center"] = G.map.getCenter();
  backFrame["zoom"] = G.map.getZoom();
  backFrame["maptype"] = G.map.getCurrentMapType();
  backFrame["text"] = G.backButtonDiv.innerHTML; // this saves the previous button text
  backFrame["methodCall"] = methodCall; //This determines if it was an internal or method call
  G.backStack.push(backFrame);
  G.backButtonDiv.innerHTML = text;
  // Back Button is turned on in resetDragZoom_()
};

/** 
 * Back Button functionality: 
 * Pops the previous map context off of the backStack and restores the map to that context
 */
DragZoomControl.prototype.restoreBackContext_ = function() {
  var G = this.globals;
  var backFrame = G.backStack.pop();
  G.map.setCenter(backFrame["center"],backFrame["zoom"],backFrame["maptype"]);
  G.backButtonDiv.innerHTML = backFrame["text"];
  G.methodCall = backFrame["methodCall"];
  if (G.backStack.length==0) G.backButtonDiv.style.display = 'none'; // if we're at the top of the stack, hide the back botton
};

/**
 * Shows the cover over the map
 */
DragZoomControl.prototype.initCover_ = function(){
  var G = this.globals;
  G.mapPosition = DragZoomUtil.getElementPosition(G.map.getContainer());
  this.setDimensions_();
  this.setButtonMode_('zooming');
  DragZoomUtil.style([G.mapCover], {display: 'block', background: '#000'});
  //DragZoomUtil.style([G.mapCover], {display: 'block', background: G.style.fillColor});
  DragZoomUtil.style([G.outlineDiv], {width: '0px', height: '0px'});

  //invoke callback if provided
  if(G.callbacks['buttonclick'] != null){
    G.callbacks.buttonclick();
  }

};

/**
 * Gets position of the mouse relative to the map
 * @param {Object} e
 */
DragZoomControl.prototype.getRelPos_ = function(e) {
  var pos = DragZoomUtil.getMousePosition(e);
  var G = this.globals;
  return {top: (pos.top - G.mapPosition.top), 
          left: (pos.left - G.mapPosition.left)};
};

/**
 * Figures out the rectangle the user's trying to draw
 * @param {Number} startX 
 * @param {Number} startY
 * @param {Object} pos
 * @param {Number} ratio
 * @return {Object} Describes the rectangle
 */
DragZoomControl.prototype.getRectangle_ = function(startX, startY, pos, ratio){
  var left = false;
  var top = false;
  var dX = pos.left - startX;
  var dY = pos.top - startY;  
  if (dX < 0) {
    dX = dX * -1;
    left = true;
  }
  if (dY < 0) {
    dY = dY * -1;
    top = true;
  }
  delta = dX > dY ? dX : dY;

  return {
    startX: startX,
    startY: startY,
    endX: startX + delta,
    endY: startY + parseInt(delta * ratio),
    width: delta,
    height: parseInt(delta * ratio),
    left:left,
    top:top
  }
};

/** 
 * Resets CSS and button display when drag zoom done
 */
DragZoomControl.prototype.resetDragZoom_ = function() {
  var G = this.globals;
  DragZoomUtil.style([G.mapCover, G.cornerTopDiv, G.cornerRightDiv, G.cornerBottomDiv, G.cornerLeftDiv], 
    {display: 'none', opacity: G.style.opacity, filter: G.style.alphaIE});
  G.outlineDiv.style.display = 'none';  
  this.setButtonMode_('normal');
  if (G.options.backButtonEnabled  && (G.backStack.length > 0)) G.backButtonDiv.style.display = 'block'; // show the back button
};



/* utility functions in DragZoomUtil.namespace */
var DragZoomUtil={};

/**
 * Alias function for getting element by id
 * @param {String} sId
 * @return {Object} DOM object with sId id
 */
DragZoomUtil.gE = function(sId) {
  return document.getElementById(sId);
}

/**
 * A general-purpose function to get the absolute position
 * of the mouse.
 * @param {Object} e  Mouse event
 * @return {Object} Describes position
 */
DragZoomUtil.getMousePosition = function(e) {
  var posX = 0;
  var posY = 0;
  if (!e) var e = window.event;
  if (e.pageX || e.pageY) {
    posX = e.pageX;
    posY = e.pageY;
  } else if (e.clientX || e.clientY){
    posX = e.clientX + 
      (document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft);
    posY = e.clientY + 
      (document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop);
  } 
  return {left: posX, top: posY};  
};

/**
 * Gets position of element
 * @param {Object} element
 * @return {Object} Describes position
 */
DragZoomUtil.getElementPosition = function(element) {
  var leftPos = element.offsetLeft;          // initialize var to store calculations
  var topPos = element.offsetTop;            // initialize var to store calculations
  var parElement = element.offsetParent;     // identify first offset parent element  
  while (parElement != null ) {                // move up through element hierarchy
    leftPos += parElement.offsetLeft;      // appending left offset of each parent
    topPos += parElement.offsetTop;  
    parElement = parElement.offsetParent;  // until no more offset parents exist
  }
  return {left: leftPos, top: topPos};
};

/**
 * Applies styles to DOM objects 
 * @param {String/Object} elements Either comma-delimited list of ids 
 *   or an array of DOM objects
 * @param {Object} styles Hash of styles to be applied
 */
DragZoomUtil.style = function(elements, styles){
  if (typeof(elements) == 'string') {
    elements = DragZoomUtil.getManyElements(elements);
  }
  for (var i = 0; i < elements.length; i++){
    for (var s in styles) { 
      elements[i].style[s] = styles[s];
    }
  }
};

/**
 * Gets DOM elements array according to list of IDs
 * @param {String} elementsString Comma-delimited list of IDs
 * @return {Array} Array of DOM elements corresponding to s
 */
DragZoomUtil.getManyElements = function(idsString){   
  var idsArray = idsString.split(',');
  var elements = [];
  for (var i = 0; i < idsArray.length; i++){
  
    var obj = DragZoomUtil.gE(idsArray[i]);  
    alert('idsArray[i]: ' + idsArray[i] + ' obj: ' + obj);
  
    elements[elements.length] = DragZoomUtil.gE(idsArray[i])
  };
  return elements;
};


	function TextualZoomControl() {
	}
	
	TextualZoomControl.prototype = new GControl();

// 	Creates a one DIV for each of the buttons and places them in a container
// 	DIV which is returned as our control element.
	TextualZoomControl.prototype.initialize = function(map) {
		var container = document.createElement("div");

// "Zoom In" button
		var zoomInDiv = document.createElement("div");
		this.setButtonStyle_(zoomInDiv);
		container.appendChild(zoomInDiv);
		zoomInDiv.appendChild(document.createTextNode("Zoom In"));
		// The "true" argument in the zoomIn() method allows continuous zooming
		GEvent.addDomListener(zoomInDiv, "click", function() {map.zoomIn(null,null,true);} );

// "Zoom Out" button
		var zoomOutDiv = document.createElement("div");
		this.setButtonStyle_(zoomOutDiv);
		zoomOutDiv.style.borderTop = 0+'px';
		container.appendChild(zoomOutDiv);
		zoomOutDiv.appendChild(document.createTextNode("Zoom Out"));
		// The "true" argument in the zoomOut() method allows continuous zooming
		GEvent.addDomListener(zoomOutDiv, "click", function() {map.zoomOut(null,true);} );

// 		We add the control to to the map container and return the element 
// 		for the map class to position properly.

		map.getContainer().appendChild(container);
		return container;
	}


// 	The control will appear in the top left corner of the map with 7 pixels of padding.
	TextualZoomControl.prototype.getDefaultPosition = function() {
		return new GControlPosition(G_ANCHOR_TOP_LEFT, new GSize(15, 7));
	}

// Sets the proper CSS for the given button element.
	TextualZoomControl.prototype.setButtonStyle_ = function(button) {
		button.style.textDecoration = "none";
		button.style.color = "black";
		button.style.backgroundColor = "white";
//		button.style.font = "12px Verdana bold";
		button.style.fontFamily = "Verdana";
		button.style.fontSize = "12px";
		button.style.fontWeight= "bold";
		button.style.border = "1px solid gray";
		button.style.padding = "0px";
		button.style.marginBottom = "0px";
		button.style.textAlign = "center";
		button.style.width = "7em";
		button.style.height = "15px";
		button.style.cursor = "pointer";
	}



// A Rectangle is a simple overlay that outlines a lat/lng bounds on the

// map. It has a border of the given weight and color and can optionally

// have a semi-transparent background color.





function Rectangle(bounds, opt_weight, opt_color) { 
      this.bounds_ = bounds;
      this.weight_ = opt_weight || 2;
      this.color_ = opt_color || "#888888";
    }

Rectangle.prototype = new GOverlay();

Rectangle.prototype.initialize = function(map) {

      // Create the DIV representing our rectangle
      var div = document.createElement("div");
      div.style.border = this.weight_ + "px solid " + this.color_;
      div.style.position = "absolute";
      div.style.background = "#ffffff";
      div.style.filter="alpha(opacity=50)";
      div.style.opacity="0.5";
      // Our rectangle is flat against the map, so we add our selves to the
      // MAP_PANE pane, which is at the same z-index as the map itself (i.e.,
      // below the marker shadows)

      map.getPane(G_MAP_MAP_PANE).appendChild(div);
      this.map_ = map;
      this.div_ = div;
      this.div_.style.zIndex = "11";

    }

 

    Rectangle.prototype.updatebounds = function(bounds){
      this.bounds_=bounds;
      //alert(bounds.getSouthWest());
      this.redraw(true);

}

    

// Remove the main DIV from the map pane
Rectangle.prototype.remove = function() {
  this.div_.parentNode.removeChild(this.div_);
}

// set transparency 
Rectangle.prototype.setOpacity = function(opct) {
    opct1 = "alpha(opacity=" + parseInt(parseFloat(opct) * 100) + ")";
    //alert(trsp + "  " + trsp1);
    this.div_.style.filter=opct1;
    this.div_.style.opacity=opct;
    this.div_.style.zIndex = "11";
}


// Copy our data to a new Rectangle

Rectangle.prototype.copy = function() {
  return new Rectangle(this.bounds_, this.weight_, this.color_, this.backgroundColor_, this.opacity_);
}



// Redraw the rectangle based on the current projection and zoom level

Rectangle.prototype.redraw = function(force) {
      // We only need to redraw if the coordinate system has changed
      if (!force) return;

      // Calculate the DIV coordinates of two opposite corners of our bounds to
      // get the size and position of our rectangle
      var c1 = this.map_.fromLatLngToDivPixel(this.bounds_.getSouthWest());
      var c2 = this.map_.fromLatLngToDivPixel(this.bounds_.getNorthEast());

      // Now position our DIV based on the DIV coordinates of our bounds
      this.div_.style.width = Math.abs(c2.x - c1.x) + "px";
      this.div_.style.height = Math.abs(c2.y - c1.y) + "px";
      this.div_.style.left = (Math.min(c2.x, c1.x) - this.weight_) + "px";
      this.div_.style.top = (Math.min(c2.y, c1.y) - this.weight_) + "px";
    }


/**
 * JavaScript for the wmsGoogleMap
 * 
 */

//general vars

var googleMap;
var geocoder = null;
var ewindow;
var menuForm;
//var infoWinUrl = "showkpinfo.php?gid=";
var mm;
var gmarkersA = [];      
var srs = "";
var bbox;
var bbox900913;
var imgW=1210;
var imgH=1170;
var imgT;
var imgL;
var copyr = "Nieuwland 2008";
var mode = "";

var Astartzoom = 13;

var mercZoomLevel = 11;
var overlaysouthwest;
var overlaynortheast;

var images=new Array();
var idx;
var currlyr = "";
var ovrly;
var ovrlytransp = 0.65;
var waasrecttransp = 0.15;
var waasrect;
var updateImage=false; 

function LatLongRD(l,f)
{ 
  //trace +="\nLatLongRD";
  x0  = 155000.00;
  y0  = 463000.00;
  
  f0 = 52.15616056;
  l0 =  5.38763889;
  
  c01=190066.98903 ;  d10=309020.31810;
  c11=-11830.85831 ;  d02=  3638.36193;
  c21=  -114.19754 ;  d12=  -157.95222;
  c03=   -32.38360 ;  d20=    72.97141;
  c31=    -2.34078 ;  d30=    59.79734;
  c13=    -0.60639 ;  d22=    -6.43481;
  c23=     0.15774 ;  d04=     0.09351;
  c41=    -0.04158 ;  d32=    -0.07379;
  c05=    -0.00661 ;  d14=    -0.05419;
                      d40=    -0.03444;
  df=(f - f0) * 0.36;
  dl=(l - l0) * 0.36;
  
  with(Math){
  dx =c01*dl + c11*df*dl + c21*pow(df,2)*dl + c03*pow(dl,3);
  dx+=c31*pow(df,3)*dl + c13*df*pow(dl,3) + c23*pow(df,2)*pow(dl,3);
  dx+=c41*pow(df,4)*dl + c05*pow(dl,5);
  x=x0 + dx;
  x=round(100*x)/100
  }
  
  with(Math){
  dy =d10*df + d20*pow(df,2) + d02*pow(dl,2) + d12*df*pow(dl,2);
  dy+=d30*pow(df,3) + d22*pow(df,2)*pow(dl,2) + d40*pow(df,4);
  dy+=d04*pow(dl,4) + d32*pow(df,3)*pow(dl,2) + d14*df*pow(dl,4);
  y=y0 + dy;
  y=round(100*y)/100}
  
  return "X: " + x + " Y: " + y;
}



//test getfeatureinfo
function toggleInfo(){

  GEvent.clearListeners(googleMap,"click");
  if(mode == "info"){
    mode = "";
    if (ovrly) ovrly.img_.style.cursor = ""; 
  //  var bar = $("bg");
  //  bar.src = codebase+"images/static.png";
    return;
    }
  mode = "info";
  if (ovrly) ovrly.img_.style.cursor = "help"; 
  GEvent.addListener(googleMap,"click", function (overlay, point){
      if(overlay){ return; }
      var pt = new GLatLng(point.y,point.x);
      addInfoTipMarker(pt);
      }
    ); 
  }
  
  function addInfoTipMarker(point){
    var htm = createInfoTipTabs(point);
    googleMap.openInfoWindowHtml(point, htm);    
  }
  
  function createInfoTipTabs(pt) {
  
  var b = googleMap.getBounds();
  var sw = b.getSouthWest();
  var ne = b.getNorthEast();
  var w = sw.lng();
  var e = ne.lng();
  var n = ne.lat();
  var s = sw.lat();
  
  //bbox is defined globally
  if (bbox900913 != null)
  {
    var span_ew = Math.abs(e - w);
    var span_ns = Math.abs(n - s);

    var mapx = pt.x;
    var mapy = pt.y;
    if (googleMap.getZoom()<= mercZoomLevel)
    {
      //convert to Mercator
      mapx=ovrly.dd2MercMetersLng900913(mapx);
      mapy=ovrly.dd2MercMetersLat900913(mapy);
    }
    var x = Math.round((mapx - w) * imgW/span_ew);
    var y = Math.round((n - mapy) * imgH/span_ns);
    
    
    bbox900913=Math.round(ovrly.dd2MercMetersLng900913(overlaysouthwest.lng()))+
      ","+Math.round(ovrly.dd2MercMetersLat900913(overlaysouthwest.lat()))+
      ","+Math.round(ovrly.dd2MercMetersLng900913(overlaynortheast.lng()))+
      ","+Math.round(ovrly.dd2MercMetersLat900913(overlaynortheast.lat()));


    var infoWindows = [];
    if (currlyr == "") return;

    var Requests = currlyr.split(",");

    if(Requests.length<1){ return; }
    for(var r = 0;r<Requests.length;r++){
      var htm ="";
      var lyr = Requests[r];
      var lyrlab = lyr.substring(0,10);

      var featureinfourl = FeatureInfoServerURL + "&SERVICE=WMS&REQUEST=GetFeatureInfo&VERSION=1.1.1&LAYERS="+lyr+"&SRS=EPSG:4326&BBOX="+w+","+s+","+e+"," + n + "&X=" + x +"&Y="+ y +"&WIDTH="+imgW+"&HEIGHT="+ imgH+"&INFO_FORMAT=text/html&FEATURE_COUNT=10&ietype=.gml&QUERY_LAYERS="+lyr;

      htm += "<iframe style=\"border:10px solid #fff;width:450px;height:200px\" src=\""; 
      htm += "featureinfo.html?" + featureinfourl;

      htm += "\" ></iframe>";
      //Bij eerste resultaat, deze teruggeven
      return htm;
    }
    return "";
    //return infoWindows;
  }
}
  
  

function updateZoomlevelInfo()
{   
  zoomlvl = googleMap.getZoom();
  infotxt = "Klik op een icoomtje om informatie op te vragen";
  zminfodiv = document.getElementById("zoomInfoDiv");
  if (zminfodiv)
  {
    if (zoomlvl < Astartzoom)
    {
      infotxt = "Knelpuntinformatie niet beschikbaar op dit zoomniveau, zoom verder in voor een vollediger beeld ";
    }

    zminfodiv.innerHTML = infotxt;
  }
  zminfodiv = null;
}


function updateRectangleBackground(){
  var bounds = googleMap.getBounds();
  var southWest = bounds.getSouthWest();
  var northEast = bounds.getNorthEast();
  var lngDelta = (northEast.lng() - southWest.lng()) *2;
  var latDelta = (northEast.lat() - southWest.lat()) *2;
  var rectBounds = new GLatLngBounds(
      new GLatLng(southWest.lat() + latDelta, southWest.lng() + lngDelta),
      new GLatLng(northEast.lat() - latDelta, northEast.lng() - lngDelta));

  if (waasrect!=null)
  {
    //Tbv IE6&7, steeds de oude waas weghalen en een nieuwe maken
    googleMap.removeOverlay(waasrect); 
  }
  waasrect=new Rectangle(rectBounds);
  googleMap.addOverlay(waasrect);
  setwaastrans(waasrecttransp);
}

function setwaastrans(trsp)
{
  if (waasrect !=null)
  {
    waasrecttransp = trsp;
    waasrect.setOpacity(trsp);
    //Bewaar de laatste gebruikte transparantie waarde
    waasrecttransp = trsp;
  }
}

function setOvrlyTransp(t) {
  ovrlytransp = t;
  if (ovrly != null) ovrly.setTransparency(t);
}

/**
 * Is called at initialization via the body onload.
 * Opens the googleMap
 */
function init() {

  if (GBrowserIsCompatible()) {
    geocoder = new GClientGeocoder();
    googleMap = new GMap2(document.getElementById("myGoogleMap"));
    googleMap.enableDoubleClickZoom();
    //the large scale control
    //googleMap.addControl(new GLargeMapControl(),new GControlPosition(G_ANCHOR_TOP_LEFT,new GSize(5,50)));
    googleMap.addControl(new GLargeMapControl(),new GControlPosition(G_ANCHOR_TOP_LEFT,new GSize(5,5)));
    //control for map/satellite/Hybrid
    googleMap.addControl(new GMapTypeControl());
    //add the terrain model
    //googleMap.addMapType(G_PHYSICAL_MAP);
    //control to show the overview
    googleMap.addControl(new GOverviewMapControl(new GSize(110,110)));
    //control to show the scalebar
    var scalec = new GScaleControl();
    googleMap.addControl(scalec);   


    //dragzoom
    var otherOpts = { 
          buttonStartingStyle: {background: '#FFF', paddingTop: '4px', paddingLeft: '6px', border:'1px solid black'},
          buttonHTML: '<img title="Zoom in dmv het trekken van een rechthoek met de muis" src="images/icons/zoomin.gif">',
          buttonStyle: {width:'22px', height:'22px'},
          buttonZoomingHTML: 'Trek een rechthoek om naar in te zoomen (klik om te annuleren)',
          buttonZoomingStyle: {background:'#ffffd3',width:'150px', height:'100%'},
          backButtonHTML: '<img title="Terug uitzoomen" src="images/icons/zoomout.gif">',  
          backButtonStyle: {display:'none',marginTop:'5px',width:'22px', height:'22px'},
          backButtonEnabled: true, 
          overlayRemoveTime: 1000} 

    googleMap.addControl(new DragZoomControl({}, otherOpts, {}), new GControlPosition(G_ANCHOR_BOTTOM_LEFT, new GSize(10,70)));

      
    //info
    var otherOpts = { 
          buttonStartingStyle: {background: '#FFF', paddingTop: '4px', paddingLeft: '6px', border:'1px solid black'},
          buttonHTML: '<img id="infobtn" title="Toon informatie bij klikken op kaart" src="images/icons/info.gif">',
          buttonStyle: {width:'22px', height:'22px'},
          buttonZoomingHTML: '<img title="Stop het tonen van informatie" src="images/icons/info.gif">',
          buttonZoomingStyle: {background:'#efa016',width:'22px', height:'22px'},
          backButtonHTML: '<img title="Stop het tonen van informatie" src="images/icons/info.gif">',  
          backButtonStyle: {display:'none',background:'#efa016', marginTop:'5px',width:'22px', height:'22px'},
          backButtonEnabled: false, 
          overlayRemoveTime: 1000} 

    googleMap.addControl(new FeatureInfo({}, otherOpts, {}), new GControlPosition(G_ANCHOR_BOTTOM_LEFT, new GSize(10,37)));
    
    //center and show
    googleMap.setCenter(initLatLng, initZoom);
    
    //add a listener to restrict zooming
    GEvent.addListener(googleMap, "zoomend", function() {

      if ( (maxZoom!=null)&&(googleMap.getZoom()>maxZoom) ) {
      
        updateImage=true;
        ovrly.remove();
        ovrly=null;
        googleMap.setZoom(maxZoom);
      }
      if ( (minZoom!=null)&&(googleMap.getZoom()<minZoom) ){
        
        updateImage=true;
        ovrly.remove();
        ovrly=null;
        googleMap.setZoom(minZoom);
        
        
      }
      if (ovrly != null) {
        ovrly.img_.style.opacity=0;
      }   
      updateImage=true;
       
      //achtergrond waas
      if (waasrect != null)
      {
        updateRectangleBackground();
      }
      //zoomlevel info
      updateZoomlevelInfo();
      
      changeWMSOverlaySlice();
    });


    //add a listener to panning
    GEvent.addListener(googleMap, "moveend", function() {

      //checkBounds();
      newsouthWest = googleMap.getBounds().getSouthWest();
      newnorthEast = googleMap.getBounds().getNorthEast();
      if ((overlaysouthwest!=null)&&(overlaysouthwest.lng()>newsouthWest.lng())){

        updateImage=true;
      }
      else if ((overlaynortheast!=null)&&(overlaynortheast.lng()<newnorthEast.lng())){

        updateImage=true;

      }
      else if ((overlaysouthwest!=null)&&(overlaysouthwest.lat()>newsouthWest.lat())){

        updateImage=true;

      }
      else if ((overlaynortheast!=null)&&(overlaynortheast.lat()<newnorthEast.lat())){

        updateImage=true;

      }

      if (updateImage)
      {
        if (waasrect != null)
        {
          updateRectangleBackground();
        }
        //images=new Array();
        changeWMSOverlaySlice();
      }
      
    });

    //add a listener to mousemove
    GEvent.addListener(googleMap, "mousemove", function(latlon) {
      var d = document.getElementById('coordsdiv');
      if (d) {
        //LatLongRD
        fWgs = latlon.lat();
        lWgs = latlon.lng();
        xy = LatLongRD(lWgs,fWgs);
        d.innerHTML = xy;
      }
    });


  }
  else
    alert('Your browser is not compatible');
} //end init()


function showAddress(address) {
  if (geocoder) {
    geocoder.getLatLng(
      address,
      function(point) {
        if (!point) {
          alert(address + " not found");
        } else {
          googleMap.setCenter(point, 17);
          //var marker = new GMarker(point);
          //googleMap.addOverlay(marker);
          
          //htmladdress = "<link rel=\"stylesheet\" type=\"text/css\" href=\"css/info.css\">";
          htmladdress = "<span id=\"straat\">";
          htmladdress += "<table border='0' cellspacing='0' cellpadding='0' width='200'>";
          htmladdress += "<tr><td>";
          htmladdress += "<table border='0' cellspacing='0' cellpadding='0' width='200'>";
          htmladdress += "<tr><th class='title'>Zoek resultaat</th></tr>";
          htmladdress += "<tr><td>" + address + "</td></tr></table>";
          htmladdress += "</td></tr></table>";
          htmladdress += "</span>";
          
          
          
          googleMap.openInfoWindowHtml(point, htmladdress);
        }
      }
    );
  }
}



function toggleLM(vis)
{
  lm = document.getElementById("maploading");
  if (lm) 
  { 
    if (vis) 
      lm.style.display = 'block';
    else
    lm.style.display = 'none';
  }
}
    
function removeWMSLayerDiv() {
  var d = document.getElementById('wmslayersdiv');
  var wmstbl = document.getElementById("wmstable");
  if (wmstbl) { 
    d.removeChild(wmstbl);
    wmstbl = null;
  }
}   
    
function AddWMSLayerDiv(lyrsarr)
{
  var numlayers = lyrsarr.length;
  var div=document.getElementById("wmslayersdiv");
  var rows=numlayers;
  var columns=1;
  var tbl=document.createElement("table");
  tbl.setAttribute("id","wmstable");
  //tbl.style.borderWidth="1px";
  //tbl.style.borderStyle="solid";
  //tbl.style.borderColor="#ccc";
  tbl.style.position="relative";
  var tb=document.createElement("tbody");
  for (var i=0;i<rows;i++)
  {
    tr=document.createElement("tr");
    var lyr = lyrsarr[i];
    var LayerName = lyr[0];
    var LayerTitle = lyr[1];

    tr.setAttribute("id",LayerName);

    for (var j=0;j<columns;j++)
    {
      var td=document.createElement("td");
      var legdivtitle =document.createElement('div');
      var contents="<a href=\"#\" onclick=\"setCheckedLegend('" + LayerName + "', 'legimg_"+LayerName+"');showLegenda('legenda_"+LayerName+"');\">" + LayerTitle + "</a>";
      legdivtitle.innerHTML = contents;
      td.style.backgroundColor="#fff";
      td.style.padding="2px";
      var chk =document.createElement('input');
      chk.setAttribute('type', 'checkbox');
      chk.setAttribute('value', LayerName); 
      chk.setAttribute('name', 'legend_checklist'); 
      chk.setAttribute('id', 'legend_checklist'); 
      chk.setAttribute('onclick', 'setCheckedLayers(this.value, this.checked)');
      td.appendChild(chk);

      //var contentsNode=document.createTextNode(contents);
      //td.appendChild(contentsNode);
      var legdiv =document.createElement('div');
      legdiv.setAttribute('id', 'legenda_'+LayerName); 
      legdiv.setAttribute('class', 'legenda_graphic');
      legdiv.style.display="none";
      var legimg=document.createElement("img");
      legimg.setAttribute('id', 'legimg_'+LayerName); 
      legimg.src="";
      legdiv.appendChild(legimg);
      var tdcontent=document.createElement("td");
      tdcontent.appendChild(legdivtitle);
      tdcontent.appendChild(legdiv);
      tr.appendChild(td);
      tr.appendChild(tdcontent);
    }
    tb.appendChild(tr);
  }
  tbl.appendChild(tb);
  div.appendChild(tbl);
}

function addWMSCapab(capabfile){

  var request = GXmlHttp.create();

  request.open("GET", capabfile, true);
  request.onreadystatechange = function() {
    if (request.readyState == 4) {

      var xmlDoc = request.responseXML;
      var markers = xmlDoc.getElementsByTagName("Layer");
      markerElementsLen = markers.length;
      var lyrsarr = [];

      for (var i = 0; i < markers.length; ++i) {
        // obtain the attributes of each marker
        var name = markers[i].getElementsByTagName("Name")[0].firstChild.nodeValue;
        var title = markers[i].getElementsByTagName("Title")[0].firstChild.nodeValue;
        var srs = markers[i].getElementsByTagName("SRS")[0].firstChild.nodeValue;
        lyr = new Array(name, title, srs);
        lyrsarr.push(lyr);
      }
      //write the table
      AddWMSLayerDiv(lyrsarr);
    }
  }
  request.send(null);

}

function managerInit()
{
  mm = new MarkerManager(googleMap);
  mm.addMarkers(gmarkersA,Astartzoom,17);

  mm.refresh();
  toggleLM(false);
} 
    
  

function toggleKnelpuntMarkers(vis) {
  toggleLM(true);
  if (vis) {
    mm.addMarkers(gmarkersA,Astartzoom,17);
    mm.refresh();
  }
  else {
    mm.clearMarkers(); 
  }
  toggleLM(false);
}



//---wms methods----

function setLayer(newlyr) {

  if (newlyr!=currlyr) 
  {
    if (newlyr != "")
    {
      updateRectangleBackground();
      setwaastrans(waasrecttransp);
    }
    else
    {
      if (waasrect != null)
      {
        waasrect.remove();
        waasrect=null;
      }
    }

    images=new Array();
    currlyr=newlyr;
    if (ovrly) 
    {
      ovrly.remove();
      ovrly=null;
    }
    updateImage = true;
    //alert(currlyr);
    changeWMSOverlaySlice();
    //googleMap.addCopyright(copyr);

  }

}


function changeWMSOverlaySlice() {

  southWest = googleMap.getBounds().getSouthWest();
  northEast = googleMap.getBounds().getNorthEast();

  var overlayBounds = new GLatLngBounds(southWest, northEast);

  if (ovrly==null) {
    ovrly = new WMSOverlay(overlayBounds,0.2,'#888888');
    googleMap.addOverlay(ovrly);
  }
  else
  {
    ovrly.redraw(true);
  }

}

function WMSOverlay(bounds, opt_transparency, opt_color) {
  this.bounds_ = bounds;
  this.transparency_ = opt_transparency || 0.5;

}

/** WMSOverlay prototype */
WMSOverlay.prototype = new GOverlay();
WMSOverlay.prototype.initialize = function(map) {

  var img = document.createElement("img");
  img.style.opacity = this.transparency_;
  img.style.position = "absolute";
  map.getPane(G_MAP_MAP_PANE).appendChild(img);
  this.map_ = map;
  this.img_ = img;
  this.img_.style.zIndex = "12";

}

WMSOverlay.prototype.remove = function() {
if (this.img_!=null&&this.img_.parentNode!=null)
  this.img_.parentNode.removeChild(this.img_);
}

WMSOverlay.prototype.copy = function() {
  return new WMSOverlay(this.bounds_, this.transparency_, this.color_, this.backgroundColor_, this.opacity_);
}

WMSOverlay.prototype.redraw = function(force) {
 
  if (this.map_!=null) {

    var b = googleMap.getBounds();
    //bounds_ (van het plaatje) moet gelijkgesteld worden aan de bounds van de kaart
    if (updateImage==true){
      this.bounds_=b;
      this.testbounds_=b;
    }
    
    var idx = 0;
    overlaysouthwest = this.bounds_.getSouthWest();
    overlaynortheast = this.bounds_.getNorthEast();
    var borderdifference = (overlaynortheast.lat()-overlaysouthwest.lat())/1.5;

    overlaysouthwest = new GLatLng(overlaysouthwest.lat()-borderdifference,overlaysouthwest.lng()-borderdifference);
    overlaynortheast = new GLatLng(overlaynortheast.lat()+borderdifference,overlaynortheast.lng()+borderdifference);
    var c1  = this.map_.fromLatLngToDivPixel(overlaysouthwest);
    var c2  = this.map_.fromLatLngToDivPixel(overlaynortheast);

    var w = Math.abs(c2.x - c1.x);
    var h = Math.abs(c2.y - c1.y);
    var l = Math.min(c2.x, c1.x);
    var t = Math.min(c2.y, c1.y);

    if ((!updateImage) || (!force)) {
      //Als het image nog niet opnieuw hoeft te worden opgevraagd, alleen positie bijwerken.    
      this.img_.style.width = w + "px";
      this.img_.style.height = h + "px";
      this.img_.style.left = l + "px";
      this.img_.style.top = t + "px";
      return;
    }
    
    imgW = w;
    imgH = h;
    imgT = t;
    imgL = l;

    var z = this.map_.getZoom();
    this.img_.style.visibility="hidden";
  
    var lngSpan = overlaynortheast.lng() - overlaysouthwest.lng();
    var latSpan = overlaynortheast.lat() - overlaysouthwest.lat();
    
    
    if ((currlyr!="") && (ovrly != null)) {
      var lsrs = 900913;
      bbox900913=Math.round(this.dd2MercMetersLng900913(overlaysouthwest.lng()))+
      ","+Math.round(this.dd2MercMetersLat900913(overlaysouthwest.lat()))+
      ","+Math.round(this.dd2MercMetersLng900913(overlaynortheast.lng()))+
      ","+Math.round(this.dd2MercMetersLat900913(overlaynortheast.lat()));
      srs = "EPSG:900913";

      //display loading img
      //alert ('show LM redraw');
      toggleLM(true);

      //bepaal het aantal punten in het zichtbare gebied
      //var b = googleMap.getBounds();
      //var sw = b.getSouthWest();
      //var ne = b.getNorthEast();
      //var lbbox = sw.lng() + ',' + sw.lat() + ',' + ne.lng() + ',' + ne.lat();
      //makePOSTRequest('numpoints.php', 'bbox=' + lbbox + '&srs=' + lsrs, showNumPoints);

      url=MapServerURL+"&REQUEST=GetMap&SERVICE=WMS&VERSION=1.1.0&LAYERS="+currlyr+"&STYLES=default&FORMAT=image/gif&BGCOLOR=0xFFFFFF&TRANSPARENT=TRUE&SRS="+srs+"&BBOX="+bbox900913+"&WIDTH="+imgW+"&HEIGHT="+imgH;
      this.img_.src=url;

      //if (images[idx] == null) 
      //{
      //  images[idx] = new Image();
      //}
      //images[idx].src=ovrly.getImageSrc();

    }

    this.img_.style.width = w + "px";
    this.img_.style.height = h + "px";
    this.img_.style.left = l + "px";
    this.img_.style.top = t + "px";
    this.img_.onload=makevis;
    
    //Image is opgevraagd, op false tot volgende request
    updateImage = false;
    
    
  }
}


function showNumPoints()
{
  if (http_request.readyState == 4) {
    if (http_request.status == 200) {
      var obj = document.getElementById('coords');
      obj.innerHTML = http_request.responseText;
    } else {
      alert('There was a problem with the request.');
    }
  }
}

//
// Maak het plaatje zichtbaar zodra deze geladen is.
//
function makevis() {
  if (ovrly)
  {
    ovrly.img_.style.visibility = "visible";
    ovrly.setTransparency(ovrlytransp);
    //hide loading img
    toggleLM(false);
  }
}


WMSOverlay.prototype.getImageSrc = function(){
  return this.img_.src;
}

WMSOverlay.prototype.setTime = function(time){
  this.imagetime=time;
}

WMSOverlay.prototype.setTransparency = function(t) {
if (ovrly!=null&&ovrly.img_!=null){
    var t2 = t;
    if (t <= 1)
    {
      t = t;
      t2 = t * 100;

    } else {
      t = 1-(t/100);
      t2 = (100-t);
    }
    ovrly.img_.style.opacity = t;
    ovrly.img_.style.filter = "alpha(opacity="+t2+")";
  }
}




WMSOverlay.prototype.MAGIC_NUMBER = 6356752.3142;
WMSOverlay.prototype.WGS84_SEMI_MAJOR_AXIS = 6378137.0;
WMSOverlay.prototype.WGS84_ECCENTRICITY = 0.0818191913108718138;

WMSOverlay.prototype.dd2MercMetersLat = function(latitude) {
  var rads = latitude * Math.PI / 180.0;
  return this.WGS84_SEMI_MAJOR_AXIS * Math.log(
    Math.tan((rads+Math.PI/2)/2) * 
    Math.pow(((1-this.WGS84_ECCENTRICITY*Math.sin(rads))/(1+this.WGS84_ECCENTRICITY*Math.sin(rads))), this.WGS84_ECCENTRICITY/2));
};
WMSOverlay.prototype.dd2MercMetersLng = function(longitude) { 
  return this.WGS84_SEMI_MAJOR_AXIS * (longitude * Math.PI / 180.0);
};


//6378137.0, 
//298.257223563

WMSOverlay.prototype.MAGIC_NUMBER900913 = 20037508.34;
WMSOverlay.prototype.WGS84_SEMI_MAJOR_AXIS900913 = 20037508.34;
WMSOverlay.prototype.dd2MercMetersLat900913 = function(latitude) {
  var y = Math.log(Math.tan((90 + latitude) * Math.PI / 360)) / (Math.PI / 180);
  return y * this.MAGIC_NUMBER900913 / 180;
};
WMSOverlay.prototype.dd2MercMetersLng900913 = function(longitude) { 
  return longitude * this.WGS84_SEMI_MAJOR_AXIS900913 / 180;
};




function clearFields(theform)
{
  theform.naam.value='';
  theform.status.value='';
  theform.kenmerk.value='';
  theform.afgegevendoor.value='';
  
  theform.locatienaam.value='';
  theform.vanafdag.options[0].selected = true;
  theform.vanafmaand.options[0].selected = true;
  theform.vanafjaar.options[0].selected = true;
  
  theform.totdag.options[0].selected = true;
  theform.totmaand.options[0].selected = true;
  theform.totjaar.options[0].selected = true;

}
function clearDates(theform)
{
  theform.vanafdag.options[0].selected = true;
  theform.vanafmaand.options[0].selected = true;
  theform.vanafjaar.options[0].selected = true;
  
  theform.totdag.options[0].selected = true;
  theform.totmaand.options[0].selected = true;
  theform.totjaar.options[0].selected = true;

}

function SubmitDcmrForm(theform,buttonClicked)
{
  if (buttonClicked.name == "locatiezoeken")
  {
    // niets hier   
  }
  else
  {
    var vanafdag = theform.vanafdag.value;
    var vanafmaand = theform.vanafmaand.value;
    var vanafjaar = theform.vanafjaar.value;

    var totdag = theform.totdag.value;
    var totmaand = theform.totmaand.value;
    var totjaar = theform.totjaar.value;

    var locatienaam = theform.locatienaam.value;
    var afgegevendoor = theform.afgegevendoor.value;
    var naam = theform.naam.value;
    var kenmerk = theform.kenmerk.value;

    thestatus = document.forms[0].status;
    thevalue = thestatus.options[thestatus.selectedIndex].value;  
  
    if ( (locatienaam == "") && (afgegevendoor == "") && (naam == "") && (vanafdag == "") && (totdag == "") && (kenmerk == ""))
    {
      alert("U dient tenminste 1 kenmerk op te geven voor een zoekactie.");
      theform.locatienaam.focus();
      return false;
    }
    
    if (thevalue == 'afgerond')
    {
      if ((vanafdag != "") || (vanafmaand != "") || (vanafjaar != "") )
      {
        if (vanafdag == "")
        {
          alert("U dient een geldige 'vanaf' datum op te geven.");
          theform.vanafdag.focus();
          return false;
        }
  
        if (vanafmaand == "")
        {
          alert("U dient een geldige 'vanaf' datum op te geven.");
          theform.vanafmaand.focus();
          return false;
        }
  
        if (vanafjaar == "")
        {
          alert("U dient een geldige 'vanaf' datum op te geven.");
          theform.vanafjaar.focus();
          return false;
        }
      }
  
      if ((totdag != "") || (totmaand != "") || (totjaar != "") )
      {
        if (totdag == "")
        {
          alert("U dient een geldige 'tot' datum op te geven.");
          theform.totdag.focus();
          return false;
        }
  
        if (totmaand == "")
        {
          alert("U dient een geldige 'tot' datum op te geven.");
          theform.totmaand.focus();
          return false;
        }
  
        if (totjaar == "")
        {
          alert("U dient een geldige 'tot' datum op te geven.");
          theform.totjaar.focus();
          return false;
        }
      }
    }
  
    theform.zoekmethode.value = buttonClicked.name;
    theform.submit();
  }
}

function showDates()
{
  var theform = document.forms['frmzoek'];
  var thestatus = document.forms['frmzoek'].status;
  var thevalue = thestatus.options[thestatus.selectedIndex].value;  
  var datum_vanaf = document.getElementById("datum_vanaf");
  var datum_tot = document.getElementById("datum_tot");
  
  if (thevalue == 'afgerond')
  {
    datum_vanaf.style.display = "block";
    datum_tot.style.display = "block";
  }
  else
  {
    datum_vanaf.style.display = "none";
    datum_tot.style.display = "none";
    
    clearDates(theform);
  }
}




//---------------------------------+
//  CARPE  S l i d e r        1.5  |
//  2006 - 01 - 03                 |
//  By Tom Hermansson Snickars     |
//  Copyright CARPE Design         |
//  http://carpe.ambiprospect.com/ |
//  Contact for custom scripts     |
//  or implementation help.        |
//---------------------------------+

// Global vars. You don't need to make changes here to change your sliders.
// Changing the attributes in your (X)HTML file is enough.
var carpeDefaultSliderLength      = 100
var carpeSliderDefaultOrientation = 'vertical'
var carpeSliderClassName          = 'carpe_slider'
var carpeSliderDisplayClassName   = 'carpe_slider_display'

// carpeGetElementsByClass: Cross-browser function that returns
// an array with all elements that have a class attribute that
// contains className
function carpeGetElementsByClass(className)
{
  var classElements = new Array()
  var els = document.getElementsByTagName("*")
  var elsLen = els.length
  var pattern = new RegExp("\\b" + className + "\\b")
  for (i = 0, j = 0; i < elsLen; i++) {
    if ( pattern.test(els[i].className) ) {
      classElements[j] = els[i]
      j++
    }
  }
  return classElements;
}
// carpeLeft: Cross-browser version of "element.style.left"
// Returns or sets the horizontal position of an element.
function carpeLeft(elmnt, pos)
{
  if (!(elmnt = document.getElementById(elmnt))) return 0;
  if (elmnt.style && (typeof(elmnt.style.left) == 'string')) {
    if (typeof(pos) == 'number') elmnt.style.left = pos + 'px';
    else {
      pos = parseInt(elmnt.style.left);
      if (isNaN(pos)) pos = 0;
    }
  }
  else if (elmnt.style && elmnt.style.pixelLeft) {
    if (typeof(pos) == 'number') elmnt.style.pixelLeft = pos;
    else pos = elmnt.style.pixelLeft;
  }
  return pos;
}
// carpeTop: Cross-browser version of "element.style.top"
// Returns or sets the vertical position of an element.
function carpeTop(elmnt, pos)
{
  if (!(elmnt = document.getElementById(elmnt))) return 0;
  if (elmnt.style && (typeof(elmnt.style.top) == 'string')) {
    if (typeof(pos) == 'number') elmnt.style.top = pos + 'px';
    else {
      pos = parseInt(elmnt.style.top);
      if (isNaN(pos)) pos = 0;
    }
  }
  else if (elmnt.style && elmnt.style.pixelTop) {
    if (typeof(pos) == 'number') elmnt.style.pixelTop = pos;
    else pos = elmnt.style.pixelTop;
  }
  return pos;
}
// moveSlider: Handles slider and display while dragging
function moveSlider(evnt)
{
  var evnt = (!evnt) ? window.event : evnt; // The mousemove event
  if (mouseover) { // Only if slider is dragged
    x = slider.startOffsetX + evnt.screenX // Horizontal mouse position relative to allowed slider positions
    y = slider.startOffsetY + evnt.screenY // Horizontal mouse position relative to allowed slider positions
    if (x > slider.xMax) x = slider.xMax // Limit horizontal movement
    if (x < 0) x = 0 // Limit horizontal movement
    if (y > slider.yMax) y = slider.yMax // Limit vertical movement
    if (y < 0) y = 0 // Limit vertical movement
    carpeLeft(slider.id, x)  // move slider to new horizontal position
    carpeTop(slider.id, y) // move slider to new vertical position
    sliderVal = x + y // pixel value of slider regardless of orientation
    sliderPos = (slider.distance / display.valuecount) * 
      Math.round(display.valuecount * sliderVal / slider.distance)
    v = Math.round((sliderPos * slider.scale + slider.from) * // calculate display value
      Math.pow(10, display.decimals)) / Math.pow(10, display.decimals)
    display.value = v // put the new value in the slider display element
    //alert(displayId);
    if (displayId =='waastransp') { 
      setwaastrans(v/100);
    }
    else if (displayId =='overlytransp') { 
      setOvrlyTransp(v);
    }
    
    return false
  }
  return
}
// slide: Handles the start of a slider move.
function slide(evnt)
{
  if (!evnt) evnt = window.event; // Get the mouse event causing the slider activation.
  slider = (evnt.target) ? evnt.target : evnt.srcElement; // Get the activated slider element.
  dist = parseInt(slider.getAttribute('distance')) // The allowed slider movement in pixels.
  slider.distance = dist ? dist : carpeDefaultSliderLength // Deafault distance from global var.
  ori = slider.getAttribute('orientation') // Slider orientation: 'horizontal' or 'vertical'.
  orientation = ((ori == 'horizontal') || (ori == 'vertical')) ? ori : carpeSliderDefaultOrientation
    // Default orientation from global variable.
  displayId = slider.getAttribute('display') // ID of associated display element.
  display = document.getElementById(displayId) // Get the associated display element.
  display.sliderId = slider.id // Associate the display with the correct slider.
  dec = parseInt(display.getAttribute('decimals')) // Number of decimals to be displayed.
  display.decimals = dec ? dec : 0 // Default number of decimals: 0.
  val = parseInt(display.getAttribute('valuecount'))  // Allowed number of values in the interval.
  display.valuecount = val ? val : slider.distance + 1 // Default number of values: the sliding distance.
  from = parseFloat(display.getAttribute('from')) // Min/start value for the display.
  from = from ? from : 0 // Default min/start value: 0.
  to = parseFloat(display.getAttribute('to')) // Max value for the display.
  to = to ? to : slider.distance // Default number of values: the sliding distance.
  slider.scale = (to - from) / slider.distance // Slider-display scale [value-change per pixel of movement].
  if (orientation == 'vertical') { // Set limits and scale for vertical sliders.
    slider.from = to // Invert for vertical sliders. "Higher is more."
    slider.xMax = 0
    slider.yMax = slider.distance
    slider.scale = -slider.scale // Invert scale for vertical sliders. "Higher is more."
  }
  else { // Set limits for horizontal sliders.
    slider.from = from
    slider.xMax = slider.distance
    slider.yMax = 0
  }
  slider.startOffsetX = carpeLeft(slider.id) - evnt.screenX // Slider-mouse horizontal offset at start of slide.
  slider.startOffsetY = carpeTop(slider.id) - evnt.screenY // Slider-mouse vertical offset at start of slide.
  mouseover = true
  document.onmousemove = moveSlider // Start the action if the mouse is dragged.
  document.onmouseup = sliderMouseUp // Stop sliding.
  return false
}
// sliderMouseUp: Handles the mouseup event after moving a slider.
// Snaps the slider position to allowed/displayed value. 
function sliderMouseUp()
{
  if (mouseover) {
    v = (display.value) ? display.value : 0 // Find last display value.
    pos = (v - slider.from)/(slider.scale) // Calculate slider position (regardless of orientation).
    if (slider.yMax == 0) {
      pos = (pos > slider.xMax) ? slider.xMax : pos
      pos = (pos < 0) ? 0 : pos
      carpeLeft(slider.id, pos) // Snap horizontal slider to corresponding display position.
    }
    if (slider.xMax == 0) {
      pos = (pos > slider.yMax) ? slider.yMax : pos
      pos = (pos < 0) ? 0 : pos
      carpeTop(slider.id, pos) // Snap vertical slider to corresponding display position.
    }
    
    if (document.removeEventListener) { // Remove event listeners from 'document' (W3C).
      document.removeEventListener('mousemove', moveSlider, false)
      document.removeEventListener('mouseup', sliderMouseUp, false)
    }
    else if (document.detachEvent) { // Remove event listeners from 'document' (IE).
      document.detachEvent('onmousemove', moveSlider);
      document.detachEvent('onmouseup', sliderMouseUp);
    
    }
  }
  mouseover = false // Stop the sliding.
}
function focusDisplay(evnt)
{
  if (!evnt) evnt = window.event; // Get the mouse event causing the display activation.
  display = (evnt.target) ? evnt.target : evnt.srcElement; // Get the activated display element.
  lock = display.getAttribute('typelock') // Is the user allowed to type into the display?
  if (lock == 'on') {
    display.blur()
  }
  
  return
}

// Set up the sliders and the displays.
function initslider() 
{
  sliders = carpeGetElementsByClass(carpeSliderClassName) // Find the horizontal sliders.
  for (i = 0; i < sliders.length; i++) {
    sliders[i].onmousedown = slide // Attach event listener.
  }
  displays = carpeGetElementsByClass(carpeSliderDisplayClassName) // Find the displays.
  for (i = 0; i < displays.length; i++) {
    displays[i].onfocus = focusDisplay // Attach event listener.
  }
}


