

/******************************************************************************
 *
 * Purpose: common JS util functions
 * Author:  Armin Burger
 *
 ******************************************************************************
 *
 * Copyright (c) 2003-2006 Armin Burger
 *
 * This file is part of p.mapper.
 *
 * p.mapper is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version. See the COPYING file.
 *
 * p.mapper is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with p.mapper; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 ******************************************************************************/

/**
 * inArray function
 * Returns true if the passed value is found in the
 * array.  Returns false if it is not.
 * Usage: if (myList.inArray('search term')) {
 */
Array.prototype.inArray = function (value)
{
    var i;
    for (i=0; i < this.length; i++) {
        // Matches identical (===), not just similar (==).
        if (this[i] === value) {
            return true;
        }
    }
    return false;
};


/*  Prototype JavaScript framework, version 1.4.0
 *  (c) 2005 Sam Stephenson <sam@conio.net>
 *
 *  Prototype is freely distributable under the terms of an MIT-style license.
 *  For details, see the Prototype web site: http://prototype.conio.net/
/*--------------------------------------------------------------------------*/
function _$() {
    var elements = new Array();

    for (var i = 0; i < arguments.length; i++) {
        var element = arguments[i];
        if (typeof element == 'string')
            element = document.getElementById(element);

        if (arguments.length == 1)
            return element;

        elements.push(element);
    }

    return elements;
}


/**
 * DOM generic functions
 */
function objL(obj) {
    return parseInt(obj.style.left || obj.offsetLeft);
}

function objT(obj) {
    return parseInt(obj.style.top || obj.offsetTop);
}

function objW(obj) {
	return parseInt( obj.style.width || obj.clientWidth );
}

function objH(obj) {
    return parseInt( obj.style.height || obj.clientHeight);
}

function hideObj(obj) {
    obj.style.visibility = 'hidden';
}

function showObj(obj) {
    obj.style.visibility = 'visible';
}

/**
 * Substitution for .innerHTML = ...
 */
function setInnerHTML(elementId , html){
    var el = _$('toc');
    el.innerHTML = html;
    evalInnerJS(el);
}

function evalInnerJS(element) {
    var scripts = element.getElementsByTagName('script');
    var code;
    for (var i = 0; i < scripts.length; i++) {
        code =  scripts[i].innerHTML ? scripts[i].innerHTML :
            scripts[i].text ? scripts[i].text :
            scripts[i].textContent;
        try {
            eval(code);
        } catch(e) {
            alert(e);
        }
    }
}


/**
* Custom temporary layers functions
* type can be: POINT, POLYGON, LINE, RASTER
*/

function addTemporaryLayer(path, title, type){
    $.ajax({
        url: PM_XAJAX_LOCATION + 'x_addtemporary.php',
        type : 'POST',
        data : 'path=' + path + '&title=' + title + '&type=' + type,
        dataType: "json",
        success: function(response){
            if(response.error){
                alert(response.error);
            } else {
                //Add layer so it's switched on
                PMap.defGroupList.push('ginput_' + response.layer_name);
                var mapurl = PM_XAJAX_LOCATION + 'x_load.php?'+SID;
                showloading();
                updateMap(mapurl, '');
                updateToc(PM_XAJAX_LOCATION + 'x_toc.php'+SID);
            }
        }
    });
}


function rmTemporaryLayer(path){
    $.ajax({
        url: PM_XAJAX_LOCATION + 'x_rmtemporary.php',
        type : 'POST',
        data : 'path=' + path,
        dataType: "json",
        success: function(response){
            if(response.error){
                alert(response.error);
            } else {
                //Rm layer so it's switched on
                PMap.defGroupList.splice(PMap.defGroupList.indexOf('ginput_' + response.layer_name), 1);
                var mapurl = PM_XAJAX_LOCATION + 'x_load.php?'+SID;
                showloading();
                updateMap(mapurl, '');
                updateToc(PM_XAJAX_LOCATION + 'x_toc.php'+SID);
            }
        }
    });
}

// ABP: jquery wrappers for left/right attrs etc

jQuery.fn.left = function(v){
    try{$(this).css('left', v);} catch(e){};
    return this;
}
jQuery.fn.top = function(v){
    try{$(this).css('top', v);} catch(e){};
    return this;
}
jQuery.fn.right = function(v){
    try{$(this).css('right', v);} catch(e){};
    return this;
}
jQuery.fn.bottom = function(v){
    try{$(this).css('bottom', v);} catch(e){};
    return this;
}
jQuery.fn.src = function(v){
    try{$(this).attr('src', v);} catch(e){};
    return this;
}
jQuery.fn.id = function(){
    return $(this).attr('id');
}
/*--------------------------------------------------|
| dTree 2.05 | www.destroydrop.com/javascript/tree/ |
|---------------------------------------------------|
| Copyright (c) 2002-2003 Geir Landrö               |
|                                                   |
| This script can be used freely as long as all     |
| copyright messages are intact.                    |
|                                                   |
| Updated: 17.04.2003                               |
|--------------------------------------------------*/

/*

 Modifications for use with p.mapper by Armin Burger

*/


// Node object
function Node(id, pid, name, url, title, target, icon, iconOpen, open, value, sl_value, checktype) {
	this.id = id;
	this.pid = pid;
	this.name = name;
	this.url = url;
	this.title = title;
	this.target = target;
	this.icon = icon;
	this.iconOpen = iconOpen;
    this.value = value;
    this.sl_value = sl_value;
    this.checktype = checktype;

	this._io = open || false;
	this._is = false;
	this._ls = false;
	this._hc = false;
	this._ai = 0;
	this._p;
};



// Tree object
function dTree(objName) {
	this.config = {
		target			: null,
		folderLinks		: true,
		useSelection	: true,
		useCookies		: true,
		useLines		: true,
		useIcons		: false,
		useStatusText	: false,
		closeSameLevel	: false,
		inOrder			: false,
        wmsdlg  	    : false
	};

    //var imgBasePath = (this.config.wmsdlg ? '../' : '');
    var imgBasePath =  '';
    //alert(this.config.useIcons);
	
    this.icon = {
        root			: imgBasePath + 'images/tree/layers.gif',
		//folder			: imgBasePath + 'images/tree/folder.gif',
		//folderOpen	    : imgBasePath + 'images/tree/folderopen.gif',
        folder			: imgBasePath + 'images/dtree/layers.gif',
		folderOpen	    : imgBasePath + 'images/dtree/layers.gif',
		//node			: imgBasePath + 'images/dtree/page.gif',
        node			: imgBasePath + 'images/dtree/layers.gif',
		empty			: imgBasePath + 'images/dtree/empty.gif',
		line			: imgBasePath + 'images/dtree/line.gif',
		join			: imgBasePath + 'images/dtree/join.gif',
		joinBottom	    : imgBasePath + 'images/dtree/joinbottom.gif',
		plus			: imgBasePath + 'images/dtree/plus.gif',
		plusBottom	    : imgBasePath + 'images/dtree/plusbottom.gif',
		minus			: imgBasePath + 'images/dtree/minus.gif',
		minusBottom	    : imgBasePath + 'images/dtree/minusbottom.gif',
		nlPlus			: imgBasePath + 'images/dtree/nolines_plus.gif',
		nlMinus			: imgBasePath + 'images/dtree/nolines_minus.gif'
	};

	this.obj = objName;
	this.aNodes = [];
	this.aIndent = [];
	this.root = new Node(-1);
	this.selectedNode = null;
	this.selectedFound = false;
	this.completed = false;
};



// Adds a new node to the node array
dTree.prototype.add = function(id, pid, name, url, title, target, icon, iconOpen, open, value, sl_value, checktype) {
	this.aNodes[this.aNodes.length] = new Node(id, pid, name, url, title, target, icon, iconOpen, open, value, sl_value, checktype);
};



// Open/close all nodes
dTree.prototype.openAll = function() {
	this.oAll(true);
};

dTree.prototype.closeAll = function() {
	this.oAll(false);
};



// Outputs the tree to the page
dTree.prototype.toString = function() {
	var str = '<div class="dtree">\n';

	if (document.getElementById) {
		if (this.config.useCookies) this.selectedNode = this.getSelected();
		str += this.addNode(this.root);
	} else str += 'Browser not supported.';

	str += '</div>';
	
    if (!this.selectedFound) this.selectedNode = null;
	this.completed = true;
	
    return str;
};



// Creates the tree structure

dTree.prototype.addNode = function(pNode) {
	var str = '';
	var n=0;
	if (this.config.inOrder) n = pNode._ai;

	for (n; n<this.aNodes.length; n++) {
		if (this.aNodes[n].pid == pNode.id) {
			var cn = this.aNodes[n];
			cn._p = pNode;
			cn._ai = n;
			this.setCS(cn);
			
            if (!cn.target && this.config.target) cn.target = this.config.target;
			if (cn._hc && !cn._io && this.config.useCookies) cn._io = this.isOpen(cn.id);
			if (!this.config.folderLinks && cn._hc) cn.url = null;
			if (this.config.useSelection && cn.id == this.selectedNode && !this.selectedFound) {
					cn._is = true;
					this.selectedNode = n;
					this.selectedFound = true;
			}

			str += this.node(cn, n);

			if (cn._ls) break;
		}
	}

	return str;
};



// Creates the node icon, url and text

dTree.prototype.node = function(node, nodeId) {
	var str = '<div class="dTreeNode">' + this.indent(node, nodeId);
    
    
    //--------------------------------------------------------------------------------------------------------------------------
    
    // Checkbox and radio button
    if (node.checktype == 1 || node.checktype == 1.1) {
        if (node.value.match(/default/)  || node.checktype == 1.1) {
            var chckd = ' checked ';
        } else {
            var chckd = '';
        }
        str += '<input type="radio" value="' + node.value + '" name="' + node.sl_value + '" ' + chckd + '>';
    } else if (node.checktype == 2) {
        if (node.id > 0) {
            var cbxName = (this.config.wmsdlg ? 'wmslayers' : 'groups');
            str += '<input type="checkbox" value="' + node.value + '" name="' + cbxName + '" id="laycbx_' + node.value + '"  onClick="javascript:setlayers()">';
        }
    }
    
    //--------------------------------------------------------------------------------------------------------------------------
    
    
	if (this.config.useIcons) {
		if (!node.icon) node.icon = (this.root.id == node.pid) ? this.icon.root : ((node._hc) ? this.icon.folder : this.icon.node);
		if (!node.iconOpen) node.iconOpen = (node._hc) ? this.icon.folderOpen : this.icon.node;
		if (this.root.id == node.pid) {
			node.icon = this.icon.root;
			node.iconOpen = this.icon.root;
		}

		str += '<img id="i' + this.obj + nodeId + '" src="' + ((node._io) ? node.iconOpen : node.icon) + '" alt="" />';
	} else {
        if (node.icon)
            str += '<img id="i' + this.obj + nodeId + '" src="' +  node.icon + '" alt="" />';
    }

	if (node.url) {
		//str += '<a id="s' + this.obj + nodeId + '" class="' + ((this.config.useSelection) ? ((node._is ? 'nodeSel' : 'node')) : 'node') + '" href="' + node.url + '"';
        str += '<a id="s' + this.obj + nodeId + '" class="nodeurl" href="' + node.url + '"';

		if (node.title) str += ' title="' + node.title + '"';
		if (node.target) str += ' target="' + node.target + '"';
		if (this.config.useStatusText) str += ' onmouseover="window.status=\'' + node.name + '\';return true;" onmouseout="window.status=\'\';return true;" ';
		if (this.config.useSelection && ((node._hc && this.config.folderLinks) || !node._hc))
			str += ' onclick="javascript: ' + this.obj + '.s(' + nodeId + ');"';

		str += '>';
	}

	else if ((!this.config.folderLinks || !node.url) && node._hc && node.pid != this.root.id)
		str += '<a href="javascript: ' + this.obj + '.o(' + nodeId + ');" class="node">';
	
    // -------------------------------------------------------------------------
    // SPANs for the group name
    str += '<span id="sp_' + node.value + '"><span ';
    if (node.pid == 0)  str += 'class="maingrp"';
    str += '>' + node.name + '</span></span>';
    
    // -------------------------------------------------------------------------
    
    
	if (node.url || ((!this.config.folderLinks || !node.url) && node._hc)) str += '</a>';

	str += '</div>';

	if (node._hc) {
		str += '<div id="d' + this.obj + nodeId + '" class="clip" style="display:' + ((this.root.id == node.pid || node._io) ? 'block' : 'none') + ';">';
		str += this.addNode(node);
		str += '</div>';
    }

	this.aIndent.pop();

	return str;
};


// Adds the empty and line icons
dTree.prototype.indent = function(node, nodeId) {
	var str = '';
	if (this.root.id != node.pid) {
		for (var n=0; n<this.aIndent.length; n++)
			str += '<img src="' + ( (this.aIndent[n] == 1 && this.config.useLines) ? this.icon.line : this.icon.empty ) + '" alt="" />';

		(node._ls) ? this.aIndent.push(0) : this.aIndent.push(1);

		if (node._hc) {
			str += '<a href="javascript: ' + this.obj + '.o(' + nodeId + ');"><img id="j' + this.obj + nodeId + '" src="';

			if (!this.config.useLines) str += (node._io) ? this.icon.nlMinus : this.icon.nlPlus;

			else str += ( (node._io) ? ((node._ls && this.config.useLines) ? this.icon.minusBottom : this.icon.minus) : ((node._ls && this.config.useLines) ? this.icon.plusBottom : this.icon.plus ) );

			str += '" alt="" /></a>';

		} else str += '<img src="' + ( (this.config.useLines) ? ((node._ls) ? this.icon.joinBottom : this.icon.join ) : this.icon.empty) + '" alt="" />';
	}

	return str;

};



// Checks if a node has any children and if it is the last sibling

dTree.prototype.setCS = function(node) {
	var lastId;
	for (var n=0; n<this.aNodes.length; n++) {
		if (this.aNodes[n].pid == node.id) node._hc = true;
		if (this.aNodes[n].pid == node.pid) lastId = this.aNodes[n].id;
	}
	if (lastId==node.id) node._ls = true;

};



// Returns the selected node
dTree.prototype.getSelected = function() {
	var sn = this.getCookie('cs' + this.obj);
	return (sn) ? sn : null;
};



// Highlights the selected node
dTree.prototype.s = function(id) {
	if (!this.config.useSelection) return;
	var cn = this.aNodes[id];
	if (cn._hc && !this.config.folderLinks) return;
	if (this.selectedNode != id) {
		/*if (this.selectedNode || this.selectedNode==0) {
                eOld = document.getElementById("s" + this.obj + this.selectedNode);
			    eOld.className = "node";
		}

		eNew = document.getElementById("s" + this.obj + id);
		eNew.className = "nodeSel";
        */
		this.selectedNode = id;
		if (this.config.useCookies) this.setCookie('cs' + this.obj, cn.id);
	}
};



// Toggle Open or close
dTree.prototype.o = function(id) {
	var cn = this.aNodes[id];
	this.nodeStatus(!cn._io, id, cn._ls);
	cn._io = !cn._io;
	if (this.config.closeSameLevel) this.closeLevel(cn);
	if (this.config.useCookies) this.updateCookie();
};



// Open or close all nodes
dTree.prototype.oAll = function(status) {
	for (var n=0; n<this.aNodes.length; n++) {
		if (this.aNodes[n]._hc && this.aNodes[n].pid != this.root.id) {
			this.nodeStatus(status, n, this.aNodes[n]._ls);
			this.aNodes[n]._io = status;
		}
	}
	if (this.config.useCookies) this.updateCookie();
};



// Opens the tree to a specific node
dTree.prototype.openTo = function(nId, bSelect, bFirst) {
	if (!bFirst) {
		for (var n=0; n<this.aNodes.length; n++) {
			if (this.aNodes[n].id == nId) {
				nId=n;
				break;
			}
		}
	}

	var cn=this.aNodes[nId];
	if (cn.pid==this.root.id || !cn._p) return;
	cn._io = true;
	cn._is = bSelect;
	if (this.completed && cn._hc) this.nodeStatus(true, cn._ai, cn._ls);
	if (this.completed && bSelect) this.s(cn._ai);
	else if (bSelect) this._sn=cn._ai;
	this.openTo(cn._p._ai, false, true);
};



// Closes all nodes on the same level as certain node

dTree.prototype.closeLevel = function(node) {
	for (var n=0; n<this.aNodes.length; n++) {
		if (this.aNodes[n].pid == node.pid && this.aNodes[n].id != node.id && this.aNodes[n]._hc) {
			this.nodeStatus(false, n, this.aNodes[n]._ls);
			this.aNodes[n]._io = false;
			this.closeAllChildren(this.aNodes[n]);
		}
	}
}



// Closes all children of a node
dTree.prototype.closeAllChildren = function(node) {
	for (var n=0; n<this.aNodes.length; n++) {
		if (this.aNodes[n].pid == node.id && this.aNodes[n]._hc) {
			if (this.aNodes[n]._io) this.nodeStatus(false, n, this.aNodes[n]._ls);
			this.aNodes[n]._io = false;
			this.closeAllChildren(this.aNodes[n]);		
		}
	}
}



// Change the status of a node(open or closed)

dTree.prototype.nodeStatus = function(status, id, bottom) {
	eDiv	= document.getElementById('d' + this.obj + id);
	eJoin	= document.getElementById('j' + this.obj + id);
	if (this.config.useIcons) {
		eIcon	= document.getElementById('i' + this.obj + id);
		eIcon.src = (status) ? this.aNodes[id].iconOpen : this.aNodes[id].icon;
	}

	eJoin.src = (this.config.useLines)?
	((status)?((bottom)?this.icon.minusBottom:this.icon.minus):((bottom)?this.icon.plusBottom:this.icon.plus)):
	((status)?this.icon.nlMinus:this.icon.nlPlus);
	eDiv.style.display = (status) ? 'block': 'none';
};




// [Cookie] Clears a cookie
dTree.prototype.clearCookie = function() {
	var now = new Date();
	var yesterday = new Date(now.getTime() - 1000 * 60 * 60 * 24);
	this.setCookie('co'+this.obj, 'cookieValue', yesterday);
	this.setCookie('cs'+this.obj, 'cookieValue', yesterday);
};



// [Cookie] Sets value in a cookie
dTree.prototype.setCookie = function(cookieName, cookieValue, expires, path, domain, secure) {
	document.cookie =
		escape(cookieName) + '=' + escape(cookieValue)
		+ (expires ? '; expires=' + expires.toGMTString() : '')
		+ (path ? '; path=' + path : '')
		+ (domain ? '; domain=' + domain : '')
		+ (secure ? '; secure' : '');
};



// [Cookie] Gets a value from a cookie
dTree.prototype.getCookie = function(cookieName) {
	var cookieValue = '';
	var posName = document.cookie.indexOf(escape(cookieName) + '=');
	if (posName != -1) {
		var posValue = posName + (escape(cookieName) + '=').length;
		var endPos = document.cookie.indexOf(';', posValue);
		if (endPos != -1) cookieValue = unescape(document.cookie.substring(posValue, endPos));
		else cookieValue = unescape(document.cookie.substring(posValue));
	}

	return (cookieValue);
};



// [Cookie] Returns ids of open nodes as a string
dTree.prototype.updateCookie = function() {
	var str = '';
	for (var n=0; n<this.aNodes.length; n++) {
		if (this.aNodes[n]._io && this.aNodes[n].pid != this.root.id) {
			if (str) str += '.';
			str += this.aNodes[n].id;
		}
	}

	this.setCookie('co' + this.obj, str);
};



// [Cookie] Checks if a node id is in a cookie
dTree.prototype.isOpen = function(id) {
	var aOpen = this.getCookie('co' + this.obj).split('.');
	for (var n=0; n<aOpen.length; n++)
		if (aOpen[n] == id) return true;
	return false;
};



// If Push and pop is not implemented by the browser
if (!Array.prototype.push) {
	Array.prototype.push = function array_push() {
		for(var i=0;i<arguments.length;i++)
			this[this.length]=arguments[i];
		return this.length;
	}
};

if (!Array.prototype.pop) {
	Array.prototype.pop = function array_pop() {
		lastElement = this[this.length-1];
		this.length = Math.max(this.length-1,0);
		return lastElement;
	}
};




//-----------------------------------------------------------------------









//-----------------------------------------------------------------------



/*****************************************************************************
 *
 * Purpose: Functions for forms and scale selection list
 * Author:  Armin Burger
 *
 *****************************************************************************
 *
 * Copyright (c) 2003-2006 Armin Burger
 *
 * This file is part of p.mapper.
 *
 * p.mapper is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version. See the COPYING file.
 *
 * p.mapper is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with p.mapper; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 ******************************************************************************/


var scale_timeout;

function initScaleSelect() {
    try {
        writeScaleList(scaleSelectList);
    } catch(e) {
        return false;
    }
}

function writeScaleList(scaleList) {
    var scaleListLen = scaleList.length;
    
    // If no scales defined don't use select function
    if (scaleListLen < 1) return false;
    
    var sobj = $('#scale_suggest');
    sobj.showv();
    sobj.html('');

    var suggest_all = '';
    for(i=0; i < scaleListLen ; i++) {
        var sclink = i<1?'scale_link_over':'scale_link';
        var suggest = '<div onmouseover="javascript:scaleOver(this);" ';
        suggest += 'onmouseout="javascript:scaleOut(this);" ';
        suggest += 'onclick="insertScaleTxt(this.innerHTML);" ';
        suggest += 'class="' + sclink + '">' + scaleList[i] + '</div>';
        suggest_all += suggest;
    }
    sobj.html(suggest_all);
}

function insertScaleTxt(value) {
    var newScale = value.replace(/,|'|\.|\s/g, '');
    $('#scaleinput').val(newScale);
    $('#scale_suggest').html('');
    hideScaleSuggest();
    zoom2scale(newScale);
}

function scaleOver(div_value) {
    div_value.className = 'scale_link_over';
}


function scaleOut(div_value) {
    div_value.className = 'scale_link';
}

function scaleMouseOut(force) {
    var sobj = _$('scale_suggest');
    var scaleDivList = sobj.getElementsByTagName('DIV');
    var hlStyle = false;

    for (var i=0; i<scaleDivList.length; i++) {
        if (scaleDivList[i].className == 'scale_link_over') {
            hlStyle = true;
        }
    }
    
    if (force) {
        setTimeout("hideScaleSuggest()", 500);
        //return false;
    } else {
    
        clearTimeout(scale_timeout);
        if (hlStyle) {
            
        } else {
            scale_timeout = setTimeout("hideScaleSuggest()", 500);
        }
    }
}


function hideScaleSuggest() { 
    $('#scale_suggest').hidev();
}

function setScaleMO() {
    scale_mouseover = true;
}

/******************************************************************************
 *
 * Purpose: Geometry library for measurements and digitizing
 * Author:  Federico Nieri, Commune di Prato
 *
 ******************************************************************************
 *
 * Copyright (c) 2006 Federico Nieri
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version. See the COPYING file.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 ******************************************************************************/



/**************************************/
/*************   POINT   **************/
/**************************************/

/**
 * Point constructor
 * @param x: x coordinate
 * @param y: y coordinate
 */
function Point(x,y){
	this.x = parseFloat(x);
	this.y = parseFloat(y);
}

/**
 * Overriting of the standard toString Object method.
 * @param xySeparator: chars separating x coordinate from y coordinate of a point. Default " ".
 * @return a string that is the sequence of the point coordinates
 *
 * Example:
 * var p = new Point(1,2);
 * p.toString();    // return "1 2"
 * p.toString("|"); // return "1|2"
 */
Point.prototype.toString = function(xySeparator){
	xySeparator = !xySeparator ? " " : ("" + xySeparator);
	return (this.x + xySeparator + this.y);
}

/**
 * Return true if this point has the same coordinates of the passed point
 * @param otherPoint: Point object to compare
 */
Point.prototype.equals = function(otherPoint){
	return (this.x == otherPoint.x && this.y == otherPoint.y);
}

/**************************************/
/*************    LINE    *************/
/**************************************/

/**
 * Line constructor
 * @param firstPoint:  first Point objetc
 * @param secondPoint: second Point objetc
 */
function Line(firstPoint,secondPoint){

	this.firstPoint = firstPoint;
	this.secondPoint = secondPoint;

	// y = a x + b;
	if(secondPoint.x == firstPoint.x){
	  // x = b;
    this.a = (secondPoint.y - firstPoint.y)<0 ? Number.NEGATIVE_INFINITE : Number.POSITIVE_INFINITE;
    this.b =  firstPoint.x;
    this.vertical = true;
  }else{
    this.a = (secondPoint.y - firstPoint.y)/(secondPoint.x-firstPoint.x);
    this.b = firstPoint.y - this.a * firstPoint.x;
    this.vertical = false;
  }

}

/**
 * Return true if this line has defining points with same coordinates of those
 * defining the passed line
 * @param otherPoint: Line object to compare
 */
Line.prototype.equals = function(otherLine){
	return (this.getFirstPoint().equals(otherLine.getFirstPoint()) && this.getSecondPoint().equals(otherLine.getSecondPoint()));
}

/**
 * Return the length of the line (distance from first point to second point)
 */
Line.prototype.getLength = function(){
	return Math.sqrt((Math.pow(this.secondPoint.x - this.firstPoint.x, 2)) + (Math.pow(this.secondPoint.y - this.firstPoint.y, 2)));
}

/**
 * Return the first Point object of the line
 */
Line.prototype.getFirstPoint = function(){
	return this.firstPoint;
}

/**
 * Return the second Point object of the line
 */
Line.prototype.getSecondPoint = function(){
	return this.secondPoint;
}

/*
 * Return true if the line is vertical
 */
Line.prototype.isVertical = function(){
  return this.vertical;
}

/*
 * Return true if the line is parallel to the line passed
 * @param otherLine: Line object to compare
 */
Line.prototype.isParallel = function(otherLine){
  return (otherLine.isVertical() && this.isVertical()) || (Math.abs(otherLine.a) == Math.abs(this.a));
}

/*
 * Return the Point object of intesection if found, null otherwise
 * @param otherLine: Line object to check for the intersection
 */
Line.prototype.intersection = function(otherLine){

  if(this.isParallel(otherLine)) return null;

  var xInt;
  var yInt;

  if(this.isVertical()){
    xInt = this.getFirstPoint().x;
    yInt = (otherLine.a * xInt) + otherLine.b;
  }else if(otherLine.isVertical()){
    xInt = otherLine.getFirstPoint().x;
    yInt = (this.a * xInt) + this.b;
  }else{
    xInt = (this.b - otherLine.b) / (otherLine.a - this.a);
    yInt = (this.a * xInt) + this.b;
  }

  if( ! (xInt >= Math.min(this.getFirstPoint().x,this.getSecondPoint().x) && xInt <= Math.max(this.getFirstPoint().x,this.getSecondPoint().x) && xInt >= Math.min(otherLine.getFirstPoint().x,otherLine.getSecondPoint().x) && xInt <= Math.max(otherLine.getFirstPoint().x,otherLine.getSecondPoint().x)))
    return null;

  if( ! (yInt >= Math.min(this.getFirstPoint().y,this.getSecondPoint().y) && yInt <= Math.max(this.getFirstPoint().y,this.getSecondPoint().y) && yInt >= Math.min(otherLine.getFirstPoint().y,otherLine.getSecondPoint().y) && yInt <= Math.max(otherLine.getFirstPoint().y,otherLine.getSecondPoint().y)))
    return null;

  return new Point(xInt,yInt);
}

/**
 * Overriting of the standard toString Object method.
 * @param xySeparator: chars separating x coordinate from y coordinate of a point. Default " ".
 * @param ptSeparator: chars separating first point coordinates from second point coordinates. Default ",".
 * @return a string that is the sequence of the first point coordinates and the second point coordinates
 *
 * Example:
 * var p1 = new Point(1,2);
 * var p2 = new Point(3,4);
 * var ln = new Line(p1,p2);
 * ln.toString();         // return "1 2,3 4"
 * ln.toString("|","-");  // return "1|2-3|4"
 * var s = "" + ln;       // s = "1 2,3 4"
 */
Line.prototype.toString = function(xySeparator, ptSeparator){

	if(!xySeparator) xySeparator=" ";
	if(!ptSeparator) ptSeparator=",";

	return (this.firstPoint.toString() + ptSeparator + this.secondPoint.toString());
}

/***************************************/
/******   POLYGON (POLYLINE)  **********/
/***************************************/

/**
 * Polygon constructor
 * @param points: array of Point objects (vertexes of polygon)
 */
function Polygon(points){
	this.setPoints(points);
}

/**
 * Return the area of the polyon. If the polyline is not closed or the number of
 * points is less than 4 (closed triangol) the returned value is 0.
 */
Polygon.prototype.getArea = function(){

	if(!this.isClosed()) {
	   //alert('Polygon is not closed');
	   return 0;
	}

	var points = this.getPoints();

	if(points.length < 4) return 0;

    var area = 0;
    for(var k=0; k < (points.length-1) ; k++) {
       area += (( points[k+1].x - points[k].x ) * ( points[k+1].y + points[k].y ));
    }
    area = area / 2;
    return area;

}

/**
 * Return the length of the polyline (perimeter of polygon).
 */
Polygon.prototype.getPerimeter = function(){

	var nSides = this.getSidesNumber();
	var perimeter = 0;

    for(var n = 1; n <= nSides ; n++) {
       perimeter += this.getSideLength(n);
    }

    return perimeter;
}

/**
 * Return an array containing all the points of the polyline
 */
Polygon.prototype.getPoints = function(){
	var tmpPoints = new Array();
	for(var i = 0 ; i < this.points.length; i++){
		tmpPoints[i] = this.points[i];
	}
	return tmpPoints;
}

/**
 * Return the point specified. Indexes start from 0.
 * @param index: index of the point in the list
 */
Polygon.prototype.getPoint = function(index){
	return this.points[index];
}

/**
 * Set the array of points defining the polyline
 * @param points: array of Point objects
 */
Polygon.prototype.setPoints = function(points){
	if(points && points instanceof Array){
		this.points = points;
	}else{
		this.points = new Array();
	}
}

/**
 * Add a point a the end of the polyline
 * @param point: Point object
 */
Polygon.prototype.addPoint = function(point){
	this.points.push(point);
}

/**
 * Return the number of points of the polyline
 */
Polygon.prototype.getPointsNumber = function(){
	return this.points.length;
}

/**
 * Return the number of sides
 */
Polygon.prototype.getSidesNumber = function(){
  if(this.points.length == 0) return 0;
	return this.points.length-1;
}

/**
 * Return an array containing the list of the x coordinate of all points
 */
Polygon.prototype.getXList = function(){
	var xList = new Array();
	for(var i = 0 ; i < this.points.length; i++){
		xList[i] = this.points[i].x;
	}
	return xList;
}

/**
 * Return an array containing the list of the y coordinate of all points
 */
Polygon.prototype.getYList = function(){
	var yList = new Array();
	for(var i = 0 ; i < this.points.length; i++){
		yList[i] = this.points[i].y;
	}
	return yList;
}

/**
 * Delete the point specified by index
 * @param index: index of the point to delete
 */
Polygon.prototype.delPoint = function(index){
	this.points.splice(index,1);
}

/**
 * Close the polyline, to obtain a polygon, if this isn't closed yet.
 * A polyline is closed if the last point is equals to the first one.
 */
Polygon.prototype.close = function(){
	if(!this.isClosed()){
		this.addPoint(this.getPoint(0));
	}
}

/**
 * Return true if the last point is equals to the first one,
 * false otherwise.
 */
Polygon.prototype.isClosed = function(){
	var points = this.getPoints();
	return (points.length>2 && points[0].equals(points[points.length-1]));
}

/* resituisce la lunghezza del lato indicato.
   Il numero dei lati comincia dal lato 1 */
Polygon.prototype.getSideLength = function(sideNumber){
	return Math.sqrt((Math.pow(this.points[sideNumber].x - this.points[sideNumber-1].x, 2)) + (Math.pow(this.points[sideNumber].y - this.points[sideNumber-1].y, 2)));
}

/**
 * Return a Line object that is the last side of the polyline
 * Indexes start from 1
 * @param sideNumber: index of the sides
 */
Polygon.prototype.getSide = function(sideNumber){
	if(sideNumber==0) return null;
	if(sideNumber > this.getSidesNumber()) return null;

	return new Line(this.getPoint(sideNumber-1),this.getPoint(sideNumber));
}

/**
 * Return the last Line object of the polyline
 */
Polygon.prototype.getLastSide = function(){
	return this.getSide(this.getSidesNumber());
}

/**
 * Return the first Line object of the polyline
 */
Polygon.prototype.getFirstSide = function(){
	return this.getSide(1);
}

/**
 * Reset the array of points defining the polyline
 */
Polygon.prototype.reset = function(){
	this.points.length = 0;
}


/**
 * Overriting of the standard toString Object method.
 * @param xySeparator: chars separating x coordinate from y coordinate of a point. Default " ".
 * @param ptSeparator: chars separating points coordinates from one to another. Default ",".
 * @return a string that is the sequence of points coordinates of the polyline
 *
 * Example:
 * var p1 = new Point(1,2);
 * var p2 = new Point(3,4);
 * var p3 = new Point(5,6);
 * var points = new Array(p1,p2,p3);
 * var poly = new Polygon(points);
 *
 * poly.toString();       // return "1 2,3 4,5 6"
 * poly.toString("|","-");  // return "1|2-3|4-5|6"
 * var s = "" + poly;       // s = "1 2,3 4,5 6"
 */
Polygon.prototype.toString = function(xySeparator, ptSeparator){

	if(!xySeparator) xySeparator=" ";
	if(!ptSeparator) ptSeparator=",";

	var pointsString = "";
	var points = this.getPoints();

	for(var i = 0; i < points.length; i++){
		pointsString += points[i].toString(xySeparator);
		if(i < (points.length-1)){
			pointsString += ptSeparator;
		}
	}
	return pointsString;
}



/*
var p1 = new Point(1,1); // 1
var p2 = new Point(4,4); // 2
var p3 = new Point(3,6); // 1
var p4 = new Point(3,0); // 2
//var p5 = new Point(4,0); // 3

var l1 = new Line(p1,p2);
var l2 = new Line(p3,p4);
//var l3 = new Line(p4,p5);

//alert("l1 is vertical = " + l1.isVertical());
//alert("l2 is vertical = " + l2.isVertical());

//alert("l1 is parallel to l2 = " + l1.isParallel(l2));

alert("intersect = " + l1.intersection(l2));
*/

//var pol = new Polygon([p1,p2,p3]);
/*
alert(" p1 uguale a p2 ? "+p1.equals(p2));
alert(" p1 uguale a p3 ? "+p1.equals(p3));
alert(" l1 uguale a l2 ? "+l1.equals(l2));
alert(" l1 uguale a l3 ? "+l1.equals(l3));
alert(" l1.toString() = "+l1.toString());
alert(" pol.toString('_','|') = "+pol.toString("_","|"));
*/

/*
var points = new Array();

points[0] = p1;
points[1] = p2;
points[2] = p3;

var pol = new Polygon();

pol.addPoint(p1);
pol.addPoint(p2);
pol.addPoint(p3);

alert("1 - is closed : ("+pol+") " + pol.isClosed());

alert("1 - Area = " + pol.getArea());
pol.close();

alert("2 - is closed : ("+pol+") " + pol.isClosed());
alert("2 - Area  = " + pol.getArea());
alert("2 - Perim = " + pol.getPerimeter());

*/

/******************************************************************************
 *
 * Purpose: sets the layout parameters (width/height, left/top) of the GUI
 * Author:  Armin Burger
 *
 ******************************************************************************
 *
 * Copyright (c) 2003-2006 Armin Burger
 *
 * This file is part of p.mapper.
 *
 * p.mapper is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version. See the COPYING file.
 *
 * p.mapper is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with p.mapper; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 ******************************************************************************/


function pmLayout_init() {
    Layout.update();
    //if ($.browser.mozilla)
    tocResizeUpdate();
}



function PM_Layout()
{

}


PM_Layout.prototype.update = function ()
{

    // Browser window inner dimensions
    var winix = 0, winiy = 0;
    if ( typeof( window.innerWidth ) == 'number' ) {
        //Non-IE
        winix = window.innerWidth;
        winiy = window.innerHeight;
    } else if( document.documentElement && ( document.documentElement.clientWidth || document.documentElement.clientHeight ) ) {
        //IE 6+ in 'standards compliant mode'
        winix = parseInt(document.documentElement.clientWidth);
        winiy = parseInt(document.documentElement.clientHeight);
    } else if( document.body && ( document.body.clientWidth || document.body.clientHeight ) ) {
        //IE 4 compatible
        winix = document.body.clientWidth;
        winiy = document.body.clientHeight;
    }


    if (_$('pm_master')) {
        var pm_master = $('#pm_master');
        if (this.MasterResize) {
            var masterW = winix - (this.MasterLeft + this.MasterMarginE);
            var masterH = winiy - (this.MasterTop + this.MasterMarginS);
        } else {
            var masterW = this.MasterWidth;
            var masterH = this.MasterHeight;
        }

        this.setParams(pm_master, this.MasterLeft, this.MasterTop, masterW, masterH);
    } else {
        var masterW = winix;
        var masterH = winiy;
    }


    var north = $('#north');
    var south = $('#south');
    var west  = $('#west');
    var east  = $('#east');

    var mapZone  = $('#mapZone');
    var map      = $('#map');
    var mapNorth = $('#mapNorth');
    var mapSouth = $('#mapSouth');
    var mapWest  = $('#mapWest');
    var mapEast  = $('#mapEast');

    var mapimgLayer = $('#mapimgLayer');
    var mapImg      = $('#mapImg');

    var loading = $('#loading');

    var refZone  = $('#refZone');
    var infoZone = $('#infoZone');


    // Get new dimensions and positions
    var innerElemH = masterH - (this.NorthHeight + this.SouthHeight + this.MarginOuterHorizN + this.MarginOuterHorizS);
    var innerElemT = this.NorthHeight + this.MarginOuterHorizN;
    var InfoZoneTotH = this.InfoZoneHeight > 0 ? this.InfoZoneHeight + this.MarginInnerHoriz : 0;

    // ABP: 4 = JQUERY
    var mapZoneH = (this.InfoZoneStyle == 4 ? innerElemH  : innerElemH - InfoZoneTotH);

    var mapZoneW = masterW - (this.MarginOuterVertW + this.MarginOuterVertE + this.MarginInnerVertW + this.MarginInnerVertE  + this.WestWidth + this.EastWidth);
    var mapZoneL = this.MarginOuterVertW + this.WestWidth + this.MarginInnerVertW;

    var mapT = innerElemT + this.MapNorthHeight;
    mapW = mapZoneW - (this.MapWestWidth + this.MapEastWidth);
    mapH = mapZoneH - (this.MapNorthHeight + this.MapSouthHeight);

    var mapWestEastH = this.MapWestEastFull ?  mapZoneH : mapH;
    var mapWestEastT = this.MapWestEastFull ? 0 : this.MapNorthHeight;

    var mapNorthSouthW = this.MapWestEastFull ? mapW : mapZoneW;
    var mapNorthSouthL = this.MapWestEastFull ? this.MapWestWidth : 0;

    var westH = (this.InfoZoneStyle == 1 ? innerElemH : mapZoneH) - (this.RefZoneHorizPos == 'w' ? this.RefZoneHeight + this.MarginInnerHoriz : 0);
    var eastH = (this.InfoZoneStyle == 2 ? innerElemH : mapZoneH) - (this.RefZoneHorizPos == 'e' ? this.RefZoneHeight + this.MarginInnerHoriz : 0);;
    var westT = (this.RefZoneHorizPos == 'w' ? (this.RefZoneVertPos == 'n' ? innerElemT + this.RefZoneHeight + this.MarginInnerHoriz : innerElemT) :  innerElemT);
    var eastT = (this.RefZoneHorizPos == 'e' ? (this.RefZoneVertPos == 'n' ? innerElemT + this.RefZoneHeight + this.MarginInnerHoriz : innerElemT) :  innerElemT);

    var refZoneL = (this.RefZoneHorizPos == 'w' ? this.MarginOuterVertW : mapZoneL + mapZoneW + this.MarginInnerVertE);
    var refZoneT = (this.RefZoneVertPos == 'n' ? innerElemT : (this.RefZoneHorizPos == 'w' ? westT + westH + this.MarginInnerHoriz : eastT + eastH + this.MarginInnerHoriz ));
    var refZoneW = (this.RefZoneHorizPos == 'w' ? this.WestWidth : this.EastWidth);

    if (this.InfoZoneStyle == 1) {
        var infoZoneL = mapZoneL;
        var infoZoneW = mapZoneW + this.MarginInnerVertE + this.EastWidth;
    } else if (this.InfoZoneStyle == 2) {
        var infoZoneL = this.MarginOuterVertW;
        var infoZoneW = this.WestWidth + this.MarginInnerVertW + mapZoneW;
    } else {
        var infoZoneL = this.MarginOuterVertW;
        var infoZoneW = masterW - (this.MarginOuterVertW + this.MarginOuterVertE);
    }


    // Apply new settings to DIV objects
    //   (obj, L, T, W, H)

    this.setParams(north, 0, 0, masterW, this.NorthHeight);
    //this.setParams(south, 0, 0, masterW, this.SouthHeight);
    south.left(0 + 'px');
    south.css('bottom', 0 + 'px');
    south.width(masterW + 'px');
    south.height(this.SouthHeight + 'px');

    this.setParams(west, this.MarginOuterVertW, westT, this.WestWidth, westH);
    this.setParams(east, mapZoneL + mapZoneW + this.MarginInnerVertE, eastT, this.EastWidth, eastH);

    this.setParams(mapZone, mapZoneL, innerElemT, mapZoneW, mapZoneH);
    this.setParams(map, this.MapWestWidth, this.MapNorthHeight, mapW, mapH);
    this.setParams(mapWest, 0, mapWestEastT, this.MapWestWidth, mapWestEastH);
    this.setParams(mapEast, this.MapWestWidth + mapW, mapWestEastT, this.MapEastWidth, mapWestEastH);
    this.setParams(mapNorth, mapNorthSouthL, 0, mapNorthSouthW, this.MapNorthHeight);
    this.setParams(mapSouth, mapNorthSouthL, this.MapNorthHeight + mapH, mapNorthSouthW, this.MapSouthHeight);

    this.setParams(refZone, refZoneL, refZoneT, refZoneW, this.RefZoneHeight);
    // ABP: fade in
    if (this.InfoZoneStyle == 4){
        this.setParams(infoZone, 0, mapZoneH + this.NorthHeight + this.SouthHeight - this.InfoZoneHeight + this.MarginOuterHorizN + this.MarginInnerHoriz , infoZoneW + this.MarginOuterVertE + this.MarginOuterVertW, this.InfoZoneHeight);
    } else {
        this.setParams(infoZone, infoZoneL, mapZoneH + this.NorthHeight + this.MarginOuterHorizN + this.MarginInnerHoriz, infoZoneW, this.InfoZoneHeight);
    }

    this.setParams(mapimgLayer, 0, 0, mapW, mapH);
    this.setParams(mapImg, 0, 0, mapW, mapH);

    var loadimg = _$('loadingimg');
    this.setParams(loading, (mapW/2 - objW(loadimg)/2), (mapH/2 - objH(loadimg)/2), objW(loadimg), objH(loadimg));


    // Update Slider s1
    updateSlider_s1(mapW, mapH) ;

    // RELOAD MAP!!!
    var mapurl = PM_XAJAX_LOCATION + 'x_load.php?'+SID+ '&mapW=' + mapW + '&mapH=' + mapH + '&zoom_type=zoompoint';

    // Timer-controlled resize of map for stupid IE resize event behaviour
    if (navigator.appName.indexOf("Microsoft")!=-1) {
        clearTimeout(PMap.resize_timer);
        PMap.resize_timer = setTimeout("updateMap('" + mapurl + "', '')",500);
    } else {
        updateMap(mapurl, '');
    }

}


PM_Layout.prototype.setParams = function (obj, L, T, W, H)
{
    if (obj) {
        obj.left(L + 'px');
        obj.top(T + 'px');
        obj.width(W + 'px');
        obj.height(H + 'px');

        // hide object if width or height == 0 px
        if (W < 1 || H < 1) obj.hidev();
    }
}

/******************************************************************************
 *
 * Purpose: main interaction with Mapserver specific requests
 *          like zoom, pan, etc.
 * Author:  Armin Burger
 *
 ******************************************************************************
 *
 * Copyright (c) 2003-2006 Armin Burger
 *
 * This file is part of p.mapper.
 *
 * p.mapper is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version. See the COPYING file.
 *
 * p.mapper is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with p.mapper; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 ******************************************************************************/


//********************************************************
// CONFIGURATION
//********************************************************/


// SET TO TRUE IF CURSOR SHALL CHANGE ACCORDING TO ACTIVE TOOL
var useCustomCursor = true;


//******************************************************* //
//         JAVASCRIPT FUNCTIONS FOR ZOOM, QUERY,          //
//******************************************************* //

/* Specifies how far (in pixels) a user needs to drag the mouse
 * to enable zoom to rectangle, otherwise zoom to point.
 * Should be set to >3
 ****************************************************************/
var jitter = 10;


/*****************************************************************************
 * FUNCTION IS CALLED BY ZOOMBOX -> FUNCTION chkMouseUp(e)
 * main function for zoom/pan interface
 * calls different zoom functions (see below)
 *****************************************************************************/
function zoombox_apply(minx, miny, maxx, maxy) {
    var imgbox = minx + "+" + miny + "+" + maxx + "+" + maxy;
    var imgxy  = minx + "+" + miny;

    // NORMAL MOUSE ACTIONS IN MAIN MAP //
    if (refmapClick == false) {

        // ZOOM/PAN ACTIONS
        var varform = _$("varform");
        var vmode = varform.mode.value;

        if (vmode == 'map' || rightMouseButton) {
            showloading();
            // Only click
            if ((minx + jitter) > maxx && (miny + jitter) > maxy) {
                if (varform.zoom_type.value == 'zoomrect') {
                    if (rightMouseButton) {
                        zoom_factor = 1;
                    } else {
                        zoom_factor = 2;
                    }
                    zoompoint(zoom_factor, imgxy);

                } else {
                   // Pan
                   var zoom_factor = varform.zoom_factor.value;
                   zoompoint(zoom_factor, imgxy);
                }

            // Zoombox
            } else {
                zoomin(imgbox);
            }

        // QUERY/IDENTIFY ACTIONS
        // query on all visible groups
        } else if (vmode == 'query') {
            showqueryresult('query', imgxy);
        // query only on selected group with multiselect
        } else if (vmode == 'nquery') {
        	var selform = _$("selform");
            if (!selform.selgroup) return false;
            if (selform.selgroup.selectedIndex != -1) {
                // only with single click
                if ((minx + jitter) > maxx && (miny + jitter) > maxy) {     // x/y point
                    showqueryresult('nquery', imgxy);
                // with zoom box
                } else {
                    showqueryresult('nquery', imgbox);                      // rectangle
                }
            }
        } else if (vmode == 'poi') {
            openPoiDlg(imgxy);
        } else if (vmode == 'resGeoRef') { // ABP:
            resGeoRef(imgxy);
        } else if (vmode == 'getCoordinatesForGeorefPointInput') { // alb:
            getCoordinatesForGeorefPointInput(imgxy);
        } else {
            try {
                eval(vmode + '_start(imgbox)');
                return false;
            } catch(e) {

            }
        }

    // ACTIONS IN REF MAP //
    } else {
        zoomref(imgxy);
    }
}


/**
 * Sample script foir custom actions/modes
 */
function digitize_start(imgxy) {
    openDigitizeDlg(imgxy);
}

/*****************************************************************************
 * ZOOM FUNCTIONS
 *******************/


/*
 * ZOOM TO POINT
 *****************/
function zoompoint(zoomfactor, imgxy) {
    var mapurl = PM_XAJAX_LOCATION + 'x_load.php?'+SID+'&mode=map&zoom_type=zoompoint&zoom_factor='+zoomfactor+'&imgxy='+imgxy;
    showloading();
    updateMap(mapurl, '');
}

/*
 * ZOOM TO RECTANGLE
 ********************/
function zoomin(extent) {
    var mapurl = PM_XAJAX_LOCATION + 'x_load.php?'+SID+'&mode=map&zoom_type=zoomrect&imgbox='+extent  ;
    //alert(mapurl);
    updateMap(mapurl, '');
}

/*
 * ZOOM TO GEO-EXTENT (MAP UNITS), APPLIED FROM INFO PAGE LINK
 ***************************************************************/
function zoom2extent(layer,idx,geoextent) {
    showloading();
    // Check if resultlayers shall be passed
    if (layer == 0 && idx == 0) {                            // no
        var layerstring = '';
    } else {
        var layerstring = '&resultlayer='+layer+'+'+idx;     // yes
    }
    var mapurl = PM_XAJAX_LOCATION + 'x_load.php?'+SID+'&mode=map&zoom_type=zoomextent&extent='+geoextent+layerstring;
    //document.varform.zoomselected.value = '1';
    updateMap(mapurl, '');
}

/*
 * ZOOM TO FULL EXTENT
 **********************/
function zoomfullext() {
    showloading();
    var mapurl = PM_XAJAX_LOCATION + 'x_load.php?'+SID+'&mode=map&zoom_type=zoomfull';
    updateMap(mapurl, '');
}

/*
 * GO BACK TO PEVIOUS EXTENT
 ******************************/
function goback() {
    showloading();
    var mapurl = PM_XAJAX_LOCATION + 'x_load.php?'+SID+'&mode=map&zoom_type=zoomback';
    updateMap(mapurl, '');
}

/*
 * GO FORWARD
 ******************************/
function gofwd() {
    showloading();
    var mapurl = PM_XAJAX_LOCATION + 'x_load.php?'+SID+'&mode=map&zoom_type=zoomfwd';
    updateMap(mapurl, '');
}


// DRAW MAP WITH NEW LAYERS/GROUPS
function changeLayersDraw() {
   	showloading();
    var mapurl = PM_XAJAX_LOCATION + 'x_load.php?'+SID+'&zoom_type=zoompoint';
    updateMap(mapurl, '');
}



function clickStopLoading() {
    stoploading();
    if (document.all) {
        document.execCommand('Stop')
    } else {
        window.stop();
    }
}




/*
 * PAN VIA ARROW BUTTONS OR KEYBOARD
 **************************************/
function arrowpan(direction) {
    showloading();
    var pansize = 0.1;   // defines how much to pan
    var px, py;
    if (direction == 'n') {
        px = (mapW - 1) / 2;
        py = (0 + pansize) * mapH;
    } else if (direction == 's') {
        px = (mapW - 1) / 2;
        py = (1 - pansize) * mapH;
    } else if (direction == 'e') {
        px = (1 - pansize) * mapW;
        py = (mapH - 1) / 2;
    } else if (direction == 'w') {
        px = (0 + pansize) * mapW;
        py = (mapH - 1) / 2;
    }

    zoompoint(1, px + "+" + py);
}


/*
 * REFERENCE IMAGE ZOOM/PAN
 ****************************/
function zoomref(imgxy) {
    showloading();
    var mapurl = PM_XAJAX_LOCATION + 'x_load.php?'+SID+'&mode=map&zoom_type=ref&imgxy='+imgxy  ;
    updateMap(mapurl, '');
}

// SET OVERVIEW IMAGE TO NEW ONE
function setRefImg(refimgsrc){
     var refimg = parent.refFrame.document.getElementById('refimg');
     refimg.src = refimgsrc;
}


/*
 * ZOOM TO SCALE
 *****************/
function zoom2scale(scale) {
    showloading();
    var mapurl = PM_XAJAX_LOCATION + 'x_load.php?'+SID+'&mode=map&zoom_type=zoomscale&scale='+scale;
    updateMap(mapurl, '');
}

/*
 * WRITE SCALE TO INPUT FIELD AFTER MAP REFRESH
 *************************************************/
function writescale(scale) {
    if (_$("scaleform")) _$("scaleform").scale.value = scale;
}




/*****************************************************************************
 * MOUSE CLICK BUTTON FUNCTIONS (FOR TOOLBAR)
 **********************************************/
function domouseclick(button) {
	var varform = _$("varform");
    resetFrames();
    switch (button) {
    case 'zoomin':
        varform.mode.value = 'map';
        varform.zoom_type.value = 'zoomrect';
        varform.maction.value = 'box';
        varform.tool.value = 'zoomin';
        break;
    case 'zoomout':
        varform.mode.value = 'map';
        varform.zoom_type.value = 'zoompoint';
        varform.zoom_factor.value = '-2';
        varform.maction.value = 'click';
        varform.tool.value = 'zoomout';
        break;
    case 'identify':
        varform.mode.value = 'query';
        varform.maction.value = 'click';
        varform.tool.value = 'identify';
        break;
    case 'pan':
        varform.mode.value = 'map';
        varform.zoom_type.value = 'zoompoint';
        varform.zoom_factor.value = '1';
        varform.maction.value = 'pan';
        varform.tool.value = 'pan';
        break;
    case 'select':
        varform.mode.value = 'nquery';
        varform.maction.value = 'box';
        var selurl = PM_XAJAX_LOCATION + 'x_select.php?'+SID;
        updateSelectTool(selurl, '');
        //_$('loadFrame').src = selurl;
        varform.tool.value = 'select';
        break;
    case 'auto_identify':
        varform.mode.value = 'iquery';
        varform.maction.value = 'move';
        varform.tool.value = 'auto_identify';
        var selurl = PM_XAJAX_LOCATION + 'x_select.php?'+SID+'&autoidentify=1';
        updateSelectTool(selurl, '');
        break;
    case 'measure':
        varform.maction.value = 'measure';
        varform.mode.value = 'measure';
        varform.tool.value = 'measure';
        createMeasureInput();
        break;
    case 'digitize':
        varform.mode.value = 'digitize';
        varform.maction.value = 'click';
        varform.tool.value = 'digitize';
        break;
    case 'poi':
        varform.mode.value = 'poi';
        varform.maction.value = 'click';
        varform.tool.value = 'poi';
        break;
    // ABP: resGeoRef
   case 'resGeoRef':
        varform.mode.value = 'resGeoRef';
        varform.maction.value = 'click';
        varform.tool.value = 'resGeoRef';
        break;
    // ABP: getCoordinatesForGeorefPointInput
   case 'getCoordinatesForGeorefPointInput':
        varform.mode.value = 'getCoordinatesForGeorefPointInput';
        varform.maction.value = 'click';
        varform.tool.value = 'getCoordinatesForGeorefPointInput';
        break;

    default:
        // for anything else (new) apply function 'button_mclick()'
        try {
            eval(button + '_click()');
            return false;
        } catch(e) {

        }
    }

    // Set cursor appropriate to slected tool
    if (useCustomCursor) {
        setCursor(false, false);
    }
}

/**
 * custom sample script for extending tool functions
 */
function poi_mclick() {
    var varform = _$("varform");
    varform.mode.value = 'poi';
    varform.maction.value = 'click';
    varform.tool.value = 'poi';

    if (useCustomCursor) {
        setCursor(false, 'crosshair');
    }
}



function resetFrames() {
	hideHelpMessage();
    var varform = _$("varform");
    if (varform.mode.value == 'nquery' || varform.mode.value == 'iquery' || varform.maction.value == 'measure') {
        if (varform.maction.value == 'measure') {
            resetMeasure();
        }
        if (varform.mode.value == 'iquery' || varform.mode.value == 'nquery') hideObj(_$('iqueryLayer'));

    } else {
        $('#mapToolArea').html('');
    }
}



function createMeasureInput() {
    var mStr =  '<form name="measureForm"><table class="TOOLFRAME"><tr><td NOWRAP>' + localeList['Total'] + '</td><td><input type=text size=9 name="sumLen"></td>';
    mStr += '<td id="mSegTxt" value="&nbsp;&nbsp;' + localeList['Segment'] + '" NOWRAP>&nbsp;&nbsp;' + localeList['Segment'] + '</td><td><input type=text size=9 name="segLen"></td>';
    mStr += '<td width=130 class="TDAR"><input type="button" id="cbut_measure" value="' + localeList['Clear'];
    //mStr += '"  class="button_off"  onClick="javascript:clearMeasure()" onmouseover="changeButtonClr(this, \'over\')" onmouseout="changeButtonClr (this, \'out\')" >';
    mStr += '"  class="button_off"  name="custombutton" onClick="javascript:clearMeasure()" >';
    mStr += '</td></tr></table></form>';

    $('#mapToolArea').html(mStr);
    pmCButton_init('cbut_measure');
    showHelpMessage(localeList['digitize_help']);
}


/*****************************************************************************
 * RELOAD APPLICATION
 **********************/
function reloadMap(remove) {
    var mapurl = PM_XAJAX_LOCATION + 'x_load.php?'+SID+'&zoom_type=zoompoint';
    if (remove) mapurl += '&resultlayer=remove&tmplayer=remove';
    updateMap(mapurl, '');
}



function showHelpMessage(hm) {
    $('#helpMessage').html(hm).showv();
}


function hideHelpMessage() {
    $('#helpMessage').html('').hidev();
}


/*****************************************************************************
 * CLOSE INFO WIN AND UNREGISTER SESSION VAR 'resultlayer'
 **********************************************************/
function clearInfo() {
	var varform = _$("varform");
    //if (infoWin == "frame") frames.infoFrame.location.href = "blank.html";
    //this.location = "blank.html";
    //if (varform.zoomselected.value == '1') {
        varform.zoomselected.value = '0';
        reloadMap(true);
    //}
}




/*****************************************************************************
 * SHOW/HIDE LOADING SPLASH IMAGE
 *********************************/
function showloading(){    // waiting/working gif-animation
    $("#loading").showv();
}

function stoploading(){
    $('#loading').hidev();
}




/******************************************************************************
 * SET SLIDER IMAGE DEPENDING ON SCALE
 * Values defined in 'config.ini'
 *************************************/
function setSlider(curscale) {
    if (myslider) {
        var sliderPos = getSliderPosition(curscale);
        myslider.setPosition(sliderPos);
        if (_$('refsliderbox')) hideObj(_$('refsliderbox'));
    }
    return false;
}




/******************************************************************************
 *
 * Purpose: core p.mapper functions (init, user interaction, open popups)
 * Author:  Armin Burger
 *
 ******************************************************************************
 *
 * Copyright (c) 2003-2006 Armin Burger
 *
 * This file is part of p.mapper.
 *
 * p.mapper is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version. See the COPYING file.
 *
 * p.mapper is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with p.mapper; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 ******************************************************************************/

/**
 * LOAD MAP IMAGE INTO PARENT WINDOW MAP DIV
 */
function loadMapImg(mapImgSrc) {
    // SWAP MAP IMG
    var theMapImg = _$("mapImg");
    theMapImg.src = mapImgSrc;
}

/**
 * Reset parameters of some DIV's
 */
function resetMapImgParams() {
    var theMapImgL = _$("mapimgLayer");
    var theMapImg  = _$("mapImg");

    theMapImg.style.width = mapW+"px";
    theMapImg.style.height = mapH+"px";

    theMapImgL.style.top  = 0+"px";
    theMapImgL.style.left = 0+"px";
    theMapImgL.style.width = mapW+"px";
    theMapImgL.style.height = mapH+"px";

    theMapImgL.style.clip = 'rect(auto auto auto auto)';  // NEEDED TO RESET DIV TO NON-CLIPPED AND ORIGINAL SIZE

    $('#zoombox').hidev();
    $('#loading').hidev();

    maploading = false;

    var varformMode = _$("varform").mode.value;
    if (varformMode == 'measure') {
        resetMeasure();
        polyline = toPxPolygon(geoPolyline);
        if (polyline.getPointsNumber()>0) {
            drawPolyline(jg,polyline);
        }
    }
}


/**
 * Update s1 value for slider settings
 */
function updateSlider_s1(pixW, pixH) {
    var maxScale1 = ((PMap.dgeo_x * PMap.dgeo_c) / pixW) / (0.0254 / 96);
    var maxScale2 = ((PMap.dgeo_y * PMap.dgeo_c) / pixH) / (0.0254 / 96);
    PMap.s1 = Math.max(maxScale1, maxScale2);
}



/*****************************************************************************
 * SWAP FUNCTIONS FOR TOOLBAR TD -> USE ALTERNATIVELY TO IMAGE SWAP
 * Changes TD class (default.css -> .TOOLBARTD...) in toolbar
 ********************************************************************/
/**
 * Function for state buttons (CLICKED TOOLS: zoomin, pan, identify, select, measure)
 * set class for active tool button
 */
function setTbTDButton(button) {
    $("#mapZone [@name='tbtd']").addClass('TOOLBARTD').removeClass('TOOLBARTD_ON');
    $('#tb_' + button).addClass('TOOLBARTD_ON').removeClass('TOOLBARTD').removeClass('TOOLBARTD_OVER');
}

/**
 * MouseDown/Up, only set for stateless buttons
 */
function TbDownUp(elId, status){
    var but = _$('tb_' + elId);
    if (status == 'd') {
        but.className='TOOLBARTD_ON';
    } else {
        but.className='TOOLBARTD';
    }
}


function changeButtonClr(myObj, myAction) {
    switch (myAction) {
        case 'over':
            myObj.className = 'button_on';
            break;

        case 'out':
            myObj.className = 'button_off';
            break;
    }
}

/*****************************************************************************
 * IMAGE SWAP FUNCTIONS FOR TOOLBAR
 * swaps images from imgname_on.gif to imgname_off.gif and vice versa
 *********************************************************************/
/**
 * SWITCH IMAGE OF CLICKED TOOL TO 'ON', ALL OTHERS TO 'OFF'
 */
function setButton(button) {
    var imgarr = document.getElementsByTagName('img');
    for (var i = 0; i < imgarr.length; i++) {
        var butid = imgarr[i].id;
        if (butid != 'sep') {
            if (butid != button) {
                setImg(butid, 'off');
            } else {
                setImg(butid, 'on');
            }
        }
    }
}

/**
 * set image to ON or OFF
 */
function setImg(obj, status){
    var source = 'images/buttons/' + obj + '_' + status + '.gif';
    imgobj = _$(obj);
    imgobj.src = source;
}




/**************************************************
 * Set cursor symbol according to tool selection
 *************************************************/
/**
 * return root path of application
 */
function getRootPath() {
	var theLoc = document.location.href;
	var theLastPos = theLoc.lastIndexOf('/');
	var RootPath = theLoc.substr(0,theLastPos) + '/';

	return RootPath;
}

/**
 * set the cursor to standard internal cursors
 * or special *.cur url (IE6+ only)
 */
function setCursor(rmc, ctype) {
    if (!rmc) {
    	var varform = _$("varform");
        if (varform) {
            var toolType = varform.tool.value;
        } else {
            var toolType = 'zoomin';
        }
    } else {
        toolType = 'pan';
    }


    /* Define settings for cursor to be used for tools
       set to true if you want to use the same cursors for all browsers (incl. IE) */
    var internalCursor = ((navigator.version < 6) || (navigator.appName == 'Netscape'));
    //var internalCursor = true;

    var rootPath = getRootPath();
    var usedCursor = (internalCursor) ? toolType : "url(" +rootPath + "images/cursors/zoomin.cur)";

    _$('mapimgLayer').style.cursor = usedCursor;

    switch (toolType) {
		case "zoomin" :
			var usedCursor = (internalCursor) ? 'crosshair' : 'url("' +rootPath + 'images/cursors/zoomin.ani")';
			break;

        case "zoomout" :
			var usedCursor = (internalCursor) ? 'e-resize' : 'url(' +rootPath + 'images/cursors/zoomout.cur)';
			break;

        case "identify" :
			//var usedCursor = (internalCursor) ? 'help' : 'url(' +rootPath + 'images/cursors/identify.cur)';
			var usedCursor = 'help';
            break;

        case "auto_identify" :
			var usedCursor = 'pointer';
            break;

        case "pan" :
			//var usedCursor = (internalCursor) ? 'move' : 'url(' +rootPath + 'images/cursors/pan.cur)';
            var usedCursor = 'move';
			break;

        case "select" :
			//var usedCursor = (internalCursor) ? 'help' : 'url(' +rootPath + 'images/cursors/select.cur)';
            var usedCursor = (internalCursor) ? 'help' : 'help';
			break;

        case "measure" :
			var usedCursor = (internalCursor) ? 'crosshair' : 'url(' +rootPath + 'images/cursors/measure.cur)';
			break;

        case "digitize" :
			var usedCursor =  'crosshair';
			break;

        default:
            var usedCursor = 'default';
    }

    if (ctype) usedCursor = ctype;
    _$('mapimgLayer').style.cursor = usedCursor;

}




/**
 * OPEN RESULT WINDOW FOR IDEBNTIFY AND SEARCH
 */
function openResultwin(winurl) {
    try {
        if (queryResultLayout == 'tree') {
            var winw = 300;
            var winh = 450;
        } else {
            var winw = 500;
            var winh = 200;
        }
    } catch(e) {
        var winw = 500;
        var winh = 200;
    }

    var w = window.open(winurl, 'resultwin', 'width=' + winw + ',height=' + winh + ',status=yes,resizable=yes,scrollbars=yes');
    return w;
}



/**
 * PRINT FUNCTIONS
 */
function openPrintDlg() {
   pmOpenDlg('printdlg.phtml', 'prdlg', 300, 180, 'c', 'no', 'no');
}


/**
 * OPEN HELP WINDOW
 */
function openHelp() {
    window.open("help.phtml?"+SID, "pmhelp","top=100,left=200,width=400,height=500,status=no,scrollbars=yes,resizable=yes");
}



function getMapTL() {
    var mapTL = new Object();
    var oMap = $('#map');
    mapTL.L = oMap.offset()['left'];
    mapTL.T = oMap.offset()['top'];
    return mapTL;
}


/************************************************************************************
 * DOWNLOAD FUNCTIONS
 * get image with higher resolution for paste in othet programs
 ****************************************************************/
function openDownloadDlg() {
    pmOpenDlg('downloaddlg.phtml', 'dldlg', 300, 200, 'c', 'no', 'no');
}

function openDownload() {
    window.open("download.phtml?"+SID, "download");
}


/**
 * Open popup dialaog for adding POI
 */
function openPoiDlg(imgxy) {
    var coordsList = imgxy.split('+');
    var mpoint = getGeoCoords(coordsList[0], coordsList[1], false);

    // Round values (function 'roundN()' in 'measure.js')
    var rfactor = 5;
    var px = isNaN(mpoint.x) ? '' : roundN(mpoint.x, rfactor);
    var py = isNaN(mpoint.y) ? '' : roundN(mpoint.y, rfactor);

    var inserttxt = prompt(localeList['addLocation'], '');
    if (inserttxt) {
        var digitizeurl = PM_XAJAX_LOCATION + 'x_poi.php?' +SID + '&up=' + px + '@@' + py + '@@' + escape(inserttxt);
        //alert(digitizeurl);
        addPOI(digitizeurl, '');
    }
}



/**
 * Open generic pop up dialog window
 */
function pmOpenDlg(docname, winname, winW, winH, pos, status, resize) {
    switch (pos) {
        case 'c':
            var winL = parseInt(screen.width/2) - (winW/2);
            var winT = parseInt(screen.height/2) - (winH/2);
            break;
    }
    var pwin = window.open(docname +'?'+SID, winname, 'left='+winL +',top='+winT + ',width='+winW + ',height='+winH +',status='+status +',resizable='+resize );
    return pwin;
}

/******************************************************************************
 *
 * Purpose: drawing functions (measurements, digitizing)
 *          uses the geometry.js library
 * Authors: Armin Burger, Federico Nieri
 *
 ******************************************************************************
 *
 * Copyright (c) 2003-2006 Armin Burger
 *
 * This file is part of p.mapper.
 *
 * p.mapper is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version. See the COPYING file.
 *
 * p.mapper is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with p.mapper; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 ******************************************************************************/


/**********************************************************************************
  USES THE JAVASCRIPT LIBRARIES JSGRAPHICS FROM WALTER ZORN
  SEE FILE /JAVASCRIPT/WZ_JSGRAPHICS.JS FOR DETAILS OF COPYRIGHT
 **********************************************************************************/

// -------------------------
//  FUNCTIONS FOR MEASURING
// -------------------------

// ADAPT LINE COLOR
var lineColor = '#FF0000';

// ADAPT LINE WIDTH
var lineWidth = 2;

// ADAPT FACTOR FOR DISTANCE/AREA CALCULATION
// eg. 1000 for km, 1 for m
var calcFact = 1;

var numSize;

var polyline = new Polygon();
var geoPolyline = new Polygon();


/**
 * Return a Point object with geo coordinate instead of px coordinate
 * @param pxPoint: Point object with px coordinate
 */
function toGeoPoint(pxPoint){
    var x_geo = minx_geo + ((pxPoint.x/mapW)  * xdelta_geo);
	var y_geo = maxy_geo - ((pxPoint.y/mapH) * ydelta_geo);
	return new Point(x_geo,y_geo);
}

/**
 * Return a Polygon object with geo coordinate instead of px coordinate
 * @param pxPolygon: Polygon object with px coordinate
 */
function toGeoPolygon(pxPolygon){
    var pxPoints = pxPolygon.getPoints();
	var geoPolygon = new Polygon();
	for(var i = 0; i < pxPoints.length; i++){
		geoPolygon.addPoint(toGeoPoint(pxPoints[i]));
	}
	return geoPolygon;
}

function toPxPolygon(geoPolygon){
	var geoPoints = geoPolygon.getPoints();
	var pxPolygon = new Polygon();
	for(var i = 0; i < geoPoints.length; i++){
		pxPolygon.addPoint(toPxPoint(geoPoints[i]));
	}
	return pxPolygon;
}

function toPxPoint(geoPoint){
  var x_px = ((geoPoint.x - minx_geo) / xdelta_geo) * mapW;
  var y_px = ((maxy_geo - geoPoint.y) / ydelta_geo) * mapH;
	return new Point(x_px,y_px);
}

/**
 * Return a geography measure unit instead of px
 * @param pxLength: length in px
 */
function toGeoLength(pxLength){
	return (pxLength/mapW) * xdelta_geo;
}


/**
 * Main function, draws symbol points between mouseclicks
 * @return void
 */
function measureDrawSymbols(e, clickX, clickY, dblClick) {
    // Polyline points number before to add the current click point
    if(polyline.isClosed()){
      polyline.reset();
    }

    var nPoints = polyline.getPointsNumber();
    var clickPoint = new Point(clickX, clickY);
    // Reset everything when last measure ended with double click
    if (nPoints == 0) resetMeasure();
    // Don't go outside map
    if ((clickX < mapW) && (clickY < mapH)) {

        // SINGLE CLICK
        if (dblClick != 1) {

	        polyline.addPoint(new Point(clickX,clickY));

        	// First point for start click
        	if (nPoints < 1) {

        		drawLineSegment(jg,new Line(clickPoint, clickPoint));

      		// Fill distance between clicks with symbol points
      		}else{

      		  // USE wz_jsgraphics.js TO DRAW LINE. lastSegment is of Line type
            var lastSegment = polyline.getLastSide();
            var sidesNumber = polyline.getSidesNumber();

      		  // check for the overlapping of the new side.
            // it will never overlap with the previous side
            if (sidesNumber > 2){
                for (var s = 1 ; s < (sidesNumber-1); s++){
                    var intersectionPoint = polyline.getSide(s).intersection(lastSegment);
                    if (intersectionPoint != null){
                        alert(localeList['digitize_over']);
                        polyline.delPoint(polyline.getPointsNumber()-1);
                        return;
                    }
                }
            }

            drawLineSegment(jg,lastSegment);
            // calls the handler of the side (segment) digitation and pass it the polyline in px coords
            onDigitizedSide(polyline);

        	}

        // DOUBLE CLICK => CALCULATE AREA
        } else if (dblClick) {

  	    	// Removes the last duplicated point because of the last 2 single click
  	    	polyline.delPoint(polyline.getPointsNumber()-1);

  	    	// Closing the polyline to have a polygon
  	    	polyline.close();

            // fix the last side
            var lastSegment = polyline.getLastSide();
  	    	var sidesNumber = polyline.getSidesNumber();

  	    	// check for the overlapping of the closing side
  	    	// it will never overlap with the first and the last side
            for (var s = 2 ; s < (sidesNumber-1); s++){
                var intersectionPoint = polyline.getSide(s).intersection(lastSegment);
                if (intersectionPoint != null){
                    alert(localeList['digitize_over']);
                    polyline.delPoint(polyline.getPointsNumber()-1);
                    return false;
                }
            }

  	    	if(lastSegment != null){
  	    		drawLineSegment(jg,lastSegment);
  	    	}

            // calls the handler of the polygon digitation before reset the polygon
            onDigitizedPolygon(polyline);

            // remove all points from the polygon
      		//polyline.reset();

        }
    }
    geoPolyline = toGeoPolygon(polyline);
}


/**
 * Handler of the digitized polygon action. It is called when a double click
 * close tha drawing polygon
 * @param poly: Polygon object passed to the handler
 */
function onDigitizedPolygon(poly){

	var polyGEO = toGeoPolygon(poly);
    var perimGEO = polyGEO.getPerimeter()/calcFact;

    var cntPerLen = Math.round(perimGEO).toString().length;
    numSize = Math.max(0, (4 - cntPerLen));

    perimGEO = roundN(perimGEO, numSize);

    var areaGEO = Math.abs(roundN (polyGEO.getArea() / (calcFact * calcFact), numSize-1)) ;

    // Change input text box to 'Area'
	document.measureForm.sumLen.value = perimGEO;
    document.getElementById("mSegTxt").innerHTML = localeList['Area'];
    document.measureForm.segLen.value = areaGEO;

}

/**
 * Handler of the digitized line action. It is called when a new click cause draw a new line
 * @param poly: Polygon object passed to the handler
 */
function onDigitizedSide(poly){
    // Polygon in map coordinates
	 var polyGEO = toGeoPolygon(poly);

    // Segment length in  map coordinates,  write values to input boxes
    var segLenGEO_0 = polyGEO.getSideLength(polyGEO.getSidesNumber()) / calcFact ;
    var perimGEO_0  = polyGEO.getPerimeter() / calcFact ;

    var cntSegLen = Math.round(segLenGEO_0).toString().length;
    numSize = Math.max(0, (4 - cntSegLen));
    var segLenGEO = roundN(segLenGEO_0, numSize);
    var perimGEO  = roundN(perimGEO_0, numSize);

    var measureSegment = false;
    if (measureSegment){
        document.measureForm.segLen.value = segLenGEO;
        if (polyGEO.getPointsNumber() >= 2){
            poly.reset();
        }
    } else {
        document.measureForm.sumLen.value = perimGEO;
        document.measureForm.segLen.value = segLenGEO;
    }
}

/**
 * REDRAW THE LAST AND THE CLOSING SIDE OF THE POLYGON
 */
function redrawAll(currX, currY) {

    if(polyline.isClosed())
      return;

    if (polyline.getPointsNumber()>0) {

        var mousePoint = new Point(currX,currY);
        jg_tmp.clear();
        jg_tmp.setColor(lineColor);
    	jg_tmp.setStroke(lineWidth);
	    // Drawing last side
	    var lastPoint = polyline.getPoint(polyline.getPointsNumber()-1);

        drawLineSegment(jg_tmp,new Line(lastPoint,mousePoint));

	    jg_tmp.setStroke(Stroke.DOTTED);
	    var firstPoint = polyline.getPoint(0);

        drawLineSegment(jg_tmp,new Line(firstPoint,mousePoint));

    }

}


function drawPolyline(jg,poly) {
    var n = poly.getSidesNumber();
    for (var i=1;i<=n;i++) {
        drawLineSegment(jg,poly.getSide(i));
    }
}


/**
 * DRAW LINE USING JSGRAPHICS
 */
function drawLineSegment(jg,line) {

    var xfrom = line.getFirstPoint().x;
    var yfrom = line.getFirstPoint().y;
    var xto = line.getSecondPoint().x;
    var yto = line.getSecondPoint().y;

    var limitSides = getLimitSides();
    var xList = limitSides.getXList();
    var yList = limitSides.getYList();

    var xMin = Math.min.apply({},xList);
    var yMin = Math.min.apply({},yList);
    var xMax = Math.max.apply({},xList);
    var yMax = Math.max.apply({},yList);

    var points = new Array();

    if  (xfrom >= xMin && xfrom <= xMax && yfrom >= yMin && yfrom <= yMax) {
        points.push(line.getFirstPoint());
    }

    if  (xto >= xMin && xto <= xMax && yto >= yMin && yto <= yMax) {
        points.push(line.getSecondPoint());
    }

    var s = 1;

    while(points.length < 2 && s <= limitSides.getSidesNumber()){
        var intersectionPoint = limitSides.getSide(s).intersection(line);
        if (intersectionPoint != null) {
            points.push(intersectionPoint);
        }
        s++;
    }

    if(points.length == 2){
        jg.drawLine(points[0].x, points[0].y, points[1].x,points[1].y);
        jg.paint();
    }

}

/**
 * GET THE RECTANGLE OF THE DRAWING AREA
 */
function getLimitSides(){

    var mapimgLayer     = _$('mapimgLayer');
    var mapimgLayerL    = objL(mapimgLayer);
    var mapimgLayerH    = objT(mapimgLayer);
    var mapW = mapimgLayer.style.width;
    var mapH = mapimgLayer.style.height;

    var xMin = mapimgLayerL;
    var xMax = mapimgLayerL + parseInt(mapW);
    var yMin = mapimgLayerH;
    var yMax = mapimgLayerH + parseInt(mapH);

    var limitSides = new Polygon();

    limitSides.addPoint( new Point(xMin,yMin) );
    limitSides.addPoint( new Point(xMax,yMin) );
    limitSides.addPoint( new Point(xMax,yMax) );
    limitSides.addPoint( new Point(xMin,yMax) );
    limitSides.close();

    return limitSides;
}

/**
 * Remove all measure settings
 */
function resetMeasure() {
    // remove lines
    polyline.reset();
    jg.clear();
    jg_tmp.clear();

    reloadData();
}

function clearMeasure(){
  resetMeasure();
  geoPolyline.reset();
}

function reloadData(){

    if (polyline.getSidesNumber() == 0) {
        // Reset form fields
        if (document.measureForm) {
            document.measureForm.sumLen.value = '';
            document.measureForm.segLen.value = '';
            document.getElementById("mSegTxt").innerHTML = localeList['Segment'];
        }
    } else if(polyline.isClosed()) {
        onDigitizedPolygon(polyline);
    } else {
        onDigitizedSide(polyline);
    }
}

function reloadDrawing(){
    var varformMode = _$("varform").mode.value;
    if (varformMode == 'measure') {
        resetMeasure();
        polyline = toPxPolygon(geoPolyline);
        if (polyline.getPointsNumber()>0) {
            drawPolyline(jg,polyline);
        }
        reloadData();
    }
}

function delLastPoint(){
    var nPoints = polyline.getPointsNumber();
    if (nPoints > 0) {
        polyline.delPoint(nPoints - 1);
        geoPolyline.delPoint(nPoints - 1);
        reloadDrawing();
    }
}

// ABP: persistenza
function persistPolygon(){
    if(geoPolyline.points.length > 0){
        // Ajax call
        var persisturl = PM_XAJAX_LOCATION + 'x_persist_polygon.php?'+SID;
        $.ajax({
            url: persisturl,
            data : 'persist_polygon='+geoPolyline.toString(),
            type : 'POST',
            success: function(response){
                alert('La linea e\' stata resa persistente, puoi eliminarla facendo clic sul pulsante "Aggiorna la mappa"');
                var mapurl = PM_XAJAX_LOCATION + 'x_load.php?'+SID;
                showloading();
                updateMap(mapurl, '');
            }
        });
    }
}


/**
 * Round to a specified decimal
 */
function roundN(numin, rf) {
    return ( Math.round(numin * Math.pow(10, rf)) / Math.pow(10, rf) );
}
/******************************************************************************
 *
 * Purpose: initialize various p.mapper settings
 * Author:  Armin Burger
 *
 ******************************************************************************
 *
 * Copyright (c) 2003-2006 Armin Burger
 *
 * This file is part of p.mapper.
 *
 * p.mapper is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version. See the COPYING file.
 *
 * p.mapper is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with p.mapper; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 ******************************************************************************/

/**
 * Global PMap object;
 * stores main status variables set via incphp/js_init.php
 */
function PMap() {
    this.scale = null;
    this.resize_timer = null;
    //this.legStyle = PMap_setLegStyle;
}

 /**
 * Initialize function; called by 'onload' event of map.phtml
 * initializes several parameters by calling other JS function
 */
function pm_init() {
    // initialization of toolbar, menu, slider HOVER's (and others)
    pmToolbar_init();
    pmMenu_init();
    pmSlider_init();


    // Add Resize Event to main window
    window.onresize = function(){pmLayout_init();};
    pmLayout_init();

    // Add properties to mapImg
    var imgTmpMap = _$("mapImg");
    imgTmpMap.onload = resetMapImgParams;
    imgTmpMap.onmouseover = startUp;

    // Initialize TOC/legend
    pmTabs_init('#tocTabs', 'tab_toc');
    pmToc_init();

    // Set zoombox class for Opera and Konqueror to non-semitransparent
    if (navigator.userAgent.match(/Opera|Konqueror/i)) {
        _$("zoombox").className = 'zoombox_nontransp';
    }

    createZSlider('zslider');
    setSearchOptions();
    domouseclick('zoomin');
    setTbTDButton('zoomin');

    // Add jQuery events
    $(document).keypress( function(event) { kp(); } );
    $('#mapimgLayer').mouseout(function() { setTimeout('mapImgMouseOut()', 800); });

    // ABP:
    if(Layout.InfoZoneStyle == 4){
        $('#infoZone').hide();
    }
}


/**
 * HOVER effect for slider
 * initialized in pm_init()
 */
function pmSlider_init() {
    $('#sliderArea').hover(
        function(){ $(this).addClass("sliderAreaOver").removeClass("sliderAreaOut"); },
        function(){ $(this).addClass("sliderAreaOut").removeClass("sliderAreaOver"); }
    );
}

/**
 * DHTML jQuery menu
 * initialized in pm_init()
 */
function pmMenu_init() {
    $('ul.pm_menu > li').each(function() {
        $(this).hover(
            function() { $(this).addClass('pm_menu_hover'); },
            function() { $(this).removeClass('pm_menu_hover'); }
        );

        $(this).click(function() {
            pmMenu_toggle($(this).parent().id());
            eval($(this).id().replace(/pmenu_/, '') + '()');
        });
    });
}

/**
 * Show/hide pm_menu
 */
function pmMenu_toggle(menu)
{
    var obj = $('#' + menu);
    if (obj.css('display') == 'none') {
        obj.show('fast');
        $('#' + menu + '_start > img').src('images/menuup.gif');
    } else {
        obj.hide('fast');
        $('#' + menu + '_start > img').src('images/menudown.gif');
    }
}

/**
 * Initialize toolbar hover's
 */
function pmToolbar_init() {
    $('#mapZone .TOOLBARTD').each(function() {
        $(this).hover(
            function(){ if (!$.className.has(this,"TOOLBARTD_ON")) $(this).addClass("TOOLBARTD_OVER"); },
            function(){ $(this).removeClass("TOOLBARTD_OVER"); }
        );
    });
}



function pmCButton_init(but) {
    $("#" + but).hover(
        function(){ $(this).addClass("button_on").removeClass("button_off"); },
        function(){ $(this).addClass("button_off").removeClass("button_on"); }
    );
}

function pmCButton_init_all() {
    $("[@name='custombutton']").each(function() {
        $(this).hover(
            function(){ $(this).addClass("button_on").removeClass("button_off"); },
            function(){ $(this).addClass("button_off").removeClass("button_on"); }
        );
    });
}


function pmTabs_init(tabdiv, activated) {
    $(tabdiv + '>ul>li>a#'+activated).parent().addClass('tabs-selected');
    var numTabs = $(tabdiv + '>ul>li').length;
    var tabW = parseInt(100 / numTabs) + '%';
    $(tabdiv + '>ul>li>a').each(function() {
        $(this).click(function() {
            $(tabdiv + '>ul>li').removeClass('tabs-selected');
            $(this).parent().addClass('tabs-selected');
        });
        $(this).parent().css('width',tabW);
    });
}


/*****************************************************************************
 *
 * Purpose: parse JSON strings to HTML (query result outputs)
 * Author:  Armin Burger
 *
 *****************************************************************************
 *
 * Copyright (c) 2003-2006 Armin Burger
 *
 * This file is part of p.mapper.
 *
 * p.mapper is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version. See the COPYING file.
 *
 * p.mapper is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with p.mapper; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 ******************************************************************************/

try {
    var queryResultLayout = opener.queryResultLayout;
} catch(e) {
    var queryResultLayout = 'table';
}


/**
 * Parse JSON query result string
 * create table view
 */
function parseJSON(jsonstr, infoWin) {
    var rhtml = '';

    // Nothing found with query, return only header
    if (jsonstr == 0) return returnNoResultHtml(infoWin);

    // Features found, parse JSON string
    var groups = jsonstr[0];

    var jlen = groups.length;


    for (var i=0; i<jlen; i++) {
        var layObj = groups[i];

        rhtml += '<div class="LAYERHEADER">' + layObj.description + '</div>';
        rhtml += '<table class="sortable" border="0" cellspacing="0" cellpadding="0">';

        //*** Header line ***/
        var hL = layObj.header;
        if (hL[0] == '@') {
            var withShpLink = true;
        } else {
            var withShpLink = false;
            //var withShpLink = true;
        }

        var hLlen = hL.length;
        rhtml += '<tr>';
        var startcol = withShpLink ? 0 : 1;
        for (var hi=startcol; hi<hLlen; hi++) {
            rhtml += '<th>' + hL[hi] + '</th>';
        }
        rhtml += '</tr>';


        //*** Values of the layer ***/
        var vL = layObj.values;
        var vLlen = vL.length;

        for (var vi=0; vi<vLlen; vi++) {

            //--- Rows ---//
            var rowL = vL[vi];
            var rowLlen = rowL.length;

            rhtml += '<tr>';
            for (var ri=startcol; ri<rowLlen; ri++) {
                // Write out shape link for zoom
                if (withShpLink && ri < 1) {
                    var shplinkL = rowL[ri].shplink;
                    rhtml += '<td class=\"zoomlink\"><a href="javascript:' + (infoWin != 'window' ? '' : 'opener.') + 'zoom2extent(\'' + shplinkL[0] + '\', \'' + shplinkL[1] + '\', \'' + shplinkL[2] + '\')">';
                    rhtml += '<img src="images/zoomto.gif" alt="zoomto"></a></td>';
                } else {
                    // Check for Hyperlinks
                    // ABP: patch for PNM (pass also zona and sottozona and shplink id)
                    var shplinkL = rowL[0].shplink;
                    if (isObject(rowL[ri])) {
                        var hypLinkL = rowL[ri].hyperlink;
                        rhtml += '<td><a href="javascript:openHyperlink(\'' + hypLinkL[0] + '\', \'' + hypLinkL[1] + '\', \'' + hypLinkL[2].replace(/"|'/, '\\\'') + '\',\'' + rowL[ri+1] +  '\',\'' +  rowL[ri+2] + '\',\'' +  shplinkL[1] + '\')">' + hypLinkL[3] + '</a></td>';
                    } else {
                        rhtml += '<td>' + rowL[ri] + '</td>';
                    }
                }
            }
            rhtml += '</tr>';
        }
        rhtml += '</table>';
    }

    /*** Zoom parameters ***/
    var zp = jsonstr[1];
    rhtml += returnZoomParamsHtml(zp, infoWin);

    try {
        rhtml += returnCustomQueryHtml(zp, infoWin);
    } catch(e) {}

    return rhtml;
}



/**
 * Parse JSON query result string
 * create TREE view
 */
function parseJSON_treeview(jsonstr, infoWin) {
    var rhtml = '';

    // Nothing found with query, return only header
    if (jsonstr == 0) return returnNoResultHtml(infoWin);


    // Features found, parse JSON string

    // Style for tree
    try {
        if (infoWin == 'window') {
            var treeCss = 'id="' + opener.queryTreeStyle['css'] + '"';
        } else {
            var treeCss = 'id="' + queryTreeStyle['css'] + '"';
        }

    } catch(e) {
        var treeCss = "";
    }

    var t = localeList['Layer'] + '<ul ' + treeCss + '>';

    var groups = jsonstr[0];
    var jlen = groups.length;

    for (var i=0; i<jlen; i++) {
        var layObj = groups[i];
        t += '<li>' + layObj.description;
        t += '<ul>';

        //*** Header line ***/
        var hL = layObj.header;
        if (hL[0] == '@') {
            var withShpLink = true;
        } else {
            var withShpLink = false;
        }

        var hLlen = hL.length;
        var startcol = withShpLink ? 0 : 1;
        var n4node = withShpLink ? 1 : 0;

        //*** Values of the layer ***/
        var vL = layObj.values;
        var vLlen = vL.length;

        for (var vi=0; vi<vLlen; vi++) {

            //--- Rows ---//
            var rowL = vL[vi];
            var rowLlen = rowL.length;

            if (isObject(rowL[n4node])) {
                var nodeAnnot = rowL[n4node].hyperlink[3];
            } else {
                var nodeAnnot = rowL[n4node];
            }

            t += '<li>' + nodeAnnot + '<ul>';

            for (var ri=startcol; ri<rowLlen; ri++) {
                // Write out shape link for zoom
                if (withShpLink && ri < 1) {
                    var shplinkL = rowL[ri].shplink;
                    var zoomlink = '<a href="javascript:' + (infoWin != 'window' ? '' : 'opener.') + 'zoom2extent(\'' + shplinkL[0] + '\', \'' + shplinkL[1] + '\', \'' + shplinkL[2] + '\')">';
                    t += '<li>' + zoomlink + '<img src="images/zoomtiny.gif" alt="" /> Zoom</a></li>';

                } else {
                    // Check for Hyperlinks
                    t += '<li><span class="qcname">' + hL[ri] + '</span>: &nbsp;';
                    if (isObject(rowL[ri])) {
                        var hypLinkL = rowL[ri].hyperlink;
                        var hlink = '<a href="javascript:openHyperlink(\'' + hypLinkL[0] + '\', \'' + hypLinkL[1] + '\', \'' + hypLinkL[2] + '\')">' ;
                        //var resrow =  '<span class="qcname">' + hL[ri] + '</span>: &nbsp;' +  hypLinkL[3];
                        t += hlink + hypLinkL[3] +'</a>';
                    } else {
                        var hlink = '';
                        //var resrow =  '<span class="qcname">' + hL[ri] + '</span>: &nbsp;' + rowL[ri];
                        t += rowL[ri];
                    }
                    t += '</li>';
                }
            }
            t += '</ul>';
            t += '</li>';
        }
        t += '</ul>';
        t += '</li>';
    }
    t += '</ul>';

    rhtml += t;

    /*** Zoom parameters ***/
    var zp = jsonstr[1];
    rhtml += returnZoomParamsHtml(zp, infoWin);

    try {
        rhtml += returnCustomQueryHtml(zp, infoWin);
    } catch(e) {}

    return rhtml;
}


/**
 * Return HTML for no results found in query
 */
function returnNoResultHtml(infoWin) {
    // ABP: close button
    var h = '<table class="restable" cellspacing="0" cellpadding="0">';
    if (infoWin == 'window'){
        h += '<td>' + localeList['noRecords'] + '</td>';
        h += '<td><a href="javascript:this.close();"><img align="right" src="images/close.gif" border=0 ></a></td>';
    } else if(Layout.InfoZoneStyle == 4) {
        h += '<td><a href="javascript:void(0);" onclick="$(\'#infoZone\').fadeOut();return false;"><img align="left" src="images/close.gif" border=0 ></a>' + localeList['noRecords'] + '</td>';
    } else {
        h += '<td>' + localeList['noRecords'] + '</td>';
    }
    h += '</tr></table>';
    return h;
}

/**
 * Return HTML for zoom parameters (zoomall, autozoom)
 */
function returnZoomParamsHtml(zp, infoWin) {
    var infoWin = zp.infoWin;
    var allextent = zp.allextent;
    var autozoom = zp.autozoom;
    var zoomall = zp.zoomall;
    var ref2opener = (infoWin != 'window' ? '' : 'opener.');

    var html = '';
    if (zoomall) {
        var zStr = '<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\" width=\"100%\"><tr><td class=\"zoomlink\">';
        zStr += "<a href=\"javascript:";
        zStr += ref2opener + 'zoom2extent(0,0,\'' + allextent + '\')';
        zStr += '\"><img src=\"images/zoomtoall.gif\"alt=\"za\"></a></td><td class=\"TDAL\">' + localeList['zoomSelected'] + '</td></tr></table>';

        html += zStr;
    }

    // Add image for onload event
    var azStr = '<img src=\"images/blank.gif\" onload=\"';
    if (autozoom) {
        if (autozoom == 'auto') {
            azStr += ref2opener + 'zoom2extent(0,0,\'' + allextent + '\');';
        } else if (autozoom == 'highlight') {
            azStr += ref2opener + 'updateMap(' + ref2opener + 'PM_XAJAX_LOCATION + \'x_load.php?' + SID +  '&mode=map&zoom_type=zoompoint\', \'\')';
        }
    } else {
        azStr += ref2opener + '$(\'#zoombox\').hidev();';
    }

    azStr += '\" />';
    html += azStr;

    return html;
}



/**
 * parse IQuery (auto-identify) result
 */
function parseJSON_IQuery(jsonstr) {

    // Nothing found with query
    if (jsonstr == 0) {
        return false;
    }

    // Features found, parse JSON string
    var groups = jsonstr[0];

    // Only take the first layer from group
    var layObj = groups[0];

    var startcol = 1;

    //*** Header line ***/
    var hL = layObj.header;
    var hLlen = hL.length;

    //*** Values of the layer ***/
    var vL = layObj.values;

    //--- Rows ---//
    var rowL = vL[0];  // <====== Only take the first from result

    // Loop through records and create HTML
    var rhtml = '';
    rhtml += '<table class="iquery" border="0" cellspacing="0" cellpadding="0">';
    rhtml += '<tr><th colspan="2" class="header">' + layObj.description + '</td></tr>';

    for (var hi=startcol; hi<hLlen; hi++) {
        rhtml += '<tr>';
        rhtml += '<th>' + hL[hi] + '</th>';

        // Check for Hyperlinks
        if (isObject(rowL[hi])) {
            var hypLinkL = rowL[hi].hyperlink;
            rhtml += '<td>' + hypLinkL[3] + '</td>';
        } else {
            rhtml += '<td>' + rowL[hi] + '</td>';
        }

        rhtml += '</tr>';
    }
    rhtml += '</table>';

    return rhtml;
}




/**
 * Parse JSON result string with parseJSON()
 * and insert resulting HTML into queryresult DIV
 */
function writeQResult(resultJSON, infoWin) {
    //alert(infoWin);
    var queryResultDiv = infoWin == 'window' ? 'queryResult' : 'infoFrame';

    if (queryResultLayout == 'table') {
        var resstr = parseJSON(resultJSON, infoWin);
        if (infoWin == 'dynwin') {
            createDnRDlg({w:400, h:200}, {resizeable:true, newsize:false}, 'pmQueryContainer', 'Result', false);
            $('#pmQueryContainer_MSG').html(resstr).addClass('pmInfo').addClass('jqmdQueryMSG');
        } else {
            $('#' + queryResultDiv).html(resstr);
        }
        sortables_init();
    } else {
        var restree = parseJSON_treeview(resultJSON, infoWin);
        if (infoWin == 'dynwin') {
            createDnRDlg({w:600, h:200}, {resizeable:true, newsize:false}, 'pmQueryContainer', localeList['Result'], false);
            $('#pmQueryContainer_MSG').html(restree).addClass('jqmdQueryMSG');
            queryResultDiv = 'pmQueryContainer_MSG';
        } else {
            $('#' + queryResultDiv).html(restree);
        }

        try {
            if (infoWin == 'window') {
                var treeStyle = opener.queryTreeStyle['treeview'];
            } else {
                var treeStyle = queryTreeStyle['treeview'];
            }
        } catch(e) {
            var treeStyle = {collapsed: true, unique: true};
        }

        $('#' + queryResultDiv  + ' > ul').Treeview(treeStyle);
    }
}



/**
 * Check if var is an object
 */
function isObject(a) {
    return (a && typeof a == 'object') || typeof a == 'function';
}


/*****************************************************************************
 *
 * Purpose: Functions for queries
 * Author:  Armin Burger
 *
 *****************************************************************************
 *
 * Copyright (c) 2003-2006 Armin Burger
 *
 * This file is part of p.mapper.
 *
 * p.mapper is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version. See the COPYING file.
 *
 * p.mapper is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with p.mapper; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 ******************************************************************************/

//var PMQuery = new PM_Query();

function PM_Query() {
    this.iquery_timer = null;
    try {this.follow = autoIdentifyFollowMouse;} catch(e) {this.follow = false;};
    this.timeW = -1;
    this.timeA = 2;
    this.timer_c = 0;
    this.timer_t = null;
    this.timer_to = null;
}

/**
 * Start identify (query) or select (nquery) 
 */
function showqueryresult(type, xy) {
    var varform = document.getElementById("varform");
    if (type == 'query') {
        var queryurl = PM_XAJAX_LOCATION + 'x_info.php?' +SID+ '&mode='+type + '&imgxy='+xy; // + layerstring;
    } else {
        var queryurl = PM_XAJAX_LOCATION + 'x_info.php?' +SID+ '&mode='+type + '&imgxy='+xy + '&groups=' + getSelectLayer();
        varform.zoomselected.value = '1';
    }

    if (PMap.infoWin == 'window') {
        openResultwin('blank.html');
    }
    
    getQueryResult(queryurl, '');
}


/**
 * Start attribute search
 */
function submitSearch() {
    var searchForm = _$('searchForm');
    var skvp = getFormKVP('searchForm');
    //alert(skvp);
    var queryurl = PM_XAJAX_LOCATION + 'x_info.php?' + SID + '&' + skvp + '&mode=search';
    
    if (PMap.infoWin == 'frame') {
        searchForm.target='infoZone';
    } else {
        var resultwin = openResultwin('blank.html');
        searchForm.target='resultwin';
    }
    
    //alert(queryurl);
    getQueryResult(queryurl, '')
}


/*
 * RETURN LAYER/GROUP FOR SELECTION
 *************************************/
function getSelectLayer() {
    var selform = _$("selform");
    if (selform) {
        if (selform.selgroup) {
            var sellayer = selform.selgroup.options[selform.selgroup.selectedIndex].value;
            var layerstring = "&groups=" + sellayer;
            //alert(sellayer);
            return sellayer;
        } else {
            return false;
        }
    } else {
        return false;
    }
}


/**
 * Start auto-identify (iquery)
 */
function applyIquery(mx, my) {
    var imgxy  = mx + "+" + my;
    var queryurl = PM_XAJAX_LOCATION + 'x_info.php?' +SID+ '&mode=iquery' + '&imgxy='+imgxy + '&groups=' + getSelectLayer();
    getQueryResult(queryurl, '');
}


/**
 * TIMER FOR OAUTO_IDENTIFY ACTION 
 * indicates for how much time the cursore remains firm on the map [by Natalia]
 */
function timedCount(moveX, moveY) {  
    if (PMQuery.timer_c == 0){
        X = moveX;
        Y = moveY;
    }
    if (PMQuery.timer_c == 1){
        PMQuery.iquery_timer = setTimeout("applyIquery(" + X + "," + Y + ")", 200);
    }
    PMQuery.timer_c += 1;
    PMQuery.timer_t = setTimeout("timedCount()",PMQuery.timeA);
}


/**
 * Display result in DIV and postion it correctly
 */
function showIQueryResults(queryResult) {
    var iQL = $('#iqueryLayer');
    var IQueryResult = parseJSON_IQuery(queryResult);
    var map = $('#mapImg');
    
    if (PMQuery.follow){
        // border limits
        var limitRG = map.iwidth() - iQL.iwidth() - 4; // Right
        var limitLF = 0;                // Left
        var limitTP = 0;                // Top
        var limitDN = map.iheight() - iQL.iheight() - 4;    // Down
        
         //gap between mouse pointer and iqueryLayer:
        var gap = 10;

        var mapElem = _$('map');//document.getElementById('map');
        if (mapElem) mapElem.onmouseover = getGeoCoords; 
        
        // right:
        if (moveX >= limitRG){
            iQL.left(moveX - iQL.iwidth() - gap + 'px');
        } else {
            iQL.left(moveX + gap +'px');
        }
        
        // down:
        if (moveY >= limitDN){
            iQL.top(moveY - iQL.iheight() - gap + 'px');
        } else {
            iQL.top(moveY + gap +'px');          
        }
    
        if (IQueryResult) {
            iQL.html(IQueryResult).showv();
            if (PMQuery.timeW != -1) PMQuery.timer_to = setTimeout("hideIQL()",PMQuery.timeW);
        } else {
            iQL.html('').hidev();
            clearTimeout(PMQuery.timer_t);
            clearTimeout(PMQuery.iquery_timer);
        }
    // no follow, display on fixed position
    } else {
        if (IQueryResult) {
            iQL.html(IQueryResult).showv();
        } else {
            iQL.html('').hidev();
        }
    }
}


function hideIQL() {
    clearTimeout(PMQuery.iquery_timer);
    $('#iqueryLayer').hidev();
}


function mapImgMouseOut() {
    //alert('out');
    var vMode = _$("varform").mode.value;
    if (vMode == 'iquery' || vMode == 'nquery') {
        $('#iqueryLayer').hidev();
    }
}
/******************************************************************************
 *
 * Purpose: JS functions for XML based search definition
 * Author:  Armin Burger
 *
 ******************************************************************************
 *
 * Copyright (c) 2003-2006 Armin Burger
 *
 * This file is part of p.mapper.
 *
 * p.mapper is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version. See the COPYING file.
 *
 * p.mapper is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with p.mapper; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 ******************************************************************************/

function setSearchOptions() {
    var url = 'incphp/xajax/x_search.php?' + SID +'&action=optionlist';
    createSearchItems(url, '');
}

function setSearchInput() {
    var searchForm = _$('searchForm');
    var searchitem = searchForm.findlist.options[searchForm.findlist.selectedIndex].value;
    var url = 'incphp/xajax/x_search.php?' + SID +'&action=searchitem&searchitem=' + searchitem;
    // ABP: leave as it is...
    // _$('searchForm').findlist.options[0].selected = true;  // reset parent select box to "Search for..."
    //alert(url);
    // ABP: check for 0
    if(!_$('searchForm').findlist.options[0].selected){
        createSearchItems(url, '');
    }
}


function json2Select(jsonObj, def) {
    var html = '<select name="' + jsonObj.selectname + '" ';
    var events = jsonObj.events;
    var size = jsonObj.size;

    if (size > 0) html += ' size="' + size +'" multiple="multiple" ';

    if (events) {
        /*for (var e in events) {
            html += e + '="' + events[e] + '" ';
        }*/
        html += events;
    }

    html += '>';

    var options = jsonObj.options;
    if (def) html += '<option value=\"#\">*</option>';
    for (var o in options) {
        html += '<option value=\"' + o + '\">' + options[o] + '</option>';
    }
    html += '</select>';

    return html;
}


function createSearchInput(jsonObj) {
    var searchitem = jsonObj.searchitem;
    var fields     = jsonObj.fields;
    //alert(fields);
    var html = '';
    for (var i=0; i<fields.length; i++) {
        var description = fields[i].description;
        var fldname     = fields[i].fldname;
        var fldsize     = fields[i].fldsize;
        var fldsizedesc = fields[i].fldsizedesc;
        var fldinline   = fields[i].fldinline;
        var definition  = fields[i].definition;

        var inputsize = fldsize ? ' size="' + fldsize + '" ' : '';
        var sizedesc = fldsizedesc ? ' style="position:absolute; left:' + fldsizedesc + 'em"' : '';

        html += '<div class="searchitem">';
        if (!definition) {
            if (fldinline) html += '<div class="search_inline">';
            html += ' <div class="searchdesc">' + description + '</div>';
            html += ' <div' + sizedesc + '>' + '<input type="text" class="search_textinput" name="' + fldname + '"' + inputsize + '></div>';
            if (fldinline) html += '</div>';

        } else {
            //alert(description + ' - ' + fldname + ' - ' + definition);
            if (definition.type == 'options') {
                html += ' <div class="searchdesc">' + description + '</div>';
                html += ' <div>' + json2Select(definition, true) + '</div>';
            } else if (definition.type == 'suggest') {
                var searchitem  = definition.searchitem;
                var minlength   = definition.minlength;
                pmSuggest.minLength[fldname] = minlength;
                html += '  <div class="searchdesc">' + description + '</div>';
                html += '  <div>';
                html += '    <input type="text" id="' + fldname + '" name="' + fldname + '" alt="Search Criteria" ';
                html +=        ' onkeyup="initSearch(\'' + searchitem + '\', \'' +  fldname + '\')" onfocus="initSearch(\'' + searchitem + '\', \'' +  fldname + '\')" ';
                html +=        ' onblur="searchMouseOut(\'' + fldname + '\')" autocomplete="off" />';
                html += '   <div id="' + fldname + '_search_suggest" class="search_suggest" onmouseover="setMouseOverSuggest()" ';
                html +=         ' onmouseout="setMouseOutSuggest()">';
                html += '   </div>';
                html += ' </div>';

            } else if (definition.type == 'checkbox') {
                var value      = definition.value;
                var defchecked = ''; //(definition.checked == 1) ? ' checked ' : '' ; //" checked="checked" ' : '' ;
                html += '<div class="searchdesc">' + description ;
                html += '<input type="checkbox" id="' + fldname + '" name="' + fldname + '" ' + '" value="' + value + '" ' + defchecked + ' /></div>';

            // Radio Button
            } else if (definition.type == 'radio') {
                var inputlist  = definition.inputlist;

                for (var ipt in inputlist) {
                    var defchecked = (definition.checked == 1) ? ' checked ' : '' ; //" checked="checked" ' : '' ;
                    html += '<div>' + inputlist[ipt]; // + '</div>';
                    html += '<input type="radio" id="' + fldname + '" name="' + fldname + '" ' + '" value="' + ipt + '" ' + defchecked + ' /></div>';
                }

            } else if (definition.type == 'operator') {
                if (fldinline) html += '<div class="search_inline">';
                html += ' <div class="searchdesc">' + description + '</div>';
                html += ' <div' + sizedesc +'>' + json2Select(definition, false);
                html += ' <input type="text" class="search_textinput" name="' + fldname + '" ' + inputsize + '></div>';
                if (fldinline) html += '</div>';
            }
        }
        html += '</div>';
    }
    // ABP: added name search_button to button
    html += '<div class="searchitem"><input type="button" name="search_button" value="' + localeList['Search'] + '" size="20" ';
    html += 'onclick="submitSearch()" onmouseover="changeButtonClr(this, \'over\')" onmouseout="changeButtonClr (this, \'out\')"></div>';

    //html += '<div class="searchitem"><a href="javascript:submitSearch()" class="pm_button"> ' + localeList['Search'] + '</a></div>';

    html += '<input type="hidden"  name="searchitem" value="' + searchitem + '" />';

    //alert(html);
    return html;

}


function getFormKVP(formid) {
    var htmlform = document.getElementById(formid);
    //alert(searchForm.elements);
    var el = htmlform.elements;
    var s = '';
    for (var i=0; i < el.length; i++) {
        var e = el[i];
        var ename = e.name;
        var evalue = e.value;
        var etype = e.type;
        var delim = (i>0 ? '&' : '');

        if (evalue.length > 0 && evalue != '#') {
            //alert(etype + ' - ' + evalue);
            switch (etype) {
                //case 'text':
                case 'select-one':
                    s += delim + ename + '=' + e.options[e.selectedIndex].value;
                    break;

                case 'select-multiple':
                    var ol = e.options;
                    var opttxt = '';
                    for (var o=0; o < ol.length; o++) {
                        if (ol[o].selected) {
                            opttxt += ol[o].value + ',';
                        }
                    }
                    s += delim + ename + '=' + opttxt.substr(0, opttxt.length - 1);
                    break;

                case 'checkbox':
                    if (e.checked) {
                        s += delim + ename  + '=' + evalue;
                    }
                    break;

                case 'radio':
                    if (e.checked) {
                        s += delim + ename  + '=' + evalue;
                    }
                    break;

                default:
                    s += delim + ename  + '=' + evalue;
                    break;

            }
        }
    }
    //alert(s);
    return s;
}


/************************************************************************
 * SUGGEST functions
 * some snippets of this code were taken from http://www.DynamicAJAX.com
   => copyright 2006 Ryan Smith / 345 Technical / 345 Group.
 ***********************************************************************/
// p.mapper Suggest object
var pmSuggest = new Object();
pmSuggest.minLength = new Object();
pmSuggest.slistobj = null;

// Cache for already executed queries
pmSuggest.suggestCache = new Object();

pmSuggest.mouseOverSuggest = false;


function setMouseOverSuggest() {
    pmSuggest.mouseOverSuggest = true;
}

function setMouseOutSuggest() {
    pmSuggest.mouseOverSuggest = false;
}


/**
 * Init suggest search with delay to avoid unnecessary DB queries while typing
 */
pmSuggest.suggest_timer = 0;
function initSearch(searchitem, fldname) {
    clearTimeout(pmSuggest.suggest_timer);
    pmSuggest.suggest_timer = setTimeout("searchSuggest('" + searchitem + "', '" + fldname +"')", 200);
}


/**
 * Run suggest search
 * use suggest cache if existing
 */
function searchSuggest(searchitem, fldname) {
    var searchStr = escape(_$(fldname).value);
    if (searchStr.length >= pmSuggest.minLength[fldname]) {
        //alert(fldname);
        // Check first if query is in cache
        if (pmSuggest.suggestCache[searchStr]) {
            writeSuggestList(pmSuggest.suggestCache[searchStr], fldname);
        // Otherwise make new query
        } else {
            var suggesturl = 'incphp/xajax/x_suggest.php?' + SID +'&search=' + searchStr + '&searchitem=' + searchitem + '&fldname=' + fldname;
            //alert(suggesturl);
            getSuggest(suggesturl, '');
        }
    } else {
        var sobj = _$(fldname + '_search_suggest');
        sobj.style.visibility = 'hidden';
    }
}


/**
 * Create the suggest list and fill the suggest div with child div's
 */
function writeSuggestList(suggestList, fldname) {
    var sobj = $('#' + fldname + '_search_suggest');
    var inputOffs = $('#' + fldname).offset();
    sobj.left(inputOffs['left'] - 10 + 'px');
    sobj.top(inputOffs['height'] + 'px');

    sobj.showv();
    sobj.html('');

    var suggest_all = '';
    for(i=0; i < suggestList.length ; i++) {
        var suggest = '<div onmouseover="javascript:suggestOver(this);" ';
        suggest += 'onmouseout="javascript:suggestOut(this);" ';
        suggest += 'onclick="setSearch(this.innerHTML, \'' + fldname + '\');" ';
        suggest += 'class="suggest_link">' + suggestList[i] + '</div>';
        suggest_all += suggest;
    }
    sobj.html(suggest_all);
}


/**
 * Mouse over function for suggest row
 */
function suggestOver(div_value) {
	div_value.className = 'suggest_link_over';
}


/**
 * Mouse out function for suggest row
 */
function suggestOut(div_value) {
	div_value.className = 'suggest_link';
}


/**
 * onClick function for suggest row
 */
function setSearch(value, fldname) {
    _$(fldname).value = value;
	_$(fldname + '_search_suggest').innerHTML = '';
    hideSuggest(fldname);
}



function searchMouseOut(fldname) {
    if (!pmSuggest.mouseOverSuggest) {
        setTimeout("hideSuggest('" + fldname + "')", 100);
    }
}

/**
 * Hide the suggest DIV when not needed (after insert or click ouside)
 */
function hideSuggest(fldname) {
    var sobj = _$(fldname + '_search_suggest');
    sobj.style.visibility = 'hidden';
}/*******************************************************************
 http://www.kryogenix.org/code/browser/sorttable/
 
 Code downloaded from the Browser Experiments section of 
 kryogenix.org is licenced under the so-called MIT licence. 
 The licence is below.

 Copyright (c) 1997-date Stuart Langridge

 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 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 AUTHORS OR COPYRIGHT 
 HOLDERS 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.

********************************************************************/

//addEvent(window, "load", sortables_init);

var SORT_COLUMN_INDEX;

function sortables_init() {
    // Find all tables with class sortable and make them sortable
    if (!document.getElementsByTagName) return;
    var tbls = document.getElementsByTagName("table");
    //alert(tbls.length);
    for (ti=0;ti<tbls.length;ti++) {
        thisTbl = tbls[ti];
        //alert(thisTbl.className);
        //if (((' '+thisTbl.className+' ').indexOf("sortable") != -1) && (thisTbl.id)) {
        if (thisTbl.className == "sortable") {
            //initTable(thisTbl.id);
            ts_makeSortable(thisTbl);
        }
    }
}

function ts_makeSortable(table) {
    if (table.rows && table.rows.length > 0) {
        var firstRow = table.rows[0];
    }
    if (!firstRow) return;
    
    // We have a first row: assume it's the header, and make its contents clickable links
    for (var i=0;i<firstRow.cells.length;i++) {
        var cell = firstRow.cells[i];
        var txt = ts_getInnerText(cell);
        var headerHtml = '<a href="#" class="sortheader" onclick="ts_resortTable(this);return false;">'+txt+'<span class="sortarrow">&nbsp;&nbsp;&nbsp;</span></a>';
        //alert(headerHtml);
        cell.innerHTML = headerHtml;
    }
}

function ts_getInnerText(el) {
	if (typeof el == "string") return el;
	if (typeof el == "undefined") { return el };
	if (el.innerText) return el.innerText;	//Not needed but it is faster
	var str = "";
	
	var cs = el.childNodes;
	var l = cs.length;
	for (var i = 0; i < l; i++) {
		switch (cs[i].nodeType) {
			case 1: //ELEMENT_NODE
				str += ts_getInnerText(cs[i]);
				break;
			case 3:	//TEXT_NODE
				str += cs[i].nodeValue;
				break;
		}
	}
	return str;
}

/**
 * Functions to align column contents of tables
 * --- Added by Armin Burger ---
 */
function ts_alignTables() {
    var tableList = document.getElementsByTagName("table");
    for (var t=0; t<tableList.length; t++) {
        if (tableList[t].className == 'sortable') {
            ts_alignCols(tableList[t]);
        }
    }
}

function ts_alignCols(table) {
    if (!table.rows[1]) return false;
    var colList = table.rows[1].cells;
    for (var cl=0; cl<colList.length; cl++) {
        var itm = ts_getInnerText(table.rows[1].cells[cl]);
        align = "left";
        if (table.rows[1].cells[cl].className == 'zoomlink') align = "center";
        if (itm.match(/^\d\d[\/-]\d\d[\/-]\d\d\d\d$/)) align = "right";
        if (itm.match(/^\d\d[\/-]\d\d[\/-]\d\d$/)) align = "right";
        if (itm.match(/^[Ł$]/)) align = "right";
        if (itm.match(/^[\d\.]+$/)) align = "right";
        
        for (var r=0; r<table.rows.length;r++) {
            if (table.rows[r].cells[cl]) {
                table.rows[r].cells[cl].style.textAlign = align;
            }
        }
    }
}




function ts_resortTable(lnk) {
    // get the span
    var span;
    for (var ci=0;ci<lnk.childNodes.length;ci++) {
        if (lnk.childNodes[ci].tagName && lnk.childNodes[ci].tagName.toLowerCase() == 'span') span = lnk.childNodes[ci];
    }
    var spantext = ts_getInnerText(span);
    var td = lnk.parentNode;
    var column = td.cellIndex;
    var table = getParent(td,'TABLE');
    
    //ts_alignCols(table);
    
    // Work out a type for the column
    if (table.rows.length <= 1) return;
    var itm = ts_getInnerText(table.rows[1].cells[column]);
    sortfn = ts_sort_caseinsensitive;
    if (itm.match(/^\d\d[\/-]\d\d[\/-]\d\d\d\d$/)) sortfn = ts_sort_date;
    if (itm.match(/^\d\d[\/-]\d\d[\/-]\d\d$/)) sortfn = ts_sort_date;
    if (itm.match(/^[Ł$]/)) sortfn = ts_sort_currency;
    if (itm.match(/^[\d\.]+$/)) sortfn = ts_sort_numeric;
    SORT_COLUMN_INDEX = column;
        
    var firstRow = new Array();
    var newRows = new Array();
    for (i=0;i<table.rows[0].length;i++) { firstRow[i] = table.rows[0][i]; }
    for (j=1;j<table.rows.length;j++) { newRows[j-1] = table.rows[j]; }

    newRows.sort(sortfn);

    if (span.getAttribute("sortdir") == 'down') {
        //ARROW = '&nbsp;&nbsp;&uarr;';
        ARROW = '&nbsp;&nbsp;<img src="images/upsimple.png">';
        newRows.reverse();
        span.setAttribute('sortdir','up');
    } else {
        //ARROW = '&nbsp;&nbsp;&darr;';
        ARROW = '&nbsp;&nbsp;<img src="images/downsimple.png">';
        span.setAttribute('sortdir','down');
    }
    
    // We appendChild rows that already exist to the tbody, so it moves them rather than creating new ones
    // don't do sortbottom rows
    for (i=0;i<newRows.length;i++) { if (!newRows[i].className || (newRows[i].className && (newRows[i].className.indexOf('sortbottom') == -1))) table.tBodies[0].appendChild(newRows[i]);}
    // do sortbottom rows only
    for (i=0;i<newRows.length;i++) { if (newRows[i].className && (newRows[i].className.indexOf('sortbottom') != -1)) table.tBodies[0].appendChild(newRows[i]);}
    
    // Delete any other arrows there may be showing
    var allspans = document.getElementsByTagName("span");
    for (var ci=0;ci<allspans.length;ci++) {
        if (allspans[ci].className == 'sortarrow') {
            if (getParent(allspans[ci],"table") == getParent(lnk,"table")) { // in the same table as us?
                allspans[ci].innerHTML = '&nbsp;&nbsp;&nbsp;';
            }
        }
    }
        
    span.innerHTML = ARROW;
}

function getParent(el, pTagName) {
	if (el == null) return null;
	else if (el.nodeType == 1 && el.tagName.toLowerCase() == pTagName.toLowerCase())	// Gecko bug, supposed to be uppercase
		return el;
	else
		return getParent(el.parentNode, pTagName);
}
function ts_sort_date(a,b) {
    // y2k notes: two digit years less than 50 are treated as 20XX, greater than 50 are treated as 19XX
    aa = ts_getInnerText(a.cells[SORT_COLUMN_INDEX]);
    bb = ts_getInnerText(b.cells[SORT_COLUMN_INDEX]);
    if (aa.length == 10) {
        dt1 = aa.substr(6,4)+aa.substr(3,2)+aa.substr(0,2);
    } else {
        yr = aa.substr(6,2);
        if (parseInt(yr) < 50) { yr = '20'+yr; } else { yr = '19'+yr; }
        dt1 = yr+aa.substr(3,2)+aa.substr(0,2);
    }
    if (bb.length == 10) {
        dt2 = bb.substr(6,4)+bb.substr(3,2)+bb.substr(0,2);
    } else {
        yr = bb.substr(6,2);
        if (parseInt(yr) < 50) { yr = '20'+yr; } else { yr = '19'+yr; }
        dt2 = yr+bb.substr(3,2)+bb.substr(0,2);
    }
    if (dt1==dt2) return 0;
    if (dt1<dt2) return -1;
    return 1;
}

function ts_sort_currency(a,b) { 
    aa = ts_getInnerText(a.cells[SORT_COLUMN_INDEX]).replace(/[^0-9.]/g,'');
    bb = ts_getInnerText(b.cells[SORT_COLUMN_INDEX]).replace(/[^0-9.]/g,'');
    return parseFloat(aa) - parseFloat(bb);
}

function ts_sort_numeric(a,b) { 
    aa = parseFloat(ts_getInnerText(a.cells[SORT_COLUMN_INDEX]));
    if (isNaN(aa)) aa = 0;
    bb = parseFloat(ts_getInnerText(b.cells[SORT_COLUMN_INDEX])); 
    if (isNaN(bb)) bb = 0;
    return aa-bb;
}

function ts_sort_caseinsensitive(a,b) {
    aa = ts_getInnerText(a.cells[SORT_COLUMN_INDEX]).toLowerCase();
    bb = ts_getInnerText(b.cells[SORT_COLUMN_INDEX]).toLowerCase();
    if (aa==bb) return 0;
    if (aa<bb) return -1;
    return 1;
}

function ts_sort_default(a,b) {
    aa = ts_getInnerText(a.cells[SORT_COLUMN_INDEX]);
    bb = ts_getInnerText(b.cells[SORT_COLUMN_INDEX]);
    if (aa==bb) return 0;
    if (aa<bb) return -1;
    return 1;
}


function addEvent(elm, evType, fn, useCapture)
// addEvent and removeEvent
// cross-browser event handling for IE5+,  NS6 and Mozilla
// By Scott Andrew
{
  if (elm.addEventListener){
    elm.addEventListener(evType, fn, useCapture);
    return true;
  } else if (elm.attachEvent){
    var r = elm.attachEvent("on"+evType, fn);
    return r;
  } else {
    alert("Handler could not be removed");
  }
} 

/******************************************************************************
 *
 * Purpose: functions for formatting TOC and legend output
 * Author:  Armin Burger
 *
 ******************************************************************************
 *
 * Copyright (c) 2003-2006 Armin Burger
 *
 * This file is part of p.mapper.
 *
 * p.mapper is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version. See the COPYING file.
 *
 * p.mapper is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with p.mapper; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 ******************************************************************************/


/**
 * initialize and write TOC by calling XMLHttp function 'updateToc()'
 *
 */
function pmToc_init() {
    var tocurl = PM_XAJAX_LOCATION + 'x_toc.php?' + SID;
    updateToc(tocurl, '');
}


/**
 * Initialize TOC tree
 */
function treeInit(catStyle, grpStyle) {
    var catcList = $('div.catc');
    for (var i=0; i<catcList.length; i++) {
        catcList[i].style.display='none';
        tg(catcList[i].id);
    }
    // collapse all groups
    if (PMap.grpStyle == 'tree') {
        $('div.grpc').hide();
    }

    // check/enable default groups
    setDefGroups();

    // check/enable all categories
    $("#toc input[@name='catscbx']").check('on');
}


/**
 * Toggle groups and categories (and related images)
 * attached as onClick script to plus/minus icons and links
 */
function tg(group) {
    var divobj = $('#' + group);
    if (divobj.css('display') == 'none') {
        $('#' + group + '_timg').src('images/tree/minus.gif');
        divobj.show();
    } else {
        $('#' + group + '_timg').src('images/tree/plus.gif');
        divobj.hide();
    }
}



/**
 * Sets popup legedn over map visible
 * attached as onClick script to button
 */
function showPopupLegend() {
    var tocurl = PM_XAJAX_LOCATION + 'x_toc.php?' + SID + '&legendonly=1';
    showMapLegend(tocurl, '');
}


/**
 * for legStyle 'swap': swap from LAYER view to LEGEND view
 * attached as onClick script to button
 */
function swapToLegendView() {
    var tocurl = PM_XAJAX_LOCATION + 'x_toc.php?' + SID + '&legendonly=1&swaplegend=1';
    swapLegend(tocurl, '');
}

/**
 * for legStyle 'swap': swap from LEGEND view to LAYER view
 * attached as onClick script to button
 */
function swapToLayerView() {
    $('#toclegend').hide();
    $('#toc').fadeIn('normal');
    // update TOC CSS depending on scale
    var tocurl = PM_XAJAX_LOCATION + 'x_toc_update.php?' + SID;
    updateTocScale(tocurl, '');
}


/**
 * Set default groups from config.ini to 'ON'
 */
function setDefGroups() {
    var defGroupListL = PMap.defGroupList.length;
    if (defGroupListL > 0) {
        for (var x=0; x<defGroupListL; x++) {
            var chkGrp = _$(PMap.defGroupList[x]);
            if (chkGrp) {
                chkGrp.checked = true;
            }
        }
    }
}


/**
 * Change layers, called from
 * - onclick event of group checkbox)
 * - and setcategories()
 */
function setlayers(selelem, noreload) {
    // if request comes from group checkbox
    if (selelem) {
        // Check if layer is not visible at current scale
        if ((_$('spxg_' + selelem).className == 'unvis') && (!noreload)) {
            noreload = true;
        }

        // Check if layers should be mutually disabled
        if (PMap.mutualDisableList) {
            var mdl = PMap.mutualDisableList;
            if (mdl.inArray(selelem)) {
                for (var i=0; i<mdl.length; i++) {
                    if (mdl[i] != selelem) {
                        _$('ginput_' + mdl[i]).checked = false;
                    }
                }
            }
        }
    }

    var layerstring = '&groups=' + getLayers();

    // reload whole map
    if ((PMap.layerAutoRefresh == '1') && (!noreload)) {
        showloading();
        var mapurl = PM_XAJAX_LOCATION + 'x_load.php?'+SID+'&zoom_type=zoompoint'+ layerstring;
        updateMap(mapurl, '');
    // just update 'groups' array of session, no map reload
    } else {
        var passurl = PM_XAJAX_LOCATION + 'x_layer_update.php?'+SID+layerstring;
        updateSelLayers(passurl, '');
    }
}


/**
 * Return layers/groups
 */
function getLayers() {
    var laystr = '';
    $("#layerform :input[@name='groupscbx'][@checked]").not(':disabled').each(function() {
        laystr += $(this).val() + ',';
    });
    laystr = laystr.substr(0, laystr.length - 1);
    return laystr;
}


/**
 * Set categories (called from onclick event of categories checkbox)
 */
function setcategories(cat) {
    var cat_activated = $('#cinput_' + cat).is(':checked');
    var grpList = $('#' + cat).find('input');
    var checkedLayers = false;
    var visLayers = false;
    for (var i=0; i<grpList.length; i++) {
        var grp = grpList[i];
        if (cat_activated) {
            grp.disabled = false;
        } else {
            grp.disabled = true;
        }
        if (grp.checked) {
            checkedLayers = true;
            if (_$('spxg_' + (grp.id.replace(/ginput_/, ''))).className == 'vis') {
                visLayers = true;
            }
        }
    }
    //alert('checkedLayers ' + checkedLayers + '  -- visLayers ' + visLayers);

    if (checkedLayers && visLayers) {
        setlayers(false, false);
    } else {
        setlayers(false, true);
    }
}


/**
 * Resize TOC container depending on window resize
 * called by pmLayout_init()
 */
function tocResizeUpdate() {
    var tocCont = $('#tocContainer');
    var parentH = tocCont.parent().iheight();
    var tDelta = 0;
    $('#tocContainer').parent().find(' >div').not('#tocContainer').each( function() {
        tDelta += parseInt($(this).height());
    });

    var tocDeltaH = (tDelta > 0 ? tDelta : $('#tocContainer').itop());
    $('#tocContainer').top(tocDeltaH + 'px').height((parentH-tocDeltaH-5) + 'px');
}



/******************************************************************************
 *
 * Purpose: functions for dynamically loading WMS layers
 * Author:  Armin Burger
 *
 ******************************************************************************
 *
 * Copyright (c) 2003-2006 Armin Burger
 *
 * This file is part of p.mapper.
 *
 * p.mapper is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version. See the COPYING file.
 *
 * p.mapper is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with p.mapper; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 ******************************************************************************/


/**
 * open WMS dialog
 */
function openWMSDlg() {
    window.open('wms_dialog.phtml?'+SID, 'wmsdlg','width=500,height=500,status=no,resizable=yes');
}



function wms_getLayers() {
    var IFrameDoc = frames['layerIFrame'];
    var inputList = IFrameDoc.document.getElementsByTagName('input');
    
    var wmsLayerTitle = escape(IFrameDoc._$('wmsLayerTitle').value);
    var layerstring = '';
    var stylestring = '';
    
    for (var i=0; i<inputList.length; i++) {
        inputElem = inputList[i];
        if (inputElem.type == 'checkbox' && inputElem.checked == true) {
            layerstring += escape(inputElem.value) + ',';
            
            var styleName = 'style_' + inputElem.value; 
            var styleList = IFrameDoc.document.getElementsByName(styleName);
            for (var s=0; s<styleList.length; s++) {
                radioElem = styleList[s];
                if (radioElem.checked == true) {
                    selStyle = (radioElem.value == 'default000' ? '' : radioElem.value);  
                    stylestring += escape(selStyle) + ',';
                }
            }
        }
    }
    
    layerstring = layerstring.substr(0, layerstring.length - 1);
    stylestring = stylestring.substr(0, stylestring.length - 1);

    var serviceParams = _$('serviceParams');
    var imgformat = serviceParams.imgformat.options[serviceParams.imgformat.selectedIndex].value;
    var srs =  serviceParams.epsg.options[serviceParams.epsg.selectedIndex].value;
    var transparent = _$('imgtransparent').checked ? 'TRUE' : 'FALSE'; 
    
    //alert(wmsLayerTitle + layerstring + stylestring + imgformat + srs)
    opener.wms_addLayers(wmsLayerTitle, layerstring, stylestring, imgformat, srs, transparent)    
}



function wms_addLayers(wmsLayerTitle, layerstring, stylestring, imgformat, srs, transparent) {
    var wmsurl = PM_XAJAX_LOCATION + 'x_addwms.php?' + SID;
    wmsurl += '&wmslayertitle=' + wmsLayerTitle +  '&layerstring=' + layerstring + '&stylestring=' + stylestring;
    wmsurl += '&imgformat=' + imgformat + '&srs=' + srs + '&transparent=' + transparent;
    //alert(wmsurl);
    addWMS(wmsurl, '');
}



function showAbstract(layerAbstract) {
    var abstractAreaTo = window.parent.document.getElementById('layerAbstractArea');
    var abstractAreaFromHTML = document.getElementById(layerAbstract).innerHTML;
    abstractAreaTo.innerHTML = abstractAreaFromHTML;
}
    
    
function writeServiceName() {
    
}


function showCapabilities() {
    var wmsURL = document.loadwmsform.wmsurl.value + 'REQUEST=GetCapabilities&SERVICE=WMS&VERSION=1.1.1';
    wmsURL = 'wms_showxml.phtml?' + opener.top.SID; // + 'wmsurl=' + escape(wmsURL) ;
    var capswin = window.open(wmsURL, "wmsCapswin","width=600,height=700,status=no,resizable=yes,scrollbars=yes");
}
/* This notice must be untouched at all times.

wz_jsgraphics.js    v. 2.3
The latest version is available at
http://www.walterzorn.com
or http://www.devira.com
or http://www.walterzorn.de

Copyright (c) 2002-2004 Walter Zorn. All rights reserved.
Created 3. 11. 2002 by Walter Zorn (Web: http://www.walterzorn.com )
Last modified: 29. 9. 2004

Performance optimizations for Internet Explorer
by Thomas Frank and John Holdsworth.
fillPolygon method implemented by Matthieu Haller.

High Performance JavaScript Graphics Library.
Provides methods
- to draw lines, rectangles, ellipses, polygons
  with specifiable line thickness,
- to fill rectangles and ellipses
- to draw text.
NOTE: Operations, functions and branching have rather been optimized
to efficiency and speed than to shortness of source code.

LICENSE: LGPL

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License (LGPL) as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA,
or see http://www.gnu.org/copyleft/lesser.html 
*/


var jg_ihtm, jg_ie, jg_fast, jg_dom, jg_moz,
jg_n4 = (document.layers && typeof document.classes != "undefined");


function chkDHTM(x, i)
{
	x = document.body || null;
	jg_ie = x && typeof x.insertAdjacentHTML != "undefined";
	jg_dom = (x && !jg_ie &&
		typeof x.appendChild != "undefined" &&
		typeof document.createRange != "undefined" &&
		typeof (i = document.createRange()).setStartBefore != "undefined" &&
		typeof i.createContextualFragment != "undefined");
	jg_ihtm = !jg_ie && !jg_dom && x && typeof x.innerHTML != "undefined";
	jg_fast = jg_ie && document.all && !window.opera;
	jg_moz = jg_dom && typeof x.style.MozOpacity != "undefined";
}


function pntDoc()
{
	this.wnd.document.write(jg_fast? this.htmRpc() : this.htm);
	this.htm = '';
}


function pntCnvDom()
{
	var x = document.createRange();
	x.setStartBefore(this.cnv);
	x = x.createContextualFragment(jg_fast? this.htmRpc() : this.htm);
	this.cnv.appendChild(x);
	this.htm = '';
}


function pntCnvIe()
{
	this.cnv.insertAdjacentHTML("BeforeEnd", jg_fast? this.htmRpc() : this.htm);
	this.htm = '';
}


function pntCnvIhtm()
{
	this.cnv.innerHTML += this.htm;
	this.htm = '';
}


function pntCnv()
{
	this.htm = '';
}


function mkDiv(x, y, w, h)
{
	this.htm += '<div style="position:absolute;'+
		'left:' + x + 'px;'+
		'top:' + y + 'px;'+
		'width:' + w + 'px;'+
		'height:' + h + 'px;'+
		'clip:rect(0,'+w+'px,'+h+'px,0);'+
		'background-color:' + this.color +
		(!jg_moz? ';overflow:hidden' : '')+
		';"><\/div>';
}


function mkDivIe(x, y, w, h)
{
	this.htm += '%%'+this.color+';'+x+';'+y+';'+w+';'+h+';';
}


function mkDivPrt(x, y, w, h)
{
	this.htm += '<div style="position:absolute;'+
		'border-left:' + w + 'px solid ' + this.color + ';'+
		'left:' + x + 'px;'+
		'top:' + y + 'px;'+
		'width:0px;'+
		'height:' + h + 'px;'+
		'clip:rect(0,'+w+'px,'+h+'px,0);'+
		'background-color:' + this.color +
		(!jg_moz? ';overflow:hidden' : '')+
		';"><\/div>';
}


function mkLyr(x, y, w, h)
{
	this.htm += '<layer '+
		'left="' + x + '" '+
		'top="' + y + '" '+
		'width="' + w + '" '+
		'height="' + h + '" '+
		'bgcolor="' + this.color + '"><\/layer>\n';
}


var regex =  /%%([^;]+);([^;]+);([^;]+);([^;]+);([^;]+);/g;
function htmRpc()
{
	return this.htm.replace(
		regex,
		'<div style="overflow:hidden;position:absolute;background-color:'+
		'$1;left:$2;top:$3;width:$4;height:$5"></div>\n');
}


function htmPrtRpc()
{
	return this.htm.replace(
		regex,
		'<div style="overflow:hidden;position:absolute;background-color:'+
		'$1;left:$2;top:$3;width:$4;height:$5;border-left:$4px solid $1"></div>\n');
}


function mkLin(x1, y1, x2, y2)
{
	if (x1 > x2)
	{
		var _x2 = x2;
		var _y2 = y2;
		x2 = x1;
		y2 = y1;
		x1 = _x2;
		y1 = _y2;
	}
	var dx = x2-x1, dy = Math.abs(y2-y1),
	x = x1, y = y1,
	yIncr = (y1 > y2)? -1 : 1;

	if (dx >= dy)
	{
		var pr = dy<<1,
		pru = pr - (dx<<1),
		p = pr-dx,
		ox = x;
		while ((dx--) > 0)
		{
			++x;
			if (p > 0)
			{
				this.mkDiv(ox, y, x-ox, 1);
				y += yIncr;
				p += pru;
				ox = x;
			}
			else p += pr;
		}
		this.mkDiv(ox, y, x2-ox+1, 1);
	}

	else
	{
		var pr = dx<<1,
		pru = pr - (dy<<1),
		p = pr-dy,
		oy = y;
		if (y2 <= y1)
		{
			while ((dy--) > 0)
			{
				if (p > 0)
				{
					this.mkDiv(x++, y, 1, oy-y+1);
					y += yIncr;
					p += pru;
					oy = y;
				}
				else
				{
					y += yIncr;
					p += pr;
				}
			}
			this.mkDiv(x2, y2, 1, oy-y2+1);
		}
		else
		{
			while ((dy--) > 0)
			{
				y += yIncr;
				if (p > 0)
				{
					this.mkDiv(x++, oy, 1, y-oy);
					p += pru;
					oy = y;
				}
				else p += pr;
			}
			this.mkDiv(x2, oy, 1, y2-oy+1);
		}
	}
}


function mkLin2D(x1, y1, x2, y2)
{
	if (x1 > x2)
	{
		var _x2 = x2;
		var _y2 = y2;
		x2 = x1;
		y2 = y1;
		x1 = _x2;
		y1 = _y2;
	}
	var dx = x2-x1, dy = Math.abs(y2-y1),
	x = x1, y = y1,
	yIncr = (y1 > y2)? -1 : 1;

	var s = this.stroke;
	if (dx >= dy)
	{
		if (s-3 > 0)
		{
			var _s = (s*dx*Math.sqrt(1+dy*dy/(dx*dx))-dx-(s>>1)*dy) / dx;
			_s = (!(s-4)? Math.ceil(_s) : Math.round(_s)) + 1;
		}
		else var _s = s;
		var ad = Math.ceil(s/2);

		var pr = dy<<1,
		pru = pr - (dx<<1),
		p = pr-dx,
		ox = x;
		while ((dx--) > 0)
		{
			++x;
			if (p > 0)
			{
				this.mkDiv(ox, y, x-ox+ad, _s);
				y += yIncr;
				p += pru;
				ox = x;
			}
			else p += pr;
		}
		this.mkDiv(ox, y, x2-ox+ad+1, _s);
	}

	else
	{
		if (s-3 > 0)
		{
			var _s = (s*dy*Math.sqrt(1+dx*dx/(dy*dy))-(s>>1)*dx-dy) / dy;
			_s = (!(s-4)? Math.ceil(_s) : Math.round(_s)) + 1;
		}
		else var _s = s;
		var ad = Math.round(s/2);

		var pr = dx<<1,
		pru = pr - (dy<<1),
		p = pr-dy,
		oy = y;
		if (y2 <= y1)
		{
			++ad;
			while ((dy--) > 0)
			{
				if (p > 0)
				{
					this.mkDiv(x++, y, _s, oy-y+ad);
					y += yIncr;
					p += pru;
					oy = y;
				}
				else
				{
					y += yIncr;
					p += pr;
				}
			}
			this.mkDiv(x2, y2, _s, oy-y2+ad);
		}
		else
		{
			while ((dy--) > 0)
			{
				y += yIncr;
				if (p > 0)
				{
					this.mkDiv(x++, oy, _s, y-oy+ad);
					p += pru;
					oy = y;
				}
				else p += pr;
			}
			this.mkDiv(x2, oy, _s, y2-oy+ad+1);
		}
	}
}


function mkLinDott(x1, y1, x2, y2)
{
	if (x1 > x2)
	{
		var _x2 = x2;
		var _y2 = y2;
		x2 = x1;
		y2 = y1;
		x1 = _x2;
		y1 = _y2;
	}
	var dx = x2-x1, dy = Math.abs(y2-y1),
	x = x1, y = y1,
	yIncr = (y1 > y2)? -1 : 1,
	drw = true;
	if (dx >= dy)
	{
		var pr = dy<<1,
		pru = pr - (dx<<1),
		p = pr-dx;
		while ((dx--) > 0)
		{
			if (drw) this.mkDiv(x, y, 1, 1);
			drw = !drw;
			if (p > 0)
			{
				y += yIncr;
				p += pru;
			}
			else p += pr;
			++x;
		}
		if (drw) this.mkDiv(x, y, 1, 1);
	}

	else
	{
		var pr = dx<<1,
		pru = pr - (dy<<1),
		p = pr-dy;
		while ((dy--) > 0)
		{
			if (drw) this.mkDiv(x, y, 1, 1);
			drw = !drw;
			y += yIncr;
			if (p > 0)
			{
				++x;
				p += pru;
			}
			else p += pr;
		}
		if (drw) this.mkDiv(x, y, 1, 1);
	}
}


function mkOv(left, top, width, height)
{
	var a = width>>1, b = height>>1,
	wod = width&1, hod = (height&1)+1,
	cx = left+a, cy = top+b,
	x = 0, y = b,
	ox = 0, oy = b,
	aa = (a*a)<<1, bb = (b*b)<<1,
	st = (aa>>1)*(1-(b<<1)) + bb,
	tt = (bb>>1) - aa*((b<<1)-1),
	w, h;
	while (y > 0)
	{
		if (st < 0)
		{
			st += bb*((x<<1)+3);
			tt += (bb<<1)*(++x);
		}
		else if (tt < 0)
		{
			st += bb*((x<<1)+3) - (aa<<1)*(y-1);
			tt += (bb<<1)*(++x) - aa*(((y--)<<1)-3);
			w = x-ox;
			h = oy-y;
			if (w&2 && h&2)
			{
				this.mkOvQds(cx, cy, -x+2, ox+wod, -oy, oy-1+hod, 1, 1);
				this.mkOvQds(cx, cy, -x+1, x-1+wod, -y-1, y+hod, 1, 1);
			}
			else this.mkOvQds(cx, cy, -x+1, ox+wod, -oy, oy-h+hod, w, h);
			ox = x;
			oy = y;
		}
		else
		{
			tt -= aa*((y<<1)-3);
			st -= (aa<<1)*(--y);
		}
	}
	this.mkDiv(cx-a, cy-oy, a-ox+1, (oy<<1)+hod);
	this.mkDiv(cx+ox+wod, cy-oy, a-ox+1, (oy<<1)+hod);
}


function mkOv2D(left, top, width, height)
{
	var s = this.stroke;
	width += s-1;
	height += s-1;
	var a = width>>1, b = height>>1,
	wod = width&1, hod = (height&1)+1,
	cx = left+a, cy = top+b,
	x = 0, y = b,
	aa = (a*a)<<1, bb = (b*b)<<1,
	st = (aa>>1)*(1-(b<<1)) + bb,
	tt = (bb>>1) - aa*((b<<1)-1);

	if (s-4 < 0 && (!(s-2) || width-51 > 0 && height-51 > 0))
	{
		var ox = 0, oy = b,
		w, h,
		pxl, pxr, pxt, pxb, pxw;
		while (y > 0)
		{
			if (st < 0)
			{
				st += bb*((x<<1)+3);
				tt += (bb<<1)*(++x);
			}
			else if (tt < 0)
			{
				st += bb*((x<<1)+3) - (aa<<1)*(y-1);
				tt += (bb<<1)*(++x) - aa*(((y--)<<1)-3);
				w = x-ox;
				h = oy-y;

				if (w-1)
				{
					pxw = w+1+(s&1);
					h = s;
				}
				else if (h-1)
				{
					pxw = s;
					h += 1+(s&1);
				}
				else pxw = h = s;
				this.mkOvQds(cx, cy, -x+1, ox-pxw+w+wod, -oy, -h+oy+hod, pxw, h);
				ox = x;
				oy = y;
			}
			else
			{
				tt -= aa*((y<<1)-3);
				st -= (aa<<1)*(--y);
			}
		}
		this.mkDiv(cx-a, cy-oy, s, (oy<<1)+hod);
		this.mkDiv(cx+a+wod-s+1, cy-oy, s, (oy<<1)+hod);
	}

	else
	{
		var _a = (width-((s-1)<<1))>>1,
		_b = (height-((s-1)<<1))>>1,
		_x = 0, _y = _b,
		_aa = (_a*_a)<<1, _bb = (_b*_b)<<1,
		_st = (_aa>>1)*(1-(_b<<1)) + _bb,
		_tt = (_bb>>1) - _aa*((_b<<1)-1),

		pxl = new Array(),
		pxt = new Array(),
		_pxb = new Array();
		pxl[0] = 0;
		pxt[0] = b;
		_pxb[0] = _b-1;
		while (y > 0)
		{
			if (st < 0)
			{
				st += bb*((x<<1)+3);
				tt += (bb<<1)*(++x);
				pxl[pxl.length] = x;
				pxt[pxt.length] = y;
			}
			else if (tt < 0)
			{
				st += bb*((x<<1)+3) - (aa<<1)*(y-1);
				tt += (bb<<1)*(++x) - aa*(((y--)<<1)-3);
				pxl[pxl.length] = x;
				pxt[pxt.length] = y;
			}
			else
			{
				tt -= aa*((y<<1)-3);
				st -= (aa<<1)*(--y);
			}

			if (_y > 0)
			{
				if (_st < 0)
				{
					_st += _bb*((_x<<1)+3);
					_tt += (_bb<<1)*(++_x);
					_pxb[_pxb.length] = _y-1;
				}
				else if (_tt < 0)
				{
					_st += _bb*((_x<<1)+3) - (_aa<<1)*(_y-1);
					_tt += (_bb<<1)*(++_x) - _aa*(((_y--)<<1)-3);
					_pxb[_pxb.length] = _y-1;
				}
				else
				{
					_tt -= _aa*((_y<<1)-3);
					_st -= (_aa<<1)*(--_y);
					_pxb[_pxb.length-1]--;
				}
			}
		}

		var ox = 0, oy = b,
		_oy = _pxb[0],
		l = pxl.length,
		w, h;
		for (var i = 0; i < l; i++)
		{
			if (typeof _pxb[i] != "undefined")
			{
				if (_pxb[i] < _oy || pxt[i] < oy)
				{
					x = pxl[i];
					this.mkOvQds(cx, cy, -x+1, ox+wod, -oy, _oy+hod, x-ox, oy-_oy);
					ox = x;
					oy = pxt[i];
					_oy = _pxb[i];
				}
			}
			else
			{
				x = pxl[i];
				this.mkDiv(cx-x+1, cy-oy, 1, (oy<<1)+hod);
				this.mkDiv(cx+ox+wod, cy-oy, 1, (oy<<1)+hod);
				ox = x;
				oy = pxt[i];
			}
		}
		this.mkDiv(cx-a, cy-oy, 1, (oy<<1)+hod);
		this.mkDiv(cx+ox+wod, cy-oy, 1, (oy<<1)+hod);
	}
}


function mkOvDott(left, top, width, height)
{
	var a = width>>1, b = height>>1,
	wod = width&1, hod = height&1,
	cx = left+a, cy = top+b,
	x = 0, y = b,
	aa2 = (a*a)<<1, aa4 = aa2<<1, bb = (b*b)<<1,
	st = (aa2>>1)*(1-(b<<1)) + bb,
	tt = (bb>>1) - aa2*((b<<1)-1),
	drw = true;
	while (y > 0)
	{
		if (st < 0)
		{
			st += bb*((x<<1)+3);
			tt += (bb<<1)*(++x);
		}
		else if (tt < 0)
		{
			st += bb*((x<<1)+3) - aa4*(y-1);
			tt += (bb<<1)*(++x) - aa2*(((y--)<<1)-3);
		}
		else
		{
			tt -= aa2*((y<<1)-3);
			st -= aa4*(--y);
		}
		if (drw) this.mkOvQds(cx, cy, -x, x+wod, -y, y+hod, 1, 1);
		drw = !drw;
	}
}


function mkRect(x, y, w, h)
{
	var s = this.stroke;
	this.mkDiv(x, y, w, s);
	this.mkDiv(x+w, y, s, h);
	this.mkDiv(x, y+h, w+s, s);
	this.mkDiv(x, y+s, s, h-s);
}


function mkRectDott(x, y, w, h)
{
	this.drawLine(x, y, x+w, y);
	this.drawLine(x+w, y, x+w, y+h);
	this.drawLine(x, y+h, x+w, y+h);
	this.drawLine(x, y, x, y+h);
}


function jsgFont()
{
	this.PLAIN = 'font-weight:normal;';
	this.BOLD = 'font-weight:bold;';
	this.ITALIC = 'font-style:italic;';
	this.ITALIC_BOLD = this.ITALIC + this.BOLD;
	this.BOLD_ITALIC = this.ITALIC_BOLD;
}
var Font = new jsgFont();


function jsgStroke()
{
	this.DOTTED = -1;
}
var Stroke = new jsgStroke();


function jsGraphics(id, wnd)
{
	this.setColor = new Function('arg', 'this.color = arg.toLowerCase();');

	this.setStroke = function(x)
	{
		this.stroke = x;
		if (!(x+1))
		{
			this.drawLine = mkLinDott;
			this.mkOv = mkOvDott;
			this.drawRect = mkRectDott;
		}
		else if (x-1 > 0)
		{
			this.drawLine = mkLin2D;
			this.mkOv = mkOv2D;
			this.drawRect = mkRect;
		}
		else
		{
			this.drawLine = mkLin;
			this.mkOv = mkOv;
			this.drawRect = mkRect;
		}
	};


	this.setPrintable = function(arg)
	{
		this.printable = arg;
		if (jg_fast)
		{
			this.mkDiv = mkDivIe;
			this.htmRpc = arg? htmPrtRpc : htmRpc;
		}
		else this.mkDiv = jg_n4? mkLyr : arg? mkDivPrt : mkDiv;
	};


	this.setFont = function(fam, sz, sty)
	{
		this.ftFam = fam;
		this.ftSz = sz;
		this.ftSty = sty || Font.PLAIN;
	};


	this.drawPolyline = this.drawPolyLine = function(x, y, s)
	{
		for (var i=0 ; i<x.length-1 ; i++ )
			this.drawLine(x[i], y[i], x[i+1], y[i+1]);
	};


	this.fillRect = function(x, y, w, h)
	{
		this.mkDiv(x, y, w, h);
	};


	this.drawPolygon = function(x, y)
	{
		this.drawPolyline(x, y);
		this.drawLine(x[x.length-1], y[x.length-1], x[0], y[0]);
	};


	this.drawEllipse = this.drawOval = function(x, y, w, h)
	{
		this.mkOv(x, y, w, h);
	};


	this.fillEllipse = this.fillOval = function(left, top, w, h)
	{
		var a = (w -= 1)>>1, b = (h -= 1)>>1,
		wod = (w&1)+1, hod = (h&1)+1,
		cx = left+a, cy = top+b,
		x = 0, y = b,
		ox = 0, oy = b,
		aa2 = (a*a)<<1, aa4 = aa2<<1, bb = (b*b)<<1,
		st = (aa2>>1)*(1-(b<<1)) + bb,
		tt = (bb>>1) - aa2*((b<<1)-1),
		pxl, dw, dh;
		if (w+1) while (y > 0)
		{
			if (st < 0)
			{
				st += bb*((x<<1)+3);
				tt += (bb<<1)*(++x);
			}
			else if (tt < 0)
			{
				st += bb*((x<<1)+3) - aa4*(y-1);
				pxl = cx-x;
				dw = (x<<1)+wod;
				tt += (bb<<1)*(++x) - aa2*(((y--)<<1)-3);
				dh = oy-y;
				this.mkDiv(pxl, cy-oy, dw, dh);
				this.mkDiv(pxl, cy+oy-dh+hod, dw, dh);
				ox = x;
				oy = y;
			}
			else
			{
				tt -= aa2*((y<<1)-3);
				st -= aa4*(--y);
			}
		}
		this.mkDiv(cx-a, cy-oy, w+1, (oy<<1)+hod);
	};



/* fillPolygon method, implemented by Matthieu Haller.
This javascript function is an adaptation of the gdImageFilledPolygon for Walter Zorn lib.
C source of GD 1.8.4 found at http://www.boutell.com/gd/

THANKS to Kirsten Schulz for the polygon fixes!

The intersection finding technique of this code could be improved
by remembering the previous intertersection, and by using the slope.
That could help to adjust intersections to produce a nice
interior_extrema. */
	this.fillPolygon = function(array_x, array_y)
	{
		var i;
		var y;
		var miny, maxy;
		var x1, y1;
		var x2, y2;
		var ind1, ind2;
		var ints;

		var n = array_x.length;

		if (!n) return;


		miny = array_y[0];
		maxy = array_y[0];
		for (i = 1; i < n; i++)
		{
			if (array_y[i] < miny)
				miny = array_y[i];

			if (array_y[i] > maxy)
				maxy = array_y[i];
		}
		for (y = miny; y <= maxy; y++)
		{
			var polyInts = new Array();
			ints = 0;
			for (i = 0; i < n; i++)
			{
				if (!i)
				{
					ind1 = n-1;
					ind2 = 0;
				}
				else
				{
					ind1 = i-1;
					ind2 = i;
				}
				y1 = array_y[ind1];
				y2 = array_y[ind2];
				if (y1 < y2)
				{
					x1 = array_x[ind1];
					x2 = array_x[ind2];
				}
				else if (y1 > y2)
				{
					y2 = array_y[ind1];
					y1 = array_y[ind2];
					x2 = array_x[ind1];
					x1 = array_x[ind2];
				}
				else continue;

				 // modified 11. 2. 2004 Walter Zorn
				if ((y >= y1) && (y < y2))
					polyInts[ints++] = Math.round((y-y1) * (x2-x1) / (y2-y1) + x1);

				else if ((y == maxy) && (y > y1) && (y <= y2))
					polyInts[ints++] = Math.round((y-y1) * (x2-x1) / (y2-y1) + x1);
			}
			polyInts.sort(integer_compare);

			for (i = 0; i < ints; i+=2)
			{
				w = polyInts[i+1]-polyInts[i];
				this.mkDiv(polyInts[i], y, polyInts[i+1]-polyInts[i]+1, 1);
			}
		}
	};


	this.drawString = function(txt, x, y)
	{
		this.htm += '<div style="position:absolute;white-space:nowrap;'+
			'left:' + x + 'px;'+
			'top:' + y + 'px;'+
			'font-family:' +  this.ftFam + ';'+
			'font-size:' + this.ftSz + ';'+
			'color:' + this.color + ';' + this.ftSty + '">'+
			txt +
			'<\/div>';
	}


	this.drawImage = function(imgSrc, x, y, w, h)
	{
		this.htm += '<div style="position:absolute;'+
			'left:' + x + 'px;'+
			'top:' + y + 'px;'+
			'width:' +  w + ';'+
			'height:' + h + ';">'+
			'<img src="' + imgSrc + '" width="' + w + '" height="' + h + '">'+
			'<\/div>';
	}


	this.clear = function()
	{
		this.htm = "";
		if (this.cnv) this.cnv.innerHTML = this.defhtm;
	};


	this.mkOvQds = function(cx, cy, xl, xr, yt, yb, w, h)
	{
		this.mkDiv(xr+cx, yt+cy, w, h);
		this.mkDiv(xr+cx, yb+cy, w, h);
		this.mkDiv(xl+cx, yb+cy, w, h);
		this.mkDiv(xl+cx, yt+cy, w, h);
	};

	this.setStroke(1);
	this.setFont('verdana,geneva,helvetica,sans-serif', String.fromCharCode(0x31, 0x32, 0x70, 0x78), Font.PLAIN);
	this.color = '#000000';
	this.htm = '';
	this.wnd = wnd || window;

	if (!(jg_ie || jg_dom || jg_ihtm)) chkDHTM();
	if (typeof id != 'string' || !id) this.paint = pntDoc;
	else
	{
		this.cnv = document.all? (this.wnd.document.all[id] || null)
			: document.getElementById? (this.wnd.document.getElementById(id) || null)
			: null;
		this.defhtm = (this.cnv && this.cnv.innerHTML)? this.cnv.innerHTML : '';
		this.paint = jg_dom? pntCnvDom : jg_ie? pntCnvIe : jg_ihtm? pntCnvIhtm : pntCnv;
	}

	this.setPrintable(false);
}



function integer_compare(x,y)
{
	return (x < y) ? -1 : ((x > y)*1);
}


/******************************************************************************
 *
 * Purpose: AJAX (XMLHTTP) requests
 * Author:  Armin Burger
 *
 ******************************************************************************
 *
 * Copyright (c) 2003-2006 Armin Burger
 *
 * This file is part of p.mapper.
 *
 * p.mapper is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version. See the COPYING file.
 *
 * p.mapper is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with p.mapper; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 ******************************************************************************/


/**
 * For loading/updating the MAP
 */
function updateMap(murl) {
    var loadObj = document.getElementById("loading");

    $.ajax({
        url: murl,
        dataType: "json",
        success: function(response){

            // Reload application when PHP session expired
            var sessionerror = response.sessionerror;
            if (sessionerror == 'true') {
               errormsg = localeList['sessionExpired'];
               //alert(errormsg);
               window.location.reload();
               return false;
            }

            var rBxL = response.refBoxStr.split(',');
            //var refW = response.refW;
            //var refH = response.refH;
            minx_geo = parseFloat(response.minx_geo);
            maxy_geo = parseFloat(response.maxy_geo);
            xdelta_geo = parseFloat(response.xdelta_geo);
            ydelta_geo = parseFloat(response.ydelta_geo);
            var geo_scale = response.geo_scale;
            var urlPntStr = response.urlPntStr;

            // Load new map image
            loadMapImg(response.mapURL);


            // Check if TOC has to be updated
            var refreshToc = eval(response.refreshToc);
            //refreshToc = true;
            if (refreshToc) {
                //alert("refresh");
                var tocurl = PM_XAJAX_LOCATION + 'x_toc_update.php?' + SID;
                updateTocScale(tocurl);
            }

            // Scale-related activities
            writescale(geo_scale);
            setSlider(geo_scale);
            PMap.scale = geo_scale;

            // Reference image: set DHTML objects
            setRefBox(rBxL[0], rBxL[1], rBxL[2], rBxL[3]);

            // reset cursor
            //setCursor(false);

            // Update SELECT tool OPTIONs in case of 'select' mode
            var vMode = _$("varform").mode.value;
            var autoidentify = '';
            if (vMode == 'nquery' || vMode == 'iquery') {
                if (vMode == 'iquery'){
                    autoidentify = '&autoidentify=1';
                }
                var selurl = PM_XAJAX_LOCATION + 'x_select.php?'+ SID + '&activegroup=' + getSelectLayer() + autoidentify;
                updateSelectTool(selurl);
            }

            // If measure was active, delete all masure elements
            if (vMode == 'measure') {
                resetMeasure();
            }


            //Update map link
            var dg = getLayers();
            var maxx_geo = xdelta_geo + minx_geo;
            var miny_geo = maxy_geo - ydelta_geo;
            var me = minx_geo + ',' + miny_geo + ',' + maxx_geo + ',' + maxy_geo;
            var confpar = PMap.config.length > 0 ? '&config=' + PMap.config : '';
            var urlPntStrPar = urlPntStr.length > 1 ? '&up=' + urlPntStr : '';
            var loc = window.location;
            var port = loc.port > 0 ? ':' + loc.port : '';
            var linkhref = loc.protocol + '/' + '/' + loc.hostname + port + loc.pathname + '?dg=' + dg + '&me=' + me + '&language=' + PMap.gLanguage + confpar + urlPntStrPar;

            if (_$('current_maplink')) _$('current_maplink').href = linkhref;

        }
    });
}


/**
 * Update the TOC
 */
function updateToc(tocurl) {
    $.ajax({
        url: tocurl,
        dataType: "json",
        success: function(response){
            var tocHTML = response.tocHTML;
            setInnerHTML('toc',tocHTML);

            var tocButtons = response.tocButtons;
            if (tocButtons.length > 0) {
                $('#autoRefreshButton').html(tocButtons);
            }

            var tocurl = PM_XAJAX_LOCATION + 'x_toc_update.php?' + SID;
            updateTocScale(tocurl);
        }
    });
}


/**
 * Update toc applying different styles to visible/not-visible layers
 */
function updateTocScale(tocurl) {
    $.ajax({
        url: tocurl,
        dataType: "json",
        success: function(response){
            var legStyle = response.legStyle;
            var layers = response.layers;

            if (legStyle == "swap" && $('#toclegend').css('display') == 'block') {
                swapToLegendView();
            }

            for (var l in layers) {
                var spanList = document.getElementsByTagName('span');
                var sl = spanList.length;
                for (var l in layers) {
                     $('#spxg_' + l).removeClass('unvis').removeClass('vis').addClass(layers[l]);
                }
            }
        }
    });
}


/**
 * Show legend over MAP
 */
function showMapLegend(tocurl) {
    $.ajax({
        url: tocurl,
        dataType: "json",
        success: function(response){
            var tocHTML = response.tocHTML;
            // alert(tocHTML);
            var legDiv = _$('maplegend');
            setInnerHTML('maplegend',tocHTML);
            legDiv.style.visibility = 'visible';
        }
    });
}


/**
 * Swap from TOC to LEGEND view
 */
function swapLegend(tocurl) {
    $.ajax({
        url: tocurl,
        dataType: "json",
        success: function(response){
            var tocHTML = response.tocHTML;
            $('#toclegend').html(tocHTML);
            $('#toc').hide();
            $('#toclegend').show(); //fadeIn('normal');
        }
    });
}


/**
 * For SELECT tool
 */
function updateSelectTool(selurl) {
    $.ajax({
        url: selurl,
        dataType: "json",
        success: function(response){
            var selStr = response.selStr;
            $('#mapToolArea').html(selStr);
            // ABP: effect
            $('#mapToolArea').fadeIn('slow');
        }
    });
}


/**
 * Update layer options list for selection/iquery
 */
function updateSelLayers(selurl) {
    $.ajax({
        url: selurl,
        dataType: "json",
        success: function(response){
            var sellayers = response.sellayers;

            // Update SELECT tool OPTIONs in case of 'select' mode
            var vMode = _$("varform").mode.value;
            if (vMode == 'nquery' || vMode == 'iquery') {
                var selurl = PM_XAJAX_LOCATION + 'x_select.php?'+ SID + '&activegroup=' + getSelectLayer() ;
                updateSelectTool(selurl);
            }
        }
    });
}


/**
 * Add point of interest to map
 */
function addPOI(digitizeurl) {
    $.ajax({
        url: digitizeurl,
        success: function(response){
            changeLayersDraw();
        }
    });
}


/**
 * Get query results and display them by parsing the JSON result string
 */
function getQueryResult(qurl, params) {
    $.ajax({
        type: "POST",
        url: qurl,
        data: params,
        dataType: "json",
        success: function(response){
            var mode = response.mode;
            var queryResult = response.queryResult;

            if (mode != 'iquery') {
                if (PMap.infoWin == 'window') {
                    openResultwin('info.phtml?'+SID);
                } else {
                    //if (PMap.infoWin == 'frame')
                    $('#infoZone').showv();
                    writeQResult(queryResult, PMap.infoWin);
                    // ABP: show
                    if(Layout.InfoZoneStyle == 4){
                        $('#infoZone').fadeIn("slow");
                        $('#infoZone').fadeTo("fast", 0.9);
                        $('div.LAYERHEADER').prepend('<a href="javascript:void(0);" onclick="$(\'#infoZone\').fadeOut();return false;"><img src="images/close.gif" border=0 ></a>&nbsp;');
                    }
                }
            } else {
                // Display result in DIV and postion it correctly
                showIQueryResults(queryResult);
            }
        }
    });
}


/**
 * Export query result
 */
function exportQueryResults(expurl) {
    $.ajax({
        url: expurl,
        success: function(response){
            //var mode = response.mode;
        }
    });
}


/**
 * Export query result
 */
function addWMS(url) {
    $.ajax({
        url: url,
        success: function(response){
            pmToc_init();
        }
    });
}


/**
 * Attribute search: create items for search definitions
 */
function createSearchItems(url) {
    $.ajax({
        url: url,
        dataType: "json",
        success: function(response){
            var searchJson = response.searchJson;
            var action = response.action;
            var divelem = response.divelem;

            if (action == 'searchitem') {
                var searchHtml = createSearchInput(searchJson);
                //alert(searchHtml);
                $('#searchitems').html(searchHtml);
            } else {
                var searchHtml = json2Select(searchJson);
                $('#searchoptions').html(searchHtml);
            }
        }
    });
}


function getSuggest(suggesturl) {
    $.ajax({
        url: suggesturl,
        dataType: "json",
        success: function(response){
            var searchGet   = response.searchGet;
            var suggestList = response.retvalue;
            var fldname     = response.fldname;

            // add result to suggest cache
            pmSuggest.suggestCache[searchGet] = suggestList;

            // write out suggest options
            writeSuggestList(suggestList, fldname);
        }
    });
}


/******************************************************************************
 *
 * Purpose: functions related to map navigation and mouse events
 * Author:  Armin Burger
 *
 ******************************************************************************
 *
 * Copyright (c) 2003-2006 Armin Burger
 *
 * This file is part of p.mapper.
 *
 * p.mapper is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version. See the COPYING file.
 *
 * p.mapper is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with p.mapper; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 ******************************************************************************/


/**
 * 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 m_offsX = 0;
var m_offsY = 0;




/**
 * 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 = document.getElementById('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');
    }

}



/**
 * FOR MOUSE OVER REFERENCE MAP
 */
function startUpRef() {
    clearTimeout(PMQuery.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') {
        var oMap = $('#map');
        mapcL = oMap.offset()['left'] + 1;
        mapcT = oMap.offset()['top'] + 1;
        mapcR = mapcL + mapW;
        mapcB = mapcT + mapH;
        var curelem = oMap;
    // REFERENCE MAP
    } else {
        var rMap = $('#refmap');
        mapcL = rMap.offset()['left'] ;
        mapcT = rMap.offset()['top'];
        mapcR = mapcL + refW ;
        mapcB = mapcT + refH ;
        var curelem = rMap;
    }

    offsX = curelem.offset()['left'] + 1;
    offsY = curelem.offset()['top'] + 1;

}

/**
 * Check position of mouse
 */
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

    return false;
}


/**
 * For MouseUp
 */
function getUpXY(e) {
    if (document.all) {
        eX = event.clientX;
        eY = event.clientY;
    } else {
        eX = e.pageX;
        eY = e.pageY;
    }

    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 = moveX - offsX;
    moveY = moveY - offsY;
}


/*
 * BASIC MOUSE FUNCTIONS: DOWN, UP, MOVE
 ******************************************************/
/**
 * Mouse DOWN
 */
function doMouseDown(e) {
    e = (e)?e:((event)?event:null);

    try {
        if (enableRightMousePan) {
            if (e.button == 2) {
                rightMouseButton = true;
                setCursor(true, false);
            } else {
                rightMouseButton = false;
            }
        }
    } catch(e) {

    }

    // ENABLES ACTIONS FOR KEYBOARD KEYS
    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;
}

/**
 * Mouse UP
 */
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' || maction == 'digitize') {
            //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;
            setCursor(false, 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
            alert(upX + ' ref out');
            return false;
        } else {
            //alert(upX +', '+ upY +', '+ upX +', '+ upY);
            zoombox_apply(upX, upY, upX, upY);
        }
    }

    return false;
}

/**
 * Mouse MOVE
 */
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(PMQuery.iquery_timer);
                            PMQuery.iquery_timer = setTimeout("applyIquery(" + moveX + "," + moveY + ")", 300);
                        }
                    } catch(e) {
                        return false;
                    }
                }
                break;

            //# zoom-out, identify
            case 'click':
                hideObj(_$('zoombox'));
                break;

            //# pan with drag
            case 'pan':
                hideObj(_$('zoombox'));
                startPan(e, moveX, moveY);
                break;

            //# measure & digitize
            case 'measure':
            case 'digitize':
                showObj(_$('measureLayer'));
                showObj(_$('measureLayerTmp'));
                redrawAll(moveX , moveY);
                break;

            //# move
            case 'move':
                if (varform.mode.value == 'iquery') {    //# iquery
                    if(PMQuery.follow){
                        PMQuery.timer_c = 0;
                        clearTimeout(PMQuery.timer_t); //
                        clearTimeout(PMQuery.iquery_timer);
                        hideObj(_$('iqueryLayer'));
                        timedCount(moveX, moveY);
                    } else{
                        clearTimeout(PMQuery.iquery_timer);
                        PMQuery.iquery_timer = setTimeout("applyIquery(" + moveX + "," + moveY + ")", 300);
                    }
                }
                break;

            default:
                try {
                    eval(maction + '_mmove(e, moveX, moveY)');
                } catch(e) {

                }
                break;
        }

    // Actions in REFERENCE MAP
    } else {
        hideObj(_$('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' || maction == 'digitize') {
        measureDrawSymbols(e, upX, upY, 1);
    } else {
        try {
            eval(maction + '_mdblclick()');
            return false;
        } catch(e) {

        }
    }
}



/*
 * 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)) {
            var zb = $("#zoombox");
            zb.showv();
            var boxL = Math.min(moveX, downX);
            var boxT = Math.min(moveY, downY);
            var boxW = Math.abs(moveX - downX);
            var boxH = Math.abs(moveY - downY);

            zb.left(boxL+"px");
            zb.top(boxT+"px");
            zb.width(boxW+"px");
            zb.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.top(mapT+"px");
            theMapImgL.left(mapL+"px");

            if (mapT > 0) {
                clipB = mapH - theMapImgL.itop();
            } else {
                clipT = -1 * theMapImgL.itop();
            }

            if (mapL > 0) {
                clipR = mapW - theMapImgL.ileft();
            } else {
                clipL = -1 * theMapImgL.ileft();
            }

            var clipRect = 'rect(' + clipT + 'px '
                                   + clipR + 'px '
                                   + clipB + 'px '
                                   + clipL + 'px)';
            //window.status = clipRect;
            theMapImgL.css('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");

    rBox.left(boxL + "px");
    rBox.top(boxT + "px");
    rBox.width(boxW + "px"); //Math.max(4, boxW);
    rBox.height(boxH + "px"); //Math.max(4, boxH);

    if (boxW < rBoxMinW) {
        rBox.hidev();
        rCross.showv();
        setRefCross(rCross, boxL, boxT, boxW, boxH);
    } else {
        rCross.hidev();
        rBox.showv();
    }

    sBox.hidev();

}

/**
 * MOVE RECTANGLE WITH MOUSE PAN
 */
function moveRefBox(moveAction) {
    var rBox   = $("#refbox");
    var rCross = $("#refcross");

    var boxL = rBox.ileft();
    var boxT = rBox.itop();
    var boxW = rBox.iwidth();
    var boxH = rBox.iheight();

    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.left(boxLnew+"px");
        rBox.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.left(Math.round((boxcX - rOffs))+"px");
    rCross.top(Math.round((boxcY - rOffs))+"px");
}


/*******************************************************************
 * Resize map image while zooming with slider
 * called from sliderMove() in slider.js
 ********************************************/
/**
 * resize MAP
 */
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.width(newW+"px");
    theMapImg.height(newH+"px");
    theMapLay.left(newLeft+"px");
    theMapLay.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.css('clip', clipRect);

        theMapLay.width(newW+"px");
        theMapLay.height(newH+"px");
    }
}

/**
 * resize REFBOX
 */
function resizeRefBox(sizeFactor) {
    var refZoomBox = $('#refbox');
    var refSliderBox = $('#refsliderbox');

    refSliderBox.showv();

    if (refZoomBox.ileft() > 0) {
        var refBoxBorderW = 1; //refZoomBox.css('border-width');  // adapt to border width in CSS

        var oldRefW    = refZoomBox.iwidth();
        var oldRefH    = refZoomBox.iheight();
        var oldRefLeft = refZoomBox.ileft();
        var oldRefTop  = refZoomBox.itop();

        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.left(newRefLeft+"px");
        refSliderBox.top(newRefTop+"px");
        refSliderBox.width(newRefW+"px");
        refSliderBox.height(newRefH+"px");
    }
}



/**
 * KEYBOARD FUNCTIONS
 * original script taken from http://ka-map.maptools.org/
 */
function kp(e) {
    try {
        e = (e)? e : ((event) ? event : null);
    } catch(e) {};
    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;
          case 46://delete last point in editing mode
            delLastPoint();
          break;
          case 83:// ABP: "S" or "s" persist polyline
          case 115:
            if(e.type == 'keypress'){
                persistPolygon();
            }
          break;
          default:
            b=false;
        }
    }
}



/**
 * MOUSEWHEEL FUNCTIONS (zoom in/out)
 * only works with IE
 */
function omw(e) {
    e = (e)?e:((event)?event:null);
    if(e) {
        try {
            var imgxy = (refmapClick ? '' : (wheelZoomPointerPosition ? moveX + "+" + moveY : ''));
            var wInv = wheelZoomGoogleStyle ? -1 : 1;
        } catch(e) {
            var imgxy = '';
            var wInv = 1;
        }
        var wD = (e.wheelDelta ? e.wheelDelta : e.detail*-1) * wInv;

        clearTimeout(PMap.resize_timer);
        if (wD < 0) {
            PMap.resize_timer = setTimeout("zoompoint(2,'" + imgxy + "')",300);
            return false;
        } else if (wD > 0) {
            PMap.resize_timer = setTimeout("zoompoint(-2,'" + imgxy + "')",300);
            return false;
        }
    }
}


/**
 * Disable right mouse context menu
 */
function disableContextMenu(e) {
    e = (e)?e:((event)?event:null);
    return false;
}




/*
 * FUNCTIONS FOR COODINATE DIPLAY FUNCTIONS
 ***********************************************/
/**
 * GET MAP COORDINATES FOR MOUSE MOVE
 */
function getGeoCoords(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
        // create your own custom function for other CRS
        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 = getGeoCoords(moveX, moveY, false);
    //var mpoint = getGeoCoords(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').html('X: ' + px); // + ' &deg;';
    $('#ycoord').html('Y: ' + py); // + ' &deg;';
}



/**
 * Convert XY coordinates from ETRS-LAEA (3035) to lat/lon (4326)
 */
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;
}


/************************************************************
                    Slider control creator
              By Mark Wilton-Jones 12-13/10/2002
Version 1.1 updated 22/10/2003 to provide hand cursor option
*************************************************************

Please see http://www.howtocreate.co.uk/jslibs/ for details and a demo of this script
Please see http://www.howtocreate.co.uk/jslibs/termsOfUse.html for terms of use

___________________________________________________________________________________________*/


/* Modifications and new functions by Armin Burger for use with MapServer */

// ***************** START OF CODE BY Armin Burger ************************

/*
 * Functions for setting scale to form input and load map
 **************************************************************************/
var myslider;
var slScale;

function createZSlider(sliderElemId) {
    if (_$(sliderElemId)) {
        myslider = new slider(
        sliderElemId,  // id of DIV where slider is inserted
        140,        //height of track
        14,       //width of track
        '#666666', //colour of track
        1,         //thickness of track border
        '#000000', //colour of track border
        2,         //thickness of runner (in the middle of the track)
        '#666666', //colour of runner
        14,        //height of button
        20,        //width of button
        '#999999', //colour of button
        1,         //thickness of button border (shaded to give 3D effect)
        '<img src="images/slider_updown.gif" style="display:block; margin:auto;" />', //text of button (if any)
        //'', //text of button (if any)
        false,      //direction of travel (true = horizontal, false = vertical)
        'sliderMove', //the name of the function to execute as the slider moves
        'sliderStop', //the name of the function to execute when the slider stops
        true          //the functions must have already been defined (or use null for none)
        
        );
    }
}



/**
 * Set Scale by moving slider
 */
function sliderMove(sliderPosition) {
    currScale = PMap.scale; //pMap_getMapScale(); 
    if (zsliderVertical) sliderPosition = 1 - sliderPosition;
    slScale = sliderx2Scale(sliderPosition);
    var strlenSlScale = parseInt(slScale).toString().length;
    var redFact = Math.pow(10, strlenSlScale - 2);
    
    slScale = Math.round(slScale/redFact) * redFact;
    
    /* FEDE */
    _$("scaleform").scale.value = slScale;
    
    var scaleRatio = currScale / slScale;
    
    // Resize map image according to new scale
    // call resizeMap() from zoombox.js
    resizeMap(scaleRatio);
    //window.status = scaleRatio;

    // Resize refbox according to new scale
    // call resizeRefBox() from zoombox.js
    resizeRefBox(scaleRatio);
}

function sliderx2Scale(x) {
    var sliderScale = (1 - x) * PMap.s1  + (x * PMap.s2) - (x * (1 - x) * PMap.s1)  ;  
    return sliderScale;
}

function sliderStop() {
    zoom2scale(slScale);
    mouseIsPressed = false;
    return false;
}


/**
 * Returns the slider position value (0 to 1) with regard to the new map scale
 * Contribution by Paul Hasenohr
 */
function getSliderPosition(curscale) {
    var s1 = PMap.s1;
    var s2 = PMap.s2;
    var eqPart = Math.sqrt((s2*s2) + (4*s1*curscale) - (4*s1*s2));
    
    var pos = ((2 * s1) - s2 + eqPart) / (2*s1) ;
    if (pos < 0 || pos > 1) {
        pos = ((2 * s1) - s2 - eqPart) / (2*s1) ;
    }
    if (pos > 1 || isNaN(pos)) pos = 1;
    
    if (zsliderVertical) pos = 1-pos;
    
    return pos;
}




// ***************** START OF ORIGINAL CODE ************************


var mouseIsPressed = false;

var MWJ_slider_controls = 0;

function sliderMousePos(e) {
	//get the position of the mouse
	if( !e ) { e = window.event; } if( !e || ( typeof( e.pageX ) != 'number' && typeof( e.clientX ) != 'number' ) ) { return [0,0]; }
	if( typeof( e.pageX ) == 'number' ) { var xcoord = e.pageX; var ycoord = e.pageY; } else {
		var xcoord = e.clientX; var ycoord = e.clientY;
		if( !( ( window.navigator.userAgent.indexOf( 'Opera' ) + 1 ) || ( window.ScriptEngine && ScriptEngine().indexOf( 'InScript' ) + 1 ) || window.navigator.vendor == 'KDE' ) ) {
			if( document.documentElement && ( document.documentElement.scrollTop || document.documentElement.scrollLeft ) ) {
				xcoord += document.documentElement.scrollLeft; ycoord += document.documentElement.scrollTop;
			} else if( document.body && ( document.body.scrollTop || document.body.scrollLeft ) ) {
				xcoord += document.body.scrollLeft; ycoord += document.body.scrollTop; } } }
	return [xcoord,ycoord];
}

function slideIsDown(e) {
	//make note of starting positions and detect mouse movements
	window.msStartCoord = sliderMousePos(e); window.lyStartCoord = this.style?[parseInt(this.style.left),parseInt(this.style.top)]:[parseInt(this.left),parseInt(this.top)];
	if( document.captureEvents && Event.MOUSEMOVE ) { document.captureEvents(Event.MOUSEMOVE); document.captureEvents(Event.MOUSEUP); }
	window.storeMOUSEMOVE = document.onmousemove; window.storeMOUSEUP = document.onmouseup; window.storeLayer = this;
	mouseIsPressed = true;
    document.onmousemove = slideIsMove; document.onmouseup = slideIsMove; return false;
}

function slideIsMove(e) {
    if (mouseIsPressed) {
        //move the slider to its newest position
        var msMvCo = sliderMousePos(e); if( !e ) { e = window.event ? window.event : ( new Object() ); }
        var theLayer = window.storeLayer.style ? window.storeLayer.style : window.storeLayer; var oPix = document.childNodes ? 'px' : 0;
        if( window.storeLayer.hor ) {
            var theNewPos = window.lyStartCoord[0] + ( msMvCo[0] - window.msStartCoord[0] );
            if( theNewPos < 0 ) { theNewPos = 0; } if( theNewPos > window.storeLayer.maxLength ) { theNewPos = window.storeLayer.maxLength; }
            theLayer.left = theNewPos + oPix;
        } else {
            var theNewPos = window.lyStartCoord[1] + ( msMvCo[1] - window.msStartCoord[1] );
            if( theNewPos < 0 ) { theNewPos = 0; } if( theNewPos > window.storeLayer.maxLength ) { theNewPos = window.storeLayer.maxLength; }
            theLayer.top = theNewPos + oPix;
        }
        //run the user's functions and reset the mouse monitoring as before
        if( e.type && e.type.toLowerCase() == 'mousemove' ) {
            if( window.storeLayer.moveFunc ) { window.storeLayer.moveFunc(theNewPos/window.storeLayer.maxLength); }
        } else {
            document.onmousemove = storeMOUSEMOVE; document.onmouseup = window.storeMOUSEUP;
            if( window.storeLayer.stopFunc ) { window.storeLayer.stopFunc(theNewPos/window.storeLayer.maxLength); }
        }
    } 
}

function setSliderPosition(oPortion) {
	//set the slider's position
	if( isNaN( oPortion ) || oPortion < 0 ) { oPortion = 0; } if( oPortion > 1 ) { oPortion = 1; }
	var theDiv = document.getElementById(this.id); if( theDiv.style ) { theDiv = theDiv.style; }
	oPortion = Math.round( oPortion * this.maxLength ); var oPix = document.childNodes ? 'px' : 0;
	if( this.align ) { theDiv.left = oPortion + oPix; } else { theDiv.top = oPortion + oPix; }
}

function slider(sliderElemId,oThght,oTwdth,oTcol,oTBthk,oTBcol,oTRthk,oTRcol,oBhght,oBwdth,oBcol,oBthk,oBtxt,oAlgn,oMf,oSf,oCrs) {
    //--- Modifications by Armin Burger ---//
    //draw the slider using huge amounts of nested layers (makes the borders look normal in as many browsers as possible)
    var sliderStr = (
        '<div style="position:relative;left:0px;top:0px;height:'+(oThght+(2*oTBthk))+'px;width:'+(oTwdth+(2*oTBthk))+'px;background-color:'+oTBcol+';font-size:0px;">'+
        '<div style="position:relative;left:'+oTBthk+'px;top:'+oTBthk+'px;height:'+oThght+'px;width:'+oTwdth+'px;background-color:'+oTcol+';font-size:0px;">'+
        '<div style="position:absolute;left:'+(oAlgn?0:Math.floor((oTwdth-oTRthk)/2))+'px;top:'+(oAlgn?Math.floor((oThght-oTRthk)/2):0)+'px;height:'+(oAlgn?oTRthk:oThght)+'px;width:'+(oAlgn?oTwdth:oTRthk)+'px;background-color:'+oTRcol+';font-size:0px;"><\/div>'+
        '<div style="position:absolute;left:'+(oAlgn?0:Math.floor((oTwdth-(oBwdth+(2*oBthk)))/2))+'px;top:'+(oAlgn?Math.floor((oThght-(oBhght+(2*oBthk)))/2):0)+'px;height:'+(oBhght+(2*oBthk))+'px;width:'+(oBwdth+(2*oBthk))+'px;font-size:0px;" ondragstart="return false;" onselectstart="return false;" onmouseover="this.hor='+oAlgn+';this.maxLength='+((oAlgn?oTwdth:oThght)-((oAlgn?oBwdth:oBhght)+(2*oBthk)))+';this.moveFunc='+oMf+';this.stopFunc='+oSf+';this.onmousedown=slideIsDown;" id="MWJ_slider_controls'+MWJ_slider_controls+'">'+
        '<div style="border-top:'+oBthk+'px solid #ffffff;border-left:'+oBthk+'px solid #ffffff;border-right:'+oBthk+'px solid #000000;border-bottom:'+oBthk+'px solid #000000;">'+
        '<div style="height:'+oBhght+'px;width:'+oBwdth+'px;font-size:0px;background-color:'+oBcol+';cursor:'+(oCrs?'pointer;cursor:move':'default')+';">'+
        '<span style="width:100%;text-align:center;">'+oBtxt+'<\/span><\/div><\/div><\/div><\/div><\/div>'
    );
    
    document.getElementById(sliderElemId).innerHTML = sliderStr;
    
    this.id = 'MWJ_slider_controls'+MWJ_slider_controls; this.maxLength = (oAlgn?oTwdth:oThght)-((oAlgn?oBwdth:oBhght)+(2*oBthk));
	this.align = oAlgn; this.setPosition = setSliderPosition; MWJ_slider_controls++;
}


