﻿/**Vers. 1.2.0934*/
/**
 * @author cknote
 * 
 * BoundingBoxMarker can draw a rectangle on a map view
 * that describes another maps extent. It can be wired to
 * listen to the other maps movements.
 *
 */

BoundingBoxMarker = Class.create();
BoundingBoxMarker.prototype = {
	
	// constructor

	initialize: function(container) {
		this.container = container;

		this.bbMarker = null;
		this.bb = null;
		this.notifier = new Array();
	},

	// external functions

	paint: function(bb,coordinates) {
		this._create();
		
		this._position(bb,coordinates);
	},
	remove: function() {
		if (this.bbMarker !== null) {
			this.container.removeChild(this.bbMarker);
			this.bbMarker = null;
		}
		this.notifier = null;
	},

	// internal functions

	_create: function() {
		if (this.bbMarker === null) {
			this.bbMarker = document.createElement("div");
			this.bbMarker.id = "bbMarker "+Math.random();
			
			Element.addClassName(this.bbMarker, "bbMarker");

			// workaround: IMX muss die Klasse bbMarker entsprechend im CSS definieren
			Element.setStyle(this.bbMarker,{position:"absolute", zIndex:200000, border:"2px solid gray"});
//			Element.setStyle(this.bbMarker,{position:"absolute", zIndex:200000});
			
			this.container.appendChild(this.bbMarker);
		}
	},
	_position: function(bb,coordinates) {
		if (coordinates) {
			// size
			var width = Math.round((bb[1][0] - bb[0][0]) / coordinates.getCurrentResolution());
			var height = Math.round((bb[0][1] - bb[1][1]) / coordinates.getCurrentResolution());
			
			// position
			var ul = coordinates.rw2px(bb[0][0],bb[0][1]);
			
			if (this.bbMarker) {
				Element.setStyle(this.bbMarker, {top:ul[1]+"px", left:ul[0]+"px", width:width+"px", height:height+"px"});
			}
		}
	},
	_notify: function(bb) {
		for (var i = 0; i < this.notifier.length ; i++) {
			this.notifier[i](bb);
		}
	}
}
/**
 * @author cknote
 * 
 * The Compass Rose object. The ugly thing that is drawn on the map
 * to be able to move the map without touching it.
 * Also fancies the freaky gamestyle-move mode...
 * 
 */
 
CompassRose = Class.create();
CompassRose.prototype = {

	// constructor

	initialize: function(mapManager,container,config) {
		this.container = container;
		this.mapManager = mapManager;
		this.config = config;
		this.dirX = 0;
		this.dirY = 0;
		this.icon = null;
		this.mapPolys = null;
		
		this.id = "compassRose"+Math.random();
		this.stopMovingObserver = this.stopMoving.bindAsEventListener(this);
		this._updateMousePositionObserver = this._updateMousePosition.bindAsEventListener(this);
	},
	
	// external functions
	
	paint: function() {
		if (this.icon == null) {
	
			this._calcPosition();
		
			this.icon = document.createElement("img");
			
			this.icon.id = this.id;
			this.icon.src = this.config.compassRoseSrc;
			
			Element.setStyle(this.icon,{ position:"absolute",left:this.left+"px",top:this.top+"px"});
			Element.addClassName(this.icon,"compassRose");
	
			this.map = document.createElement("map");
			this.map.id = this.id+"_map";
			this.map.name = this.id+"_map";
	
			this.container.appendChild(this.icon);
				
			var oneEighth = Math.round( this.config.compassRoseSize / 8 );
			var oneFourth = Math.round( this.config.compassRoseSize / 4 );
			var oneHalf = Math.round( this.config.compassRoseSize / 2 );
			
			this.mapPolys = new Array(9);
			
			this.downNEObserver = this.downNE.bindAsEventListener(this);
			this.downNObserver = this.downN.bindAsEventListener(this);
			this.downNwObserver = this.downNw.bindAsEventListener(this);
			this.downWObserver = this.downW.bindAsEventListener(this);
			this.downSWObserver = this.downSW.bindAsEventListener(this);
			this.downSObserver = this.downS.bindAsEventListener(this);
			this.downSEObserver = this.downSE.bindAsEventListener(this);
			this.downEObserver = this.downE.bindAsEventListener(this);
			this.downGamestyleObserver = this.downGamestyle.bindAsEventListener(this);
			for ( var i = 0 ; i < this.mapPolys.length ; i++ ) {
				this.mapPolys[i] = document.createElement("area");
				this.mapPolys[i].shape = "poly";
				switch(i) {
					case 0: // ne
						this.mapPolys[i].coords = '0,'+oneFourth+',0,0,'+oneFourth+',0,'+(oneFourth+oneEighth)+','+oneFourth+','+oneFourth+','+(oneFourth+oneEighth);
						Event.observe(this.mapPolys[i],"mousedown",this.downNEObserver,false);
						break;
					case 1: // n
						this.mapPolys[i].coords = oneFourth+',0,'+(oneHalf+oneFourth)+',0,'+(oneHalf+oneEighth)+','+oneFourth+','+(oneFourth+oneEighth)+','+oneFourth;
						Event.observe(this.mapPolys[i],"mousedown",this.downNObserver,false);
						break;
					case 2: // nw
						this.mapPolys[i].coords = (oneHalf+oneFourth)+',0,'+this.config.compassRoseSize+',0,'+this.config.compassRoseSize+','+oneFourth+','+(oneHalf+oneFourth)+','+(oneFourth+oneEighth)+','+(oneHalf+oneEighth)+','+oneFourth;
						Event.observe(this.mapPolys[i],"mousedown",this.downNwObserver,false);
						break;
					case 3: // w
						this.mapPolys[i].coords = this.config.compassRoseSize+','+oneFourth+','+this.config.compassRoseSize+','+(oneHalf+oneFourth)+','+(oneHalf+oneFourth)+','+(oneHalf+oneEighth)+','+(oneHalf+oneFourth)+','+(oneFourth+oneEighth);
						Event.observe(this.mapPolys[i],"mousedown",this.downWObserver,false);
						break;
					case 4: // sw
						this.mapPolys[i].coords = this.config.compassRoseSize+','+(oneHalf+oneFourth)+','+this.config.compassRoseSize+','+this.config.compassRoseSize+','+(oneHalf+oneFourth)+','+this.config.compassRoseSize+','+(oneHalf+oneEighth)+','+(oneHalf+oneFourth)+','+(oneHalf+oneFourth)+','+(oneHalf+oneEighth);
						Event.observe(this.mapPolys[i],"mousedown",this.downSWObserver,false);
						break;
					case 5: // s
						this.mapPolys[i].coords = (oneHalf+oneFourth)+','+this.config.compassRoseSize+','+oneFourth+','+this.config.compassRoseSize+','+(oneFourth+oneEighth)+','+(oneHalf+oneFourth)+','+(oneHalf+oneEighth)+','+(oneHalf+oneFourth);
						Event.observe(this.mapPolys[i],"mousedown",this.downSObserver,false);
						break;
					case 6: // se
						this.mapPolys[i].coords = oneFourth+','+this.config.compassRoseSize+',0,'+this.config.compassRoseSize+',0,'+(oneHalf+oneFourth)+','+oneFourth+','+(oneHalf+oneEighth)+','+(oneFourth+oneEighth)+','+(oneHalf+oneFourth);
						Event.observe(this.mapPolys[i],"mousedown",this.downSEObserver,false);
						break;
					case 7: // e
						this.mapPolys[i].coords = '0,'+(oneHalf+oneFourth)+',0,'+oneFourth+','+oneFourth+','+(oneFourth+oneEighth)+','+oneFourth+','+(oneHalf+oneEighth);
						Event.observe(this.mapPolys[i],"mousedown",this.downEObserver,false);
						break;
					case 8: // gamestyle
						this.mapPolys[i].coords = oneFourth+','+(oneFourth+oneEighth)+','+(oneFourth+oneEighth)+','+oneFourth+','+(oneHalf+oneEighth)+','+oneFourth+','+(oneHalf+oneFourth)+','+(oneFourth+oneEighth)+','+(oneHalf+oneFourth)+','+(oneHalf+oneEighth)+','+(oneHalf+oneEighth)+','+(oneHalf+oneFourth)+','+(oneFourth+oneEighth)+','+(oneHalf+oneFourth)+','+oneFourth+','+(oneHalf+oneEighth);
						Event.observe(this.mapPolys[i],"mousedown",this.downGamestyleObserver,false);
						break;
					default:
						break;
				}
				Event.observe(this.mapPolys[i],"mouseup",this.stopMovingObserver,false);
				this.map.appendChild(this.mapPolys[i]);
			}
			this.container.appendChild(this.map);
			
			this.icon.useMap = "#"+this.id+"_map";
		}
	},
	/* move actions */
	downNE: function(e) {
		this._triggerDirMover(1,1,e);
	},
	downN: function(e) {
		this._triggerDirMover(0,1,e);
	},
	downNw: function(e) {
		this._triggerDirMover(-1,1,e);
	},
	downW: function(e) {
		this._triggerDirMover(-1,0,e);
	},
	downE: function(e) {
		this._triggerDirMover(1,0,e);
	},
	downSE: function(e) {
		this._triggerDirMover(1,-1,e);
	},
	downS: function(e) {
		this._triggerDirMover(0,-1,e);
	},
	downSW: function(e) {
		this._triggerDirMover(-1,-1,e);
	},
	downGamestyle: function(e) {
		this.moving = true;
		this.gamestyleMouseZero = new Array(Event.pointerX(e),Event.pointerY(e));
		this.mousePosition = new Array(Event.pointerX(e),Event.pointerY(e));
		this._attachMouseMoveObserver();
		this._attachStopMovingObserver();
		this._gamestyleMover();
		Event.stop(e);
	},

	stopMoving: function(e) {
		Event.stop(e);
		this.moving = false;
		this._detachStopMovingObserver();
	},
	remove: function() {
		if (this.mapPolys != null) {
			for ( var i = 0 ; i < this.mapPolys.length ; i++ ) {
				switch(i) {
					case 0: // ne
						Event.stopObserving(this.mapPolys[i],"mousedown",this.downNEObserver,false);
						break;
					case 1: // n
						Event.stopObserving(this.mapPolys[i],"mousedown",this.downNObserver,false);
						break;
					case 2: // nw
						Event.stopObserving(this.mapPolys[i],"mousedown",this.downNwObserver,false);
						break;
					case 3: // w
						Event.stopObserving(this.mapPolys[i],"mousedown",this.downWObserver,false);
						break;
					case 4: // sw
						Event.stopObserving(this.mapPolys[i],"mousedown",this.downSWObserver,false);
						break;
					case 5: // s
						Event.stopObserving(this.mapPolys[i],"mousedown",this.downSObserver,false);
						break;
					case 6: // se
						Event.stopObserving(this.mapPolys[i],"mousedown",this.downSEObserver,false);
						break;
					case 7: // e
						Event.stopObserving(this.mapPolys[i],"mousedown",this.downEObserver,false);
						break;
					case 8: // gamestyle
						Event.stopObserving(this.mapPolys[i],"mousedown",this.downGamestyleObserver,false);
						break;
					default:
						break;
				}
				Event.stopObserving(this.mapPolys[i],"mouseup",this.stopMovingObserver,false);
			}
		}
		
		this._detachMouseMoveObserver();
		this._detachStopMovingObserver();
		
		this.downNEObserver = null;
		this.downNObserver = null;
		this.downNwObserver = null;
		this.downWObserver = null;
		this.downSWObserver = null;
		this.downSObserver = null;
		this.downSEObserver = null;
		this.downEObserver = null;
		this.downGamestyleObserver = null;

		this._updateMousePositionObserver = null;
		this.stopMovingObserver = null;

		try {
			this.container.removeChild(this.map);
			this.container.removeChild(this.icon);
		} catch(e) {
			////console.debug("removing compassrose icon failed");
		}
//		//debug.writeline("compassrose removed");
	},
	
	// internal functions
	
	_calcPosition: function() {
		switch(this.config.compassRosePosition) {
			// TODO: alle Möglichkeiten implementieren!
			case "bottom-right":
				this.left = this.config.compassRosePadding;
				this.top = this.container.style.height.delPx() - this.config.compassRoseSize - this.config.compassRosePadding;
				break;
			case "top-left":
				this.left = this.container.style.width.delPx() - this.config.compassRoseSize - this.config.compassRosePadding;
				this.top = this.config.compassRosePadding;
				break;
			default:
				this.left = this.container.style.width.delPx() - this.config.compassRoseSize - this.config.compassRosePadding;
				this.top = this.container.style.height.delPx() - this.config.compassRoseSize - this.config.compassRosePadding;
				break;
		}
	},
	_updateMousePosition: function(e) {
		this.mousePosition = new Array(Event.pointerX(e),Event.pointerY(e));
	},
	_gamestyleMover: function(e) {
		if (this.moving) {
			this.mapManager.move(Math.round((this.mousePosition[0] - this.gamestyleMouseZero[0])/(1/this.config.compassRoseGamestyleSpeed)), Math.round((this.mousePosition[1] - this.gamestyleMouseZero[1])/(1/this.config.compassRoseGamestyleSpeed)));
			setTimeout(this._gamestyleMover.bind(this),20);
		}
		else this._detachMouseMoveObserver();
	},
	_triggerDirMover: function(x,y,e) {
		Event.stop(e);
		if (!this.moving) {
			this.dirX = x;
			this.dirY = y;
			this.moving = true;
			this._attachStopMovingObserver();
			this._dirMover(x,y);
		}
		else this.moving = false;
	},
	_dirMover: function() {
		this.mapManager.move(this.dirX * this.config.compassRoseSpeed , this.dirY * this.config.compassRoseSpeed);
		if (this.moving) setTimeout(this._dirMover.bind(this),20);
	},
	_attachMouseMoveObserver: function() {
		Event.observe(this.icon,"mousemove",this._updateMousePositionObserver);
		Event.observe(this.container,"mousemove",this._updateMousePositionObserver);
	},
	_detachMouseMoveObserver: function() {
		if (this.icon != null) Event.stopObserving(this.icon,"mousemove",this._updateMousePositionObserver);
		Event.stopObserving(this.container,"mousemove",this._updateMousePositionObserver);
	},
	_attachStopMovingObserver: function() {
		Event.observe(this.icon,'mouseup',this.stopMovingObserver);
		Event.observe(this.container,'mouseup',this.stopMovingObserver);
		Event.observe(document,'mouseup',this.stopMovingObserver);
	},
	_detachStopMovingObserver: function() {
		if (this.icon != null) Event.stopObserving(this.icon,'mouseup',this.stopMovingObserver);
		Event.stopObserving(this.container,'mouseup',this.stopMovingObserver);
		Event.stopObserving(document,'mouseup',this.stopMovingObserver);
	}
}
/**
 * @author cknote
 * 
 * ContentContainer is an abstraction for everything
 * that can be displayed tile-wise as a map layer
 * e. g. map tiles, vector tiles..
 * 
 * is created to be a map tile container by default.
 *
 */
ContentContainer = Class.create();
ContentContainer.prototype = {
	
	// constructor

	initialize: function(mapSource, parent, config, name) {
		this.name = name
		this.mapSource = mapSource;
		this.container = parent;
		this.config = config;
		
		if (this.mapSource != null) {
			this.coordinates = this.mapSource.coordinates;
		}
		
		if (this.config) {
			this.tileSize = { width: this.config.tileWidth, height: this.config.tileHeight};
			this.mapSize = { width : this.config.width, height : this.config.height};
			this.borderCache = this.config.borderCache;
		}

		this.tileBox = new Array();
		this.tileCon=null;
		this.tileCon = document.createElement("div");
		this.painted = false;
	},
	
	// getter / setter
	getBorderCache: function() {
		return this.borderCache;
	},
	setBorderCache: function(borderCache) {
		this.borderCache = borderCache;
	},
	getTileContainer: function() {
		return this.tileCon;
	},
	// should not be called from outside...
	_setTileContainer: function(tileCon) {
		this.tileCon = tileCon;
	},
	getTileSize: function() {
		return this.tileSize;
	},
	setTileSize: function(width,height) {
		this.tileSize.width = width;
		this.tileSize.height = height;
	},
	getMapSize: function() {
		return this.mapSize;
	},
	setMapSize: function(width,height) {
		this.mapSize.width = width;
		this.mapSize.height = height;
	},
	
	// external functions
	
	createTileCon: function() {
		if (this.hidden) this.setHidden();
				
		Element.setStyle(this.tileCon,{position:"absolute",top:-this.mapSource.pxYoff+"px",left:-this.mapSource.pxXoff+"px"});		
		Element.addClassName(this.tileCon,"tileCon");
		
		this.container.appendChild(this.tileCon);
	},	
	prepare: function() {
		this.mapSource.prepare();
		this.createTileCon();
	},
	paint: function() {
		// don't do if we are already painted...
		if (this.painted) return;
		
		this.tMWidth = Math.floor(this.mapSize.width / this.tileSize.width) + (2*this.borderCache);
		this.tMHeight = Math.floor(this.mapSize.height / this.tileSize.height) + (2*this.borderCache);
		
		//es: +1 in Vertikale führt dazu, dass in der OV-Map unten keine Kacheln mehr fehlen
		if(this.config.isOverviewMap){
			this.tMHeight = this.tMHeight +1;
		}

		// ////console.debug("tile matrix size: "+this.tMWidth+"x"+this.tMHeight);

		var tileOff = this.getCurrentTileOffset();

		// more "natural" loading sequence, think of a ccw spiral...

		// get the most centered tile
		var centerTileX = Math.floor(this.tMWidth / 2);
		var centerTileY = Math.floor(this.tMHeight / 2);
		
		// adjust center if count of tiles is even and would not be negative if decremented
		if (Math.floor(this.tMWidth / 2) == (this.tMWidth / 2) && centerTileX > 0) centerTileX--;
		if (Math.floor(this.tMHeight / 2) == (this.tMHeight / 2) && centerTileY > 0) centerTileY--;
		
		var runlength = 1;
		var tileX = centerTileX;
		var tileY = centerTileY;

		// begin in the center and load tiles "spiraling" ccw outwards
		this._addTile(tileX - this.borderCache + tileOff[0], tileY - this.borderCache + tileOff[1]);
		while (runlength < [this.tMWidth, this.tMHeight].max()) {
			var dirSwitch = 1;
			if (Math.floor(runlength / 2) == (runlength / 2)) dirSwitch = -1;

			for (var increment = 1; increment <= runlength ; increment++) {
				tileX += dirSwitch;
				this._addTile(tileX - this.borderCache + tileOff[0], tileY - this.borderCache + tileOff[1]);
			}
			for (var increment = 1; increment <= runlength ; increment++) {
				tileY += dirSwitch;
				this._addTile(tileX - this.borderCache + tileOff[0], tileY - this.borderCache + tileOff[1]);
			}
			runlength++;
		}

		this.painted = true;
	},
	getCurrentTileOffset: function() {
		var pxOff = this.coordinates.rw2px(this.config.lon,this.config.lat);
		return new Array( Math.floor(pxOff[0] / this.tileSize.width), Math.floor(pxOff[1] / this.tileSize.height));
	},
	show: function(){
		if (!this.painted) {
			this.mapSource.prepare();
			this.paint();
		}
		Element.show(this.tileCon);
	},
	checkTiles: function() {
		var pxXoff = this.mapSource.pxXoff;
		var pxYoff = this.mapSource.pxYoff;
		for (var i = 0; i < this.tileBox.length ; i++) this.tileBox[i].check(pxXoff,pxYoff);
	},
	hide: function(){
		Element.hide(this.tileCon);
		this.remove();
	},
	remove: function(){
		this.painted = false;
	},
	
	// internal functions
	
	_createTile: function() {
 		return new MapTile(this.tileCon,this.config,this.mapSource,this.tMWidth,this.tMHeight);
	},
	_addTile: function(xIndex,yIndex) {
		var tile = this._createTile();

		tile.setTileSize(this.tileSize.width,this.tileSize.height);
		tile.setIndex(xIndex,yIndex);
		tile.create();
		tile.paint();
		
		this.tileBox.push(tile);
	}
}

/**
 * @author cknote
 *
 * as you can see - ContentContainer defaults to TileContainer
 * :)
 *
 */
TileContainer = Class.create();
TileContainer.prototype = Object.extend(new ContentContainer(),{
});

/**
 * @author cknote
 *
 * nice example for simple ancestry.
 * A VectorContainer holds a set of vectorTiles,
 * created to draw vectors on the map.
 *
 */
 
VectorContainer = Class.create();
VectorContainer.prototype = Object.extend(new ContentContainer(),{

	// internal functions

	_createTile: function() {
 		return(new VectorTile(this.tileCon,this.config,this.mapSource,this.tMWidth,this.tMHeight));
	}
});

/**
 * @author cknote
 * 
 * Handles all kind of control communication between the map and the server,
 * such as authentification, geocoding preparation etc...
 * 
 */

ControlConnector = Class.create();
ControlConnector.prototype = {

	// constructor

	initialize: function(map) {
		this.request = null;
		this.map = map;
	},
	
	// external functions
	
	checkGeocodeID: function(poi) {
		this.currentID = poi.id;
		this.request = new Ajax.Request(
			this.map.config.editGetPOIServlet, 
			{
				method: "get",
				parameters: "sessionId="+this.map.config.sessionId+"&"+$H(poi).toQueryString(),
				onComplete:this._evalGeocodeID.bind(this)
			}
		);
	},
	
	getBestViewForArea: function(idArray) {
		var ids = $A(idArray);
		var idStr="";
		ids.each(function(id){
				idStr = idStr + id + ",";
			});
		this.idString = idStr;
		
		this.request = new Ajax.Request(
			this.map.config.bestViewServlet, 
			{
				method: "get",
				parameters: "mapWidth="+this.map.config.width+"&mapHeight="+this.map.config.height+"&ids="+this.idString+"&area="+this.map.config.isArea+"&sessionId="+this.map.config.sessionId,
				onComplete:this._evalBestViewForArea.bind(this)
			}
		);
	},
	/**
	 * es werden die übergebenen IDs (tash-IDs! nicht a4-IDs) gemerkt,
	 *  damit man nach Response in der Methode evalBestView die zurückgelieferten 
	 *  POIs damit vergleichen kann. Ist ein POI mit seiner tash-ID dann 
	 *  gespeichert, so bekommt er einen "bubble"
	 * @param {Object} idArray
	 */
	getBestView: function(idArray, isBubble, hasPopUps, regId) {
		var tashIds =  $A(idArray);
		var idStr="";
		if (!regId){
			tashIds.each(function(id){
				idStr = idStr + id + ","; //es: überhaupt verwendet/nötig?
			});
			this.map.config.isArea = false;
		}else{
			idStr = regId
			this.map.config.isArea = true;
		}
		this.idString = idStr;
		this.map.config.isBubble = isBubble;
		this.map.config.hasPopUps = hasPopUps;
		if (isBubble || hasPopUps){
			this.map.config.tashIds = tashIds;
		}
		
		// Bestview
		this.map.eventLogger.log(11);

		this.request = new Ajax.Request(
			this.map.config.bestViewServlet, 
			{
				method: "get",
				parameters: "mapWidth="+this.map.config.width+"&mapHeight="+this.map.config.height+"&ids="+this.idString+"&area="+this.map.config.isArea+"&sessionId="+this.map.config.sessionId,
				onComplete:this._evalBestView.bind(this)
			}
		);
	},
	showPOI: function(tid){
		var pois = $A(this.map.mapManager.currentTileMatrix.poiBox.pointBox);
		for (var p in pois) {
			if (typeof(pois[p]) == "object") {
				if (pois[p].idTash==tid){
					this.map.mapManager.moveTo(pois[p].point.getX(),pois[p].point.getY());
					pois[p].popUp.open();
				}
			}
		}
		
	},
	remove: function () {
		this.request = null;
		this.map = null;
//		//debug.writeline("ControlConnector removed");
	},
	
	// internal functions
	
	_evalBestViewForArea: function(jsonstring) {
		try {
			var data = eval( "("+jsonstring.responseText+")" );
		}
		catch(e){
			////console.debug("getPOI? response syntax error");
		}
		if (data != null) {
			if (data.successful) {
				this.map.config.lon = data.lon;
				this.map.config.lat = data.lat;
				this.map.setMapScale(data.mapScale);
				//manipuliere die eintraege für topics, areas und targetGroups
				//die relevanten POI-IDs statisch an die URL hängen
				//Komma am Ende abtrennen
				//alert("areas: " + this.idString.substring(0, this.idString.length-1));
				this.map.config.activeAreas="0";
				this.map.config.activeTargetGroups="0";
				this.map.config.activeTopics="0";
				//this.map.config.poiServletAddress = this.map.config.poiServletAddress + "&areas=" + this.idString + "&topics="+this.topicString+"&targetGroups="+this.targetgroupString;
				this.map.paint();
			}
			else {
				//alert("The server returned false!");
				//debug.writeline("getPOI? server responded 'sucessful false'!");
			}
		}
	},
	_evalBestView: function(jsonstring) {
		try {
			var data = eval( "("+jsonstring.responseText+")" );
		}
		catch(e){
			////console.debug("getPOI? response syntax error");
		}
		if (data != null) {
			if (data.successful) {
				this.map.config.lon = data.lon;
				this.map.config.lat = data.lat;
				//ES: Übersichtskarte soll mit aktualisiert werden
				if(this.map.map.hasOverviewMap){			
					this.map.map.overviewMap.config.lon = data.lon;
					this.map.map.overviewMap.config.lat = data.lat;
					
					var ovMapLevel = this.map.scale2zoomLevel(data.mapScale) - this.map.config.overviewMapZoomlevelDifference;
					if (ovMapLevel < 0)	ovMapLevel = 0;
					this.map.map.overviewMap.config.zoomLevel = ovMapLevel;	
				}
				this.map.setMapScale(data.mapScale);
				//this.map.config.poiServletAddress = this.map.config.poiSearchExtentAddress;
				//die relevanten POI-IDs statisch an die URL hängen
				//this.map.config.poiServletAddress = this.map.config.poiServletAddress + "ids=" + this.idString;
				if (this.map.painted) {
					this.map.repaint();
				}else {
					this.map.paint();
				}
			}
			else {
				// alert("The server returned false!");
				//debug.writeline("getPOI? server responded 'sucessful false'!");
			}
		}
	},
	_evalGeocodeID: function(jsonstring) {
		//debug.writeline("getPOI? returned "+jsonstring.responseText);
		try {
			var data = eval( "("+jsonstring.responseText+")" );
		}
		catch(e){
			////console.debug("getPOI? response syntax error");
		}
		if (data != null) {
			if (data.successful) {
				var poi = data[this.currentID];
				
				if (poi.lat==0 || poi.lon==0){
					poi.lat = this.map.config.lat;
					poi.lon = this.map.config.lon;
					poi.mapScale = this.map.config.agsScale[1];
				} else{
					this.map.config.editObject.successfullyGeocoded=true;
				}
				
				this.map.config.editObject.id = this.currentID;
				this.map.config.editObject.lon = poi.lon;
				this.map.config.editObject.lat = poi.lat;
				this.map.config.editObject.origLon = poi.lon;
				this.map.config.editObject.origLat = poi.lat;
				this.map.config.editObject.type = poi.type;
				this.map.config.editObject.name = poi.name;
				this.map.setCenter(new Array(poi.lon,poi.lat));
				
				//ES: Übersichtskarte soll mit aktualisiert werden
				if(this.map.map.hasOverviewMap){			
					this.map.map.overviewMap.config.lon = poi.lon;
					this.map.map.overviewMap.config.lat = poi.lat;
								
					var ovMapLevel = this.map.scale2zoomLevel(poi.mapScale) - this.map.config.overviewMapZoomlevelDifference;
					if (ovMapLevel < 0)	ovMapLevel = 0;
					this.map.map.overviewMap.config.zoomLevel = ovMapLevel;	
				}
				try {
					this.map.setMapScale(poi.mapScale);
				 }
				 catch(e) {
				 	////console.debug("Waiting for Ollis getPOI mapScale JSON update");
				 }

				this.map.config.editMode = true;

				//debug.writeline("getPOI? new gecoding POI "+poi.name+" ("+poi.type+") at "+poi.lat+"x"+poi.lon+" (zF "+poi.zoomFactor+")");
			}
			else {
				//alert("The server returned false! Does the requested ID ("+this.currentID+") exist?");
				//debug.writeline("getPOI? server responded 'sucessful false'!");
			}
		}
		if (this.map.painted) {
			this.map.repaint();
		}else {
			this.map.paint();
		}
	}
	/* never called??
	confirmNoticeCoordinates: function(rawData) {
		var evaluatedData = eval( "("+rawData.responseText+")" );		
		var successful = evaluatedData.successful;
		if(successful){
			this.map.config.lon = evaluatedData.lon;
			this.map.config.lat = evaluatedData.lat;
			this.map.config.editObject.lon = evaluatedData.lon;
			this.map.config.editObject.lat = evaluatedData.lat;
			this.map.mapManager.currentTileMatrix.poiCache.refreshCache();
			//this.map.repaint();
			this.map.mapManager.moveTo(this.map.config.editObject.lon, this.map.config.editObject.lat);
		}
	}
	*/
}
/**
 * @author cknote
 * 
 * Doing all real world coordinate calculations
 * 
 */
Coordinates = Class.create();
Coordinates.prototype = {

	// constructor

	initialize: function(config,tileMatrix) {
		this.config = config;
		this.tileMatrix = tileMatrix;
		
		this.mouseX = 0;
		this.mouseY = 0;
		
		// docu:	using the LUT provided by Bartosz, converting IDs to Lat
		this.idConvArr = new Array(0.0,1.00668700435474,2.01305915501797,3.0188021006333,4.02360249251984,5.02714848104625,6.02913020607975,7.02924027961646,8.02717425874077,9.02263110714088,10.0153136434893,11.0049289750908,11.9911889153081,12.9738103833864,13.9525157854222,14.9270333753506,15.8970975949536,16.8624493920382,17.8228365160615,18.7780137906281,19.7277433624221,20.6717949262715,21.6099459261829,22.5419817323097,23.4676957939472,24.3868897687665,25.2993736286116,26.2049657422923,27.1034929359004,27.9947905312729,28.8787023632820,29.7550807767831,30.6237866039589,31.4846891230484,32.3376659993363,33.1826032093987,34.0193949495992,34.8479435298631,35.6681592537599,36.4799602859389,37.2832725079563,38.0780293635265,38.8641716942195,39.6416475666031,40.4104120918126,41.1704272384979,41.9216616400704,42.6640903971397,43.3976948759857,44.1224625038963,44.8383865621189,45.5454659771848,46.2437051112803,46.9331135523207,47.6137059043295,48.2855015786883,48.9485245867775,49.6028033344877,50.2483704190425,50.8852624285296,51.5135197445056,52.1331863479955,52.7443096291796,53.3469402010199,53.9411317170504,54.5269406935255,55.1044263360825,55.6736503710697,56.2346768816238,56.7875721486187,57.3324044965118,57.8692441441611,58.3981630606204,58.9192348259263,59.4325344968634,59.9381384776857);
	},
	prepare: function() {
		this.UL = new Array(this.config.xSegments.min(),this.config.ySegments.max());
		this.LR = new Array(this.config.xSegments.max(),this.config.ySegments.min());

		this.pxExtent = new Array( this.config.xSegments.length * this.config.tileWidth ,  this.config.ySegments.length * this.config.tileHeight );

//		this.currentZoomFactor = this.config.zoomFactors[this.config.zoomLevel];
		this.currentZoomFactor = this.config.agsScale[0] / this.config.agsScale[this.config.zoomLevel];		
		this.mouseObserver = this.getMouseCoords.bindAsEventListener(this);

		this.attachMouseCoordsCalc();
	},
	attachMouseCoordsCalc: function() {
		// assign the colportated map center,
		// so zooming will be +- correct when done before mouse
		// has been moved for the first time.
		// (Because no mouse coordinates could be found...)
		this.mouseX = this.config.DOMParentOffsetX + Math.round(this.config.width / 2);
		this.mouseY = this.config.DOMParentOffsetY + Math.round(this.config.height / 2);

		Event.observe(this.tileMatrix.container,"mousemove",this.mouseObserver,true);
		Event.observe(document,"mousemove",this.mouseObserver,true);		
	},
	mapMouseX: function() {
		return this.viewPortMouseX() + this.tileMatrix.mapSource.getPxOff("x");
	},
	mapMouseY: function() {
		return this.viewPortMouseY() + this.tileMatrix.mapSource.getPxOff("y");
	},
	viewPortMouseX: function() {
		// es war nicht klar, warum hier style.left hinzu musste.
		// Ohne funktioniert es richtig.
//		return this.mouseX - this.tileMatrix.container.style.left.delPx() - this.config.DOMParentOffsetX;
//		alert("mouseX "+this.mouseX+" tMstyle.left "+this.tileMatrix.container.style.left.delPx()+" domp "+this.config.DOMParentOffsetX);
		return this.mouseX - this.config.DOMParentOffsetX;
	},
	viewPortMouseY: function() {
		// es war nicht klar, warum hier style.top hinzu musste.
		// Ohne funktioniert es richtig.
//		return this.mouseY - this.tileMatrix.container.style.top.delPx() - this.config.DOMParentOffsetY;
		return this.mouseY - this.config.DOMParentOffsetY;
	},
	getMouseCoords: function(e) {
		this.mouseX = Event.pointerX(e);
		this.mouseY = Event.pointerY(e);
		
		// Accuracy testing: PX -> RW -> PX
		//var rwHin = this.px2rw(this.mapMouseX(),this.mapMouseY());
		//var pxBack = this.rw2px(rwHin[0],rwHin[1]);

//		window.defaultStatus = "Screen "+this.mouseX+"x"+this.mouseY+" | ViewPort "+this.viewPortMouseX()+"x"+this.viewPortMouseY()+" | Map "+this.mapMouseX()+"x"+this.mapMouseY()+" | RW "+this.px2rw(this.mapMouseX(),this.mapMouseY())+" | ||    pxOff: "+this.tileMatrix.mapSource.getPxOff("x")+"x"+this.tileMatrix.mapSource.getPxOff("y")+" | tileOff "+this.tileMatrix.mapSource.getTileOff("x")+"x"+this.tileMatrix.mapSource.getTileOff("y")+" | ";
	},
	getCurrentZoomFactor: function() {
		return this.currentZoomFactor;
	},
	getCurrentZoomLevel: function() {
		return this.config.zoomLevel;
	},
	getBB : function() {
		var bb = new Array( new Array(0,0), new Array(0,0));
		var ulX = this.tileMatrix.mapSource.getPxOff("x");
		var ulY = this.tileMatrix.mapSource.getPxOff("y");
		var lrX = ulX + this.config.width;
		var lrY = ulY + this.config.height;
	
		var UL = this.px2rw(ulX,ulY);
		var LR = this.px2rw(lrX,lrY);
		bb = new Array( UL , LR );

		return bb;
	},
	getCenter: function() {
		var ulX = this.tileMatrix.mapSource.getPxOff("x");
		var ulY = this.tileMatrix.mapSource.getPxOff("y");
		var centerX = ulX + this.config.width/2;
		var centerY = ulY + this.config.height/2;
		
//		alert("starting with "+centerX+","+centerY);
		return this.px2rw(centerX,centerY);
	},
	getCurrentSizeInPx: function() {
	
	},
	getMousePosInRW: function() {
//		window.defaultStatus += " using px off "+this.tileMatrix.mapSource.getPxOff("x")+", "+this.tileMatrix.mapSource.getPxOff("y")+" : viewPort "+this.viewPortMouseX()+", "+this.viewPortMouseY()+" DOMParentOFF "+this.config.DOMParentOffsetX+", "+this.config.DOMParentOffsetY;
		return this.px2rw(this.mapMouseX(),this.mapMouseY());
	},
	px2rw : function(x,y) {
		// docu:	one tiles is supposed to be 1 degree in zF 1
		var pxSizeX = 1 / (this.currentZoomFactor * this.config.tileWidth);
		var lon = this.UL[0] + (pxSizeX * x);
	
		// docu:	y direction is more complicated! First, we go from bottom to top, so switch coordinate direction
		var pxFromBottom = this.pxExtent[1] * this.currentZoomFactor - y;
		// docu:	which tile are we on?
		var yTile = Math.floor(pxFromBottom / (this.config.tileHeight*this.currentZoomFactor));
		// docu:	how many pixels left?
		if (yTile > 0) var yRest = pxFromBottom % (yTile * this.config.tileHeight * this.currentZoomFactor);
		else yRest = pxFromBottom;

		var yID = this.config.ySegments[this.config.ySegments.length - 1] + yTile;



		// AHHHHHH, magic number!! Used to account for px offset reasoned in the non linear representation of the subtiles.
		var zaehler = (this.currentZoomFactor / 2) - ( Math.abs( Math.floor(yRest / this.config.tileHeight) - (this.currentZoomFactor / 2) ) );
		var nenner = (this.currentZoomFactor / 2);
		
		var off = (zaehler / nenner) * this.config.magicNumberPX_Y * this.currentZoomFactor;
				
		yRest += off;



		// docu:	now cartographic bullshit, but better than nothing:
		// docu:	linear interpolation between two id / degree steps to get "exact" lat pos.
		var lat = this.index2lat(yID) + (yRest / (this.config.tileHeight*this.currentZoomFactor)) * (this.index2lat(yID+1) - this.index2lat(yID));

		return new Array(lon, lat);
	},
	rw2px : function(lon, lat) {
		var rwDelta = lon - this.UL[0];
		var rwSize = (this.LR[0]+1) - this.UL[0];
		
		var x = (rwDelta/rwSize) * (this.pxExtent[0] * this.currentZoomFactor);
				
		// docu:	theory to get to the px position:
		// docu:	traverse through id array unit item > lat
		// docu:	fraction of (lat - id array item) / (id array item+1 - id array item) * tile size

		var i = this.lat2index(lat);

		// docu: 	now allright, we got the lower bound
		var lowerYTileRW = this.index2lat(i);

		var yDelta = lat - lowerYTileRW;

		var pxDelta = (yDelta / (this.index2lat(i+1) - this.index2lat(i))) * (this.config.tileHeight * this.currentZoomFactor);
		
		// AHHHHHH, magic number!! Used to account for px offset reasoned in the non linear representation of the subtiles.
		// 		32		-		(	31 	- 	32	)
		var zaehler = (this.currentZoomFactor / 2) - ( Math.abs( Math.floor(pxDelta / this.config.tileHeight) - (this.currentZoomFactor / 2) ) );
		var nenner = (this.currentZoomFactor / 2);
		
		var off = (zaehler / nenner) * this.config.magicNumberPX_Y * this.currentZoomFactor;
		
//		window.defaultStatus = this.currentZoomFactor+" , "+this.config.tileHeight+" , "+lat+" , "+zaehler+" / "+nenner+" = "+off;
		
		pxDelta -= off;

		var revPos = (i - this.config.ySegments[this.config.ySegments.length - 1]) * this.config.tileHeight * this.currentZoomFactor + pxDelta;
		var y = (this.pxExtent[1] * this.currentZoomFactor) - revPos;
		
		return new Array(Math.round(x),Math.round(y));
	},
	index2lat : function(index) {
		if (index >= 0 && index < this.idConvArr.length) return this.idConvArr[index];
		else return -1;
	},
	lat2index : function(lat) {
		var i = this.config.ySegments[this.config.ySegments.length - 1];
		while (this.index2lat(i) < lat && i < this.idConvArr.length) i++;
		i--;
		return i;
	},
	remove : function() {
		Event.stopObserving(this.tileMatrix.container,"mousemove",this.mouseObserver,true);
		Event.stopObserving(document,"mousemove",this.mouseObserver,true);
		
		this.mouseObserver = null;
		
		this.tileMatrix = null;
		this.config = null;
		this.mouseObserver = null;
	}
}



AGS_Coordinates = Class.create();
AGS_Coordinates.prototype = Object.extend(new Coordinates(),{
	initialize: function(config,tileMatrix) {
		this.config = config;
		this.tileMatrix = tileMatrix;
		
		this.mouseX = 0;
		this.mouseY = 0;
	},
	prepare: function() {
		this.currentZoomFactor = this.config.agsScale[0] / this.config.agsScale[this.config.zoomLevel];		
//		//debug.writeline("ags_coordinates: currentZoomFactor is "+this.currentZoomFactor);

		this.UL = this.config.agsTileOrigin;
		this.mouseObserver = this.getMouseCoords.bindAsEventListener(this);

		this.attachMouseCoordsCalc();
	},
	getCurrentResolution: function() {
		return this.config.agsResolution[this.getCurrentZoomLevel()];
	},
	getCurrentScale: function() {
		return this.config.agsScale[this.getCurrentZoomLevel()];
	},
	px2rw : function(x,y) {
		var lon = this.UL[0] + this.getCurrentResolution() * x;
		var lat = this.UL[1] - this.getCurrentResolution() * y;

		return new Array(lon, lat);
	},
	rw2px : function(lon, lat) {
		var x = (lon - this.UL[0]) / this.getCurrentResolution();
		var y = (this.UL[1] - lat) / this.getCurrentResolution();

		return new Array(Math.round(x),Math.round(y));
	}
});

/*
 * 
 * Adding copyright information to the map, drawing them on the bottom right
 * 
 */
CopyrightInfo = Class.create();
CopyrightInfo.prototype = {
	initialize: function(config,container) {
		this.config = config;
		this.container = container;
		this.div = null;
		this.items = new Array();
	},
	paint: function() {
		if (this.div == null) {
			this.div = document.createElement("div");

			Element.addClassName(this.div,"copyrightInfo");
	
			for (var item = 0 ; item < this.config.copyrightInfos.length ; item++) {
				this.items.push(document.createElement("a"));
				this.items[this.items.length - 1].href = this.config.copyrightInfos[item][1];
							
				this.items[this.items.length - 1].innerHTML = this.config.copyrightInfos[item][0];
				
				this.div.appendChild(this.items[this.items.length - 1]);
				
				this.container.appendChild(this.div);
	
				if (item < (this.config.copyrightInfos.length - 1)) {
					var txt_between = document.createTextNode(" | ");
					this.div.appendChild(txt_between);
				}
			}
		}
		this.position();
	},
	position: function() {
		Element.setStyle(this.div,{position:"absolute",top:(this.config.height - this.config.copyrightInfosOffsetY)+"px",left:this.config.copyrightInfosOffsetX+"px"});
	},
	remove: function() {
		this.config = null;
		if (this.div != null) {
			while(this.div.hasChildNodes()) {
				this.div.removeChild(this.div.firstChild);
			}
			this.container.removeChild(this.div);
		}
		this.container = null;
		this.items = null;
//		//debug.writeline("copyrightInfo removed");
	}
}


DebugConsole = Class.create();
DebugConsole.prototype = {
	initialize: function(container,x,y,width,height) {
		this.container = container;
		this.debugBox = null;
		this.x = x;
		this.y = y;
		this.width = width;
		this.height = height;
		this.painted = false;
	},
	paint: function() {
		if (this.debugBox == null) {
			this.debugBox = document.createElement("textarea");
			this.debugBox.cols = this.width;
			this.debugBox.rows = this.height;
			Element.setStyle(this.debugBox,{zIndex:10000000,position:"absolute",top:this.y+"px",left:this.x+"px"});
			this.container.appendChild(this.debugBox);
		}
	},
	writeline: function(txt) {
		if (this.painted) {
			var time = new Date();
			this.debugBox.value = time.getTime()+": "+txt + "\r" + this.debugBox.value;
		}
	},
	clear: function() {
		this.debugBox.value = "";
	}
}


/*	EditBar
 * 
 * provides the set knob when editing a point
 * 
 */
EditBar = Class.create();
EditBar.prototype = {
	initialize: function(poi,config) {
		this.poi = poi;
		this.config = config;
		this.initialPosition = this.poi.getPxCoords();
		this.hideCountdown = null;
		this.cancelHideObserver = this.cancelHide.bindAsEventListener(this);
		this.triggerHideObserver = this.triggerHide.bindAsEventListener(this);		
	},
	paint: function() {
		this.div = document.createElement("div");
		
		Element.addClassName(this.div,"poiEditBar");
		this.addButtons();
		this.addPosition();
		
		this.update();
		
		this.poi.container.appendChild(this.div);
	},
	remove: function() {
		while(this.div.hasChildNodes()) {
			this.div.removeChild(this.div.firstChild);
		}
		this.poi.container.removeChild(this.div);
		this.div = null;
	},
	update: function() {
		var pixelPos = this.poi.getPxCoords();
		var icon = this.poi.getIcon(this.poi.type);
		Element.setStyle(this.div,{position:"absolute",top:pixelPos[1] + Math.round(icon[2]/2) +"px",left:pixelPos[0]+"px",display:"none"});
	},
	triggerHide: function() {
		if (this.hideCountdown == null) {
			this.hideCountdown = setTimeout(this.hide.bind(this),this.poi.config.popUpHideDelay);
		}
	},
	cancelHide: function() {
		if (this.hideCountdown != null) {
			clearTimeout(this.hideCountdown);
			this.hideCountdown = null;
		}
	},
	hide: function() {
		Element.setStyle(this.div,{display:"none"});
	},
	show: function() {
		Element.setStyle(this.div,{display:"block"});
		this.cancelHide();
	},
	addButtons: function() {
		this.setButton = this.addInput("set","set","submit",this.setPOI.bindAsEventListener(this));
		this.div.appendChild(this.setButton);

/*		this.resetButton = this.addInput("reset","reset","submit",this.resetPOI.bindAsEventListener(this));
		this.div.appendChild(this.resetButton);

		this.removeButton = this.addInput("remove","remove","submit",this.removePOI.bindAsEventListener(this));
		this.div.appendChild(this.removeButton);
*/	},
	addInput: function(name,value,type,callBack) {
		var button = document.createElement("input");
		button.type = type;
		button.value = value;
		button.name = name;
		button.onclick = callBack;

		Event.observe(button,"mouseover",this.cancelHideObserver);
		Event.observe(button,"mouseout",this.triggerHideObserver);

		return button;
	},
	addPosition: function() {
		// will display current point coordinates when moving the point
	},
	setPOI: function() {
		window.location.href = this.config.editServletAddress + "poi="+this.poi.id+"&lat="+this.poi.point.getY()+"&lon="+this.poi.point.getX()+"&sessionId="+this.config.sessionId;
	},
	resetPOI: function() {
		this.poi.setPxCoords(this.initialPosition);
		this.poi.update();
	},
	removePOI: function() {
//		alert("now removing "+this.poi.id);
	}
}


/*	EditPOICache
 * 
 * Handles the caching of the POIs. Is based on a zoom factor aware raster.
 * Edit cache simulates normal POI cache but does not question the server,
 * only saves POIs between zooming and panning.
 * 
 */
EditPOICache = Class.create();
EditPOICache.prototype = {
	initialize: function(poiManager) {
		this.poiManager = poiManager;
		this.config = poiManager.config;
		this.caching = false;
	},
	addDataSource: function(name,ds){
	
	},
	startCaching: function(listenerDispenser) {
		if (!this.caching) {
			this.cachePOIs();
			this.caching = true;
		}
	},
	stopCaching: function() {
	},
	cachePOIs: function() {
		this.poiManager.addPOI(this.config.editObject.lon,this.config.editObject.lat,this.config.editObject.id,this.config.editObject.type,this.config.editObject.name, undefined ,this.config.editObject.successfullyGeocoded);
	},
	refreshCache: function() {
		var thePOI = this.poiManager.pointBox[this.config.editObject.id];
		var oldX = thePOI.point.x;
		var oldY = thePOI.point.y;
		var newX = this.config.editObject.lon;
		var newY = this.config.editObject.lat;
		//alert("refreshCache");
		thePOI.point.x = newX ;
		thePOI.point.y = newY ;
		thePOI.update();
	},
	remove: function() {
		this.config = null;
		this.poiManager = null;
	}
}


/* EventLogger
 * 
 * Logs all map actions like drawing, moving, zooming to the alta4gis logger
 * 
 */
EventLogger = Class.create();
EventLogger.prototype = {
	initialize: function(url, userId, project) {
		this.url = url;
		this.userId = userId;
		this.project = project;
		this.active = false;
	},
	toggle: function(doLog) {
		this.active = doLog;
	},
	log: function(type) {
		if (this.active) {
			var parameter = "userid="+this.userId+"&projekt="+this.project+"&kategorie="+type+"&rand="+Math.random();
			var aRequest = new Ajax.Request(
				this.url, 
				{
					method: "get",
					parameters: parameter
				}
			);
		}
	},
	remove: function() {
	}
}
/**
 * Google Analytics tracker
 */
GoogleTracker = Class.create();
GoogleTracker.prototype = {
	initialize: function() {
		this.userID = null;
		this.scriptTag = null;
		this.tracker = null;
	},
	hookUp: function(head) {
		if (this.scriptTag == null && !$("googleAnalyticsMapUseTracker")) {
			this.scriptTag = document.createElement("script");
			this.scriptTag.type="text/javascript";
			this.scriptTag.id = "googleAnalyticsMapUseTracker";
			
			// from Google Analytics
			var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
			var gaJsSrc = gaJsHost + "google-analytics.com/ga.js";
	
			this.scriptTag.src=gaJsSrc;
			
			head.appendChild(this.scriptTag);
		}
	},
	trackPageView: function(userID) {
		if (this.tracker != null) {
			this.tracker = _gat._getTracker(userID);
			this.tracker._initData();
			this.tracker._trackPageview();
		}
	},
	dispose: function() {
		this.tracker = null;
		this.scriptTag = null;
		this.userID = null;
	}
}
/*	Helper
 * 
 * Helper functions, providing extended abilities for the basic types
 * 
 */
 
var loadedScripts = {
	callFunction: function(){
	}
};
var observer = {
	name: "alta4 observer",
	/**
	 * diese Methode wird aufgerufen, sobald der noticeCoordinates-Request abgearbeitet wurde. Überschreiben um sich dort reinzuhängen
	 * 
	 */
	update: function(){
		//alert(this.name + " : "+$A(arguments).join(', '));
	}
};

function loadClasses() {
	loadedScripts.callFunction();
};
 
String.prototype.delPx = function() {
	var str = this.valueOf();
	var len = this.length;
	if (str.substring((len-2),len) == "px") {
		str = str.substring(0, (len-2));
		str = parseInt(str, 10);
	}
	return str;
}

/*	ImageCache

Provides ability to cache images and retrieve them, therefore optimizing page load time

*/
ImageCache = Class.create();
ImageCache.prototype = {
	initialize: function(size) {
		this.images = new Array();
		this.cacheSize = size;
		this.cacheFill = 0;
	},
	get: function(src) {
		if (this.cacheFill > this.cacheSize) this.clear();

		if (!this.images[src]) {
			this.images[src] = new Image();
			this.images[src].src = src;
			this.cacheFill++;
		}
		return this.images[src].src;
	},
	clear: function() {
		this.images = new Array();
		this.cacheFill = 0;
	}
};

/*	Interactions
 * 
 * Interactions will hold any HID events and dispense them to the defined event handler.
 * Implemented are:
 * 
 * * panning the map with the direction keys
 * * zooming with the mouse wheel
 * 
 */
Interactions = Class.create();
Interactions.prototype = {
	initialize: function(mapContainer, mapManager, CompassRose) {
		this.container = mapContainer;
		this.mapManager = mapManager;
		this.compassRose = CompassRose;
		this.keyboardMoving = false;
		this.keyboardDownObserver = null;
		this.keyboardUpObserver = null;
	},
	keyboard: function() {
		this.keyboardDownObserver = this.keyboardDown.bindAsEventListener(this);
		this.keyboardUpObserver = this.keyboardUp.bindAsEventListener(this);
		Event.observe(document,'keydown', this.keyboardDownObserver);
		Event.observe(document,'keyup', this.keyboardUpObserver);
	},
	mouse: function() {
		this.mouseWheelObserver = this.mousewheelActions.bindAsEventListener(this);
		Event.observe(this.container,"mousewheel",this.mouseWheelObserver,true);
		Event.observe(this.container,"DOMMouseScroll",this.mouseWheelObserver,true);
	},
	keyboardDown: function(e) {
		if (!this.keyboardMoving) {
			if(e.keyCode == Event.KEY_UP) this.compassRose.downN(e);
			if(e.keyCode == Event.KEY_DOWN) this.compassRose.downS(e);
			if(e.keyCode == Event.KEY_LEFT) this.compassRose.downE(e);
			if(e.keyCode == Event.KEY_RIGHT) this.compassRose.downW(e);
		}
	},
	keyboardUp: function(e) {
		if (this.compassRose) this.compassRose.stopMoving(e);
		this.keyboardMoving = false;
	},
	mousewheelActions: function(e) {
		Event.stop(e);
		(e.wheelDelta) ? amount = e.wheelDelta / -120 : amount = e.detail / 3;
		this.mapManager.zoom(-amount, true);
	},
	remove: function() {
		Event.stopObserving(document,'keydown',this.keyboardDownObserver,true);
		Event.stopObserving(document,'keyup',this.keyboardUpObserver,true);
		Event.stopObserving(this.container,"mousewheel",this.mouseWheelObserver,true);
		Event.stopObserving(this.container,"DOMMouseScroll",this.mouseWheelObserver,true);
		//debug.writeline("interactions removed");
		//////console.debug("interactions removed");
	}
}

/*	JSONParser
 * 
 * Handles the server communication for POI retrieval. All communications based on JSON and AJAX.
 * 
 */
	
JSONParser = Class.create();
JSONParser.prototype = {
	initialize: function() {		
	},
	load: function(servletAddress,params,onCompleteFuncion) {
		//////console.debug("JSONParser.load(...) ");
		//this.working = true;
			//debug.writeline(servletAddress+params);
		this.request = new Ajax.Request(
			servletAddress, 
			{
				method: "get",
				parameters: params,
				onComplete:onCompleteFuncion
			}
		);
	},
	abort: function(){
		//////console.debug("JSONParser.abort() - request: "+this.request);
		this.request.abort();
	},
	remove: function() {
		this.request = null;
	}
}

/**
 * Quelle: http://dev.rubyonrails.org/ticket/11311
 * 
 * Ajax.Request.abort
 * extend the prototype.js Ajax.Request object so that it supports an abort method
 */
Ajax.Request.prototype.abort = function() {
    // prevent and state change callbacks from being issued
    this.transport.onreadystatechange = Prototype.emptyFunction;
    // abort the XHR
    this.transport.abort();
    // update the request counter
    Ajax.activeRequestCount--;
};

	
/*	ListenerDispenser
 * 
 * Listener Dispenser enables a class to define events which are then dispersed to other classes methods.
 * Other classes can attach "listeners" to the events specified. 
 * 
 */

ListenerDispenser = Class.create();
ListenerDispenser.prototype = {
	initialize: function() {
		this.listener = new Array();
	},
	attachListener: function(action,callbackMethod) {
		if (typeof(this.listener[action]) != "object") this.listener[action] = new Array();
		this.listener[action].push(callbackMethod);
	},
	trigger: function(action) {
		// if action exists loop through all attached listeners and execute the callback functions
		if (typeof(this.listener[action]) == "object") {
			for (var i = 0 ; i < this.listener[action].length ; i++) {
				this.listener[action][i]();
			}
		}
	},
	remove: function() {
		this.listener = null;
	}
}
/*	Map

Map is the wrapper class, which is exposed to the user.

*/
Map = Class.create();
Map.prototype = {
	/**
	 * 
	 * @param {Object} DOMParent	der Container in dem die Anwendung läuft
	 * @param {Object} width	breite der sichtbaren Karte
	 * @param {Object} height 	Höhe der sichtbaren Karte
	 */
	initialize: function(DOMParent, width, height, portalClientId) {
		this.mapContainer = DOMParent;
		this.width = width;
		this.height = height;
		this.portalClientId = portalClientId;
		this.doAggregation = true;
		this.poiObservers = {};
		
		if (!this.doAggregation){
			mapOptions.isAggregation=false
			overviewMapOptions.isAggregation=false
		}else{
			mapOptions.isAggregation=true
			overviewMapOptions.isAggregation=true
		}
		
		this.hasOverviewMap = true;
		if (width<=300 && height <= 300){
			this.hasOverviewMap = false;
		}			
		
		this.map = null;
		this.overviewMap = null;
		this.overviewMapContainer = null;
		
		this.map = new MapIntern(this.mapContainer, this.width, this.height, mapOptions, this, this.portalClientId);

		if (this.hasOverviewMap) {
			this.createOverviewMap(120,120);
		}
		
/*
		this.googleTracker = new GoogleTracker();
		this.googleTracker.hookUp(document.getElementsByTagName("head")[0]);
		this.googleTracker.trackPageView("UA-3566079-1");
		this.googleTracker.trackPageView("UA-3566079-2");
*/

	},
	setAggregation: function(isAggregation) {
		this.map.setAggregation(isAggregation);
		if (this.overviewMap !== null) {
			this.overviewMap.setAggregation(isAggregation);
		}
	},
	createOverviewMap: function(width, height) {
		if (! $("overviewMapContainer")) {
			this.overviewMapContainer = document.createElement("div");
			this.overviewMapContainer.id = "overviewMapContainer";
			Element.setStyle(this.overviewMapContainer, { position:"relative" , top:"0px" , left:"0px", zIndex:20000, border:overviewMapOptions.overviewMapBorderStyle , width:width+"px", height:height+"px" });
			this.mapContainer.appendChild(this.overviewMapContainer);
		}
		else this.overviewMapContainer = document.getElementById("overviewMapContainer");
		
		if (this.overviewMap === null) {
			this.overviewMap = new MapIntern(this.overviewMapContainer, width, height, overviewMapOptions, this, this.portalClientId);

			this.map.connectMap(this.overviewMap);
			
			this.overviewMap.setMoveObserver(this.map,this.map.observeMoves);
			this.overviewMap.setCenterObserver(this.map, this.map.observeCenter);
			this.overviewMap.setBBObserver(this.map, this.map.observeBB);
		}
	},
	destroyOverviewMap: function() {
		if (this.overviewMap !== null) {
			this.overviewMap.remove();
			this.overviewMap.shutdown();
		}
		if (this.overviewMapContainer !== null) {
			this.mapContainer.removeChild(this.overviewMapContainer);
		}
	},
	/*
	 * drawing
	 */
	paint: function() {
		this.map.paint();
		if (this.overviewMap !== null) this.overviewMap.paint();
	},
	repaint: function() {
		this.map.repaint();
		if (this.overviewMap !== null) this.overviewMap.repaint();
	},
	suspendRedraw: function(suspendState){
		this.map.suspendRedraw(suspendState);
		if (this.overviewMap !== null) this.overviewMap.suspendRedraw(suspendState);		
	},
	remove: function() {
		this.map.remove();
		if (this.overviewMap !== null) this.overviewMap.remove();		
	},
	shutdown: function() {
		this.map.shutdown();
		if (this.overviewMap !== null) this.destroyOverviewMap();		
	},
	/*
	 * map manipulation
	 */
	setCenter: function(pos) {
		this.map.setCenter(pos);
		if (this.overviewMap !== null) this.overviewMap.setCenter(pos);		
	},
	setZoomLevel: function(level) {
		this.map.setZoomLevel(level);
	},
	setZoomFactor: function(factor) {
		this.map.setZoomFactor(factor);
	},
	setMapScale: function(scale) {
		this.map.setMapScale(scale);
	},
	setFullWidth: function() {
		this.map.setFullWidth();
	},
	setFullHeight: function() {
		this.map.setFullHeight();
	},
	setWidth: function(width) {
		this.map.setWidth(width);
	},
	setHeight: function(height) {
		this.map.setHeight(height);
	},
	zoomTo: function(level) {
		this.map.zoomTo(level);
	},
	hasLayerSelector: function(hasLayerSelector){
	},
	hasZoomBar: function(hasZoomBar){
		this.map.hasZoomBar(hasZoomBar);
	},
	hasCompassRose: function(hasCompassRose){
		this.map.hasCompassRose(hasCompassRose);
	},
	/*
	 * state
	 */
	getState: function() {
		return this.map.getState();
	},
	setState: function(state) {
		this.map.setState(state);
		if (this.overviewMap != null) {
			// the overview map zoomlevel
			// is certainly not the same
			// as the one of the main map...
			state.zoomLevel = null;
			this.overviewMap.setState(state);
		}
	},
	getServiceIndex: function() {
		return this.map.getServiceIndex();
	},
	isLayerVisible: function(layer){
		return this.map.isLayerVisible(layer);
	},
	getZoomLevel: function(){
		return this.map.getCurrentZoomLevel();
	},
	/*
	 * edit session
	 */
	setEditSession: function(bool) {
		this.map.setEditSession(bool);
	},
	setEditRecode: function(bool) {
		this.map.setEditRecode(bool);
	},
	setEditID: function(id) {
		this.map.setEditID(id);
	},
	setEditType: function(type) {
		this.map.setEditType(type);
	},
	setEditName: function(name) {
		this.map.setEditName(name);
	},
	setEditPassThrough_geocodeStatus: function(content) {
		this.map.setEditPassThrough_geocodeStatus(content);
	},
	setEditPassThrough_showNeverGeocodePOIs: function(content) {
		this.map.setEditPassThrough_showNeverGeocodePOIs(content);
	},
	setEditPassThrough_list: function(content) {
		this.map.setEditPassThrough_list(content);
	},
	checkEditPOIPosition: function() {
		this.map.checkEditPOIPosition();
	},
	deletePOI: function() {
		this.map.deletePOI();
	},
	resetEditObject: function() {
		this.map.resetEditObject();
	},
	/*
	 * content manipulation
	 */
	setLang: function(content) {
		this.map.setLang(content);
	},
	setSearchResultIds: function(content) {
		this.map.setSearchResultIds(content);
	},
	setArea: function(regionId) {
		this.map.setArea(regionId);
	},
	setGeocodePOI: function(poi) {
		this.map.setGeocodePOI(poi);
	},
	/**
	 * Karte mit übergebenen POI-IDs aufrufen.
	 * 
	 * Einstiegspunkt Bestview (Angebotsliste im Portal)
	 * @param {Object} guids (infomax IDs)
	 * @param {Object} isBubble (has Bubble)
	 * @param {Object} hasPopUps
	 * @param {Object} regId (regions ids..., wenn region als bestview verwendet werden soll (wahrscheinlich?!)
	 * @param {Object} bubbleStartIdx (wenn bubbles: gewünschter StartNummer; wg. Paging) param. optional
	 */
	setPOIs: function(guids, isBubble, hasPopUps, regId, bubbleIdxStart) {
		//this.setAggregation(false);
		this.map.setPOIs(guids, isBubble, hasPopUps, regId, bubbleIdxStart);
	},
	/**
	 * Karte mit übergebenen POI-IDs aufrufen zur anzeige als Teaser-Bild.
	 * 
	 * Einstiegspunkt Bestview (Startseite im Portal)
	 * @param {Object} guids (infomax IDs)
	 * @param {Object} isBubble (has Bubble)
	 * @param {Object} hasPopUps
	 * @param {Object} regId (regions ids..., wenn region als bestview verwendet werden soll (wahrscheinlich?!)
	 */
	setTeasers: function(guids, isBubble, hasPopUps, regId) {
		//this.setAggregation(false);
		this.map.setTeasers(guids, isBubble, hasPopUps, regId);
	},
	setVisibleTopics: function(arguments) {
		this.map.setVisibleTopics(arguments);
	},
	setVisibleAreas: function(arguments) {
		this.map.setVisibleAreas(arguments);
	},
	setVisibleTargetGroups: function(arguments) {
		this.map.setVisibleTargetGroups(arguments);
	},
	hideLayer: function(layers) {
		//ausblenden
		this.map.hideLayer(layers);
		
		//ES: Aus Zoom-Listener entfernen(falls drin); würde sonst nach einem zoom wieder angezeigt obwohl hiermit deselektiert
		for (aLayerIdx in layers){
			var type = typeof(layers[aLayerIdx]);
			
			if( type != "function"
				&&this.poiObservers["zoomlevelSensitiveLayerObserver"] != null){ //just in case...
				
				//////console.debug('  > hideLayer:'+layers[aLayerIdx]);
				var idx = this.poiObservers["zoomlevelSensitiveLayerObserver"].layerArray.indexOf(layers[aLayerIdx]);
				if(idx >=0) this.poiObservers["zoomlevelSensitiveLayerObserver"].layerArray.splice(idx, 1); //betreffenden Layer entfernen (falls gülltiger layer angegeben)
			}
		}
	
	},
	showLayer: function(layers) {
		this.map.showLayer(layers);
	},
	/** 
	 * Layer, die erst ab einer bestimmten Zoomstufe angezeigt werden sollen 
	 * ES
	 * */
	showLayerFromZoomlevel: function(layers, minZoomLevel) {
		//wg. 0002993 ist jetzt Umrechnung des Zoomlayers nötig, da jetzt die in Zoombar angezeigte zoomstufe nicht mehr der realen entsprichte (für API-User maskieren)
		//vorher war nur ein Layer drunter (index 0) -> umrechnung war dann nicht nötigt
		minZoomLevel = minZoomLevel + (this.map.config.minimumAllowedZoomLevel -1); 
		
		this.map.showLayerFromZoomlevel(layers, minZoomLevel); //wirk ja nur, wen zum Zeitpunkt des Aufrufs (durch das Portal ) die Karte über dem mindestzoom liegt 
		
		
		//Zoom-Listener, der die Layer der Karte ein und ausschaltet (bei über- bzw. unterschreitung des minZoomLevel)
		this.zoomlevelSensitiveLayerObserver =  {
				/**LayerIDs für die der Lister greifen soll...*/
				layerArray: layers,
				/**Prüft bei ob Zoomlayer dazuzugeschaltet werden muss (als Observer nach jeder Zoom-Aktion aufgerufen)*/
				update: function() {
					var data = $A(arguments);
					var caller = data[0];
					var method = data[1];
					var zoomLevel = data[2];
					var callerIsOverviewMap = data[3];
					
					var debugString =  'minZoomLevel: '+minZoomLevel+' zoomLevel: '+zoomLevel+ ' callerIsOverviewMap: '+callerIsOverviewMap;
					if(!callerIsOverviewMap && (zoomLevel >= minZoomLevel)){
						caller.map.showLayerFromZoomlevel(this.layerArray, minZoomLevel); //
						//alert(debugString);
						////console.debug(" showLayerFromZoomlevel.update with params "+this.layerArray+", "+debugString);
					}else if(!callerIsOverviewMap && (zoomLevel < minZoomLevel)){
						caller.map.hideLayer(this.layerArray); //
						//alert("hide layers: "+layers+" "+debugString);
						////console.debug(" call hideLayer with params "+this.layerArray+", "+debugString);
					}
				} 
		}
		
		//Zoom-Listener bei Karte anmelden
		//Stand: nur mit Radwege-Layer getestet...
		this.addObserver("zoomlevelSensitiveLayerObserver", this.zoomlevelSensitiveLayerObserver);
		////console.debug("call showLayerFromZoomlevel");
	},
	setWeatherStations: function(stations){
		this.map.setWeatherStations(stations);
	},
	showPOI: function(poiId){
		this.map.showPOI(poiId);
	},
	/*
	 * environment
	 */
	getBrowserDimensions: function() {
		return this.map.getBrowserDimensions();
	},
	getBrowserLang: function() {
		return this.map.getBrowserLang();
	},
	getDOMParentPosition: function() {
		return this.getDOMParentPosition();
	},
	/*
	 * session handling
	 */
	openSession: function(id) {
		this.map.openSession(id);
	},
	setSessionId: function(id) {
		this.map.setSessionId(id);
	},
	/*
	 * helper
	 */
	// this function will check all the set*** inputs, if they are a valid list
	checkInput: function(input) {
		return this.map.checkInput(input);
	},
	notifyObservers: function(){
		var data = $A(arguments);
		if (data[0]=="poiId"){
			this.activePoiId = this.map.activePoiId;
			this.activePoiType = this.map.activePoiType;
			this.activePoi = this.map.activePoi;
			for (o in this.poiObservers){
				this.poiObservers[o].update(this,data[0]);
			}
		}else if(data[0]=="addPOI"){
			var poi = data[1];
			for (o in this.poiObservers){
				this.poiObservers[o].update(this,data[0],poi);
			}
		}else if(data[0]=="zoom"){
			var newZoomLevel = data[1];
			var isOverviewMap = data[2];
			for (o in this.poiObservers){
				this.poiObservers[o].update(this,data[0], newZoomLevel, isOverviewMap);
			}
		}
		//////console.debug("notifyObservers: "+data[0]+" - "+data.toString());
	},
	addObserver: function(name, observer){
		this.poiObservers[name]=observer;
	},
	closePopUps: function(){
		//ES: nicht mehr benötigt (da Mini-Maximap-Popup-Problem in PopiManager.addPOI gelöst)
	},
	historyBack: function(){
		this.map.historyBack();
	},
	historyForward: function(){
		this.map.historyForward();
	},
	/**
	 * Transformiert eine Punkt-Koordinate von WGS84 zu GK3 und vice versa.
	 * 
	 * estykow 
	 * @param {lat:val, lon:val, coordinateSystem: 'val'}
	 * 
	 * @return
	 */
	transformPoint: function(point){
		return this.map.transformPoint(point);
	},
	/**
	 * Karte auf Init-Extent setzen (zu 0002268).
	 * @return
	 */
	showInitMap: function(){
		this.map.showInitMap();
	}
	
}
/*	MapIntern

MapIntern is the base class, which is self contained and holds everything.

*/
MapIntern = Class.create();
MapIntern.prototype = {
	/**
	 * 
	 * @param {Object} DOMParent	der Container in dem die Anwendung läuft
	 * @param {Object} width	breite der sichtbaren Karte
	 * @param {Object} height 	Höhe der sichtbaren Karte
	 */
	initialize: function(DOMParent, width, height, options, theMap, portalClientId) {
		this.config = new cloneObject(options);	
		this.DOMParent = DOMParent;
		this.map = theMap;
		this.serviceIndex = new ServiceIndex(portalClientId);
		this.checkConfig();
		this.setWidth(width);
		this.setHeight(height);
		this.portalClientId = portalClientId;
		
		if(!this.config.isOverviewMap && width<=300 && height <= 300){ //feststellen, ob das hier eine Minimap ist 
			this.config.isMiniMap = true;
			this.config.hasHistory = false; //braucht keine History
			
			//Annahme: Minimap hat keine Overviewmap -> Minimap kann auch die erste Zoomstufe nutzen 
			this.config.minimumAllowedZoomLevel	= 2;
			this.config.zoomLevel = 2;
			
		}		
		this.searchIds = [];
		// will be the visible map object
		this.mapManager = null;

		// compass rose
		this.compassRose = null;
		// zoom bar
		this.zoomBar = null;	
		// interactions are all things like mouse gestures, key strokes etc.
		this.interactions = null;
		// draws the copyright infos
		this.copyrightInfo = null;
		//poi spezifisch
		this.activePoiId=null;
		this.activePoiIdTash=null;
		this.activePoi = null;
		
		// log map drawing
		this.eventLogger = new EventLogger(this.config.loggingURL, this.config.loggingUserId, this.config.loggingProject);
		if (this.config.loggingActive) this.eventLogger.toggle(true);

		// handles all control communication with the server (auth, geocode...)
		this.controlConnector = new ControlConnector(this);
		//hack
		this.config["controlConnector"] = this.controlConnector;
		
		//Ausgangs-Extent merken (wird ja später überschrieben und ginge sonst verloren) 
		if (this.config != null && !this.config.isOverviewMap ){
			////console.debug(' **init coord:'+this.config.lat +' '+this.config.lon +' z: '+this.config.zoomLevel)
			this.config.historyInitMapLat = this.config.lat;
			this.config.historyInitMapLon = this.config.lon;
			this.config.historyInitMapZoomLevel = this.config.zoomLevel;
		}

		this.painted = false;
	},
	/**
	 * interne Methode
	 */
	createMapCon: function() {
		if (this.container == null) {
			this.container = document.createElement("div");
		
			// should be unique, to avoid confusion if more than one map is displayed on the page
			this.container.id = "map"+Math.random();

			Element.setStyle(this.container, { position:"absolute" , left:this.config.left+"px" , top:this.config.top+"px" , width:this.config.width+"px" , height:this.config.height+"px" });
			Element.addClassName(this.container,"mapCon");
	
			// linking the whole thing to the page
			this.DOMParent.appendChild(this.container);
		}
	},
	/**
	 * interne Methode
	 */
	checkConfig: function() {	
		if (this.config.width == "full") this.setFullWidth();
		if (this.config.height == "full") this.setFullHeight();
		
		// backup: if no lang tag is defined, use browser information
		this.getBrowserLang();

		// update container offset
		this.getDOMParentPosition();
				
		// update position information for edit point
		if (this.config.editMode) this.checkEditPOIPosition();
	},
	/**
	 * 
	 * @param {Object} content
	 */
	setLang: function(content) {
		if (content.indexOf("fr") != -1) this.config.usedLang = 0;
		if (content.indexOf("de") != -1) this.config.usedLang = 1;
		if (content.indexOf("en") != -1) this.config.usedLang = 2;
	},
	setCenter: function(pos) {
		//es: namentliche zuweisung vorziehen (ist dan reihenfolgen-unabhängig)
		if(pos.lat && pos.lon){
			this.config.lon = pos.lon;
			this.config.lat = pos.lat;
		} else{
			this.config.lon = pos[0];
			this.config.lat = pos[1];
		}
	},
	setZoomLevel: function(level) {
		if (this.config.minimumAllowedZoomLevel > level){
			this.config.zoomLevel = this.config.minimumAllowedZoomLevel;
		}else{
			this.config.zoomLevel = parseInt(level);
		}
	},
	getCurrentZoomLevel: function(){
		return this.mapManager.getCurrentZoomLevel();
	},
	setZoomFactor: function(factor) {
		for (var item = 0; item < this.config.agsResolution.length ; item++) {
			if (this.config.agsResolution[item] == factor) this.config.zoomLevel = item;
		}
	},
	setMapScale: function(scale) {
		for (var item = 0; item < this.config.agsScale.length ; item++) {
			if (this.config.agsScale[item] == scale) this.config.zoomLevel = item;	
		}
	},
	/**
	 * Gibt den Zoomlevel zu einem Maßstab zurück.
	 * @author es
	 */
	scale2zoomLevel: function (scale){
		var zoomLevel = null;
		for (var item = 0; item < this.config.agsScale.length ; item++) {
			if (this.config.agsScale[item] == scale) zoomLevel = item;	
		}
		return zoomLevel;
	},
	setFullWidth: function() {
		var dim = this.getBrowserDimensions();
		this.config.width = dim[0] - this.config.left;
	},
	setFullHeight: function() {
		var dim = this.getBrowserDimensions();
		this.config.height = dim[1] - this.config.top;
	},
	setWidth: function(width) {
		this.config.width = width;
	},
	setHeight: function(height) {
		this.config.height = height;
	},
	setEditSession: function(bool) {
		if (bool == "true") this.config.editMode = true;
	},
	setEditRecode: function(bool) {
		if (bool == "true") this.config.editObject.recode = true;
	},
	setEditID: function(id) {
		this.config.editObject.id = id;
	},
	setEditType: function(type) {
		this.config.editObject.type = type;
	},
	setEditName: function(name) {
		this.config.editObject.name = decodeURIComponent(name);
	},
	setEditPassThrough_geocodeStatus: function(content) {
		this.config.editPassThrough += "&geocodeStatus="+content;
	},
	setEditPassThrough_showNeverGeocodePOIs: function(content) {
		this.config.editPassThrough += "&showNeverGeocodePois="+content;
	},
	setEditPassThrough_list: function(content) {
		this.config.editPassThrough += "&list="+content;
	},
	setSearchResultIds: function(content) {
		// if parameter ids is set, then only search results are displayed. Therefore we override the normal extent queries by
		// changing "..../extent?" to "..../searchExtent?ids=123,456,789&" so the rest is the same for this session.
		// Advantage: No code change necessary...
		this.config.showOnlySearchResults = true;
		this.config.searchResultIds = content.split(",");
		this.config.poiServletAddress = this.config.searchResultServletAddress+"ids="+content;
	},
	connectMap: function(map) {
		this.config.connectedMap = map;
		this.config.hasConnectedMap = true;
	},
	getState: function() {
		var state = null;
		
		//SI übernehmen
		var si = this.serviceIndex;
		var exportSI = new ServiceIndex(this.portalClientId);
		for (l in si.idx){
			exportSI.idx[l].isVisible = si.idx[l].isVisible
		}
		
		if (this.mapManager != null) {
			var center = this.mapManager.getCenter();

			state = new State(center[1], center[0], this.mapManager.getCurrentZoomLevel(), exportSI);
			
			//offene Popups auch merken
			state.setActivePoiId(this.activePoiId);
			state.setActivePoiIdTash(this.activePoiIdTash);
		}
		else {
			// if we haven't drawn the map yet assume the config is right...
			state = new State(this.config.lat, this.config.lon, this.config.zoomLevel, exportSI);
		}
		return state;
	},
	setState: function(state) {
		if (state.zoomLevel != null) this.setZoomLevel(state.zoomLevel);
		
		// also paint the overview map if necessary
		if (state.zoomLevel != null &&
			this.config.hasConnectedMap && !this.config.isOverviewMap) {
			this.config.connectedMap.setZoomLevel(state.zoomLevel - this.config.overviewMapZoomlevelDifference);
		}
		
		var center = new Array(state.lon, state.lat);
		this.serviceIndex=state.serviceIndex;
		this.setCenter(center);
		
		// also paint the overview map if necessary
		if (center != null &&
			this.config.hasConnectedMap && !this.config.isOverviewMap) {
			this.config.connectedMap.setCenter(center)
		}
				
		this.activePoiId = state.getActivePoiId();
		this.activePoiIdTash = state.setActivePoiIdTash();
		
		// STATE REPAINT OR NOT?
		this.repaint();
	},
	setMoveObserver: function(obj, callBack) {
		this.config.moveObserver = callBack.bindAsEventListener(obj);
	},
	setCenterObserver: function(obj, callBack) {
		this.config.centerObserver = callBack.bindAsEventListener(obj);
	},
	setBBObserver: function(obj, callBack) {
		this.config.bbObserver = callBack.bindAsEventListener(obj);
	},
	observeMoves: function(center) {
		this.setCenter(center);
		this.repaint();
	},
	observeCenter: function() {
		return this.mapManager.getCenter();
	},
	observeBB: function() {
		return this.mapManager.getBB();
	},
	zoomTo: function(level) {
		this.mapManager.zoomTo(level);
	},
	checkEditPOIPosition: function() {
		this.config.editObject.lon = this.config.lon;
		this.config.editObject.lat = this.config.lat;
	},
	getBrowserDimensions: function() {
		var winWidth, winHeight, d=document;
		if (typeof(window.innerWidth) !='undefined') {
			winWidth = window.innerWidth;
			winHeight = window.innerHeight;
		}
		else {
			if (d.documentElement && (typeof(d.documentElement.clientWidth) !='undefined') && (d.documentElement.clientWidth != 0)) {
				winWidth = d.documentElement.clientWidth;
				winHeight = d.documentElement.clientHeight;
			}
			else {
				if (d.body && (typeof(d.body.clientWidth) != 'undefined')) {
					winWidth = d.body.clientWidth;
					winHeight = d.body.clientHeight;
				}
			}
		}
		return new Array(winWidth,winHeight);
	},
	getBrowserLang: function() {
		// all based on lang array, defined in config -> 0 = fr, 1 = de, 2 = en
		// default to german!
		this.config.usedLang = 1;

		var testLang = "de";
		if (typeof(navigator.browserLanguage) != "undefined") testLang = navigator.browserLanguage; // works in IE
		if (typeof(navigator.language) != "undefined") testLang = navigator.language; // works in FF, Opera, Netscape
			
		if (testLang.indexOf("en") != -1) this.config.usedLang = 2;
		if (testLang.indexOf("fr") != -1) this.config.usedLang = 0;
	},
	getDOMParentPosition: function() {
       var off = Position.cumulativeOffset(this.DOMParent);
       this.config.DOMParentOffsetX = off[0];
       this.config.DOMParentOffsetY = off[1];
    },
	paint: function() {
	
    	this.createMapCon();
    	if (this.mapManager == null){
			if (this.serviceIndex==null) this.serviceIndex = new ServiceIndex(this.portalClientId)
			this.mapManager = new MapManager(this,this.container,this.config, this.serviceIndex, this.eventLogger, this.portalClientId);	
		}

		// compass rose
		if (this.compassRose == null) this.compassRose = new CompassRose(this.mapManager,this.container,this.config);
		// zoom bar
		if (this.zoomBar == null) this.zoomBar = new ZoomBar(this.mapManager,this.container,this.config);	
		// interactions are all things like mouse gestures, key strokes etc.
		if (this.interactions == null) {
			if (!this.config.isOverviewMap || (this.config.isOverviewMap && this.config.hasInteractions)) {
				this.interactions = new Interactions(this.container,this.mapManager,this.compassRose);
			}
		}
		// draws the copyright infos
		if (this.copyrightInfo == null) this.copyrightInfo = new CopyrightInfo(this.config,this.container);

		this.mapManager.paint();
    	if (this.config.suspendRedraw){ //ES: (0003509) nach bestView + repaint muss die Karte unbeding angelegt werden (aber geschlossen..)-> Refactor OV-Map minimizer-Init 
    		this.mapManager.minimizer.toggle();
    	}
		
		if (this.config.hasCompassRose) this.compassRose.paint();
		if (this.config.hasZoomBar) this.zoomBar.paint();
		if (this.config.hasCopyrightInfo) this.copyrightInfo.paint();

		if (this.interactions != null) this.interactions.keyboard();
		if (!this.config.isOverviewMap) this.interactions.mouse();
		
		// also paint the overview map if necessary
		if (this.config.hasConnectedMap && !this.config.isOverviewMap) {
			this.config.connectedMap.paint();
		}

		if (this.config.isOverviewMap && this.config.hasBoundingBoxMarker) {
			this.mapManager.bbMarker.paint(this.config.bbObserver(), this.mapManager.currentTileMatrix.coordinates);
		}

		this.painted = true;
	},
	repaint: function() {
		if (this.config.suspendRedraw) return;

//		this.remove();
		this.painted = false;
		if (this.config.hasConnectedMap && !this.config.isOverviewMap){
//			//debug.writeline("Overview map found - removing")
			this.config.connectedMap.remove();
//			//debug.writeline("Overview map removed");
		}
		if (this.compassRose != null) this.compassRose.remove();
		if (this.mapManager != null) this.mapManager.remove();
		if (this.zoomBar != null) this.zoomBar.remove();
		if (this.copyrightInfo != null) this.copyrightInfo.remove();
		if (this.interactions != null) this.interactions.remove();

		try {
			this.container.parentNode.removeChild(this.container);
		}
		catch(e) {
			////console.debug("removing map container failed");
		}
//		//debug.writeline("--- remove successfull ---");

		this.compassRose = null;
		this.mapManager = null;
		this.zoomBar = null;
		this.copyrightInfo = null;
		this.interactions = null;
		this.container = null;

		this.paint();
		/*this.mapManager.paint();
		if (this.config.hasCompassRose) this.compassRose.paint();
		if (this.config.hasZoomBar) this.zoomBar.paint();
		if (this.config.hasCopyrightInfo) this.copyrightInfo.paint();

		if (this.interactions != null) this.interactions.keyboard();
		if (!this.config.isOverviewMap) this.interactions.mouse();
		
		// also paint the overview map if necessary
		if (this.config.hasConnectedMap && !this.config.isOverviewMap) {
			this.config.connectedMap.paint();
		}*/

		this.painted = true;
	},
	notify: function(type) {
		switch(type) {
			case "zoom":
				if (this.config.isOverviewMap && this.config.hasBoundingBoxMarker) {
					this.mapManager.bbMarker.paint(this.config.bbObserver(), this.mapManager.currentTileMatrix.coordinates);
				}
				break;
		}
	},
	suspendRedraw: function(susp){
		this.config.suspendRedraw = susp;
	},
	
	openSession: function(id) {
		this.config.sessionId = id;
	},
	
// here comes the official API for the TASH project:
 
	setArea: function(regionId) {
		var region = new Array();
		region.push(regionId);
		this.config.isArea=true;
		this.controlConnector.getBestViewForArea(region);
	},
	setSessionId: function(id) {
		this.openSession(id);
		//debug.writeline("sessionId set: "+id);
	},
	setGeocodePOI: function(poi) {
		// try to log the CMS event:
		// we got not only a POI id, but:
		if (poi.zipCode) {
			// we have (only) a coordinate transform request
			if (poi.lon) {
				this.eventLogger.log(5);
			}
			// we have a full geocode request
			else {
				this.eventLogger.log(6);
			}
		}
		// simple show poi
		else this.eventLogger.log(4);

		//debug.writeline("geocodeID requested: "+id);
		this.controlConnector.checkGeocodeID(poi);
	},
	/**
	* Die Funkiton nutzt zuerst den BestView-Aufruf, um den optimalen Kartenausschnitt zu berechnen.
	* Danach werden die Extent-Aurufe gemacht
	* Danach die übergebenen POI-Ids explizit per searchExtent aufgerufen 
	*/
	setPOIs: function(guids, isBubble, hasPopUps, regId, bubbleIdxStart) {
		this.searchIds = guids;
		this.config.dataSources["searchExtent"] = new SearchExtentDataSource() //default Datasource. laedt die POIs von extent-Servlet
		this.config.dataSources["searchExtent"].setIds(guids);
		this.config.dataSources["searchExtent"].setBubbleIdxStart(bubbleIdxStart);
		this.config.dataSources["searchExtent"].setBubble(isBubble);
		if (hasPopUps){
			this.activePoiIdTash = guids[0];
		}
		
		////console.debug('-> historyMake setPois');
		this.historyMake();
		
		this.controlConnector.getBestView(guids, isBubble,hasPopUps, regId);
		//this.controlConnector.getBestView(guids, isBubble, isArea);
	},
	/**
	* Die Funkiton zeigt die übergebenen Teaser-Bilder auf Karte an; in TASH-Extent (keine BestView-Ermittling)
	* Danach werden die Extent-Aurufe gemacht
	* Danach die übergebenen POI-Ids explizit per searchExtent aufgerufen
	*
	* ES 
	*/
	setTeasers: function(guids, isBubble, hasPopUps, regId) {
		this.searchIds = guids;
		this.config.dataSources["searchExtent"] = new SearchExtentTeaserDataSource() //erweiterte Datasource. laedt die POIs von extent-Servlet
		this.config.dataSources["searchExtent"].setIds(guids);
		this.config.dataSources["searchExtent"].setBubble(isBubble);
		if (hasPopUps){
			this.activePoiIdTash = guids[0];
		}
		//TODO: kein BestView; nur Start-Extent
		//this.controlConnector.getBestView(guids, isBubble,hasPopUps, regId);
		if (this.map.painted) {
			this.repaint();
		}else {
			this.paint();
		}
		
		//this.controlConnector.getBestView(guids, isBubble, isArea);
	},
	setVisibleTopics: function(arguments) {
		this.config.activeTopics = this.checkInput(arguments);
		//debug.writeline("setVisibleTopics to "+this.config.activeTopics);
	},
	setVisibleAreas: function(arguments) {
		this.config.activeAreas = this.checkInput(arguments);
		//debug.writeline("setVisibleAreas to "+this.config.activeAreas);
	},
	setVisibleTargetGroups: function(arguments) {
		this.config.activeTargetGroups = this.checkInput(arguments);
		//debug.writeline("setVisibleTargetGroups to "+this.config.activeTargetGroups);
	},
	// this function will check all the set*** inputs, if they are a valid list
	checkInput: function(input) {
		var outArray = new Array();
		for (var node = 0 ; node < input.length ; node++) {
			var asNum = parseInt(input[node]);
			if (!isNaN(asNum)) {
				outArray.push(asNum);	
			}
		}
		var outString = "0";
		if (outArray.length > 0) outString = outArray.join(",");
		return outString;
	},
	
	/*
	layer aus service index unsichtbar machen
	*/
	hideLayer: function(layers) {		
			for(var i=0;i<layers.length;i++){
				var tmp = layers[i];
				
				try {
					this.serviceIndex.idx[this.config.typeMapMapping[tmp]].isVisible = false;
				} catch (e) {
					////console.debug("hideLayer - TypID unbekannt:"+tmp);
				}
				if (this.mapManager != null){
					if(this.isRWLayers(tmp)){
						this.mapManager.currentTileMatrix.hide(this.config.typeMapMapping[tmp]);
					}else{
						this.mapManager.currentTileMatrix.poiBox.hidePOIDiv(this.config.typeMapMapping[tmp]);
					}
				}
			}
			if(this.mapManager != null){ //ES sonst Fehler in RW-Einzelseite... 
				this.mapManager.currentTileMatrix.poiBox.updatePOIContainer();
			}
		
		//debug.writeline("hideLayer");
	},
	/*
	layer aus service index sichtbar machen
	*/
	showLayer: function(layers) {
		//debug.writeline("showLayer");
		for(var i=0;i<layers.length;i++){
			var tmp = layers[i];
			
			try {
				this.serviceIndex.idx[this.config.typeMapMapping[tmp]].isVisible = true;
			} catch (e) {
				////console.debug("showLayer - TypID unbekannt:"+tmp);
			}
			if (this.mapManager != null){
				if(this.isRWLayers(tmp)){
					this.mapManager.currentTileMatrix.show(this.config.typeMapMapping[tmp]);
				}else{
					this.mapManager.currentTileMatrix.poiBox.showPOIDiv(this.config.typeMapMapping[tmp]);
				}
			}
		}
		if(this.mapManager != null){ //ES sonst Fehler in RW-Einzelseite... 
			 this.mapManager.currentTileMatrix.poiBox.loadPOIs();
		}
		
		//neuen Zusatand des ServiceIndex merken; für History - TODO: Inkonsistez mit SI im Portal lösen!
		if (this.config != null && !this.config.isOverviewMap && this.config.hasHistory) {
			////console.debug('-> historyMake showLayer');
			this.historyMake();
		}		

	},
	/** 
	 * Layer nur eiblenden, wenn sich die Karte in best. Mindest-Zoomlevel befindet; sonst Anfrage ignorieren.
	 * ES
	 * */
	showLayerFromZoomlevel: function(layers, minZoomLevel) {
		if(this.getCurrentZoomLevel() >= minZoomLevel ){ 
			this.showLayer(layers);
		}
	},
	isRWLayers: function(rwId){
		if (rwId==1997 || rwId==1998 || rwId==1999
			|| rwId==1987 || rwId==1988 || rwId==1989
			|| rwId==1977 || rwId==1978 || rwId==1979){
			return true;
		}else{
			return false;
		}
	},
	/*
		Gibt den ServiceIndex zurück
	*/
	getServiceIndex: function() {
		return this.serviceIndex;
	},
	isLayerVisible: function(layer){
		return this.serviceIndex.idx[this.config.typeMapMapping[layer]].isVisible;
	},
	hideCartography: function(cartographyLayers) {
	},
	showCartography: function(cartographyLayers) {
	},
	resetConfig: function() {
		// here we will reset the configuration object which we will have saved at the beginning
	},
	deletePOI: function() {
		// UGLY!!!!
		if (this.config.editMode) {			
			this.resetEditObject();
			if (this.painted) this.repaint();
		}
	},
	resetEditObject: function() {
		this.config.editMode = true;
		this.config.editObject = {
			recode: false,
			id: 0,
			lon: 0,
			lat: 0,
			type: null,
			name: "",
			successfullyGeocoded:false
		};
	},
	remove: function() {
//		//debug.writeline("--- remove ---");

		this.painted = false;

		if (this.config.hasConnectedMap && !this.config.isOverviewMap){
//			//debug.writeline("Overview map found - removing")
			this.config.connectedMap.remove();
//			//debug.writeline("Overview map removed");
		}
		if (this.compassRose != null) this.compassRose.remove();
		if (this.mapManager != null) this.mapManager.remove();
		if (this.zoomBar != null) this.zoomBar.remove();
		if (this.copyrightInfo != null) this.copyrightInfo.remove();
		if (this.interactions != null) this.interactions.remove();

		try {
			this.container.parentNode.removeChild(this.container);
		}
		catch(e) {
			////console.debug("removing map container failed");
		}
//		//debug.writeline("--- remove successfull ---");
		this.compassRose = null;
		this.mapManager = null; 
		this.zoomBar = null;
		this.copyrightInfo = null;
		this.interactions = null;
		this.container = null;
	},
	shutdown: function() {
		//debug.writeline("--- full shutdown ---");
		//this.remove();
		if (this.controlConnector != null) this.controlConnector.remove();
		this.controlConnector = null;
		//debug.writeline("--- map is down, bye bye! ---");
	},
	
	hasZoomBar: function(hasZoomBar){
		this.config.hasZoomBar = hasZoomBar;
	},
	
	hasCompassRose: function(hasCompassRose){
		this.config.hasCompassRose = hasCompassRose;
	},
	setWeatherStations: function(stations){
		for(i=0;i<stations.length;i++){
			var img = this.config.wetterMapping[stations[i].weather];
			var minTmp = stations[i].attribs["minTmp"];
			var maxTmp = stations[i].attribs["maxTmp"];
			this.config.wetterInfos[stations[i].tashId] = {"img":img, "minTmp":minTmp, "maxTmp":maxTmp};
			//call hook-function
		}
	},
	
	showPOI: function(poiId){
		this.controlConnector.showPOI(poiId);
	},
	setAggregation: function(isAggregation) {
		this.config.isAggregation=isAggregation;
	},
	/* +++++++++++++ Historisierung geöffneter POI-Popups  ++++++++ */
	/**
	 * In History zurück navigieren.
	 */
	historyBack: function(){
		if(this.config.hasHistory == false && this.config.history.size() == 0){
			return;
		}
		
		var step = this.config.historyCursor -1; 
		this._historyGo(step);
	},
	historyForward: function(){
		if(this.config.hasHistory == false && this.config.history.size() > this.config.historyCursor){
			return;
		}
		//laufende Request abbrechen (da karte eh verschoben wird)
		//this.mapManager.currentTileMatrix.removePOIs();
		
		var step = this.config.historyCursor +1; 
		this._historyGo(step);
	},
	/**
	 * Fuhrt den eigentlichen Schritt aus (vor/zurück).
	 * @param {Object} step:  +/-[int]
	 */
	_historyGo: function(step){
		//invalide anfragen nicht zulassen
		if(this.config.hasHistory == false  
			|| step > this.config.history.size() //drüber
			|| step < 0 						 //drunter
			|| this.config.history.size() == 0  //nicht drin				
			){
			return;
		}
		
		
		this.config.historyCursor = step; //merken, wenn in history navigiert wird
		
		//alter status
		var olderState = this.config.history[step];
		
		//laufende Request abbrechen, wenn sich zoomstufe geändert(damit sich die pois nicht in er falschen zoomstufe ankommen, wenn schnell schnell zw. den zoomstufen gewechselt wird)
		if(olderState != null && olderState.zoomLevel != this.mapManager.getCurrentZoomLevel()){
			this.mapManager.currentTileMatrix.removePOIs();
			//////console.debug("removePOIs da Zoomlevel-Wechsel");
		}

		if (olderState != null) {
			//merker zurcücksetzen, sonst geht der zuletzt geöffnete Popup auf
			this.activePoiId = null;
			this.activePoiIdTash = null;
			
			////console.debug('_historyGo step=='+step+ ' history.size =='+this.config.history.size());
			this.setState(olderState);
		} 
	},
	/**
	 * Neuen History-Punkt anlegen (nur bei Hauptkarte)
	 */
	historyMake: function(){
		if(!this.config.isOverviewMap && this.config.hasHistory){
			if(this.config.historyCursor == null){ //initialisierung nötig
				this.config.historyCursor =0;  
			}else{
				//nur die letzen X Schritte merken; Rest der History verwerfen
				if(this.config.historyCursor >= this.config.historyMax){
					this.config.history = this.config.history.splice(1); //erstesn Hist.-Schritt wegschmeißen
					//hochzähle nicht nötig da erste schritt weg ist ?!		
				} else{
					//hochzäheln
					this.config.historyCursor +=1; 				
				}
				
			}	
			
			//den schritt merken
			//this.config.history = this.config.history.without(this.config.historyCursor -3);
			var aState = this.getState();
			this.config.history[this.config.historyCursor] =aState; 
			////console.debug('historyMake');
		}
	},
	/**
	 * Transformiert eine Punkt-Koordinate von WGS84 zu GK3 und vice versa.
	 * 
	 * estykow 
	 * @param {lat:val, lon:val, coordinateSystem: 'val'}
	 * 
	 * @return
	 */
	transformPoint: function(point){
		var result= new Object();
		
		//Koordinaten vom Server Transormienen - auf response warten
		var request = new Ajax.Request(
				this.config.editServletAddress, 
				{ 
					method: "get",
					asynchronous: false,
					parameters: "lat="+point.lat+"&lon="+point.lon+"&sessionId="+this.config.sessionId+'&from_sr='+point.coordinateSystem,
					onComplete: function(response) {
									var evaluatedData = eval( "("+response.responseText+")" );	
									//alert('back: '+evaluatedData.sucessfull);
									result = evaluatedData;
							}
				}
			);
		
		//alert('result: '+result.lat);
		return result;
	},
	/**
	 * Karte auf Init-Extent setzen (zu 0002268).
	 * @return
	 */
	showInitMap: function(){
		
		//Karte auf config-Inits setzen
		this.setCenter(new Array(this.config.historyInitMapLon, this.config.historyInitMapLat));
		this.zoomTo(this.config.historyInitMapZoomLevel);
		////console.debug('-> historyMake showInitMap');
		this.historyMake();
	}
}
	

/*	MapManager
 * 
 * Handles all "external" map actions, abstract, no real image shuffling, no map src calcs
 * 
 * estykow: Führt die eigentlichen manipulationen an der Karte durch bzw. deligiert diese.
 * 
 */
MapManager = Class.create();
MapManager.prototype = {
	initialize: function(map,parent,config, serviceIndex, eventLogger, portalClientId) {
		this.map = map;
		this.container = parent;
		this.config = config;
		this.serviceIndex = serviceIndex;

		this.currentZoomLevel = this.config.zoomLevel;
		
		this.portalClientId = portalClientId;

		// used to prevent race conditions while zooming / panning
		this.moving = false;
		this.zooming = false;
				
		// predefine what should happen when the user interacts with the map
		// ! should be moved to interactions, shouldn't it?
		//MINIMAP-MAXIMAP GLEICH
		this.handDownObserver = this.down.bindAsEventListener(this);	
		this.handMoveObserver = this.handMove.bindAsEventListener(this);
		
		//es: wenn es eine Minimap ist ->  kein zoomen; Maximap öffnen
		//MINIMAP-MAXIMAP UNTERSCHIEDLICH
		if(this.config.isMiniMap){ 
			this.dblClickObserver = this.openBigMap.bindAsEventListener(this);
			this.handUpObserver = this.openBigMap.bindAsEventListener(this);
		} else{		
			this.dblClickObserver = this.zoomIn.bindAsEventListener(this);
			this.handUpObserver = this.up.bindAsEventListener(this);
		}


		// enables other objects to hook up to map events like panning and zooming
		this.listenerDispenser = new ListenerDispenser();
		
		// logs all actions to the alta4 clickCounter
		this.eventLogger = eventLogger;
		
		this.currentTileMatrix = null;
		
		this.minimizer = null;
		this.bbMarker = null;
	},
	paint: function() {
		// 0 is a4log "paint" event
		// 1 is a4log "move" event
		// 2 is a4log "zoom" event
		// 3 is a4log "identify" event
		this.eventLogger.log(0);

		if (this.currentTileMatrix == null) {
	
			// attach a new tile matrix and create the tiles. Position and zoomlevel is defined in config
			//this.currentTileMatrix = new TileMatrix(this,this.config,this.container);
			//new
			this.currentTileMatrix = new TileMatrix(this,this.config,this.container, this.portalClientId);
			this.currentTileMatrix.paint();
	
			if (this.config.hasPOIs) this.currentTileMatrix.startCaching();
			
			if (this.config.hasMinimizer) {
				this.minimizer = new Minimizer(this);
				this.minimizer.paint();
			}
			
			if (this.config.hasBoundingBoxMarker) {
				this.bbMarker = new BoundingBoxMarker(this.currentTileMatrix.tileContainer[0].getTileContainer());
				this.bbMarker.paint(this.config.bbObserver(), this.currentTileMatrix.coordinates);
			}
			
			this.attachEventHandlers();
			this.map.map.notifyObservers("paint");	
		}
	},
	openBigMap: function(e){
		Event.stop(e);
		Event.stopObserving(this.container,"dblclick",this.dblClickObserver,false); //es: ok?
		Event.stopObserving(document,"mouseup",this.handUpObserver,true);
		Event.stopObserving(document,"mousemove",this.handMoveObserver,true);
		
		//Karte vergrößern damit man was sieht
		enlargeMap(this, null); //IMX-Funktion -> ToDo: über Map-API die Funktion dyn. setzen lassen (wg. evtl. Umbenennung etc.)
	},
	attachEventHandlers: function() {
		if (this.config.hasInteractions) {
			Event.observe(this.container,"mousedown",this.handDownObserver,false);
		}
		if (!this.config.isOverviewMap) {
			Event.observe(this.container,"dblclick",this.dblClickObserver,false);
		}
	},
	detachEventHandlers: function() {
		if (this.config.hasInteractions) {
			Event.stopObserving(this.container,"mousedown",this.handDownObserver,false);
			Event.stopObserving(document,"mousemove",this.handMoveObserver,false);
			Event.stopObserving(document,"mouseup",this.handUpObserver,false);
		}
		if (!this.config.isOverviewMap) Event.stopObserving(this.container,"dblclick",this.dblClickObserver,false);
	},
	zoom: function(amount) {
		// see if we got a flag for using mouse coords rather then map center
		//////console.debug(new Date()+" zoom("+amount+")");
		var data =  $A(arguments);
		var doZoomOnMousePos = false;
		if (data.length > 1) doZoomOnMousePos = data[1];
		
		// update container offset
		this.map.getDOMParentPosition();

		// get center coordinates to create new tile matrix centered there
		var oldCenter = this.currentTileMatrix.coordinates.getCenter();
		// if it should be an mouse triggered event, use the cursor position to zoom to...
		if (doZoomOnMousePos) oldCenter = this.currentTileMatrix.coordinates.getMousePosInRW();

		amount = this.filterZoomAmount(amount);
		
		if (!this.zooming && Math.abs(amount) != 0 ) {
			
			// log map drawing		
			// 0 is a4log "paint" event
			// 1 is a4log "move" event
			// 2 is a4log "zoom" event
			// 3 is a4log "identify" event
			this.eventLogger.log(2);
			this.listenerDispenser.trigger("preZoom");

			this.zooming = true;

			//////console.debug(new Date()+" BEGIN removePOIs()");
			this.currentTileMatrix.removePOIs();
						
			// update zoom level
			this.currentZoomLevel += amount;
			
			// if we have a connected overview map, update its zoomlevel too...
			if (this.config.hasConnectedMap && !this.config.isOverviewMap) {
				var ovMapLevel = this.currentZoomLevel - this.config.overviewMapZoomlevelDifference;
				if (ovMapLevel < 0) ovMapLevel = 0;
				this.config.connectedMap.zoomTo(ovMapLevel);
			}

			// prepare the new tile matrix config
			this.config.zoomLevel = this.currentZoomLevel;
			this.config.lon = oldCenter[0];
			this.config.lat = oldCenter[1];
			
			//ES: Regio-Radwege ab zoomstufe 3 mit einblenden (Ticket 003000)
			//-> Steuerung muss vom Portal: 
			/*if(this.serviceIndex.isFernradwegeVisible() && this.config.zoomLevel >=3 ){ 
				//alert("zeige Regionalruten");
				this.currentTileMatrix.show("rw_hlms_gesamt");
				this.serviceIndex.idx["rw_hlms_gesamt"].isVisible = true;
			} else	if(this.serviceIndex.isFernradwegeVisible() && this.config.zoomLevel <3 ){ 
				this.currentTileMatrix.hide("rw_hlms_gesamt");
				this.serviceIndex.idx["rw_hlms_gesamt"].isVisible = false;
			}*/

			// save the old tile matrix into a temporary variable
			this.tempTileMatrix = this.currentTileMatrix;

			// create the new one
			this.currentTileMatrix = new TileMatrix(this,this.config,this.container, this.portalClientId);
			this.currentTileMatrix.prepare();

			//defines that the tile matrix is invisible when created
			this.currentTileMatrix.setHidden();
			this.currentTileMatrix.paint();
					
			this.zoom2();
		}
	},
	/**
	 * Zoom getrennt, damit dazwischen eine Zoom-Animation dazwischen angezeigt werden kann
	 */
	zoom2: function() {
		this.currentTileMatrix.setVisible();
		this.currentTileMatrix.startCaching();

		if (this.tempTileMatrix) {
			this.tempTileMatrix.remove();
			this.tempTileMatrix = null;
		}

		this.zooming = false;

		if (!this.config.isOverviewMap && this.config.hasConnectedMap) {
			this.config.connectedMap.notify("zoom");
		}
		if (this.config.hasBoundingBoxMarker) {
			this.bbMarker = new BoundingBoxMarker(this.currentTileMatrix.tileContainer[0].getTileContainer());
			this.bbMarker.paint(this.config.bbObserver(), this.currentTileMatrix.coordinates);
		}
		
		//es, ck: TODO: funtionaufruf in Funktion nach zoom2() und up() immer aufgerufen wird (lt. CK evtl. vorhanden)
		this.updateOverviewMap();
		this.listenerDispenser.trigger("postZoom");
		this.map.map.notifyObservers("zoom", this.getCurrentZoomLevel(), this.config.isOverviewMap); //es: neuen zoomlevel mitgeben und herkunft (zur Untscheidung OV-Map oder Hauptkarte) 
	},
	//ES: refactored: Bei Überschlägen wird amount auf den jeweiligen Randwert gesetzt. 
	filterZoomAmount: function(amount) {
		var filteredAmount = amount;
		if (this.currentZoomLevel + amount >= this.config.agsResolution.length){
			filteredAmount = ((this.config.agsResolution.length-this.currentZoomLevel) -1);	//den amount setzen, mit der der User von der aktuellen zur höchsten Zoomstufe kommt
		} 
		if (this.currentZoomLevel + amount < this.config.minimumAllowedZoomLevel){
			filteredAmount = ((this.config.minimumAllowedZoomLevel-this.currentZoomLevel)); //den amount setzen, dem nötig ist um auf die kleinste Zoomstufe zum kommen 
		}
		//////console.debug("currrentZoomLevel: "+this.currentZoomLevel + amount+" amount:"+amount+" filteredAmount:"+filteredAmount);
		return filteredAmount;
	},
	updateOverviewMap: function(){
		if (this.config.hasConnectedMap) {
			this.config.connectedMap.setCenter(this.currentTileMatrix.coordinates.getCenter());
			this.config.connectedMap.repaint();
		}
	},
	zoomIn : function(e) {
		// check if we are triggered by an mouse event (then zoom on mouse pos)
		if (typeof(e) == "object") {
			Event.stop(e);
			this.zoom(1,true);
		}
		else this.zoom(1);
	},
	zoomOut : function(e) {
		this.zoom(-1);
	},
	zoomTo: function(level) {
		var amount = level - this.currentZoomLevel;
		if (amount != 0) {
			this.zoom(amount);
		}
	},
	getCurrentZoomLevel: function() {
		return this.currentZoomLevel;
	},
	getCurrentZoomFactor: function() {
//		return this.config.zoomFactors[this.currentZoomLevel];
		return this.config.agsScale[0] / this.config.agsScale[this.currentZoomLevel];
	},
	getCurrentPxOff: function(dir) {
		if (this.currentTileMatrix) return this.currentTileMatrix.mapSource.getPxOff(dir);
	},
	// Event handler: Panning
	down: function(e){
		// log map move
		// 0 is a4log "paint" event
		// 1 is a4log "move" event
		// 2 is a4log "zoom" event
		// 3 is a4log "identify" event
		this.eventLogger.log(1);
		this.moving = true;
		this.oldMouseX = Event.pointerX(e);
		this.oldMouseY = Event.pointerY(e);

		Event.observe(document,"mousemove",this.handMoveObserver,true);
		Event.observe(document,"mouseup",this.handUpObserver,true);

		Event.stop(e);
	},
	up: function(e){
		this.moving = false;
		Event.stopObserving(document,"mousemove",this.handMoveObserver,true);
		Event.stopObserving(document,"mouseup",this.handUpObserver,true);
		
		var center = this.getCenter(); 
		//var center = this.getCenterNew(); //es: alterCenter -> Minimap synchron bei pann aber nicht bei Doublecklick-zoomTo
		 
		this.config.lon = center[0];
		this.config.lat = center[1];

		this.updateOverviewMap();
		if (this.config.moveObserver !== null) {
			this.config.moveObserver(center);
		}

		Event.stop(e);		
	},
	handMove: function(e){
		if(this.moving) {
			this.move(Event.pointerX(e) - this.oldMouseX, Event.pointerY(e) - this.oldMouseY);
			this.oldMouseX = Event.pointerX(e);
			this.oldMouseY = Event.pointerY(e);
			Event.stop(e);
		}
	},
	getCenter: function() {
		return this.currentTileMatrix.coordinates.getCenter();
	},
	/**
	 * Gibt die den Center der aktuellen Karte zurück (currentTileMatrix hat noch die alten ?).
	 * status: DEV
	 * estykow
	 */
	getCenterNew: function() {
		var center = new Array(this.currentTileMatrix.coordinates.config.lon, this.currentTileMatrix.coordinates.config.lat);
		//var center = new Array(this.config.lon, this.config.lat);
		//var center = new Array(this.currentTileMatrix.config.lon, this.currentTileMatrix.config.lat);
		//var center = new Array(this.currentTileMatrix.tileMatrix.config.lon, this.currentTileMatrix.tileMatrix.config.lat);
		//var center = new Array(this.map.config.lon, this.map.config.lat);
		return center;
	},
	getBB: function() {
		return this.currentTileMatrix.coordinates.getBB();
	},
	centerAt: function(rwX,rwY){
		if (typeof(this.currentTileMatrix) == "object") {
			// log map move
			// 0 is a4log "paint" event
			// 1 is a4log "move" event
			// 2 is a4log "zoom" event
			// 3 is a4log "identify" event
			this.eventLogger.log(1);

			var currentCenter = this.getCenter();

			var currentCenterPx = this.currentTileMatrix.coordinates.rw2px(currentCenter[0],currentCenter[1]);
			
			var targetCenterPx = this.currentTileMatrix.coordinates.rw2px(rwX,rwY);
			
			var pxDeltaX = currentCenterPx[0] - targetCenterPx[0];
			var pxDeltaY = currentCenterPx[1] - targetCenterPx[1];

			//this.moveBy(pxDeltaX,pxDeltaY);
			// we start at
			this.alreadyMovedX = 0;
			this.alreadyMovedY = 0;

			// we want to
			this.moveX = pxDeltaX;
			this.moveY = pxDeltaY;

			// this means direction
			(pxDeltaX != 0) ? this.moveDirX = this.moveX/Math.abs(this.moveX) : this.moveDirX = 1;
			(pxDeltaY != 0) ? this.moveDirY = this.moveY/Math.abs(this.moveY) : this.moveDirY = 1;
			
			// and step size
			this.moveStepX = this.moveX;
			this.moveStepY = this.moveY;
			
			this.move(this.moveStepX,this.moveStepY);

		}
	},
	moveTo: function(rwX,rwY) {
		if (typeof(this.currentTileMatrix) == "object") {
			// log map move
			// 0 is a4log "paint" event
			// 1 is a4log "move" event
			// 2 is a4log "zoom" event
			// 3 is a4log "identify" event
			this.eventLogger.log(1);

			var currentCenter = this.getCenter();

			var currentCenterPx = this.currentTileMatrix.coordinates.rw2px(currentCenter[0],currentCenter[1]);
			
			var targetCenterPx = this.currentTileMatrix.coordinates.rw2px(rwX,rwY);
			
			var pxDeltaX = currentCenterPx[0] - targetCenterPx[0];
			var pxDeltaY = currentCenterPx[1] - targetCenterPx[1];

			this.moveBy(pxDeltaX,pxDeltaY);
		}
	},
	moveBy: function(deltaX,deltaY) {
		if (!this.moving) {
			// log map move
			// 0 is a4log "paint" event
			// 1 is a4log "move" event
			// 2 is a4log "zoom" event
			// 3 is a4log "identify" event
			this.eventLogger.log(1);

			// we start at
			this.alreadyMovedX = 0;
			this.alreadyMovedY = 0;

			// we want to
			this.moveX = deltaX;
			this.moveY = deltaY;

			// this means direction
			(deltaX != 0) ? this.moveDirX = this.moveX/Math.abs(this.moveX) : this.moveDirX = 1;
			(deltaY != 0) ? this.moveDirY = this.moveY/Math.abs(this.moveY) : this.moveDirY = 1;
			
			// and step size
			this.moveStepX = this.moveX / this.config.moveSpeed;
			this.moveStepY = this.moveY / this.config.moveSpeed;

			// now trigger
			var that = this;
			new PeriodicalExecuter(function(pe) {
 				if ((that.alreadyMovedX+Math.abs(that.moveStepX)) <= Math.abs(that.moveX) || (that.alreadyMovedY+Math.abs(that.moveStepY)) <= Math.abs(that.moveY)) {
    				that.move(that.moveStepX,that.moveStepY);
					that.alreadyMovedX += Math.abs(that.moveStepX);
					that.alreadyMovedY += Math.abs(that.moveStepY);
				}else{
					pe.stop();
				}
			}, 0.05);
//			this.numberMove();
		}
	},
	numberMove: function() {
		if (this.moving) {
			if ((this.alreadyMovedX+Math.abs(this.moveStepX)) <= Math.abs(this.moveX) || (this.alreadyMovedY+Math.abs(this.moveStepY)) <= Math.abs(this.moveY)) {

				this.move(this.moveStepX,this.moveStepY);

				this.alreadyMovedX += Math.abs(this.moveStepX);
				this.alreadyMovedY += Math.abs(this.moveStepY);

				setTimeout(this.numberMove.bind(this),20);
			}
			else this.moving = false;
		}
	},
	moveToAndCall: function(rwX,rwY, func) {
		if (typeof(this.currentTileMatrix) == "object") {
			// log map move
			// 0 is a4log "paint" event
			// 1 is a4log "move" event
			// 2 is a4log "zoom" event
			// 3 is a4log "identify" event
			this.eventLogger.log(1);

			var currentCenter = this.getCenter();

			var currentCenterPx = this.currentTileMatrix.coordinates.rw2px(currentCenter[0],currentCenter[1]);
			
			var targetCenterPx = this.currentTileMatrix.coordinates.rw2px(rwX,rwY);
			
			var pxDeltaX = currentCenterPx[0] - targetCenterPx[0];
			var pxDeltaY = currentCenterPx[1] - targetCenterPx[1];
			this.moveByAndCall(pxDeltaX,pxDeltaY,func);
		}
	},
	moveByAndCall: function(deltaX,deltaY,func) {
		if (!this.moving) {
			// log map move
			// 0 is a4log "paint" event
			// 1 is a4log "move" event
			// 2 is a4log "zoom" event
			// 3 is a4log "identify" event
			this.eventLogger.log(1);

			// we start at
			this.alreadyMovedX = 0;
			this.alreadyMovedY = 0;

			// we want to
			this.moveX = deltaX;
			this.moveY = deltaY;

			// this means direction
			(deltaX != 0) ? this.moveDirX = this.moveX/Math.abs(this.moveX) : this.moveDirX = 1;
			(deltaY != 0) ? this.moveDirY = this.moveY/Math.abs(this.moveY) : this.moveDirY = 1;
			
			// and step size
			this.moveStepX = this.moveX / this.config.moveSpeed;
			this.moveStepY = this.moveY / this.config.moveSpeed;

			// now trigger
			var that = this;
			new PeriodicalExecuter(function(pe) {
 				if ((that.alreadyMovedX+Math.abs(that.moveStepX)) <= Math.abs(that.moveX) || (that.alreadyMovedY+Math.abs(that.moveStepY)) <= Math.abs(that.moveY)) {
    				that.move(that.moveStepX,that.moveStepY);
					that.alreadyMovedX += Math.abs(that.moveStepX);
					that.alreadyMovedY += Math.abs(that.moveStepY);
				}else{
					pe.stop();
					func();
				}
			}, 0.05);
		}
	},
	numberMoveAndCall: function(func) {
		if (this.moving) {
			if ((this.alreadyMovedX+Math.abs(this.moveStepX)) <= Math.abs(this.moveX) || (this.alreadyMovedY+Math.abs(this.moveStepY)) <= Math.abs(this.moveY)) {

				this.move(this.moveStepX,this.moveStepY);

				this.alreadyMovedX += Math.abs(this.moveStepX);
				this.alreadyMovedY += Math.abs(this.moveStepY);

				setTimeout(this.numberMoveAndCall.bind(this, func),20);
			}
			else {
				this.moving = false;
				func();
			}
		}
	},
	
	move: function(deltaX,deltaY) {
		// some more plausibility checks on the deltas:
		if (isNaN(deltaX)) deltaX = 0;
		if (isNaN(deltaY)) deltaY = 0;
		
		if(this.currentTileMatrix !== null){ //ES der fall ist schonmal bei Navigation über Map-History aufgetreten
			this.currentTileMatrix.move(deltaX,deltaY);
			this.listenerDispenser.trigger("move");
		}	
	},
	setSize: function(width, height) {
		this.container.style.height = height+"px";
		this.container.style.width = width+"px";
	},
	remove: function() {
		Event.stopObserving(document,"mousemove",this.handMoveObserver,true);
		Event.stopObserving(document,"mouseup",this.handUpObserver,true);
		Event.stopObserving(this.container,"mousedown",this.handDownObserver,false);
		Event.stopObserving(this.container,"mousemove",this.handMoveObserver,false);
		Event.stopObserving(this.container,"mouseup",this.handUpObserver,false);
		Event.stopObserving(this.container,"dblclick",this.dblClickObserver,false);

		this.handDownObserver = this.down.bindAsEventListener(this);	
		this.handMoveObserver = this.handMove.bindAsEventListener(this);
		this.handUpObserver = this.up.bindAsEventListener(this);
		this.dblClickObserver = this.zoomIn.bindAsEventListener(this);
		
		if (this.currentTileMatrix != null) {
			this.currentTileMatrix.remove();
			this.currentTileMatrix = null;
		}
		if (this.listenerDispenser != null) {
			this.listenerDispenser.remove();
			this.listenerDispenser = null;
		}
		if (this.tempTileMatrix != null) {
			this.tempTileMatrix.remove();
			this.tempTileMatrix = null;
		}
		if (this.eventLogger != null) {
			this.eventLogger.remove();
			this.eventLogger = null;
		}
		if (this.bbMarker != null) {
			this.bbMarker.remove();
			this.bbMarker = null;
		}
//		//debug.writeline("mapManager removed");
	}
}

/*	MapSource
 * 
 * MapSource is responsible for the map displayed on the tiles. This is the connection to the map server.
 * MapSource does nothing else as to connect a tile offset with a src from the map server
 * 
 */
MapSource = Class.create();
MapSource.prototype = {
	initialize: function(config, coordinates, url, tileExtension) {
		this.coordinates = coordinates;
		this.config = config;
		this.pxXoff = 0;
		this.pxYoff = 0;
		this.tileXoff = 0;
		this.tileYoff = 0;
		this.pxDelta = 0;
		this.url = url;
		this.tileExtension = tileExtension;
	},
	prepare: function() {
		this.currentZoomLevel = this.config.zoomLevel;
		this.currentZoomFactor = this.config.agsScale[0] / this.config.agsScale[this.currentZoomLevel];

		this.pxDelta = this.coordinates.rw2px(this.config.lon,this.config.lat);

		// adding half of a viewport width as we want to center the map.
		this.pxXoff = this.pxDelta[0] - Math.round(this.config.width / 2);
		this.pxYoff = this.pxDelta[1] - Math.round(this.config.height / 2);
	},
	getSrc: function(xIndex,yIndex) {
		xIndex += this.tileXoff;
		var xDirArrIndex = Math.floor( xIndex / this.currentZoomFactor);
		var goodX = xIndex - xDirArrIndex * this.currentZoomFactor;

		yIndex += this.tileYoff;
		var yDirArrIndex = Math.floor( yIndex / this.currentZoomFactor);
		var goodY = yIndex - yDirArrIndex * this.currentZoomFactor;
		
		if ( ((xDirArrIndex >= 0) && (xDirArrIndex < this.config.xSegments.length)) && ((yDirArrIndex >= 0) && (yDirArrIndex < this.config.ySegments.length))) {
			if (goodX >= 0 && goodX < this.currentZoomFactor && goodY >= 0 && goodY < this.currentZoomFactor) {
				return this.config.mapTileDir + this.url + this.config.xSegments[xDirArrIndex] + "-" + (this.config.xSegments[xDirArrIndex] + 1) + "_" + this.config.ySegments[yDirArrIndex] + "-" + (this.config.ySegments[yDirArrIndex] + 1) + "/" + this.currentZoomFactor + "x" + this.currentZoomFactor + "/" + ((this.currentZoomFactor - 1) - (goodY - this.currentZoomFactor * Math.floor(goodY / this.currentZoomFactor))) + "x" + (goodX - this.currentZoomFactor * Math.floor(goodX / this.currentZoomFactor)) +  "." + this.tileExtension;
			}
		}
		return this.config.spacerImg;
	},
	addPxOff: function(x,y) {
		//window.defaultStatus = "adding px off "+x+", "+y+" --> "+this.pxXoff+", "+this.pxYoff;
		this.pxXoff += x;
		this.pxYoff += y;
	},
	//ES: wenn vorher nicht die Werte Neuberechnet werden (->prepare), dann liefert der Getter falsche werte!?!
	getPxOff: function(dir) {
		if (dir == "y") return this.pxYoff;
		else return this.pxXoff;
	},
	getTileOff: function(dir) {
		if (dir == "y") return Math.floor(this.pxYoff / this.config.tileHeight);
		else return Math.floor(this.pxXoff / this.config.tileHeight);
	},
	changeURL: function(newURL) {
		this.url = newURL;
	},
	remove: function() {
		this.config = null;
		this.coordinates = null;
	}
}


AGS_MapSource = Class.create();
AGS_MapSource.prototype = Object.extend(new MapSource(), {
	getSrc: function(xIndex,yIndex) {

		var zoomLevel = this.currentZoomLevel.toString();
		while (zoomLevel.length < 2) zoomLevel = "0"+zoomLevel;

		var folder = this.config.mapTileDir+this.url+zoomLevel;
		
		xIndex += this.tileXoff;
		yIndex += this.tileYoff;

		var subFolder = this.dez2hex(yIndex);
		while (subFolder.length < 8) subFolder = "0" + subFolder;
	
		var imgNr = this.dez2hex(xIndex);
		while (imgNr.length < 8) imgNr = "0"+imgNr;

		return folder + "/R" + subFolder+ "/C"+ imgNr + "." + this.tileExtension;
	},
	hex2dez: function(hex) {
		return parseInt(hex,16);
	},
	dez2hex: function(dez) {
		return dez.toString(16);
	}
});
/**
 * Verkleinert die Karte
 */

Minimizer = Class.create();
Minimizer.prototype = {
	initialize: function(mapManager) {
		this.mapManager = mapManager;
		this.config = this.mapManager.config;
		this.img = null;
		
		this.maximized = true;

		this.clickHandler = this.toggle.bindAsEventListener(this);
	},
	paint: function() {
		this.img = document.createElement("img");
		this.img.src = this.config.minimizerMinimizeImageSrc;

		this.img.width = this.config.minimizerImageSize[0];
		this.img.height = this.config.minimizerImageSize[1];
				
		this.positionIcon(this.config.height - this.config.minimizerImageSize[0], this.config.width - this.config.minimizerImageSize[1]);

		this.mapManager.container.appendChild(this.img);
		
		Event.observe(this.img,"mousedown",this.clickHandler,true);
	},
	toggle: function(e) {
		if (this.maximized) {
			this.mapManager.setSize(this.config.minimizerImageSize[0],this.config.minimizerImageSize[1]);
			this.mapManager.detachEventHandlers();

			this.positionIcon(0,0);
			this.img.src = this.config.minimizerMaximizeImageSrc;
			
			Element.setStyle(this.mapManager.map.DOMParent, { width:this.config.minimizerImageSize[0]+"px" , height:this.config.minimizerImageSize[1]+"px" });

			this.maximized = false;
			this.config.suspendRedraw = true;
		}
		else {
			var newCenter = this.config.centerObserver();
			this.mapManager.centerAt(newCenter[0], newCenter[1]);
		
			this.mapManager.setSize(this.config.width, this.config.height);
			this.mapManager.attachEventHandlers();

			this.img.src = this.config.minimizerMinimizeImageSrc;
			this.positionIcon(this.config.height - this.config.minimizerImageSize[0], this.config.width - this.config.minimizerImageSize[1]);

			Element.setStyle(this.mapManager.map.DOMParent, { width:this.config.width+"px" , height:this.config.height+"px" });

			this.maximized = true;
			this.config.suspendRedraw = false;
		}
		Event.stop(e);
	},
	positionIcon: function(top, left) {
		this.img.style.position="absolute";
		this.img.style.zIndex = 20000;
		this.img.style.top = top+"px";
		this.img.style.left = left+"px";
	},
	remove: function() {
		if (this.img !== null) {
			Event.stopObserving(this.img,"click",this.clickHandler,false);
			this.mapManager.container.removeChild(this.img);
		}
	},
	dispose: function() {
		this.remove();
		this.img = null;
	}
};
/*	POI
 * 
 * One single point. All actions. NameTag, PopUp, Data loading.
 * 
 */
POI = Class.create();
POI.prototype = {
	initialize: function(poiManager,parent,container,coordinates,point,id,type,name,idTash,config,logger) {
		this.classname="POI";
		this.poiManager = poiManager;
		this.parent = parent; // Map Container
		this.container = container; // POICon
		this.coordinates = coordinates;
		this.config = config;
		this.type = type;
		this.point = point;
		this.id = id;
		this.name = name;
		this.idTash = idTash;
		this.isMoveable = false;
		this.data = null;
		this.nameTag = null;
		this.nameDiv = null;
		this.hideCountdown = null;
		this.popupIsVisible = false;
		this.nameDivIsVisible = false;
		this.poiObservers = {};
		this.iconInfo = null;
		this.upObserver = this.up.bindAsEventListener(this);
			
		this.usedIcons = null;
		if (this.config != null) {
			this.usedIcons = this.config.usedIcons;
		}
		
		// preparation for possible edit mode, when points can be moved
		this.editBar = null;
		this.eventLogger = logger;
		
		this.clickActionName = "default";
	},
	notifyObservers: function() {
		var data = $(arguments)
		for (o in this.poiObservers){
			this.poiObservers[o].update(this,data[0]);
		}
	},
	addObserver: function(name, observer){
		this.poiObservers[name]=observer;
	},
	setIcons: function(iconList) {
		this.usedIcons = iconList;
	},
	getIcon: function(type) {
		if (this.iconInfo==null){
			if (typeof(this.usedIcons[type]) == "object"){
				this.iconInfo = this.usedIcons[type];
			}
			else 
				this.iconInfo = this.config.defaultIcon;
		}
		return this.iconInfo;
	},
	zoomToPOI: function(e) {
		this.clickedId = this.id;
		this.notifyObservers("singlePoiClickHandler");
		this.config.controlConnector.getBestView([this.idTash], false,true);
		Event.stop(e);
	},
	setClickAction: function(actionType) {
		switch(actionType) {
			case "zoomTo":
				this.clickActionName = "zoomTo";
				this.downObserver=this.zoomToPOI.bindAsEventListener(this);
//				this.upObserver=null;
				break;
			case "openBigMap":
				this.clickActionName = "openBigMap";
				this.downObserver = this.down.bindAsEventListener(this); 
				this.upObserver = this.openPopUpInBigMap.bindAsEventListener(this);
				break;
			default:
				this.downObserver = this.down.bindAsEventListener(this);
				this.upObserver = this.up.bindAsEventListener(this);
				break;
		}
	},
	paint: function() {
		if (this.icon == null) {
			this.div = document.createElement("div");
			this.div.style.zIndex = 10; //standard-wert -> bezogen auf eigenen GrouPayer (neuer Stack) 
			this.icon = document.createElement("img");
			this.icon.src = this.getIcon(this.type)[0];
			this.sizeX = this.getIcon(this.type)[1];
			this.sizeY = this.getIcon(this.type)[2];

			//z-Index bei Icon 1 höher als beim PopUp (macht sich aber nur bei Überlappung bemerkbar -> bei TeaserPOI relevant)
			Element.setStyle(this.icon, { display:"inline", width:this.sizeX+"px", height:this.sizeY+"px", position:"absolute", zIndex:2});
			
			this.div.appendChild(this.icon);

			var delayClose = true;
			if (this.type == "meta") delayClose = false;
			this.popUp = this.createPopUp(delayClose);
			this.showNameObserver = this.showName.bindAsEventListener(this);
			this.hideObserver = this.hide.bindAsEventListener(this);
			if (!this.config.editMode) {
				Event.observe(this.icon,"mouseover",this.showNameObserver,false);
				Event.observe(this.icon,"mouseout",this.hideObserver,false);
			}		
			if (this.config.width > this.config.showPopUpMinWidth && this.config.height > this.config.showPopUpMinHeight) {						
				// aggregated points do not have a popup.
				if (this.type != "meta") {
					this.setClickAction(this.clickActionName);
					Event.observe(this.icon,"mousedown",this.downObserver,false);
					Event.observe(this.icon,"mouseup",this.upObserver,false);
				}				
			}	
			//es: wenn in minimap und klick auf POI -> maximap soll göffnet werden mit offenem popup des pois
			if(this.config.isMiniMap){ 
				this.setClickAction("openBigMap");
				Event.observe(this.icon,"mousedown",this.downObserver,false);
				Event.observe(this.icon,"mouseup",this.upObserver,false);
			}

			this.update();
			if (this.type != "meta") this.container.appendChild(this.div);
			
		}
	},
	/**
	* Factory-Methode, die einem das passende PopUp liefert (Bequem zum überschreiben durch Sub-Klassen.)
	* estykow
	*/
	createPopUp:function(delayClose){
		return new PopUp(this,this.div, this.sizeX ,0 ,delayClose);
	},
	openPopUpInBigMap: function(e){
		
		Event.stopObserving(document,"mouseup",this.upObserver,false);
		Event.stop(e);
		if(this.poiManager.isRadweg(this.type) || this.poiManager.isRadwegRegio(this.type) || this.poiManager.isRadwegHLMS(this.type)){
			enlargeMap(this, this.type); //Area-Aufruf mit RW-ID
		} else{
			//Karte vergrößern mit geöffnetem popUp
			enlargeMapWithPoi(this, this.idTash); //IMX-Funktion -> ToDo: über Map-API die Funktion dyn. setzen lassen (wg. evtl. Umbenennung etc.) 
		}
	
		  
		
	},
	showBubble: function(bubbleType){
				this.overlay = document.createElement("div");				
				this.textNode = document.createTextNode(""+this.idx);
				this.textContainer = document.createElement("span");
				this.textContainer.appendChild(this.textNode);
				this.overlay.appendChild(this.textContainer);
				Element.addClassName(this.overlay,"bubblesOverlay");

				//seit dem Paging müssen auch 3stellige Zahlen ins Bubble passen
				var bubbleSizeSuffix = "";
				if(bubbleType && bubbleType=="big") bubbleSizeSuffix = "Big";
					
				//### Der OSG und das TASH-Portal (+ HLMS) haben verschieden Farbgebungen 
				//### (z.B. bei Kategorie Kurltur- und Freizeiteinrichtungen)
				 
				// Portal specific switch:
				if (this.poiManager.portalClientId == 4) {
					//OSG	
					switch (this.type) {
						case "Tourismusinformation":
						case "Bahnhof":
						case "Busunternehmen":
						case "ReedereiSchiffFaehre":
						case "Flughafen":
						case "Leuchttuerme":
							Element.addClassName(this.overlay, "bubblesOverlayGray"+bubbleSizeSuffix);
							break;
						case "HotelPension":
						case "FerienwohnungHaus":
						case "Campingplatz":
						case "Jugendherberge":
						case "Bauernhof":
						case "BettBike":
						case "WellnesshotelBeautyfarm":
						case "Gastronomie":
						case "Gasthof":
						case "Ferienpark":
							Element.addClassName(this.overlay, "bubblesOverlayOrange"+bubbleSizeSuffix);
							break;
						case "Naturerlebnis":
						case "Article":
						case "StrandBaden":
						case "Segeln":
						case "Erlebnisbad":
						case "NaturerlebniszentrumAquarium":
						case "Freizeitpark":
						case "MuseumDenkmal":
						case "Theater":
						case "SchlossGarten":
						case "KlosterKirche":
						case "TierparkZoo":
							Element.addClassName(this.overlay, "bubblesOverlayBlue"+bubbleSizeSuffix);
							break;
						case "FahrradverleihReparaturservice":
						case "AbschliessbareFahrradbox":
						case "RastplatzSchutzhuette":
						case "Ferienpark":
						case "Veranstaltungen":
						case "Event":
							Element.addClassName(this.overlay, "bubblesOverlayGreen"+bubbleSizeSuffix);
							break;
						default:
							Element.addClassName(this.overlay, "bubblesOverlayGreen"+bubbleSizeSuffix);
							break;
					}			
				}else{	
					//TASH, HLMS u.a.
					switch (this.type) {
						case "Tourismusinformation":
						case "Bahnhof":
						case "Busunternehmen":
						case "ReedereiSchiffFaehre":
						case "Flughafen":
						case "Leuchttuerme":
						case "CmsArtikel":
							Element.addClassName(this.overlay, "bubblesOverlayGray"+bubbleSizeSuffix);
							break;
						case "HotelPension":
						case "FerienwohnungHaus":
						case "Campingplatz":
						case "Jugendherberge":
						case "Bauernhof":
						case "BettBike":
						case "WellnesshotelBeautyfarm":
						case "Gastronomie":
						case "MuseumDenkmal":
						case "Theater":
						case "SchlossGarten":
						case "KlosterKirche":
						case "Freizeitpark":
						case "TierparkZoo":
						case "Event":
						case "Appartmenthaus":
						case "Gasthof":
							Element.addClassName(this.overlay, "bubblesOverlayOrange"+bubbleSizeSuffix);
							break;
						case "Naturerlebnis":
						case "Article":
						case "StrandBaden":
						case "Segeln":
						case "Erlebnisbad":
						case "NaturerlebniszentrumAquarium":
							Element.addClassName(this.overlay, "bubblesOverlayBlue"+bubbleSizeSuffix);
							break;
						case "FahrradverleihReparaturservice":
						case "AbschliessbareFahrradbox":
						case "RastplatzSchutzhuette":
						case "Ferienpark":
						case "Veranstaltungen":
							Element.addClassName(this.overlay, "bubblesOverlayGreen"+bubbleSizeSuffix);
							break;
						default:
							Element.addClassName(this.overlay, "bubblesOverlayGreen"+bubbleSizeSuffix);
							break;
					}
				}
				this.div.appendChild(this.overlay);
	},
	update: function() {
		var pixelPos = this.getPxCoords();
		Element.setStyle(this.div,{position:"absolute",left: pixelPos[0] - Math.round(this.sizeX/2) + "px",top: pixelPos[1] - Math.round(this.sizeY/2) + "px"});
		if (this.editBar != null) this.editBar.update();
	},
	remove: function() {
		if (this.popUp != null) this.popUp.close();
		if (this.icon != null) {
			try {
				this.container.removeChild(this.icon);
			}
			catch(e) {
//				////console.debug("removing POI icon failed");
			}
		}
		if (this.editBar != null) this.editBar.remove();
	},
	deletePopup: function(){
		
		//soll den standard-z-wert bekommen (damit es kein popup überdeckt)
		this.div.style.zIndex = '';
		
		if (this.popUp != null){
			this.popupIsVisible = false;
			this.popUp.close();
		}
	},
	showName: function() {
		if(!this.popupIsVisible){ //ES: Name-Div anzeigen nur wenn PopUp des Pois nicht offen ist (da in Felsinfo nicht gleich lang)
			this.openName();
			if (this.editBar != null) this.editBar.show();
		}
	},
	/**
	 * Zeigt den Namen an (als Tooltip).
	 */
	openName: function() {
		if (this.nameTag == null) {
			this.nameTag = document.createElement("p");
			Element.addClassName(this.nameTag,"nameTag");
		}
		this.nameTag.innerHTML = this.name;
		if (this.nameDiv == null) {
			this.nameDiv = document.createElement("div");
			this.nameDiv.id = this.id+"_popUp";
			Element.addClassName(this.nameDiv,"popUp");
			var pixelPos = this.getPxCoords();
			var offsetY = Math.ceil((this.sizeY/2));
			var offsetX = Math.ceil(this.sizeX/2);
			Element.setStyle(this.nameDiv,{position:"absolute",top:pixelPos[1]-offsetY+"px",left:pixelPos[0]+offsetX+"px",zIndex:20000});
		}
		this.nameDivIsVisible = true;
		this.nameDiv.appendChild(this.nameTag);
		this.container.appendChild(this.nameDiv);
	},
	hide: function() {
		this.triggerClose();
		if (this.editBar != null) this.editBar.triggerHide();
	},
	triggerClose: function(){
		if (this.hideCountdown == null) {
			this.hideCountdown = setTimeout(this.close.bind(this),this.config.popUpHideDelay);
		}
	},
	/**
	 * Schließt den Name-Tooltip.
	 * @return
	 */
	close: function() {
		try {
			if(this.nameDivIsVisible) this.container.removeChild(this.nameDiv);
			this.nameDivIsVisible = false;
		}catch(e){
			//////console.debug("removing name tag failed");
		}
		this.hideCountdown = null;
	},
	down: function(e){
		Event.stop(e);
		
		// log identifies
		// 0 is a4log "paint" event
		// 1 is a4log "move" event
		// 2 is a4log "zoom" event
		// 3 is a4log "identify" event
		if (this.eventLogger != null) this.eventLogger.log(3);
		
		if (this.config.editMode) {
			this.isMoveable = true;
			this.moveObserver = this.move.bindAsEventListener(this);
			Event.observe(this.parent,"mousemove",this.moveObserver,true);
		}
		else{
			//coordinate ermitteln und falls POI zu nah am Rand Karte zentrieren
			this.notifyObservers("down");
			this.showPopUp();
		} 
		Event.observe(document,"mouseup",this.upObserver,false);
	},
	showPopUp: function(){
			if(!this.popupIsVisible){ 		
				this.popupIsVisible = true;
				this.close();  //evtl. offenen Name-Tooltip schließen
				if(this.data == null){
					this.loadDataFromServlet();			
				}else{
					this.popUpEvent();
				}
				
				//es: let's make some history!
				if( this.config.historyCursor ==null || (this.config.history[this.config.historyCursor]).getActivePoiId() != this.id){ //nur wenn dieser showPopUp-Aufruf nicht selbs von einem History-Navigation stammmt (-> sonst schleife)
					//ES: TODO: activePoiIdTash auch prüfen (?)
					//dieser aufruf gehört nicht in die showPopUp da diese auch bei historyBack aufgerufen wird (-> schleife)
					this.poiManager.tileMatrix.mapManager.map.historyMake();
				}
			}else{
				this.closePopUp();
			}
	},
	closePopUp: function() {
		this.popupIsVisible = false;
		this.popUp.close();
		
		//beim Zoomout darf das popup nicht wieder offen sein (da hiermit geschlossen)
		this.poiManager.tileMatrix.mapManager.map.activePoi = null;
		this.poiManager.tileMatrix.mapManager.map.activePoiId = null;
		this.poiManager.tileMatrix.mapManager.map.activePoiType= null;
		
	},
	up: function(e){
		if (this.config.editMode) {
			this.isMoveable = false;

			// save the coordinates in the persistent edit object in config to retrieve them again after zoom
			this.config.editObject.lon = this.point.getX();
			this.config.editObject.lat = this.point.getY();

			// update the server session to reflect new coordinates
			this.noticeCoords();

			Event.stopObserving(this.parent,"mousemove",this.moveObserver,true);
		}

		Event.stopObserving(document,"mouseup",this.upObserver,false);
		Event.stop(e);
	},
	move: function(e){
		if(this.isMoveable){
			//////console.debug("poi.move - id "+this.id+" (x: "+this.point.getX()+", y:"+this.point.getY()+") - pre start move");
			
			//bugfix 0002498, aber offset nach zoomen!!!
			this.coordinates.tileMatrix.mapSource.prepare(); //es: damit auch nach einem zoom die Werte wieder passen (0002976)!  sonst liefert getPxOff "alte" Werte.
			var pxXoff = this.coordinates.tileMatrix.mapSource.getPxOff("x");
			var pxYoff = this.coordinates.tileMatrix.mapSource.getPxOff("y");
			var tX = this.coordinates.viewPortMouseX() + pxXoff;
			var tY = this.coordinates.viewPortMouseY() + pxYoff;

			//////console.debug("poi.move - mapSource.pxDelta[0]: "+this.coordinates.tileMatrix.mapSource.pxDelta[0]+" mapSource.pxDelta[1]: "+this.coordinates.tileMatrix.mapSource.pxDelta[1]);
			//////console.debug("poi.move - coordinates.viewPortMouseX: "+this.coordinates.viewPortMouseX()+" Y: "+this.coordinates.viewPortMouseY());
			
			var rwPos = this.coordinates.px2rw(tX,tY);
			this.point.setX(rwPos[0]);
			this.point.setY(rwPos[1]);
			
			//////console.debug("poi.move - id "+this.id+" (x: "+this.point.getX()+", y:"+this.point.getY()+") - after recalc");
			
			this.update();
			Event.stop(e);
		}
	},
	getPxCoords: function() {
		return this.coordinates.rw2px(this.point.getX(),this.point.getY());
	},
	setPxCoords: function(newCoords) {
		var rwCoords = this.coordinates.px2rw(newCoords[0],newCoords[1]);
		this.point.setXY(rwCoords[0],rwCoords[1]);
	},	
	noticeCoords: function() {
		//debug.writeline(this.config.editServletAddress+"id="+this.id+"&lat="+this.point.getY()+"&lon="+this.point.getX()+"&sessionId="+this.config.sessionId);
		this.request = new Ajax.Request(
			this.config.editServletAddress, 
			{ 
				method: "get",
				parameters: "id="+this.id+"&lat="+this.point.getY()+"&lon="+this.point.getX()+"&sessionId="+this.config.sessionId,
				onComplete: this.evalNoticeCoords.bind(this)
			}
		);
	},
	evalNoticeCoords: function(rawData) {
		//alert(rawData.responseText)
		var evaluatedData = eval( "("+rawData.responseText+")" );		
		var successful = evaluatedData.successful;
		if(successful){
			observer.update({lat:evaluatedData.lat,lon:evaluatedData.lon});
		}
		//debug.writeline("noticeCoordinates? (id "+this.id+" ("+this.point.getX()+", "+this.point.getY()+")): "+rawData.responseText);		
	},
	getData: function() {
		return this.data;
	},
	loadDataFromServlet: function() {
		if (this.data == null) {
			//debug.writeline(this.config.poiDataServletAddress+"id="+this.id+"&lang="+this.config.langs[this.config.usedLang]+"&sessionId="+this.config.sessionId);
			this.request = new Ajax.Request(
				this.config.poiDataServletAddress, 
				{ 
					method: "get",
					parameters: "id="+this.id+"&lang="+this.config.langs[this.config.usedLang]+"&sessionId="+this.config.sessionId+"&portalClientId="+this.poiManager.portalClientId,
					onComplete:this.addDataFromServlet.bind(this)
				}
			);
		}
	},
	addDataFromServlet: function(rawData){
		//alert(rawData.responseText);
		var evaluatedData = eval( "("+rawData.responseText+")" );
		this.data = evaluatedData[this.id];
		this.popUpEvent();
	},
	popUpEvent: function() {
		this.createLUXaddOns();	
						
		this.assignPopUpColor();//Farbcode setzen	
		this.popUp.create();
		this.popUp.fill();
		var w = this.popUp.width;
		var h = this.popUp.height;
		
		var rwCenter = this.coordinates.getCenter();
		var center = this.coordinates.rw2px(rwCenter[0],rwCenter[1]);
		var popupWidth = w;
		var popupHeight = h;
		var coord = this.getPxCoords();
		
		var newX = this.config.width/2.0 + center[0];
		var newY = this.config.height/2.0 + center[1];
		
		var popUpMaxY = coord[1] + popupHeight;
		var popUpMaxX = coord[0] + popupWidth;
		var isInMovePosition = false;
		var newCenterX = center[0]+1;
		var newCenterY = center[1]+1;
		this.moveMapToPopUp(newX, newY, newCenterX, newCenterY, popUpMaxX, popUpMaxY, isInMovePosition);
		//PopUp soll über allen POI's erscheinen 
		//-> GroupLayer mit aus dem der PopUp "kommt" soll über allen andren GroupLayern angezeigt werden
		this.poiManager.resetZindexAllTypes();
		this.container.style.zIndex=(parseInt(this.container.style.zIndex)+1000);	//diesen GroupLayer hochsezen
		this.div.style.zIndex = 2000;
		
		//var newImg = this.getIconActive(this.type)[0]; //DAV
		var newImg = this.getIcon(this.type)[0];
		this.icon.src = newImg; //andres Icon für aktives POI	
	},
	/**
	 * Verschiebt die Karte falls nötig, so dass das PopUp reinpasst.
	 * 
	* (Aus popUpEvent extrahiert, damit es von Sub-Klassen überschrieben werden kann.)
	* estykow
	*/
	moveMapToPopUp: function(newX, newY, newCenterX, newCenterY, popUpMaxX, popUpMaxY, isInMovePosition){
		if ((popUpMaxX > newX)){
			newCenterX = Math.round(newCenterX+(popUpMaxX - newX + 10));
			isInMovePosition = true;
		}
		if((popUpMaxY > newY)){
			newCenterY = Math.round(newCenterY+(popUpMaxY - newY - 10));
			isInMovePosition = true;
		}
		if(isInMovePosition){
			var moveToPoint = this.coordinates.px2rw(newCenterX,newCenterY);
			this.poiManager.tileMatrix.mapManager.moveTo(moveToPoint[0],moveToPoint[1]);			
		}
	},
	/**
	* Weist je nach Portal und POI-Typ dem PopUp eine Farbecode (und damit Template)zu.
	* estykow
	*/
	assignPopUpColor: function(){
		//### Der OSG und das TASH-Portal (+ HLMS) haben verschieden Farbgebungen 
		//### (z.B. bei Kategorie Kurltur- und Freizeiteinrichtungen)
		 
		// Portal specific switch:
		if (this.poiManager.portalClientId == 4) {
			//OSG
			switch (this.type) {
				case "Tourismusinformation":
				case "Busunternehmen":
				case "ReedereiSchiffFaehre":
				case "Flughafen":
				case "Leuchttuerme":
					/*this.popUp.color = "gray20";*/
					this.popUp.color = "gray";
					break;
				case "Bahnhof":					
					this.popUp.color = "gray20";
					break;
				case "HotelPension":
				case "FerienwohnungHaus":
				case "Campingplatz":
				case "Jugendherberge":
				case "Bauernhof":
				case "BettBike":
				case "WellnesshotelBeautyfarm":
				case "Gastronomie":
				case "Appartmenthaus":
				case "Gasthof":
				case "Ferienpark":
					this.popUp.color = "orange";
					break;
				case "Article":
				case "Naturerlebnis":
				case "KlosterKirche":
				case "Erlebnisbad":
				case "Freizeitpark":
				case "MuseumDenkmal":
				case "NaturerlebniszentrumAquarium":
				case "SchlossGarten":
				case "Theater":
				case "TierparkZoo":
					this.popUp.color = "blue";
					break;
				case "StrandBaden":
					this.popUp.color = "blue60";
					break;
				case "Segeln":
					this.popUp.color = "blue80";
					break;
				case "FahrradverleihReparaturservice":
				case "Event":
					this.popUp.color = "green91";
					break;
				case "Veranstaltungen":
					this.popUp.color = "green130";
					break;
				case "AbschliessbareFahrradbox":
					this.popUp.color = "green92";
					break;
				case "RastplatzSchutzhuette":
					this.popUp.color = "green92";
					break;
				case "rw1":
				case "rw2":
				case "rw3":
				case "rw4":
				case "rw5":
				case "rw6":
				case "rw7":
				case "rw8":
				case "rw9":
				case "rw10":
				case "rw11":
				case "rw12":
				case "rw13":
				case "rw14":
				case "rw15":
				case "rw16":
				case "rw17":
				case "rw18":
					this.popUp.color = "rw";
					break;
				default:
					this.popUp.color = "green";
					break;
			}
		} else{
			//TASH, HLMS u.a.
			switch (this.type) {
				case "Tourismusinformation":				
				case "CmsArtikel":				
					this.popUp.color = "gray10";
					break;
				case "Leuchttuerme":
					this.popUp.color = "gray";
					break;					
				case "Bahnhof":
					this.popUp.color = "gray20";
					break;
				case "HotelPension":
				case "FerienwohnungHaus":
				case "Campingplatz":
				case "Jugendherberge":
				case "Bauernhof":
				case "BettBike":
				case "WellnesshotelBeautyfarm":
				case "Gastronomie":
				case "MuseumDenkmal":
				case "Theater":
				case "SchlossGarten":
				case "KlosterKirche":
				case "Freizeitpark":
				case "TierparkZoo":
				case "Event":
					this.popUp.color = "orange";
					break;
				case "Veranstaltungen":
					this.popUp.color = "green130";
					break;					
				case "Naturerlebnis":
				case "Article":
					this.popUp.color = "blue";
					break;
				case "StrandBaden":
					this.popUp.color = "blue60";
					break;
				case "Segeln":
					this.popUp.color = "blue80";
					break;
				case "Ferienpark":
				case "FahrradverleihReparaturservice":
					this.popUp.color = "green91";
					break;
				case "AbschliessbareFahrradbox":
					this.popUp.color = "green92";
					break;
				case "RastplatzSchutzhuette":
					this.popUp.color = "green92";
					break;
				case "rw1":
				case "rw2":
				case "rw3":
				case "rw4":
				case "rw5":
				case "rw6":
				case "rw7":
				case "rw8":
				case "rw9":
				case "rw10":
				case "rw11":
				case "rw12":
				case "rw13":
				case "rw14":
				case "rw15":
				case "rw16":
				case "rw17":
				case "rw18":
					this.popUp.color = "rw";
					break;
				default:
					this.popUp.color = "green";
					break;
			}
		}	
	},
	openWindow: function() {
		this.dbChildJustOpenened = true;
		this.dbChild = window.open(this.config.luxInterfaceAddress+""+this.data.idLux,"");
	},
	createLUXaddOns: function() {
		if (this.data.webSite) {
			if (this.data.webSite.length > 18) this.data.niceWebSite = this.data.webSite.substring(0,18)+"...";
			else this.data.niceWebSite = this.data.webSite;
			
			if (this.data.webSite.substr(0,4) != "http") this.data.webSite = "http://"+this.data.webSite;
			// check for empty links
			if (this.data.niceWebSite == "/" || this.data.niceWebSite == "" || this.data.niceWebSite == "http://") {
				this.data.webSite = "";
				this.data.niceWebSite = "";
			}
		}
		if (this.data.email) {
			if (this.data.email.length > 25) this.data.niceEmail = this.data.email.substring(0,25)+"...";
			else this.data.niceEmail = this.data.email;
		}
	}
}

/**
* estykow
*/
var TeaserPOI = Class.create();
TeaserPOI.prototype = Object.extend(new POI(), { 
	assignPopUpColor: function(){
		//bei Teaser-Popups keine Unterscheidung der Teplates nacht POI-Type; alle gleich
		this.popUp.color = "plainTeaser";
		
		//ES: DIRTY 
		//-> TODO: wie überschreibt man die Variable bei INIT des TeaserPOIs !? 
		this.classname="TeaserPOI";
	},
	getIcon: function(type) {
		if (this.iconInfo==null){
			this.iconInfo = ["symbols/tash/icon_teaser.png",15,15];
		}
		return this.iconInfo;
	},
	createPopUp: function(delayClose){
		//Teaser mittig auf Icon positioniert
		return new PopUp(this,this.div, (this.sizeX/2) , (this.sizeY/2) ,delayClose);
	},
	moveMapToPopUp: function(newX, newY, newCenterX, newCenterY, popUpMaxX, popUpMaxY, isInMovePosition){
		//leer, da TeaserPOI-Popups immer beim zeichnen geöffnet werden (und die Karte dann nicht "springen" soll)
	}
});


var WeatherPOI = Class.create();
WeatherPOI.prototype = Object.extend(new POI(), {
	paint: function() {
		if (this.icon == null) {
			this.div = document.createElement("div");
			this.icon = document.createElement("img");
			this.icon.src = this.getIcon(this.type)[0];
			this.sizeX = this.getIcon(this.type)[1];
			this.sizeY = this.getIcon(this.type)[2];
			//Element.addClassName(this.icon,"poiIcon");
			Element.setStyle(this.icon,{
				display: 'inline',
  				width: this.sizeX+"px",
  				height: this.sizeY+"px"
			});
			Element.setStyle(this.div,{
  				width: this.sizeX+"px"
			});
			this.div.appendChild(this.icon);
				
			this.overlay = document.createElement("div");
			Element.addClassName(this.overlay,"weatherOverlay");
			/*this.div.setStyle({
  				width: this.sizeX+"px"
			});*/
			this.div.appendChild(this.overlay);
			var c = this.getContents();
			new Insertion.Top(this.overlay, c);

			//Element.addClassName(this.div,"poi");
			
			this.update();
			this.container.appendChild(this.div);
		}
	},
	getContents: function(){
		var v = this.config.wetterInfos[this.idTash];
		var myTemplate = new Template('<span>#{name}</span><img src="#{img}" /> #{minTmp}°/#{maxTmp}°');
		if (v == undefined){//add Default data
			myTemplate = new Template('<span>#{name}</span>');
			v = {name: this.name};
		}
		v.name = this.name;
		return  myTemplate.evaluate(v);
	},
	
	getIcon: function(type) {
		if (this.iconInfo==null){
			this.iconInfo = ["/tash/design/weather/dot.png",10,10];
		}
		return this.iconInfo;
	}
});


/* POICache
 * 
 * Handles the caching of the POIs. Is based on a zoom factor aware raster.
 * 
 */
POICache = Class.create();
POICache.prototype = {
	initialize: function(poiManager,serviceIndex,tMWidth,tMHeight, portalClientId) {
		this.poiManager = poiManager;
		this.serviceIndex = serviceIndex;
		this.coordinates = poiManager.coordinates;
		this.config = poiManager.config;
		this.tMWidth = tMWidth;
		this.tMHeight = tMHeight;
		this.isCached = new Array();
		this.dataSources = {};
		this.portalClientId = portalClientId;
	},
	addDataSource: function(name,ds){
		this.dataSources[name] = ds;
	},	
	startCaching: function(listenerDispenser) {
		if (this.coordinates.getCurrentZoomLevel() >= this.config.poiMinimumZoomLevel) {
			this.caching = true;	
			listenerDispenser.attachListener("move",this.cachePOIsOnMove.bind(this));
			this.cachePOIsOnMove();
		}
		else this.stopCaching();
	},
	stopCaching: function() {
		//////console.debug("POICache.stopCaching()");
		this.caching = false;
		var dss = $H(this.dataSources);
		dss.each(function(elem){elem.value.stop()});
		this.isCached = new Array();
	},
	cachePOIsOnMove: function() {
		if (this.caching) {
			var bb = this.poiManager.getRasterBB(this.coordinates.getBB());
/*
			this.checkAndLoad(bb[0],bb[1],bb[2],bb[3]);
			this.checkAndLoad(bb[0],bb[3],bb[2],bb[3] + (bb[3]-bb[1]));
			this.checkAndLoad(bb[2],bb[1],bb[2] + (bb[2]-bb[0]),bb[3]);
			this.checkAndLoad(bb[2],bb[3],bb[2] + (bb[2]-bb[0]),bb[3] + (bb[3]-bb[1]));
*/
			//CK if it works the server load is reduced by 3 quarters
			//ES  -> alt: 4 Request für TASH-Extent -> neu: nur 1 Request
			this.checkAndLoad(bb[0], bb[1], bb[2] + (bb[2]-bb[0]),bb[3] + (bb[3]-bb[1]) );
//			this.isCached[ bb[0] + bb[3] * 10000 + "_tile"] = true;
//			this.isCached[ bb[2] + bb[1] * 10000 + "_tile"] = true;
//			this.isCached[ bb[2] + bb[3] * 10000 + "_tile"] = true;
		}
	},
	checkAndLoad: function(minX,minY,maxX,maxY,layers) {
		if ( ! this.isCached[ minX + minY * 10000 + "_tile"] ) {
			this.load(minX , minY , maxX , maxY, this.portalClientId);
			this.isCached[ minX + minY * 10000 + "_tile"] = true;
		}
	},
	load: function(minX , minY , maxX , maxY, portalClientId){
		var dss = $H(this.dataSources);
		var that = this;
		dss.each(function(elem){elem.value.load(that.poiManager,minX , minY , maxX , maxY, portalClientId)});
	},
	remove: function() {
		this.stopCaching();
		this.parser.remove();
		this.config = null;
		this.coordinates = null;
		this.poiManager = null;
	}
}

/**
 * @author agutheil
 */
	PoiContainer = Class.create();
	PoiContainer.prototype = {
		initialize: function(poiManager,parent,coordinates, config){
			this.classname="PoiContainer";
			this.lat=0;
			this.lon=0;
			this.name="";
			this.type="";
			this.parent=parent;
			this.poiManager = poiManager;
			this.serviceIndex = poiManager.serviceIndex;
			this.eventLogger = poiManager.eventLogger;
			this.coordinates = coordinates;
			this.config = config;
			this.content=null;
			this.container = null;
			this.poilistContainer = null;
			this.allePoisAggrContainer = null;
			this.types = null;
			this.poiObservers = {};
			this.poiAggrObservers = {};
			this.singlePoiObservers = {};
			this.poiContainerObservers = {};
			this.clickedType="";
			this.clickedSubType="";
			this.clickedId=null;
			this.id = null;
			this.dataModell = {};
			this.actualClickedPoiAggrItem=null;

			this.zIndex = 1; //dafault, wird später überschreiben
			//this.zIndex = (poiManager.inc()+100); //ES: soll über den Subset-POIs liegen (die den Group-Layern verteilt sind)
			
			this.typesConf = this.getTypesConfForPortal(poiManager.portalClientId);
		},
		addData: function(id,data){
			this.id = id;
			this.lat = data.lat;
			this.lon = data.lon;
			this.name = data.name;
			this.type = data.type;
			this.content = data.content;
			this.checkBaseTypes(this.content);			
		},
		checkBaseTypes: function(content){
			var baseTypes = {   	//Anzahl Basetypes
				gray:0,
				orange:0,
				blue:0,
				green:0
			};
			var baseTypesValues = {   //Anzahl POIs in den Basetypes 
				gray:0,
				orange:0,
				blue:0,
				green:0
			};
			var typeArrays = {  
				gray:[],
				orange:[],
				blue:[],
				green:[]
			};

			
			var img="";
			var text="";
			
			var showLabelNumbers = 0; //hält fest, welche Aggregationszahlen im Icon agezeigt werden sollen (variiert zw. den Prortalen)
			
			//### Der OSG und das TASH-Portal (+ HLMS) haben verschieden Farbgebungen 
			//### (z.B. bei Kategorie Kurltur- und Freizeiteinrichtungen)
		 
			// Portal specific switch:
			if (this.poiManager.portalClientId == 4) {				
				
				//OSG
				showLabelNumbers = 2;
				for (var type in content){	
					var isTypeVisible = this.serviceIndex.idx[type].isVisible;
					switch(type){
						case "Tourismusinformation":		  	
				  		case "Bahnhof":
						case "Busunternehmen":
						case "ReedereiSchiffFaehre":
						case "Flughafen":
						case "Leuchttuerme":
							var i = baseTypes.gray;
							var d =this.dataForType(type, content[type]);
							typeArrays.gray[i]= d
							//nur wenn der Type sichtbar, counter hochzählen
							if (isTypeVisible){
							 	baseTypes.gray++; 	  		//Anzeige in Aggreg-Icon: Anzahl Kategorien
							 	baseTypesValues.gray = baseTypesValues.gray + content[type]; 	//Anzeige in Aggreg-Icon: Anzahl POIs in Kategorien  										
							}
					  		break;
					  	case "HotelPension":
				  		case "FerienwohnungHaus":
				  		case "Campingplatz":
						case "Jugendherberge":
				  		case "Bauernhof":
				  		case "BettBike":
				  		case "WellnesshotelBeautyfarm":
				  		case "Event":
						case "Appartmenthaus":
						case "Gastronomie":
						case "Gasthof":
						case "Ferienpark":
							var i = baseTypes.orange;
							var d =this.dataForType(type, content[type]);
							typeArrays.orange[i]=d;
							if (isTypeVisible) {
								baseTypes.orange++;
								baseTypesValues.orange = baseTypesValues.orange + content[type];
							}	
				  			break;
				  		case "Naturerlebnis":
				  		case "Article":
				 	 	case "StrandBaden":
				  		case "Segeln":
						case "Erlebnisbad":
						case "NaturerlebniszentrumAquarium":
						case "KlosterKirche":
						case "Freizeitpark":
						case "MuseumDenkmal":
						case "SchlossGarten":
						case "Theater":
				  		case "TierparkZoo":
							var i = baseTypes.blue;
							var d =this.dataForType(type, content[type]);
							typeArrays.blue[i]=d;
							if (isTypeVisible){
								baseTypes.blue++;			  	
								baseTypesValues.blue = baseTypesValues.blue + content[type];								
							} 
				  			break;
				  		case "FahrradverleihReparaturservice":
				  		case "AbschliessbareFahrradbox":
				  		case "RastplatzSchutzhuette":
				  		case "Golfen":
				  		case "Reiten":
						case "Veranstaltungen":
							var i = baseTypes.green;
							var d =this.dataForType(type, content[type]);
							typeArrays.green[i]=d;
							if (isTypeVisible){
								baseTypes.green++;	
								baseTypesValues.green = baseTypesValues.green + content[type];
							} 
				  			break;
				  		default:	
				    		break;
					}
				}
			}else{
				
				//TASH, HLMS u.a.
				showLabelNumbers = 2;
				for (var type in content){	
					var isTypeVisible = this.serviceIndex.idx[type].isVisible;
					switch(type){
						case "Tourismusinformation":		  	
				  		case "Bahnhof":
						case "Busunternehmen":
						case "ReedereiSchiffFaehre":
						case "Flughafen":
						case "Leuchttuerme":
							var i = baseTypes.gray;
							var d =this.dataForType(type, content[type]);
							typeArrays.gray[i]= d
							//nur wenn der Type sichtbar, counter hochzählen
							if (isTypeVisible){
								baseTypes.gray++;  //Anzeige in Aggreg-Icon: Anzahl Kategorien  	  		
								baseTypesValues.gray= baseTypesValues.gray + content[type];  //Anzeige in Aggreg-Icon: Anzahl POIs in Kategorien						
							}
					  		break;
					  	case "HotelPension":
				  		case "FerienwohnungHaus":
				  		case "Campingplatz":
						case "Jugendherberge":
				  		case "Bauernhof":
				  		case "BettBike":
				  		case "WellnesshotelBeautyfarm":
				  		case "Gastronomie":
				  		case "MuseumDenkmal":
				  		case "Theater":
				  		case "SchlossGarten":
				  		case "KlosterKirche":
				  		case "Freizeitpark":
				  		case "TierparkZoo":
				  		case "Event":
						case "Appartmenthaus":
						case "Gasthof":
						case "Ferienpark":
							var i = baseTypes.orange;
							var d =this.dataForType(type, content[type]);
							typeArrays.orange[i]=d;
							if (isTypeVisible) {
								baseTypes.orange++;
								baseTypesValues.orange = baseTypesValues.orange + content[type];
							}	
				  			break;
				  		case "Naturerlebnis":
				  		case "Article":
				 	 	case "StrandBaden":
				  		case "Segeln":
						case "Erlebnisbad":
						case "NaturerlebniszentrumAquarium":
							var i = baseTypes.blue;
							var d =this.dataForType(type, content[type]);
							typeArrays.blue[i]=d;
							if (isTypeVisible){
								baseTypes.blue++;			  	
								baseTypesValues.blue = baseTypesValues.blue + content[type];
							} 
				  			break;
				  		case "FahrradverleihReparaturservice":
				  		case "AbschliessbareFahrradbox":
				  		case "RastplatzSchutzhuette":
				  		case "Golfen":
				  		case "Reiten":
						case "Veranstaltungen":
							var i = baseTypes.green;
							var d =this.dataForType(type, content[type]);
							typeArrays.green[i]=d;
							if (isTypeVisible){
							 	baseTypes.green++;	
								baseTypesValues.green = baseTypesValues.green + content[type];
							}
				  			break;
				  		default:	
				    		break;
					}
				}	
			}//end else
			this.types = {baseTypes:baseTypes,typeArrays:typeArrays, baseTypesValues:baseTypesValues, showLabelNumbers:showLabelNumbers};
		},
		dataForType: function(t, c){
			var d ={
				type : t,
				imgUrl : this.getType(t).img,
				txt : this.getType(t).txt,
				cnt : c	
			};
			return d;
		},
		getType: function(t) {
			if (this.typesConf[t] != null) {
				return(this.typesConf[t]);
			}
			else {
				return this.typesConf.defaultType;
			}
		},
		rw2px: function(lat,lon){
			return {top:lat+"px", left:lon+"px"};
		},
		paint: function(){
			this.paintPoiContainer();
		},
		repaintPoiContainer: function(){
			this.checkBaseTypes(this.content);
			this.paintPoiContainer();	
		},
		//erste ebene
		paintPoiContainer: function(){
			this.removePoiContainer();
			var poicontainer = createElement("div");
			var pxCoord = this.rw2px(this.lat,this.lon)
			Element.setStyle(poicontainer,{
  				position:'absolute',
                top:pxCoord.top,
                left:pxCoord.left,
				zIndex:this.zIndex,			
				fontSize: '0.9em',  
    			margin:'0px',
   			 	padding:'0px'
			});
			var pois = createElement("div");			
			poicontainer.appendChild(pois);
			var anzPoi = 0;
			for (var t in this.types.baseTypes){				
				var cnt = this.types.baseTypes[t];			//Anzahl Kategorien
				var cntValues = this.types.baseTypesValues[t];		//Anzahl POIs in Kategorien		
				if (cnt > 0){
					anzPoi++;		
					var span = createElement("span");
					Element.setStyle(span,{
						position: 'absolute',
					    textAlign:'center',
					    width: '23px',		//span muss Icon überdecken, damit event sauber (ohne flackern) 
					    height: '23px',	
						lineHeight:'23px',  //damit zahl middle angezeigt werden kann 
						verticalAlign: 'middle',
					    color:'White',
					    fontWeight:'bold',
					    fontSize:'11px'
					});
					
					//welche Zahl soll als Labeltext erscheinen
					var txt = null;
					if(this.types.showLabelNumbers ==1){
						txt = document.createTextNode(cnt);
					}else{
						txt = document.createTextNode(cntValues);
					}
					//(ES keine Anzahl für Demo am 03.12.2008)
					span.appendChild(txt);
					this.dataModell[t] = {cnt:this.types.baseTypes[t], container:txt}; 
					var poi = createElement("div");
					Element.setStyle(poi,{
						position: 'relative',
					    float: 'left',
		 				width: '23px ',
					    height: '23px ',
						margin: '0px',		
						padding: '0px',
	   			 		cursor:'pointer'
					});
					var style = this.styleForType(t);
					poi.style.backgroundImage=style.backgroundImage;
					span.style.color=style.color;
					poi.appendChild(span);
					pois.appendChild(poi);				
					this.poiObservers[poi]= this.clickHandler.bindAsEventListener(this,t);
					//Event.observe(poi, 'mousedown', this.poiObservers[poi]);
					//aggregliste bereits bei mouseover einbleben
					Event.observe(poi, 'mouseover', this.poiObservers[poi]);
					 
				}				
			}
			var w = '23px';
			var h = '23px';
			if (anzPoi == 2){
				w = '46px';
				h = '23px';
			}else if (anzPoi > 2){
				w = '46px';
				h = '46px';
			}
			Element.setStyle(pois,{
				position:'relative',
    			width:w,
    			height:h,
    			lineHeight:'100%',
    			fontSize:'10px',
    			margin:'0px',
   			 	padding:'0px'
			});
			var clearBr = createElement("br");
			clearBr.style.clear="both";
			pois.appendChild(clearBr);
			this.parent.appendChild(poicontainer);
			this.container = poicontainer;
			
		},
		
		//zweite ebene
		paintPoilistContainer: function(){
			var d = $A(arguments);
			var type = d[0];
			var data = d[1];
			var typesArray = data;
			var tmpContainer = null;
			
			this.removePoilistContainer();
			var poilistContainer = createElement("div");	
			poilistContainer.makePositioned();					
			Element.setStyle(poilistContainer,{
  				zIndex:'100',
				display:'block',
			    backgroundColor:'White', 
			    width:'150px',
				margin: '0px',		
				padding: '0px'
			});
			//poilistContainer.addClassName('poi_list_container');		
			var heading = createElement("div");
			//heading.addClassName('',');
			
			Element.setStyle(heading,{
  				fontSize:'12px',
    			color:'White',
    			fontWeight:'bold',
    			backgroundColor:headingBGcolor[type],
    			padding:'2px',
				margin: '0px'	
			});
			
			
			//die poi_aggr_list
			var poiAggrList = createElement("div");
			//poiAggrList.addClassName('poi_aggr_list');
			Element.setStyle(poiAggrList,{
				position:'relative'
			});
				
			heading.appendChild(document.createTextNode(this.getType(type).txt));
			var showTypeHeading = false;
			
			for (var i=0;i<typesArray.length;i++){
				//check if Type is visible in serviceIndex				
				var poiAggr = createElement("div");
					Element.setStyle(poiAggr,{
					position:'relative',
					margin: '0px',		
					padding: '0px',
   			 		cursor:'pointer',
   			 		backgroundImage:"url('"+aggrPoiBGImg[type]+"')",
  					backgroundRepeat:'no-repeat',
  					backgroundPosition:'right bottom'
				});
				poiAggr.addClassName('poi_cat_elem');
				var isLayerVisible = this.serviceIndex.idx[typesArray[i].type].isVisible;
				if (!isLayerVisible) Element.hide(poiAggr);
				if(isLayerVisible) showTypeHeading = true; //wenn min. ein poityp der selektierten Farbkategorie sichtbar(wenn es was zum anzeigen gibt), nur dann Ueberschrift nötig/anzeigen
				
				var poiAggrImg = createElement("img");
				poiAggrImg.setAttribute('alt',typesArray[i].type);
				poiAggrImg.setAttribute('src','/tash/symbols/tash/'+typesArray[i].imgUrl);
				Element.setStyle(poiAggrImg,{
					margin: '0px',
    				padding : '0px',
    				borderWidth: '0px',
					width:'23px ',
					height:'23px '			
				});
				var poiAggrSpan = createElement("span");
				poiAggrSpan.appendChild(document.createTextNode(typesArray[i].txt));
				Element.setStyle(poiAggrSpan,{
					margin: '3px',
					padding : '0px'  								
				});
				var poiAggrSpan2 = createElement("span");
				poiAggrSpan2.appendChild(document.createTextNode("("+typesArray[i].cnt+")"));
				Element.setStyle(poiAggrSpan2,{
					margin: '3px',
					padding : '0px'   								
				});
				poiAggr.appendChild(poiAggrImg);
				poiAggr.appendChild(poiAggrSpan); 
				poiAggr.appendChild(poiAggrSpan2);
				this.poiAggrObservers[poiAggr] = this.poiAggrClickHandler.bindAsEventListener(this,typesArray[i].type,0,10,poiAggr, type)
				Event.observe(poiAggr, 'mousedown', this.poiAggrObservers[poiAggr]);
				poiAggrList.appendChild(poiAggr);
				var tmpType = typesArray[i].type;
				if (this.clickedSubType == tmpType){
					//dritte ebene zeichnen
					tmpContainer = poiAggr;					
				}				
			}
			
			if(showTypeHeading){
				poilistContainer.appendChild(heading);
			}	
			poilistContainer.appendChild(poiAggrList);
			this.container.appendChild(poilistContainer);
			this.poilistContainer = poilistContainer;
			Element.setStyle(this.container,{
				zIndex:this.zIndex + this.poiManager.max() + 1
			});					
			var cumPosThis = Position.cumulativeOffset(this.container);
			var dimsThis = this.container.getDimensions();
			var cumPosThisMax = {
				left: cumPosThis[0] + (dimsThis.width + 10), 
				top: cumPosThis[1] + (dimsThis.height + 10)
			};
			var cumPosMapCon = Position.cumulativeOffset(this.poiManager.tileMatrix.parent);
			var dimsMapCon = this.poiManager.tileMatrix.parent.getDimensions();
			var cumPosMapConMax = {
				left: cumPosMapCon[0] + dimsMapCon.width, 
				top: cumPosMapCon[1] + dimsMapCon.height
			};
			var isMoveX = false;
			var isMoveY = false;
			var moveX = 1;
			var moveY = 1;
			if (cumPosThisMax.left > cumPosMapConMax.left){
				moveX = cumPosMapConMax.left - cumPosThisMax.left;
				isMoveX = true;
			}
			if (cumPosThisMax.top > cumPosMapConMax.top){
				moveY = cumPosMapConMax.top - cumPosThisMax.top;
				isMoveY = true;
			}
			if(isMoveX || isMoveY){
				this.poiManager.tileMatrix.mapManager.moveBy(moveX,moveY);		
			}
			if(tmpContainer!=null){
				this.repaintAllePoisAggr(tmpContainer, this.clickedSubType);
			}					
		},
		repaintAllePoisAggr: function(parent, type){
			if(this.actualClickedPoiAggrItem!=null){
				this.paintAllePoisAggr(
				parent,type,
				this.actualClickedPoiAggrItem.data,
				this.actualClickedPoiAggrItem.start,
				this.actualClickedPoiAggrItem.pages,
				this.actualClickedPoiAggrItem.parentType
				);
			}
		},
		
		//dritte ebene
		paintAllePoisAggr: function(parent,type, data,start,pages,parentType){
			this.clickedSubType = type;
			this.actualClickedPoiAggrItem={};
			this.actualClickedPoiAggrItem.data=data;
			this.actualClickedPoiAggrItem.start=start;
			this.actualClickedPoiAggrItem.pages=pages;
			this.actualClickedPoiAggrItem.parentType=parentType;
			this.removeAllePoisAggr();
			var anzahlEintraege=0;
			var allePoisAggr = createElement("div");
			allePoisAggr.zIndex='1001';
			Element.setStyle(allePoisAggr,{
				zIndex:this.zIndex + this.poiManager.max() + 1,
				position:'absolute',
    			top:'0px',
    			left:'150px',
    			width:'150px',
   				backgroundColor:'White',
   				margin: '0px',
				padding : '0px' 
			});

			var heading = createElement("div");
			Element.setStyle(heading,{
  				fontSize:'12px',
    			color:'White',
    			fontWeight:'bold',
    			backgroundColor:headingBGcolor[parentType],
   				margin: '0px',
				padding : '3px' 
			});
			//heading.appendChild(document.createTextNode(type));
			var headingTxt = this.getType(type).txt;
			heading.appendChild(document.createTextNode(headingTxt));	
				
			allePoisAggr.appendChild(heading);
			var poiList = createElement("div");
			//poiList.addClassName('poi_list');
			Element.setStyle(poiList,{
				position:'relative',
    			backgroundColor:'White',
   				margin: '0px',
				padding : '0px' 
			});
			allePoisAggr.appendChild(poiList);
			var normaleEinrueckung = '3px';
			var weiterEinrueckung = '9px';
			var einrueckung = normaleEinrueckung;		
			for (var p in data){
				if (data[p].type==type){				
					if ( this.poiManager.portalClientId != 4  //es: basetype-Filterung entfernt, da diese bei der Aggregation für TASH/HLMS auf Server-Seite verlagert!
						|| (this.poiManager.portalClientId == 4	&& (!data[p].idTash.match(/offer/gi) || data[p].type.match(/bettbike/gi)))
						){ //im OSG sollen nur Addressbase angezeigt werden, in Andren portalen aber nicht (vorrerst)
						anzahlEintraege = anzahlEintraege + 1; 
						var singlePoi = createElement("div");
						Element.setStyle(singlePoi,{
								margin:'3px',					
								padding : '0px',
		   			 			cursor:'pointer' 
							});										
						
						singlePoi.appendChild(document.createTextNode(data[p].name));
						//Name enthält jetzt HTMLSpecialChars; sollen interpretiert werden				
						//singlePoi.innerHTML += data[p].name;				
						poiList.appendChild(singlePoi);
						this.singlePoiObservers[singlePoi] = this.singlePoiClickHandler.bindAsEventListener(this,data[p],p)
						Event.observe(singlePoi, 'mousedown', this.singlePoiObservers[singlePoi]);
					}else{
						var a = 3;
					}
				}
			}
			Element.setStyle(allePoisAggr,{
				position:'absolute',
   				margin: '0px',
				padding : '0px' 				
			});
			/*
			.paging {
                margin:3px;
                text-align:center;
            }
            .paging span{
                margin:3px;
            }  
			*/
			var paging = createElement("div");
			Element.setStyle(paging,{
				margin:'3px',
                textAlign:'center',
				padding : '0px' 							
			});
			if (start!=0){
				var p1 = createElement("span");		
				Element.setStyle(p1,{
					margin:'3px',           
					padding : '0px', 	
					cursor:'pointer'			
				});	
				var obs1 = this.poiAggrClickHandler.bindAsEventListener(this,type,start-pages,pages,parent,parentType)
				Event.observe(p1, 'mousedown', obs1);
				var txt = document.createTextNode("<");
				p1.appendChild(txt);
				paging.appendChild(p1);
			}
			if (anzahlEintraege==pages){
				var p2 = createElement("span");
				Element.setStyle(p2,{
					margin:'3px',           
					padding : '0px',
					cursor:'pointer' 		 				
				});	
				var obs2 = this.poiAggrClickHandler.bindAsEventListener(this,type,start+pages,pages,parent,parentType)
				Event.observe(p2, 'mousedown', obs2);
				var txt2 = document.createTextNode(">");
				p2.appendChild(txt2);
				paging.appendChild(p2);
			}
			
			allePoisAggr.appendChild(paging);
			parent.appendChild(allePoisAggr);
			
			this.allePoisAggrContainer = allePoisAggr;
			
			var dim_w = this.container.getDimensions();
			var p_w = Position.cumulativeOffset(this.container);
			var p_w_max = {
				left: p_w[0] + dim_w.width,
				top: p_w[1] + dim_w.height
			};
			var dim_c = allePoisAggr.getDimensions();
			var p_c = Position.cumulativeOffset(allePoisAggr);
			var p_c_max = {
				left: p_c[0] + dim_c.width,
				top: p_c[1] + dim_c.height
			};
			var cumPosThisMax = {
				left: Math.max(p_w_max.left, p_c_max.left) + 10,
				top: Math.max(p_w_max.top, p_c_max.top) + 10
			};
			var dim_container = {
				width: cumPosThisMax.left - p_w[0],
				height: cumPosThisMax.top - p_w[1]
			};	
			
			var cumPosMapCon = Position.cumulativeOffset(this.poiManager.tileMatrix.parent);
			var dimsMapCon = this.poiManager.tileMatrix.parent.getDimensions();
			var cumPosMapConMax = {
				left: cumPosMapCon[0] + dimsMapCon.width, 
				top: cumPosMapCon[1] + dimsMapCon.height
			};
			var isMoveX = false;
			var isMoveY = false;
			var moveX = 1;
			var moveY = 1;	
			if (cumPosThisMax.left > cumPosMapConMax.left){
				moveX = cumPosMapConMax.left - cumPosThisMax.left;
				isMoveX = true;
			}
			if (cumPosThisMax.top > cumPosMapConMax.top){
				moveY = cumPosMapConMax.top - cumPosThisMax.top;
				isMoveY = true;
			}
			if(isMoveX || isMoveY){
				this.poiManager.tileMatrix.mapManager.moveBy(moveX,moveY);					
			}				
			
		},
		
		clickHandler: function(e){
			Event.stop(e);
			var data = $A(arguments);
			var t = data[1];			
			this.actualClickedPoiAggrItem=null;
			this.notifyObservers("clickHandler");
			if (this.poilistContainer != null && this.clickedType == t){ //also popup1 sichtbar
				this.clickedType = "";				
				this.deletePopup();
			}else{	//kein Popup sichtbar

				// klick auf Aggregationspoi
				this.eventLogger.log(8);

				this.clickedType = t;
				this.paintPoilistContainer(this.clickedType, this.types.typeArrays[this.clickedType]);
			}			
			
		},
		mouseHandler: function(e){
			var data = $A(arguments);
			var t = data[1];
			this.notifyObservers("mouseHandler");
			var caller = $(Event.element(e));
			var m =  this.poiObservers[caller];
			Event.stopObserving(caller, 'mouseover', m);
			this.poiObservers[caller]=null;
			this.clickedType = t;
			var url = 'http://localhost:8080/tash/testdata/req2.txt';
			new Ajax.Request(url, {
			  	method: 'get',
			 	onSuccess: this.req2success.bind(this,this.clickedType)
			});
			
			/*
			 * this.poiObservers[poi]= this.mouseHandler.bindAsEventListener(this,t);
				Event.observe(poi, 'mouseover', this.poiObservers[poi]);
			 */	
			
		},
		notifyObservers: function() {
			var data = $A(arguments);
			for (o in this.poiContainerObservers){
				this.poiContainerObservers[o].update(this,data[0]);
			}
		},
		addObserver: function(name, observer){
			this.poiContainerObservers[name]=observer;
		},
		/**
		 * funktion muss type kennen und html-container, um Inhalt ranzuhaengen
		 */
		poiAggrClickHandler: function(e){
			var data = $A(arguments);			
			var type = data[1];
			var start = data[2]; 
			var pages = data[3];
			var parent = data[4];
			var parentType = data[5];
			Event.stop(e);
			var url = "/tash/controller/leaves?";
			new Ajax.Request(url, {
			  	method: 'get',
				//TODO: client nicht hardcoded
				parameters: "id="+this.id+"&type="+type+"&start="+start+"&count="+pages+"&portalClientId="+this.poiManager.portalClientId,
			 	onSuccess: this.poiAggrSuccess.bind(this,parent,type,start,pages,parentType)
			});
			
			//es: let's make some history!
			if( this.config.historyCursor ==null || (this.config.history[this.config.historyCursor]).getActivePoiId() != this.id){ //nur wenn dieser showPopUp-Aufruf nicht selbst von einem History-Navigation stammt (-> sonst schleife)
				//ES: TODO: activePoiIdTash auch prüfen (?)
				//ES: TODO: wiederholtes öffnen verschieder LEAVES eines Aggreg-Icon nur einmal historiesieren !
				//dieser aufruf gehört nicht in die showPopUp da diese auch bei historyBack aufgerufen wird (-> schleife)
				this.poiManager.tileMatrix.mapManager.map.historyMake();
			}
		},
		poiAggrSuccess: function(parent,type,start,pages,parentType,data){	
			var leavesData = eval('('+data.responseText+')');

			// klick auf POITypen
			this.eventLogger.log(9);

			this.paintAllePoisAggr(parent,type, leavesData,start,pages,parentType);
		},
		singlePoiClickHandler: function(e){
			var d = $A(arguments);
			var data = d[1];
			var id = d[2];
			this.clickedId = id;
			var idTash = data.idTash;
			Event.stop(e);
			//alert(id);
			this.notifyObservers("singlePoiClickHandler");
	
			// Klick auf POI
			this.eventLogger.log(10);

			this.config.controlConnector.getBestView([idTash], false,true);			
		},
		styleForType: function(type){
			var style = {};
			switch(type){
				case 'blue':
					style.backgroundImage="url('"+this.getType(type).img+"')";
					style.color="Blue";
					break;
				case 'green':
					style.backgroundImage="url('"+this.getType(type).img+"')";
					style.color="Green";
					break;
				case 'orange':
					style.backgroundImage="url('"+this.getType(type).img+"')";
					style.color="Orange";
					break;
				case 'gray':
					style.backgroundImage="url('"+this.getType(type).img+"')";
					style.color="Gray";
					break;
				default:
					style.backgroundImage="url('/tash/symbols/tash/meta.png')";
					style.color="White";
					break;
			}
			return style;
		},
		remove: function(){
			this.actualClickedPoiAggrItem=null;
			this.removePoiContainer();
		},
		removePoiContainer: function(){
			if (this.container != null){
				this.removePoilistContainer();
				Element.remove(this.container);				
				this.container = null;
			} 
		},
		removePoilistContainer: function(){
			if (this.poilistContainer != null){
				this.removeAllePoisAggr();
				Element.remove(this.poilistContainer);
				this.poilistContainer = null;
				
				Element.setStyle(this.container,{
					zIndex:this.zIndex //alten z-index setzen, damit er die neu geoeffneten popups nicht uebelagert werden
				});
			} 
		},
		removeAllePoisAggr: function(){
			if (this.allePoisAggrContainer != null) {
				Element.remove(this.allePoisAggrContainer);
				this.allePoisAggrContainer = null;
			}
		},			
		deletePopup: function(){
			/*this.container.setStyle({
				zIndex:this.zIndex
			});*/
			this.removePoilistContainer();
		},
		setZindex: function(newZindex){
			this.zIndex = newZindex;
		},
		getTypesConfForPortal: function(portalClientId){
			var typesConf ; 
			
			//OSG-Portal hat andere Icons und Kategorie-Bezeichnungen as TASH (+ HMLS usw.)		
			if(portalClientId ==4){
				//OSG
				typesConf = this.config.aggregTypesConf;
			} else{
				//TASH, HLMS u.ä.
				typesConf = this.config.aggregTypesConfOSG;
			}
			
			typesConf.defaultType = this.config.aggregTypesConfDefault;
			
			return typesConf;
		}
		
	};
	var createElement = function(elemName){
		var elem = document.createElement(elemName);
		return $(elem);
	};
	
	

	var headingBGcolor = {
		blue:"#008fc7",
		gray:"#8b8b8b",
		green:"#2b9f12",
		orange:"#e8882f"
	}
	var aggrPoiBGImg = {
		blue:"/tash/symbols/tash/olc_blue.gif",
		gray:"/tash/symbols/tash/olc_gray.gif",
		green:"/tash/symbols/tash/olc_green.gif",
		orange:"/tash/symbols/tash/olc_orange.gif"
	}
/*	POIManager
 * 
 * Handles all things POI. Creating, moving, icons...
 * 
 */
POIManager = Class.create();
POIManager.prototype = {
	initialize: function(tileMatrix, portalClientId) {
		this.tileMatrix = tileMatrix;
		this.container = tileMatrix.container;
		this.coordinates = tileMatrix.coordinates;
		this.config = tileMatrix.config;
		this.pointBox = new Array();
		this.poiConBox = new Array();
		this.zIndexCount=0;
		this.poiCache = null;
		this.poiContainerList=new Array();
		this.eventLogger = this.tileMatrix.mapManager.eventLogger;
		this.serviceIndex = this.tileMatrix.serviceIndex;
		this.getPOIConBox(-1);
		this.hasPoiContainer=false;
		this.stepSize=0;
		this.dataSources = this.config.dataSources;
		this.portalClientId = portalClientId;
				
		//this.pb_counter = 1;
		//die ersten z-Index-Nummer ist für die Low-Prio-Layer reserviert 
		this.pb_counter = this.config.typeWithLowLayerPrio.length;
	},
	addDataSource: function(name,ds){
		this.dataSources[name] = ds;
		this.poiCache.dataSources = this.dataSources;
	},	
	calcStepSize: function() {
		var res = this.coordinates.getCurrentResolution();
		var width = this.config.width;
		var height = this.config.height;
		
		var extent = new Array(this.config.width * this.coordinates.getCurrentResolution(),this.config.height * this.coordinates.getCurrentResolution());
		// The stepsize should be a little bit smaller than the shorter side of the viewport
		// wenn ich diese zeile ändere funktionierts auch mit dem Laden der POIs
		//this.stepSize = extent.min() - Math.round(extent.min()/100);
		this.stepSize = extent.min();
		//debug.writeline("POI Caching raster is "+this.stepSize);
	},
	getRaster: function(val) {
		var num = val - (val % this.stepSize);
		num = Math.floor(num * Math.pow(10,this.config.poiMaxPrecision)) / Math.pow(10,this.config.poiMaxPrecision);
		return num;
//		return val;
	},
	getRasterBB: function(bb) {
		var minX = this.getRaster(bb[0][0]);
		var minY = this.getRaster(bb[1][1]);
		var maxX = this.getRaster(bb[1][0]);
		var maxY = this.getRaster(bb[0][1]);

		return new Array(minX,minY,maxX,maxY);
	},
	cleanAddStep: function(val) {
		// MAGIC NUMBER: As JS is not able to calculate floats in the way I want ( 5.1 + 0.1 != 5.2 but == 5.20000000000000000005) it gets some "buffer".
		var num = val + 1.2*this.stepSize;
		return this.getRaster(num);
	},
	/**
	* methode laedt pois nach
	*/
	loadPOIs: function(){
		var bb = this.getRasterBB(this.coordinates.getBB());
		////console.debug("PoiManager.loadPOIs()");
		
		//clientID bei load mitgegeben, da Klasse in mapOptions.js initialisiert wird
		// no reason to do it 4 times..
/*
		this.dataSources.extent.load(this,bb[0],bb[1],bb[2],bb[3], this.portalClientId );
		this.dataSources.extent.load(this,bb[0],bb[3],bb[2],bb[3] + (bb[3]-bb[1]), this.portalClientId );
		this.dataSources.extent.load(this,bb[2],bb[1],bb[2] + (bb[2]-bb[0]),bb[3], this.portalClientId );
		this.dataSources.extent.load(this,bb[2],bb[3],bb[2] + (bb[2]-bb[0]),bb[3] + (bb[3]-bb[1]), this.portalClientId );
*/
		this.dataSources.extent.load(this,bb[0],bb[1],bb[2] + (bb[2]-bb[0]),bb[3] + (bb[3]-bb[1]), this.portalClientId );
	},
	setPoiCache: function(poiCache){
		this.poiCache = poiCache;
		this.poiCache.dataSources = this.dataSources;
	},
	startCaching: function(listenerDispenser){
		//////console.debug("PoiManager.startCaching("+listenerDispenser+")");
		this.calcStepSize();
		this.poiCache.startCaching(listenerDispenser);
	},
	stopCaching: function() {
		this.poiCache.stopCaching();
	},
	incrementZindex:function(){
		this.zIndexCount++;
		return this.zIndexCount;
	},
	max:function(){
		return this.zIndexCount;
	},
	addNewPoiContainer: function(container,coordinates, config,id,data){
		this.hasPoiContainer=true;
		var poiContainer = new PoiContainer(this,container,coordinates, config);
		poiContainer.setZindex(this.incrementZindex()+100); //ES: soll über den Subset-POIs liegen (die den Group-Layern verteilt sind)
		poiContainer.addObserver("clickObserver",this);
		this.poiContainerList.push(poiContainer);
		poiContainer.addData(id,data);
		return poiContainer;
	},
	addNewPoi: function(parent,container,poiConBoxType,coordinates,point,id,type,name,idTash,config,logger){
		var poi = new POI(parent,container,poiConBoxType,coordinates,point,id,type,name,idTash,config,logger);
		poi.addObserver("clickObserver",this);
		this.poiContainerList.push(poi);
		return poi;
	},
	addNewTeaserPoi: function(parent,container,poiConBoxType,coordinates,point,id,type,name,idTash,config,logger){
		var poi = new TeaserPOI(parent,container,poiConBoxType,coordinates,point,id,type,name,idTash,config,logger);
		poi.addObserver("clickObserver",this);
		this.poiContainerList.push(poi);
		return poi;
	},
	addNewWeatherPoi: function(parent,container,coordinates,point,id,type,name,idTash,config,logger){
		var poi = new WeatherPOI(parent,container,coordinates,point,id,type,name,idTash,config,logger);
		poi.addObserver("clickObserver",this);
		this.poiContainerList.push(poi);
		return poi;
	},
	update: function(){
		var data = $A(arguments);
		var caller = data[0];
		var method = data[1];	
		if (method == "singlePoiClickHandler"){
			this.tileMatrix.mapManager.map.activePoiId=caller.clickedId;
		}else{
			this.tileMatrix.mapManager.map.activePoiId=caller.id;	
			this.tileMatrix.mapManager.map.activePoi = caller;
			for (var i = 0; i < this.poiContainerList.length; i++){
				//TODO: ES Prüfen, ob das auch schöne geht (Überschreiben wird aber schwierig, da es nur einen POIManager gibt...) -> Vorschlag: close-Popups-Event antriggern, und TEaserPOIs nicht als Observer registrieren; die restlichen POIs schon -> REFAFACTOR
				if (caller != this.poiContainerList[i] && this.poiContainerList[i].classname !== "TeaserPOI" ) this.poiContainerList[i].deletePopup();
			}
		}
	},
	removeAll: function(){
		for (var i = 0; i < this.poiContainerList.length; i++){
			this.poiContainerList[i].remove();
		}
		this.zIndexCount=0;
	},
	getPOIConBox: function(type) {	//lazy
		if (typeof(this.poiCon) != "object") {
			this.poiCon = document.createElement("div");
			this.poiCon.id = "poiCon_"+Math.random();

			Element.addClassName(this.poiCon,"poiCon");
			var xOff = -this.tileMatrix.mapSource.getPxOff("x");
			var yOff = -this.tileMatrix.mapSource.getPxOff("y");
			Element.setStyle(this.poiCon,{position:"absolute",top:yOff+"px",left:xOff+"px"});

			this.container.appendChild(this.poiCon);
		}
		if (typeof(this.poiConBox[type]) != "object") {
			this.pb_counter++;
			this.poiConBox[type] = document.createElement("div");
			this.poiConBox[type].id = type+"_poiCon_"+Math.random();
			
			//jeder GroupLayer kriegt einen expliziten zIndex (nix mit 'auto')
			if(type != -1 && this.config.typeWithLowLayerPrio.indexOf(type) > -1){ //ist ein LOW-PRIO-layer -> niedrigen z-index vergeben, restlich fortlaufend drüber
				this.poiConBox[type].style.zIndex	=(this.config.typeWithLowLayerPrio.indexOf(type)+1); 
				this.poiConBox[type].origZ			=(this.config.typeWithLowLayerPrio.indexOf(type)+1); //merken
				////console.debug (" ---lowPrioLayerBox für: "+type);
			} else if(type != -1 && type == 'standalone'){ //HIGHT PRIO: über setPOIs hinzugefügte POIs sollen über den regulären angezeigt werden
				this.poiConBox[type].style.zIndex	=(this.pb_counter +100);
				this.poiConBox[type].origZ			=(this.pb_counter +100); //merken
				////console.debug (" ---hight Prio LayerBox für: "+type);
			} else if(type != -1 ){		//NORMAL PRIO
				////console.debug (" ---pb_counter: "+this.pb_counter + ' type=='+type);
				this.poiConBox[type].style.zIndex	=this.pb_counter;
				this.poiConBox[type].origZ			=this.pb_counter; //merken
			}
			this.poiConBox[type].style.position='absolute'; //ES: sonst wird Z-Index ignoriert	
			/*ACHTUNG: position:relative bringt beim pannen im IE7 die POI's zum verschwinden!!!
			this.poiConBox[type].style.position='relative';	//sonst ignoriert der IE6 & IE7 den Z-Index ! -> u.U. PopUp durch POI verdeckt
			*/

			this.poiCon.appendChild(this.poiConBox[type]);		
		}
		return this.poiConBox[type];
	},	
	resetZindexAllTypes: function() {
			//Z-Index bei allen GroupLayern auf initalwert setzen
				
			for (var type in  this.poiConBox){
					 
					 if (typeof(this.poiConBox[type]) == "object" && type!="-1") { // nur bei "richtigen" GroupLayern
					 	var newZ = this.poiConBox[type].origZ;
					 	this.poiConBox[type].style.zIndex = newZ; // Original-Index zuweisen
					}
			}
	},	
	isNonToggleType: function(type){
		for (var index = 0; index < this.config.nonToggleTypes.length; ++index) {
   			var item = this.config.nonToggleTypes[index];
			if (item == type){
				return true;
			} 
  		}
		return false;
	},
	isRadweg: function(type){
		var check = false;
		var rwX = ['rw1','rw2','rw3','rw4','rw5','rw6','rw7','rw8','rw9','rw10','rw11','rw12'];
		for (var index = 0, len = rwX.length; index < len; ++index) {
  			var item = rwX[index];
  			if(type==item){
  				check = true;
  			}
		}
		return check;
	},
	/* TODO: zusammenfassenes in eine RW-Funktion (?) */
	isRadwegRegio: function(type){
		var check = false;
		var rwX = ['rw18'];
		for (var index = 0, len = rwX.length; index < len; ++index) {
  			var item = rwX[index];
  			if(type==item){
  				check = true;
  			}
		}
		return check;
	},
	/* TODO: zusammenfassenes in eine RW-Funktion (?) */
	isRadwegHLMS: function(type){
		var check = false;
		var rwX = ['rw13','rw14','rw15','rw16','rw17'];
		for (var index = 0, len = rwX.length; index < len; ++index) {
			var item = rwX[index];
			if(type==item){
				check = true;
			}
		}
		return check;
	},
	addMetaPOIInfo: function(id,data) {
		if (typeof(this.pointBox[id]) != "object") {
			var type = "meta"
			this.getPOIConBox(type);
			//if (typeof(this.poiConBox[type]) == "object") Element.setStyle(this.poiConBox[type],{visibility:this.serviceIndex.idx[type].getStyle()});
			this.pointBox[id] = this.addNewPoiContainer(this.getPOIConBox("meta"),this.coordinates, this.config,id,data)					
			this.pointBox[id].paint();
		}
	},
	/*
	x lon
	y lat
	id id
	type type
	name name
	*/
	addPOI: function(x,y,id,type,name,idTash, successfullyGeocoded) {
	 	if (this.config.editMode){
			this.pointBox[id] = this.addNewPoi(this,this.container,this.getPOIConBox(type),this.coordinates,new Point(x,y),id,type,name,idTash,this.config,this.eventLogger);

			// Der POI muss nichts davon wissen daß es mehr als 1 Icons-Liste gibt!
			this.pointBox[id].setIcons(this.config.usedIcons);
		
			this.pointBox[id].paint();
			if (typeof(this.poiConBox[type]) == "object"){	
				 Element.show(this.poiConBox[type]);
			} 
			
			//nach erfolgreicher geokodierung sollen die Koord. ins CMS-Formular geschrieben (nicht nur nach manuellem verschieben des POIs)
			if(successfullyGeocoded){
				this.pointBox[id].noticeCoords();
			}
			
					
		} else if(  this.portalClientId !=4 	//es: basetype-Filterung entfernt, da diese bei der Aggregation für TASH/HLMS auf Server-Seite verlagert!  
					|| (this.portalClientId ==4 && !idTash.match(/offer/gi)) ){	
			if (typeof(this.pointBox[id]) != "object") {
				var theVisibility = "hidden";
				var isLayerVisible = false;
				//Fernradwege od. HLMS-Regio-Wege als separate Layer anlegen (beide im HLMS verwenent)
				if (this.isRadweg(type)) {
					if (this.serviceIndex.idx["rw_anhaenger"].isVisible || this.serviceIndex.idx["rw_belag"].isVisible || this.serviceIndex.idx["rw_gesamt"].isVisible || this.config.editMode) {
						theVisibility = "visible";
						isLayerVisible = true;
					}
					this.pointBox[id] = this.addNewPoi(this, this.container, this.getPOIConBox("Radweg"), this.coordinates, new Point(x, y), id, type, name, idTash, this.config, this.eventLogger);
					type = "Radweg";

				}else if (this.isRadwegRegio(type)){
					if(this.serviceIndex.idx["rw_regio_anhaenger"].isVisible || this.serviceIndex.idx["rw_regio_belag"].isVisible || this.serviceIndex.idx["rw_regio_gesamt"].isVisible || this.config.editMode){
						theVisibility = "visible";
						isLayerVisible = true;
					}
					this.pointBox[id] = this.addNewPoi(this,this.container,this.getPOIConBox("RadwegRegio"),this.coordinates,new Point(x,y),id,type,name,idTash,this.config,this.eventLogger);
					type="RadwegRegio";
									
				}else if (this.isRadwegHLMS(type)){
					if(this.serviceIndex.idx["rw_hlms_anhaenger"].isVisible || this.serviceIndex.idx["rw_hlms_belag"].isVisible || this.serviceIndex.idx["rw_hlms_gesamt"].isVisible || this.config.editMode){
						theVisibility = "visible";
						isLayerVisible = true;
					}
					this.pointBox[id] = this.addNewPoi(this,this.container,this.getPOIConBox("RadwegHLMS"),this.coordinates,new Point(x,y),id,type,name,idTash,this.config,this.eventLogger);
					type="RadwegHLMS";
					
				}else{
					this.getPOIConBox(type);
					var isLayerVisible = this.serviceIndex.idx[type].isVisible;				
					if (isLayerVisible || this.config.editMode){
						theVisibility = "visible";
						isLayerVisible=true;
					}
					if (type=="Wetter"){
						this.pointBox[id] = this.addNewWeatherPoi(this,this.container,this.getPOIConBox(type),this.coordinates,new Point(x,y),id,type,name,idTash,this.config,this.eventLogger);
					}else{
						this.pointBox[id] = this.addNewPoi(this,this.container,this.getPOIConBox(type),this.coordinates,new Point(x,y),id,type,name,idTash,this.config,this.eventLogger);
					}
				}
				
				if (typeof(this.poiConBox[type]) == "object"){
					if(isLayerVisible){
				 		Element.show(this.poiConBox[type]);
				 	}else{
				 		Element.hide(this.poiConBox[type]);
				 	}
				} 
				
				// Der POI muss nichts davon wissen daß es mehr als 1 Icons-Liste gibt!
				if (this.portalClientId == 4) this.pointBox[id].setIcons(this.config.usedIconsOSG);
				else this.pointBox[id].setIcons(this.config.usedIcons);

				//if (typeof(this.poiConBox[type]) == "object") Element.setStyle(this.poiConBox[type],{visibility:this.serviceIndex.idx[type].getStyle()});
				this.pointBox[id].paint();
				
				if (this.tileMatrix.mapManager.map.activePoiId == id && !this.config.editMode && !this.config.isMiniMap){
					this.pointBox[id].showPopUp();
				}else if (this.tileMatrix.mapManager.map.activePoiIdTash == idTash && !this.config.editMode 
							&& type != "Radweg" && !this.config.isMiniMap
							){   //ES: bei radwegepois ist die idTash für alles pois des Radweges gleich -> es würden dann alle geöffnet
					this.pointBox[id].showPopUp();
				}						
			}
		}else{
			var a = 1;
		}
	},
	addSubsetPOI: function(x,y,id,type,name,idTash, successfullyGeocoded) {
		if (typeof(this.pointBox[id]) != "object") {
			this.getPOIConBox(type);
			this.pointBox[id] = this.addNewPoi(this,this.container,this.getPOIConBox(type),this.coordinates,new Point(x,y),id,type,name,idTash,this.config,this.eventLogger);
			this.pointBox[id].setClickAction("zoomTo");
			
			//die SubsetPOI sollen in 2 + 3 Zoomstufe etwas größer sein (2/3 der orig.Icons)
			var iconList = null;
			switch(this.config.zoomLevel){
				case 1:
					iconList = this.getSubsetIconsForPortal(this.portalClientId).smallSize;
					break;
				case 2:
					iconList = this.getSubsetIconsForPortal(this.portalClientId).mediumSize;
					break;
				case 3:
					iconList = this.getSubsetIconsForPortal(this.portalClientId).mediumSize;
					break;
				default:	//sollte eigentlich nicht eintreten
					iconList = this.getSubsetIconsForPortal(this.portalClientId).mediumSize;
		    		break;
			}
			this.pointBox[id].setIcons(iconList);
		}
/*		if (typeof(this.poiConBox[type]) == "object"){
	 		Element.show(this.poiConBox[type]);
		} 
*/
		this.pointBox[id].paint();
	},
	addStandalonePOI: function(x,y,id,type,name,idTash,isBubble,idx) {
		if (typeof(this.pointBox[id]) != "object") {
			this.getPOIConBox("standalone");
			this.pointBox[id] = this.addNewPoi(this,this.container,this.getPOIConBox("standalone"),this.coordinates,new Point(x,y),id,type,name,idTash,this.config,this.eventLogger);					
			this.pointBox[id].paint();
			if(isBubble && !this.config.editMode){
				this.pointBox[id].idx = idx;
				
				if(idx && idx >= 100) { //3stellige kriegen größeres Bubble
					this.pointBox[id].showBubble('big');
				}else{
					this.pointBox[id].showBubble();					
				}
			}
			if (this.tileMatrix.mapManager.map.activePoiId == id && !this.config.editMode){
				this.pointBox[id].showPopUp();
			}else if (this.tileMatrix.mapManager.map.activePoiIdTash == idTash && !this.config.editMode){
				this.pointBox[id].showPopUp();
			}	
		}
	},
	/**
	* Teaser-Bildern zur Karte hinzufügen.
	* estykow
	*/
	addStandaloneTeaserPOI: function(x,y,id,type,name,idTash,isBubble,idx) {
		if (typeof(this.pointBox[id]) != "object") {
			this.getPOIConBox("standalone");
			//TODO: Anzeige ohne POI-Icon
			this.pointBox[id] = this.addNewTeaserPoi(this,this.container,this.getPOIConBox("standalone"),this.coordinates,new Point(x,y),id,type,name,idTash,this.config,this.eventLogger);
			//this.pointBox[id].setIcons(this.config.usedIconsPOISubset);					
			this.pointBox[id].paint();
			if(isBubble && !this.config.editMode){
				this.pointBox[id].idx = idx;
				this.pointBox[id].showBubble();
			}
			
			//PopUp immer öffnen
			this.pointBox[id].showPopUp();
				
		}
	},	
	
	hidePOIs: function(type) {
		var idx = this.serviceIndex.idx[type];
		if (idx != undefined && typeof(idx) == "object"){

			this.serviceIndex.idx[type].isVisible=false;

			this.hidePOIDiv();

			this.updatePOIContainer();
		}
	},
	showPOIs: function(type) {

		var idx = this.serviceIndex.idx[type];

		if (idx != undefined && typeof(idx) == "object"){

			this.serviceIndex.idx[type].isVisible=true;

			this.showPOIDiv(type);
			
			if (typeof(this.poiConBox[type]) != "object")
				this.loadPOIs();

			this.updatePOIContainer();
		}

	},
	hidePOIDiv: function(type) {
		var poiDivBox = this.poiConBox[type];

		// wir haben einen div container, also zeigen wir ihn.			
		if (typeof(poiDivBox) != 'undefined' && typeof(poiDivBox) == "object") {
			Element.hide(this.poiConBox[type]);
		}
	},
	showPOIDiv: function(type) {
		var poiDivBox = this.poiConBox[type];

		// wir haben einen div container, also zeigen wir ihn.			
		if (typeof(poiDivBox) != 'undefined' && typeof(poiDivBox) == "object") {
			////console.debug("showing "+type);
			Element.show(this.poiConBox[type]);
		}
	},
	updatePOIContainer: function() {
		if (this.poiContainerList.length>0) {	//aggregated pois
			for (var i = 0; i < this.poiContainerList.length; i++){
				if (this.poiContainerList[i].classname=="PoiContainer"){		
					this.poiContainerList[i].repaintPoiContainer();
				}						
			}
			try
			{
				this.tileMatrix.mapManager.map.activePoi.paintPoilistContainer(this.tileMatrix.mapManager.map.activePoi.clickedType, this.tileMatrix.mapManager.map.activePoi.types.typeArrays[this.tileMatrix.mapManager.map.activePoi.clickedType]);
			}catch(e){}
		}
	},
	updatePOIs: function() {
		for (var one in this.pointBox) {
		//for (var i = 0; i < this.pointBox.length; i++){
			if (typeof(this.pointBox[one]) == "object"){
				 this.pointBox[one].update();
			}
		}
	},
	removePOIs: function() {

		for (var one in this.pointBox) {
			if (typeof(this.pointBox[one]) == "object") this.pointBox[one].remove();
		}
		this.pointBox = new Array();
		
		if (typeof(this.poiCon) == "object" && typeof(this.container) == "object") this.container.removeChild(this.poiCon);
	},
	remove: function() {
		this.tileMatrix = null;
		this.coordinates = null;
		this.container = null;
		this.config = null;
	},
	getSubsetIconsForPortal: function(portalClientId){
		var iconList ; 
		
		//OSG-Portal hat andere Icons und Kategorie-Bezeichnungen as TASH (+ HMLS usw.)		
		if(portalClientId ==4){
			//OSG
			iconList = this.config.usedIconsPOISubsetOSG;
		} else{
			//TASH, HLMS u.ä.
			iconList = this.config.usedIconsPOISubset;
		}
		
		return iconList ;
	}
};

/*	Point
 * 
 * Point is the most advanced class in the whole code.
 * 
 */
Point = Class.create();
Point.prototype = {
	initialize: function(x,y) {
		this.x = x;
		this.y = y;
	},
	setX: function(x) {
		this.x = x;
	},
	setY: function(y) {
		this.y = y;
	},
	getX: function() {
		return this.x;
	},
	getY: function() {
		return this.y;
	},
	setXY: function (x,y) {
		this.x = x;
		this.y = y;
	},
	getXY: function() {
		return new Array(this.x,this.y);
	}
}

/*	PopUp
 * 
 * The PopUp object itself. All things displaying. Filling the template.
 * 
 */
PopUp = Class.create();
PopUp.prototype = {
	initialize: function(poi,parent,offsetX,offsetY,hasDelayClose) {
		this.poi = poi;
		this.container = parent;
		this.offsetX = offsetX;
		this.offsetY = offsetY;
		this.height=0;
		this.width=0;
		this.hideCountdown = null;
		this.hasDelayClose = hasDelayClose;
		this.cancelCloseObserver = this.cancelClose.bindAsEventListener(this);
		this.triggerCloseObserver = this.triggerClose.bindAsEventListener(this);
		this.clickObserver = this.close.bindAsEventListener(this);
		
		this.items = new Array();		
		this.color;
	},
	open: function() {
		this.cancelClose();
		this.create();
		if (this.poi.data == null) this.poi.loadDataFromServlet();
		else this.fill();
	},
	triggerClose: function() {
		if (this.hideCountdown == null) {
			this.hideCountdown = setTimeout(this.close.bind(this),2000);
		}
	},
	cancelClose: function() {
		if (this.hideCountdown != null) {
			clearTimeout(this.hideCountdown);
			this.hideCountdown = null;
		}
	},
	close: function() {
		try {this.container.removeChild(this.div);}
		catch(e){}
		this.hideCountdown = null;
	},
	clear: function() {
		if (typeof(this.div) == "object") {
			while ( this.div.hasChildNodes() ) { 
				this.div.removeChild(this.div.firstChild);
			}
		}
	},
	create: function() {
		if (this.div == null) {
			this.div = document.createElement("div");
			this.div.id = this.poi.id+"_popUp";
		
			Element.addClassName(this.div,"popUp");
		}
		this.position();

		this.container.appendChild(this.div);
	},
	position: function() {
		var pixelPos = this.poi.getPxCoords();
		//Element.setStyle(this.div,{position:"absolute",top:"0px",left:"22px"});
		Element.setStyle(this.div,{position:"absolute",top:this.offsetY+"px",left:this.offsetX+"px", zIndex:1});
	},
	setOffset: function(x, y){
		this.offsetY = y;
		this.offsetX = x;
	},
	/**
	 * Füllt das komplette PopUp.
	 */
	fill: function() {		
		var template = this.getTemplateByColor(this.color);
		

		for (var key in this.poi.data) {
			var imgClass = "thumbnail"; //default für previewImage
			
			var usedKey = key;
			var replaceWith = this.poi.data[key];
			
			//keine fixe Bildabmessung zuweisen (sonst verzerrt) bei
			if (usedKey == "previewImage" && this.poi.data.certifiedBnB) {  //zertifizierten Bett&Bike (Logo, statt Foto)
				replaceWith = this.poi.config.certifiedBnBLogo;
				var imgClass = "thumbnail_a4"; 
			}
			if(usedKey == "imageUrl" && (this.poi.poiManager.isRadweg(this.poi.type) 
				|| this.poi.poiManager.isRadwegRegio(this.poi.type)
				|| this.poi.poiManager.isRadwegHLMS(this.poi.type))){					//bei Radwege-Popups 
				var imgClass = "thumbnail_a4"; 
			}
			
			if (replaceWith != "") {
				switch (usedKey) {
					case "previewImage":
					case "imageUrl":  //Radwege					
						replaceWith = "<img src=\""+replaceWith+"\" alt=\"\" class=\""+imgClass +"\" />";
						break;
					case "phone1":
						replaceWith = "Fon: "+replaceWith+"<br />";
						break;
					case "email":
						replaceWith = "<a href=\"mailto:"+replaceWith+"\" title=\""+replaceWith+"\" class=\"smaller_link\">&gt; E-Mail</a>";
						break;
					case "homepage":
						//bei Radwegen ist die Homepage ohne Protokoll in DB 
						//-> bereinigen, wenn andere POIS auch eine Hopemage "kriegen"
						replaceWith = "<a href=\"http://"+replaceWith+"\" title=\""+replaceWith+"\" class=\"smaller_link\" target=\"_blank\">&gt; Homepage</a>";
						break;
					case "address1Street": //ist mit hausnummer
						replaceWith = replaceWith+"<br />";
						break;
					case "address1City":
						replaceWith = replaceWith+"<br />";
						break;
					/*
					 es: nicht mehr nötig, da str+nr in div gepackt 
					 case "streetNumber":
						replaceWith = replaceWith+"<br />";
						break;*/
					case "city":
						replaceWith = replaceWith+"<br />";
						break;
					case "shortDescription":
						if(replaceWith.match(/Länge/gi)) {
							replaceWith = replaceWith.replace(/Länge/gi,"<br />Länge");
						}
						if(this.poi.type == "FahrradverleihReparaturservice"){
							replaceWith = replaceWith.replace(/;/,"<br />"); //; als Trennzeichen für die beiden Flags vereinbart
						}
						break;
					case "name":
						if (replaceWith.length > this.poi.config.maxNameLength) {
							replaceWith = replaceWith.substring(0,this.poi.config.maxNameLength)+"...";
						}
						break;
					case "addressbaseName":
						replaceWith = replaceWith+"<br />";
						break;
					case "link": 		//bei Radwegen
					case "detailLink":
						//TODO: Block als Funktion auslagern und dann in TeaserPopUp überschreiben
						if (replaceWith != "null" && this.color != 'plainTeaser') {
							replaceWith = "<p class=\"morelink\"><a href=\"" + replaceWith + "\">&gt; Mehr</a></p>";
						} else if (replaceWith != "null" && this.color == 'plainTeaser') { //ES: bei Teaser nur die URL; da als HREF für Bild verwende ->  URLY!
							replaceWith =  replaceWith ;
						} else{
							//damit nicht der String "null" nicht drin steht 
							replaceWith = "";
						}
						break; 																
					case "offerDetailLinks": //Liste der Angebote einer Addressbase
						var linktTextNice = "";  //hilfvariablen   
						var linktTitle = "";
						       
						var detailLinks= replaceWith ; 	//Array-Daten sichern ...
						replaceWith = "<br />Angebote:<br />";  				//... da in replaceWith fertiges HTML reinkommt
						for (var i = 0; i < detailLinks.length; i++) {	
								if(detailLinks[i].offerTitle.length > 25){
									linktTextNice= detailLinks[i].offerTitle.substring(0,25)+"...";
									linktTitle = detailLinks[i].offerTitle; //hover-Title nur bei langen 						
								} else{
									linktTextNice = detailLinks[i].offerTitle;
								}
								replaceWith += "<p class=\"morelink\"><a href=\"" + detailLinks[i].offerUrl + "\" title=\""+linktTitle+"\">&gt; "+linktTextNice+"</a></p>";
							
						}
						break; 																
				}
			}
			else {
				// wenn kein Bild vorhanden ist, dann kleben wir die
				// Adresse an die linke Seite
				if (usedKey == "previewImage") {
					var changeClassExpr = new RegExp('<p class="address">',"g");
					template = template.replace(changeClassExpr,'<p class="address-left">');
				}
			}
			var toReplace = new RegExp("_"+usedKey+"_","g");
			template = template.replace(toReplace,replaceWith);
		}
		// now clean up every tag which is not used
		for (var i = 0; i < this.poi.config.popUpTagNames.length ; i++) {
			var toReplace = new RegExp("_"+this.poi.config.popUpTagNames[i]+"_","g");
			template = template.replace(toReplace,"");
		}
		this.div.innerHTML = template;
		
		var c = this.div.getElementsByClassName('overlay-window')[0];
		var dims = c.getDimensions();
		var popupWidth = dims.width;
		var popupHeight = dims.height;
		this.width=popupWidth;
		this.height=popupHeight;
	},
	getTemplateByColor: function(color){
		var template = null;
		
		switch (color) {
		  case "gray":
		   	template = this.poi.config.popUpTemplateGray;
		  	break;
		  case "gray10":
		   	template = this.poi.config.popUpTemplateGray10;
		  	break;
		  case "gray20":
		   	template = this.poi.config.popUpTemplateGray20;
		  	break;
		  case "orange":
		  	template = this.poi.config.popUpTemplateOrange;
		  	break;
		  case "blue":
		  	template = this.poi.config.popUpTemplateBlue;
		  	break;
		  case "blue60":
		  	template = this.poi.config.popUpTemplateBlue60;
		  	break;
		  case "blue80":
		  	template = this.poi.config.popUpTemplateBlue80;
		  	break;
		  case "green91":
		  	template = this.poi.config.popUpTemplateGreen91;
		  	break;
		  case "green92":
		  	template = this.poi.config.popUpTemplateGreen92;
		  	break;		
		  case "green130":
		  	template = this.poi.config.popUpTemplateGreen130;
		  	break;		
		  case "rw":
		  	template = this.poi.config.popUpTemplateRW;
		  	break;	    
		  case "plainTeaser":
		  	template = this.poi.config.plainTeaser;
		  	break;	    		  	
		  default:
		    template = this.poi.config.popUpTemplateGreen;
		    break;
		}
		return template;
	}
}

ServiceIndex = Class.create();
ServiceIndex.prototype = {
	initialize: function(portalClientId){
		
		//1. initialisieren/definieren
		this.idx= { 
			"Article":{isVisible:false},
			"Offer":{isVisible:false},
			"Event":{isVisible:false},
			"Tourismusinformation":{isVisible:false},
			"Bahnhof":{isVisible:false},
			"HotelPension":{isVisible:false},
			"FerienwohnungHaus":{isVisible:false}, 
			"Campingplatz":{isVisible:false},
			"Jugendherberge":{isVisible:false},
			"Bauernhof":{isVisible:false},
			"BettBike":{isVisible:false},
			"WellnesshotelBeautyfarm":{isVisible:false},
			"Gastronomie":{isVisible:false},
			"MuseumDenkmal":{isVisible:false},
			"Theater":{isVisible:false},
			"SchlossGarten":{isVisible:false},
			"KlosterKirche":{isVisible:false},
			"Freizeitpark":{isVisible:false},
			"TierparkZoo":{isVisible:false},
			"StrandBaden":{isVisible:false},
			"Naturerlebnis":{isVisible:false},
			"Segeln":{isVisible:false},
			"FahrradverleihReparaturservice":{isVisible:false},
			"AbschliessbareFahrradbox":{isVisible:false},
			"RastplatzSchutzhuette":{isVisible:false},
			"Golfen":{isVisible:false},
			"Reiten":{isVisible:false},
			"Wetter":{isVisible:false},
			"meta":{isVisible:false},
			"baseMap":{isVisible:true},
			"Radweg":{isVisible:false},
			"rw_anhaenger":{isVisible:false},
			"rw_belag":{isVisible:false},
			"rw_gesamt":{isVisible:false},
			//"myFirstVectorContainer":{isVisible:true},
			//Regio-Radwege 
			"RadwegRegio":{isVisible:false},
			"rw_regio_anhaenger":{isVisible:false},
			"rw_regio_belag":{isVisible:false},
			"rw_regio_gesamt":{isVisible:false},
			//HLMS-Radwege 
			"RadwegHLMS":{isVisible:false},
			"rw_hlms_anhaenger":{isVisible:false},
			"rw_hlms_belag":{isVisible:false},
			"rw_hlms_gesamt":{isVisible:false},
			//Salesguide
			"Busunternehmen":{isVisible:false},
			"ReedereiSchiffFaehre":{isVisible:false},
			"Flughafen":{isVisible:false},
			"Appartmenthaus":{isVisible:false},
			"Ferienpark":{isVisible:false},
			"Gasthof":{isVisible:false},
			"Erlebnisbad":{isVisible:false},
			"NaturerlebniszentrumAquarium":{isVisible:false},
			"Veranstaltungen":{isVisible:false},
			"Leuchttuerme": {isVisible: false},
			"CmsArtikel": {isVisible: false}
		};
		
		//Hardcodierung der Anzeige von B+ TIs entfernt (siehe 0002999); jetzt von IMX gesteuert
		
		////console.debug("ServiceIndex intialisiert (Portal: "+portalClientId+")");
	},
	
	//ES
	isFernradwegeVisible: function (){
		var result = false;
		
		if(	this.idx["rw_gesamt"].isVisible == true | 
			this.idx["rw_belag"].isVisible == true | 
			this.idx["rw_anhaenger"].isVisible == true ) result = true;
		
		return result; 
	}
};
/**
 * Merkt sich den Zustand der Karte.
 * 
 */
State = Class.create();
State.prototype = {
	initialize: function(lat, lon, zoomLevel, serviceIndex) {
		this.lat = lat;
		this.lon = lon;
		this.zoomLevel = zoomLevel;
		this.serviceIndex = serviceIndex;
		
		this.activePoiIdTash = null;
		this.activePoiId  = null;
	},	
	/**
	 * Merken des zuletzt geöffneten PopUps 
	 * 
	 * ToDo: die mapinnter-variablen activepoiid etc. durch eine Implementierung hier ersetzen?
	 * @param {Object} poiId
	 * @author estykow
	 */
	setActivePoiId: function(poiId){
		this.activePoiId = poiId;
	},
	setActivePoiIdTash: function(poiIdTash){
		this.activePoiIdTash = poiIdTash;
	},
	getActivePoiId: function(){
		return this.activePoiId ;
	},
	getActivePoiIdTash: function(){
		return this.activePoiIdTash;
	}
}
/**
 * @author cknote
 * 
 * Tile is an abstract class to define any tile which
 * can be drawn on the map. Should normally be
 * contained by some ContentContainer derived species.
 * Default configuration resembles MapTile.
 */
 
Tile = Class.create();
Tile.prototype = {
	initialize: function(container,config,mapSource,tMWidth,tMHeight) {
		this.container = container;
		this.config = config;
		this.mapSource = mapSource;		
		this.tMWidth = tMWidth;
		this.tMHeight = tMHeight;

		if (this.config) {
			this.tileSize = { width: this.config.tileWidth, height: this.config.tileHeight};
			this.mapSize = { width : this.config.width, height : this.config.height};
			this.borderCache = this.config.borderCache;
		}
		if (this.mapSource) {
			this.coordinates = this.mapSource.coordinates;
		}

		// will hold vectors / map tile image obj
		// (whatever one can add to the DOM)
		this.tile = null;
		
		this.drawn = false;
	},
	
	// getter / setter
	getTileSize: function() {
		return this.tileSize;
	},
	setTileSize: function(width,height) {
		this.tileSize.width = width;
		this.tileSize.height = height;
	},
	getMapSize: function() {
		return this.mapSize;
	},
	setMapSize: function(width,height) {
		this.mapSize.width = width;
		this.mapSize.height = height;
	},
	getBorderCache: function() {
		return this.borderCache;
	},
	setBorderCache: function(cache) {
		this.borderCache = cache;
	},
	getIndex: function() {
		return new Array(this.xIndex,this.yIndex);
	},
	setIndex: function(x,y) {
		this.xIndex = x;
		this.yIndex = y;
	},
	
	// external routines
	
	create: function() {
		this.tile = document.createElement("img");
		Element.addClassName(this.tile,"tile");

		// calculate rw bounds to be able to know when to draw / remove
		this._setBounds();
		
		// prepare position
		this._position();
	},
	paint: function() {
		if (this.drawn) return;

		this._position();
		this._getContent();
		this.container.appendChild(this.tile);

		this.drawn = true;
	},
	check: function(pxXoff,pxYoff) {
		// ////console.debug("checking: "+this.x+"-"+pxXoff+" against "+this.lowerXBound);
		if ((this.x - pxXoff) < this.lowerXBound) {
			this._moveTo(this.xIndex + this.tMWidth,this.yIndex);
			return;
		}
		if ((this.x - pxXoff) > this.upperXBound) {
			this._moveTo(this.xIndex - this.tMWidth,this.yIndex);
			return;
		}
		if ((this.y - pxYoff) < this.lowerYBound) {
			this._moveTo(this.xIndex,this.yIndex + this.tMHeight);
			return;
		}
		if ((this.y - pxYoff) > this.upperYBound) {
			this._moveTo(this.xIndex,this.yIndex - this.tMHeight);
			return;
		}
	},	
	remove: function() {
		try {
			this.container.removeChild(this.tile);
		}
		catch(e) {}
		this.tile = null;
		this.config = null;
		this.mapSource = null;
		this.drawn = false;
	},
	
	// internal functions
	
	_moveTo: function(xIndex,yIndex) {
		// set a new index
		this.setIndex(xIndex,yIndex);
		this._repaint();
		
	},
	_repaint: function() {
		this._getContent();

		this._position();
	},
	_getContent: function() {
		if (typeof(this.tile) == "object") {
			this.tile.src = this.mapSource.getSrc(this.xIndex,this.yIndex);
		}
	},
	_setBounds: function() {
		this.lowerXBound = -this.tileSize.width*this.borderCache;
		this.upperXBound = this.mapSize.width + this.tileSize.width*this.borderCache;
		this.lowerYBound = -this.tileSize.height*this.borderCache;
		this.upperYBound = this.mapSize.height + this.tileSize.height*this.borderCache;
	},
	_position: function() {
		this.x = this.xIndex * this.tileSize.width;
		this.y = this.yIndex * this.tileSize.height;

		if (typeof(this.tile) == "object") {
			Element.setStyle(this.tile,{top:this.y+"px",left:this.x+"px"});
			Element.setStyle(this.tile,{width:this.tileSize.width+"px",height:this.tileSize.height+"px"});
		}
	}
}

/**
 * @author cknote
 *
 * Currently the same as the base Tile type. 
 * A normal map image tile.
 *
 */

MapTile = Class.create();
MapTile.prototype = Object.extend(new Tile(),{
});

/**
 * @author cknote
 *
 * A VectorTile is the vector analogon to a MapTile,
 * it can hold vectorShapes and draw them on a specific
 * position on the map. It has the ability to load features from
 * the server when instructed so - in the same manner
 * a map tile is requested to check its position.
 *
 */

VectorTile = Class.create();
VectorTile.prototype = Object.extend(new Tile(), {
	create: function() {
		dojo.require("dojox.gfx");

		this.tile = document.createElement("div");
		Element.addClassName(this.tile,"tile");
		Element.setStyle(this.tile,{width:this.tileSize.width+"px",height:this.tileSize.height+"px"});

		this.surface = dojox.gfx.createSurface(this.tile,this.tileSize.width, this.tileSize.height);

		this.shapeBox = new Array();
		
		// calculate rw bounds to be able to know when to draw / remove
		this._setBounds();
		
		// prepare position
		this._position();
	},
	remove: function() {
		this.surface.clear();
		try {
			this.container.removeChild(this.tile);
		}
		catch(e) {}
		this.surface = null;
		this.tile = null;
		this.config = null;
		this.mapSource = null;
	},
	
	// internal
	
	_getContent: function() {

		//{"0":{idTash:"aS_2_113",type:"meta",name:"Aggregation",points:[[100,120]]}}
		//"scripts/application/vectorTest.json", 
		//"http://www.sh-tourismus.de/tash/controller/extent?",
		var params = "minX=3325819.1516&minY=5820183.5153&maxX=3658401.0668&maxY=5986474.4729&mapScale="+this.coordinates.getCurrentScale()+"&sessionId=0&topics=0&areas=0&targetGroups=0&aggregationMode=subset&portalClientId=2&layers=myFirstVectorContainer";
		//{"0":{idTash:"aS_2_113",type:"meta",name:"Aggregation",points:[[100,120]]}}
		this.request = new Ajax.Request(
			//"http://www.sh-tourismus.de/tash/controller/extent?",
			//"/tash/controller/extent?",
			"scripts/application/vectorTest.json",
			{
				method: "get",
				parameters: params,
				onComplete:this._add.bind(this)
			}
		);
	},
	_add: function(rawData) {
		var evaluatedData = null;
		
//		////console.debug("trying to add some shapes");
		
		try{
			evaluatedData = eval( "("+rawData.responseText+")" );
		}
		catch(e) {}

		for (var item in evaluatedData) {
			try {
				var one = evaluatedData[item];
//				changed to accomodate fake use of extent servlet...
//				one.points = [[one.lon,one.lat]];
				
				this._addShape(one);
				
//				////console.debug("adding shape successful ID: "+one.idTash+" type:"+one.type);
			}
			catch(ex) {
				////console.debug("adding shape did not work out ID: "+one.idTash+" type:"+one.type);
			}
		}
//		////console.debug("added "+length(this.shapeBox)+" shapes");
	},
	_addShape: function(shapeObj) {
//		////console.debug("add shape");
//		////console.debug(shapeObj);
	
		var newShape = null;
		switch(shapeObj.shapeType) {
			case "poly":
				newShape = new VectorPoly(this.config,this.surface,this.coordinates);
				break;
			case "line":
				newShape = new VectorLine(this.config,this.surface,this.coordinates);
				break;
			default:
				newShape = new VectorPoint(this.config,this.surface,this.coordinates);
				break;
		}
		// add coordinate offset to enable drawing on abs. positioned tiles
		newShape.setOffset(this.x,this.y);
		newShape.setSurfaceSize(this.tileSize.width,this.tileSize.height);
		
		newShape.setPoints(shapeObj.points,true);
		newShape.setType(shapeObj.type);
		newShape.setShapeType(shapeObj.shapeType);
		newShape.setName(shapeObj.name);
		// where to draw popups onto
		newShape.setPopupCon(this.container); 

		this.shapeBox.push(newShape);

//		////console.debug("now painting");

		// could be separated...
		this.shapeBox[this.shapeBox.length - 1].paint();
		
//		////console.debug("done");
	}
});

/**
 * @author cknote
 * 
 * TileMatrix is responsible for all kinds of tile shuffling, how the tiles will be draw,
 * when they will load...
 * 
 */
TileMatrix = Class.create();
TileMatrix.prototype = {

	// constructor

	initialize: function(mapManager,config,parent, portalClientId) {
		this.parent = parent;
		this.serviceIndex = mapManager.serviceIndex;
		this.poiBox = null;
		this.config = config;
		this.mapManager = mapManager;
		
		this.container = document.createElement("div");
		this.parent.appendChild(this.container);

		this.coordinates = new AGS_Coordinates(this.config,this);

		// check if the chosen center coordinates lie within config.visibleBounds
		var newCenter = this.validateCenterCoordinates(this.config.lat,this.config.lon);
		this.config.lon = newCenter[0];
		this.config.lat = newCenter[1];

		this.portalClientId = portalClientId;
		
		// hold the tile containers (i.e. layers of the map) and the
		// corresponding map sources.
		// should be able to clone a map source, but threw errors...
		this.tileContainer = new Array();
		this.mapSources = new Array();
		
//		//TODO: Komplett aus Config auslesen (pfad, extension) -> Angedacht: config.tileCOntainerSourceConfisgGanzLangVariable... 
		this.addTileContainer("baseMap", "200908/tash_bg_jpg/Digitaler Atlas SH/_alllayers/L", this.config.mapTileImgFormat);
		
		//ES: hardcodete Vektor-Bsp ertmal nicht anzeigen; erst wenn Vektoren komplett umgesetzt werden sollen
		//this.addVectorContainer("myFirstVectorContainer","tash_bg/Digitaler Atlas SH/_alllayers/L");
		
		//RadwegeLayer einbinden (Portalen: unterschiedliche Hierarchie)
		if ( portalClientId == 2 ) {
			/*this.addTileContainer("rw_hlms_gesamt", "hlms_rw_g/Digitaler Atlas SH/_alllayers/L", this.config.mapTileImgFormatTransparent);
			this.addTileContainer("rw_hlms_belag", "hlms_rw_b/Digitaler Atlas SH/_alllayers/L", this.config.mapTileImgFormatTransparent);
			this.addTileContainer("rw_hlms_anhaenger", "hlms_rw_a/Digitaler Atlas SH/_alllayers/L", this.config.mapTileImgFormatTransparent);*/
			//TASH: Fernradwege über den Region anzeigen (0003000)

			this.addTileContainer(this.config.radwegeLayerConf['regioradwege'][0].layername, this.config.radwegeLayerConf['regioradwege'][0].path, this.config.mapTileImgFormatTransparent);
			this.addTileContainer(this.config.radwegeLayerConf['regioradwege'][1].layername, this.config.radwegeLayerConf['regioradwege'][1].path, this.config.mapTileImgFormatTransparent);
			this.addTileContainer(this.config.radwegeLayerConf['regioradwege'][2].layername, this.config.radwegeLayerConf['regioradwege'][2].path, this.config.mapTileImgFormatTransparent);
			
			this.addTileContainer(this.config.radwegeLayerConf['fernradwege'][0].layername, this.config.radwegeLayerConf['fernradwege'][0].path, this.config.mapTileImgFormatTransparent);
			this.addTileContainer(this.config.radwegeLayerConf['fernradwege'][1].layername, this.config.radwegeLayerConf['fernradwege'][1].path, this.config.mapTileImgFormatTransparent);
			this.addTileContainer(this.config.radwegeLayerConf['fernradwege'][2].layername, this.config.radwegeLayerConf['fernradwege'][2].path, this.config.mapTileImgFormatTransparent);

		} else if(portalClientId == 3){
			//TASH: Region-RW über den Fernradwege anzeigen 
			this.addTileContainer(this.config.radwegeLayerConf['fernradwege'][0].layername, this.config.radwegeLayerConf['fernradwege'][0].path, this.config.mapTileImgFormatTransparent);
			this.addTileContainer(this.config.radwegeLayerConf['fernradwege'][1].layername, this.config.radwegeLayerConf['fernradwege'][1].path, this.config.mapTileImgFormatTransparent);
			this.addTileContainer(this.config.radwegeLayerConf['fernradwege'][2].layername, this.config.radwegeLayerConf['fernradwege'][2].path, this.config.mapTileImgFormatTransparent);

			this.addTileContainer(this.config.radwegeLayerConf['hlmsradwege'][0].layername, this.config.radwegeLayerConf['hlmsradwege'][0].path, this.config.mapTileImgFormatTransparent);
			this.addTileContainer(this.config.radwegeLayerConf['hlmsradwege'][1].layername, this.config.radwegeLayerConf['hlmsradwege'][1].path, this.config.mapTileImgFormatTransparent);
			this.addTileContainer(this.config.radwegeLayerConf['hlmsradwege'][2].layername, this.config.radwegeLayerConf['hlmsradwege'][2].path, this.config.mapTileImgFormatTransparent);

		} else{
			this.addTileContainer(this.config.radwegeLayerConf['fernradwege'][0].layername, this.config.radwegeLayerConf['fernradwege'][0].path, this.config.mapTileImgFormatTransparent);
			this.addTileContainer(this.config.radwegeLayerConf['fernradwege'][1].layername, this.config.radwegeLayerConf['fernradwege'][1].path, this.config.mapTileImgFormatTransparent);
			this.addTileContainer(this.config.radwegeLayerConf['fernradwege'][2].layername, this.config.radwegeLayerConf['fernradwege'][2].path, this.config.mapTileImgFormatTransparent);
			
		}
		

		// map source is unfortunatley used in other contexts to,
		// so provide the old link...
		this.mapSource = this.mapSources[0];

		Element.setStyle(this.container,{position:"absolute",top:-this.mapSource.pxYoff+"px",left:-this.mapSource.pxXoff+"px"});	

		this.tMWidth = 0;
		this.tMHeight = 0;
		this.hidden = false;
		
		this.checkTilesObserver = null;
		this.prepare();

		this.setTileConVisibility();
	},

	// external functions

	addTileContainer: function(name, url, tileExtension) {
		this.mapSources.push(new AGS_MapSource(this.config,this.coordinates, url, tileExtension));
		
		var aTileCon = new TileContainer(this.mapSources[this.mapSources.length-1], this.container, this.config, name);
		this.tileContainer.push(aTileCon);
	},
	addVectorContainer: function(name,url) {
		this.mapSources.push(new AGS_MapSource(this.config,this.coordinates, url, null ));
		
		var aTileCon = new VectorContainer(this.mapSources[this.mapSources.length-1], this.container, this.config, name);
		aTileCon.setTileSize(512,512);
		//plural
		this.tileContainer.push(aTileCon);
	},
	prepare: function() {
		this.coordinates.prepare();
		for (var i = 0; i < this.tileContainer.length ; i++) this.tileContainer[i].prepare();
	},
	setHidden: function() {
		this.hidden = true;
		if (this.container) Element.setStyle(this.container,{visibility:"hidden"});
	},
	setVisible: function() {
		this.hidden = false;
		if (this.container) Element.setStyle(this.container,{visibility:"visible"});
	},
	setTileConVisibility: function() {
		for (var i = 0; i < this.tileContainer.length ; i++){
			var aTileCon = this.tileContainer[i];
			
			if (this.serviceIndex.idx[aTileCon.name].isVisible) aTileCon.show();
			else aTileCon.hide();
		}
	},
	show: function(tcName){
		for (var i = 0; i < this.tileContainer.length ; i++){
			if (this.tileContainer[i].name == tcName){
				this.tileContainer[i].show();
			}
		}
	},
	hide: function(tcName){
		for (var i = 0; i < this.tileContainer.length ; i++){
			if (this.tileContainer[i].name == tcName){
				this.tileContainer[i].hide();
			}
		}
	},
	paint: function() {
		for (var i = 0; i < this.tileContainer.length ; i++) {
			if (this.serviceIndex.idx[this.tileContainer[i].name].isVisible) {
				this.tileContainer[i].paint();
			}
		}
		// if we enable POIs, we create a new POI manager and attach it to the map (internal)
		if (this.config.hasPOIs) {
			this.poiBox = new POIManager(this, this.portalClientId);
		}		
		this._startCheckTiles();
	},
/*	never called??
	loadPOIs: function(){
		//////console.debug("TileMatrix.loadPOI("+layer+")");
		if (this.config.hasPOIs) {
			this.poiBox.loadPOIs();
		}
	},
*/
	startCaching: function() {
		//////console.debug("TileMatrix.startCaching()");
		if (this.config.hasPOIs) {
			// create a new POI Cache to draw POIs, if edit session, use edit cache
			if (this.config.editMode) this.poiBox.setPoiCache(new EditPOICache(this.poiBox));
			else this.poiBox.setPoiCache(new POICache(this.poiBox,this.serviceIndex,this.tMWidth,this.tMHeight, this.portalClientId));
			// start caching and provide listener dispenser for move listening
			this.poiBox.startCaching(this.mapManager.listenerDispenser);
		}
	},
	removePOIs: function() {
		if (this.config.hasPOIs) {
			this.poiBox.stopCaching();
			this.poiBox.removePOIs();
		}
	},
	move: function(deltaX,deltaY) {
		var bb = this.coordinates.getBB();
		var rwStep = [deltaX * this.coordinates.getCurrentResolution(), deltaY * this.coordinates.getCurrentResolution()];

		// upper right boundary check
		if (deltaX > 0) {
			if ((bb[0][0] - rwStep[0]) <= this.config.visibleBounds.ul[0]) deltaX = 0;
		}
		if (deltaY > 0) {
			if ((bb[0][1] + rwStep[1]) >= this.config.visibleBounds.ul[1]) deltaY = 0;
		}
		// lower right boundary check
		if (deltaX < 0) {
			if ((bb[1][0] - rwStep[0]) >= this.config.visibleBounds.lr[0]) deltaX = 0;
		}
		if (deltaY < 0) {
			if ((bb[1][1] + rwStep[1]) <= this.config.visibleBounds.lr[1]) deltaY = 0;
		}
		
		// last check for ugly deltas:
		deltaX = Math.round(deltaX);
		deltaY = Math.round(deltaY);

		this.container.style.left = this.container.style.left.delPx() + deltaX + "px";
		this.container.style.top = this.container.style.top.delPx() + deltaY + "px";
		
		// inform the tile containers about the move	
		for (var i = 0; i < this.tileContainer.length ; i++) this.tileContainer[i].mapSource.addPxOff(-deltaX,-deltaY);
	},
	remove: function() {
		this._stopCheckTiles();
		if (this.config.hasPOIs) this.poiBox.remove();
	
		for (var i = 0; i < this.tileContainer.length ; i++){
			this.tileContainer[i].remove();
		}
		for (var i = 0; i < this.mapSources.length ; i++){
			this.mapSources[i].remove();
		}

		if (typeof(this.tileCon) == "object") {
			this.container.removeChild(this.tileCon);
		}
		
		this.coordinates.remove();
		this.tileContainer = null;
		this.tileBox = null;

		this.mapSources = null;
		
		this.coordinates = null;
		this.poiBox = null;
		this.parent.removeChild(this.container);
		this.container = null;
	},
	
	// check if the chosen center coordinates lie within config.visibleBounds
	validateCenterCoordinates: function(lat,lon) {
		var clientWidth = this.config.width * this.coordinates.getCurrentResolution();
		var clientHeight = this.config.height * this.coordinates.getCurrentResolution();

		//////console.debug("Client size: "+clientWidth+" x "+clientHeight);

		// upper right boundary check
		if ( ( lon - 0.5*clientWidth ) <= this.config.visibleBounds.ul[0]) lon = this.config.visibleBounds.ul[0] + 0.5*clientWidth;
		if ( ( lat + 0.5*clientHeight ) >= this.config.visibleBounds.ul[1]) lat = this.config.visibleBounds.ul[1] - 0.5*clientHeight;

		// lower right boundary check
		if ( ( lon + 0.5*clientWidth ) >= this.config.visibleBounds.lr[0]) lon = this.config.visibleBounds.lr[0] - 0.5*clientWidth;
		if ( ( lat - 0.5*clientHeight ) <= this.config.visibleBounds.lr[1]) lat = this.config.visibleBounds.lr[1] + 0.5*clientHeight;
		
		return ( [lon, lat] );
	},
	
	// internal functions
	
	_startCheckTiles: function() {
		this.checkTilesObserver = this._checkTiles.bind(this);
		Event.observe(this.container,"mousemove",this.checkTilesObserver,false);
	},
	_stopCheckTiles: function() {
		if (this.checkTilesObserver) Event.stopObserving(this.container,"mousemove",this.checkTilesObserver,false);
	},
	_checkTiles: function() {
		//if (!this.checked) {
			for (var i = 0; i < this.tileContainer.length ; i++) this.tileContainer[i].checkTiles();
		//}
		//this.checked = true;
	}
}

/*
 * 
 * URLHandler is invoked when the user adds HTTP GET Strings to the called URL.
 * Each action must have a return function as a parameter, which will then be called
 * if the parameter is set in the URL.
 * This function is given the parameters found in the GET string.
 * The only action taken is a .split("_")
 * 
 */
URLHandler = Class.create();
URLHandler.prototype = {
	initialize: function() {
		this.searchString = "";
		this.searchArguments = new Array();
	},
	parse: function(searchString) {
		this.searchString = searchString;
		if (this.searchString != "") {
			// remove possible leading #
			var toReplace = new RegExp("#","");
			var processingString = this.searchString.replace(toReplace,"");
			// remove leading ?
			processingString = processingString.substring(1,processingString.length);
			// if we have more than one argument
			if (processingString.indexOf("&") != -1) {
				// the whole key=value pairs
				var rawSearchArguments = processingString.split("&");
				// for each pair, divide by "=" and create array ( array(key,value) , array(key,value) ...)
				for (var i = 0 ; i < rawSearchArguments.length ; i++) this.searchArguments[i] = rawSearchArguments[i].split("=");
			}
			else this.searchArguments[0] = processingString.split("=");
		}
	},
	handle: function(argument,returnFunction) {
		for (var i = 0; i < this.searchArguments.length ; i++ ) {
			if (this.searchArguments[i][0] == argument) {
				// check if the parameter has "_" and create array if necessary. Call return function with the values.
				var parameter = this.searchArguments[i][1];
				if (parameter.indexOf("_") != -1) parameter = parameter.split("_");
				returnFunction(parameter);
			}
		}
	}
}
/**
 * @author cknote
 *
 * A VectorShape is the basic vector object in this application.
 * It contains code for geometry representation as well
 * as drawing routines.
 * Vector shapes also feature a popup to be able to show information.
 * Popup.class is used in the same way as it is for "normal" POIs,
 * mind that VectorShape has to fake some properties of a POI to be
 * Popup.class compatible (data, loadDataFromServlet, id, poiManager).
 *
 */

VectorShape = Class.create();
VectorShape.prototype = {

	// constructor

	initialize: function(config,surface,coordinates) {
		// parameters passed
		this.config = config;
		this.coordinates = coordinates;
		this.surface = surface;

		// "dummy" geometry appearance		
		this.name = "";
		this.shapeType = "point";
		this.type = "";
		this.points = [{x:0,y:0}];
		this.rawPoints = [{x:0,y:0}];
		
		this.surfaceSize = { x: 100, y:100 };
		
		// coordinate offset (we are on vector tiles!)
		// rw -> pixel is done relative to map 0,
		// when on a certain tile, the tile's offest has to be subtracted
		this.offset = {x:0,y:0};
		
		// get defaults from config, care for 
		// not existing config due to calling when extending object
		// (before instantiated...)
		if (this.config) {
			this.fill = this.config.vectors.points.defaultFill;
			this.stroke = this.config.vectors.points.defaultStroke;
			this.radius = this.config.vectors.points.defaultRadius;
		}

		// will hold the svg/vml object		
		this.geometry = null;
		
		// to delete the event handlers
		this.clickEventHandle = null;
		
		// the popup
		this.popup = null;
		this.popupCon = null;
		this.popupDiv = null;
	},
	
	// getter, setter
	
	getPoints: function() {
		return this.points;
	},
	setPoints: function(points,transform) {
		this.points = this._transformPoints(points,transform);
		this.rawPoints = points;
	},
	getShapeType: function() {
		return this.shapeType;
	},
	setShapeType: function(shapeType) {
		this.shapeType = shapeType;
	},
	getType: function() {
		return this.type;
	},
	setType: function(type) {
		this.type = type;
	},
	getName: function() {
		return this.name;
	},
	setName: function(name) {
		this.name = name;
	},
	getFill: function() {
		return this.fill;
	},
	setFill: function(fill) {
		this.fill = fill;
	},
	getStroke: function() {
		return this.stroke;
	},
	setStroke: function(stroke) {
		this.stroke = stroke;
	},
	getPopupCon: function() {
		return this.popupCon;
	},
	setPopupCon: function(popupCon) {
		this.popupCon = popupCon;
	},
	getOffset: function() {
		return this.offset;
	},
	setOffset: function(x,y) {
		this.offset = {x:x,y:y};
	},
	getSurfaceSize: function() {
		return this.offset;
	},
	setSurfaceSize: function(x,y) {
		this.surfaceSize = {x:x,y:y};
	},
	
	// external routines

	paint: function() {
		this._drawGeometry();
//		this._createPopup();
//		this._attachEventHandler();
	},
	remove: function() {
//		this._detachEventHandler();
		this._removeGeometry();
	},

	// internal routines

	_transformPoints: function(points, transform) {
		var coords = new Array();

		// create a "point" object from each coordinate tupel
		for (var i = 0 ; i < points.length; i++) {
//			////console.debug("transform coords:");
//			////console.debug(points);
			
			var aCoordPair = points[i];
//			////console.debug("aCoordPair");
//			////console.debug(aCoordPair);

			// do coordinate transformation if rw coords input
			if (transform) aCoordPair = this.coordinates.rw2px(aCoordPair[0],aCoordPair[1]);
			
//			////console.debug("transformed");
//			////console.debug(aCoordPair);

			// !! applying offset...
			coords.push({x:aCoordPair[0]-this.offset.x,y:aCoordPair[1]-this.offset.y});
			
//			////console.debug("added offset");
//			////console.debug(coords[coords.length-1]);
		}
		return coords;
	},
	// event handler
	_attachEventHandler: function() {
		this.clickEventHandle = this.geometry.connect("onclick",this,"_paintPopup");
	},
	_detachEventHandler: function() {
		this.geometry.disconnect(this.clickEventHandle);
	},
	// pop up
	_createPopup: function() {
		var labelPoint = this._getLabelPoint();
		
		this.popupDiv = document.createElement("div");		
		Element.setStyle(this.popupDiv,{position:"absolute",top:labelPoint.y+"px",left:(labelPoint.x-22)+"px"});
		this.popupCon.appendChild(this.popupDiv);
		
		this.popup = new PopUp(this,this.popupDiv,0,0,true);
	},
	_paintPopup: function() {
		this.popup.open();
		// don't let it open so long
		this.popup.triggerClose();
	},
	_hidePopup: function() {
		this.popup.close();
	},
	_removePopup: function() {
		try {
			this.popupCon.removeChild(this.popupDiv);
		}
		catch(e) {}
		
		this.popup.remove();
	},
	// common geometry operations
	_removeGeometry: function() {
		try {
			this.geometry.remove();
		}
		catch (e) {}
	},
	// faking to satisfy popup interface needs (simulating POI object)
	data: {
	},
	loadDataFromServlet: function() {
		// ////console.debug("loading");
	},
	id: 12,
	poiManager: {
		isRadweg: function() { return false; },
		isRadwegRegio: function() { return false; },
		isRadwegHLMS: function() { return false; }
	}
}

VectorPoly = Class.create();
VectorPoly.prototype = Object.extend(new VectorShape(), {

	// internal functions

	_drawGeometry: function() {
//		////console.debug("creating polygon");
//		////console.debug(this.points);
		try {
			this.geometry = this.surface.createPolyline(this.points)
				.setStroke(this.stroke)
				.setFill(this.fill);
		}
		catch(e) {
			////console.debug("creating polygon did not work");
		}
	},
	_getLabelPoint: function() {
		var centerPoint = {x:0,y:0};
		for (var i = 0 ; i < this.points.length ; i++) {
			centerPoint.x = centerPoint.x + this.points[i].x;
			centerPoint.y = centerPoint.y + this.points[i].y;
		}
		centerPoint.x = Math.floor(centerPoint.x / this.points.length);
		centerPoint.y = Math.floor(centerPoint.y / this.points.length);

//		////console.debug("calculated center at: "+centerPoint.x+"x"+centerPoint.y);

		return centerPoint;
	}
});
VectorLine = Class.create();
VectorLine.prototype = Object.extend(new VectorShape(), {

	// internal functions

	_drawGeometry: function() {
//		////console.debug("creating polyline");
//		////console.debug(this.points);
		try {
			this.geometry = this.surface.createPolyline(this.points);
//			////console.debug("created polyline");
			this.geometry.setStroke(this.stroke);
//			////console.debug("set stroke");
		}
		catch(e) {
			////console.debug("creating polyline did not work");
		}
	},
	_getLabelPoint: function() {
		var centerPointIndex = Math.floor(this.points.length / 2);
		return this.points[centerPointIndex];
	}
});
VectorPoint = Class.create();
VectorPoint.prototype = Object.extend(new VectorShape(), {

	// internal functions

	_drawGeometry: function() {
		try {
//			////console.debug("trying to create a point geometry");
//			////console.debug(this.points);
			var point = this.points[0];
//			////console.debug(point);
			if (point.x > 0 && point.x < this.surfaceSize.x && point.y > 0 && point.y < this.surfaceSize.y) {
				this.geometry = this.surface.createCircle({ cx:this.points[0].x, cy:this.points[0].y, r:this.radius });
//				////console.debug("created");
				this.geometry.setStroke(this.stroke);
//				////console.debug("set stroke");
				this.geometry.setFill(this.fill);
//				////console.debug("set fill");
			}
		}
		catch(e) {
			////console.debug("creating point did not work");
		}
	},
	_getLabelPoint: function() {
//		////console.debug("label at "+this.points[0].x+" x "+this.points[0].y);
		return this.points[0];
	}
});



/*	ZoomBar
 * 
 * The zoom bar object.
 * 
 */
ZoomBar = Class.create();
ZoomBar.prototype = {
	initialize: function(mapManager,container,config) {
		this.mapManager = mapManager;
		this.container = container;
		this.config = config;
		this.triggerZoomInObserver = null;
		this.triggerZoomOutObserver = null;
		this.knobDownObserver = null;
		this.zoomBarCon = null;
	},
	paint: function() {
		if (this.zoomBarCon == null) {
			
			this.zoomBarCon = document.createElement("div");
			Element.addClassName(this.zoomBarCon,"zoomBarCon");
			
			this.zoomPlus = document.createElement("img");
			Element.addClassName(this.zoomPlus,"zoomPlus");
			this.zoomPlus.src = this.config.plusImg;
			
			this.zoomMinus = document.createElement("img");
			Element.addClassName(this.zoomMinus,"zoomMinus");
			this.zoomMinus.src = this.config.minusImg;
			
			this.zoomKnob = document.createElement("img");
			Element.addClassName(this.zoomKnob,"zoomKnob");
			this.zoomKnob.src = this.config.knobImg;
			
			this.zoomStepImgs = new Array();
			
			this.oneZoomLevelHeight = this.config.knobImgHeight;
			
			this.stepMultiplier = Math.ceil(this.oneZoomLevelHeight / this.config.stepImgHeight);
			this.zoomBarHeight = 0;
			
			this.zoomBarCon.appendChild(this.zoomPlus);
			this.zoomBarHeight += this.config.zoomBarPlusImgHeight;
			
			
			if (this.config.zoomBarStyle == "full") {
				for (var i = 0; i < ( (this.config.agsResolution.length - this.config.minimumAllowedZoomLevel) * this.stepMultiplier ) ; i ++) {
					
					var zoomStepImg = document.createElement("img");
					Element.addClassName(zoomStepImg,"zoomStepImg");
					this.zoomStepImgs.push(zoomStepImg);
					this.zoomStepImgs[this.zoomStepImgs.length - 1].src = this.config.stepImg;
					this.zoomStepImgs[this.zoomStepImgs.length - 1].height = this.config.stepImgHeight;
					this.zoomBarCon.appendChild(this.zoomStepImgs[this.zoomStepImgs.length - 1]);
					this.zoomBarHeight += this.config.stepImgHeight;
					
					var targetZoomLevel = (this.config.agsResolution.length -i -1);
					Event.observe(zoomStepImg,'click',this.triggerZoomTo.bindAsEventListener(this, targetZoomLevel),false);
					Event.observe(zoomStepImg,'dblclick',this.triggerZoomTo.bindAsEventListener(this, targetZoomLevel),false); //TODO: check IE!
					
					////console.debug("zoomBar paint: i=="+i+' targetZoomLevel=='+targetZoomLevel);
				}
			}
			this.zoomBarCon.appendChild(this.zoomMinus);
			this.zoomBarHeight += this.config.minusImgHeight;
					
			// MAGIC NUMBER: Zoombar Image is not symmetric horizontally, therefore, the knob offset is less then "center" -> -4
			// TODO: Positionierungsberechnungen unabhängig von bestimmter Positionierung implementieren!
			//var knobLeft = Math.round( ( this.config.stepImgWidth - this.config.knobImgWidth ) / 2) - 4;
			var knobLeft = 0;
			// workaround for IE 6, zoomKnob displaced..
			if (navigator.userAgent.match(/MSIE 6/gi)) {
				//seit DOCTYPE-Korrektur nicht mehr nötig
				//knobLeft = 3;
			}
			//Element.setStyle(this.zoomKnob,{position:"absolute",top:"60px",left: knobLeft+"px"});
			Element.setStyle(this.zoomKnob,{position:"absolute",top: ( this.container.style.height.delPx() - this.config.zoomBarPaddingHeight + this.config.minusImgHeight + this.config.knobImgHeight) + "px",left: knobLeft+"px"});
			
			if (this.config.zoomBarStyle == "full") this.zoomBarCon.appendChild(this.zoomKnob);
			
			//Element.setStyle(this.zoomBarCon,{position:"absolute",top: ( this.container.style.height.delPx() - this.config.zoomBarPaddingBottom - this.zoomBarHeight ) + "px", left:"0px",width: this.config.stepImgWidth+"px" });
			var ie6Displacing = 0;
			// workaround for IE 6, zoomBar displaced..
			if (navigator.userAgent.match(/MSIE 6/gi)) {
				//seit DOCTYPE-Korrektur nicht mehr nötig
				//ie6Displacing = 3;
			}
			
			Element.setStyle(this.zoomBarCon,{position:"absolute",top: ( this.config.zoomBarPaddingHeight ) + "px", left: ( this.container.style.width.delPx() - 46 - ie6Displacing) + "px" ,width: this.config.stepImgWidth+"px" });
			//Element.addClassName(this.zoomBarCon,"zoomBarCon");
			
			this.container.appendChild(this.zoomBarCon);
			
			this.addEventHandler();
			
			this.mapManager.listenerDispenser.attachListener("postZoom",this.positionKnob.bind(this));
		}		
		this.positionKnob(this.mapManager.getCurrentZoomLevel());
	},
	addEventHandler: function() {
		
		this.knobDownObserver = this.knobDown.bindAsEventListener(this);
		this.triggerZoomInObserver = this.triggerZoomIn.bindAsEventListener(this);
		this.triggerZoomOutObserver = this.triggerZoomOut.bindAsEventListener(this);
		
		Event.observe(this.zoomKnob,'mousedown',this.knobDownObserver,false);
		Event.observe(this.zoomPlus,'click',this.triggerZoomInObserver,false);
		Event.observe(this.zoomMinus,'click',this.triggerZoomOutObserver,false);
	},
	triggerZoomIn: function() {
		this.mapManager.zoomIn();
	},
	triggerZoomOut: function() {
		this.mapManager.zoomOut();
	},
	/**
	 * ES
	 * @return
	 */
	triggerZoomTo: function(e, newZoomLevel) {
		////console.debug('- zoombar.triggerZoomTo level=='+newZoomLevel);
		//this.positionKnob(newZoomLevel); //anzeige aktualisieren noch vor dem 'repaint' -> schöner
		this.mapManager.zoomTo(newZoomLevel);
		Event.stop(e);
	},
	positionKnob: function(zoomLevel) {
		////console.debug('- zoombar.positionKnob level=='+zoomLevel);
		if (this.config.zoomBarStyle == "full") {
			if (typeof(zoomLevel) != "number") zoomLevel = this.mapManager.getCurrentZoomLevel();
			var knobTop = this.config.zoomBarPlusImgHeight;
			var levelCount = this.config.agsResolution.length - this.config.minimumAllowedZoomLevel - zoomLevel;
			
			//ES: vorher
			//knobTop += this.stepMultiplier * levelCount * this.config.stepImgHeight;
			//ES: mit mehr Zoomstufen-Puffer zw. Ü-Karte und hauptkarte
			knobTop += (this.stepMultiplier * levelCount * this.config.stepImgHeight)+((this.config.minimumAllowedZoomLevel-1)*this.config.stepImgHeight);
			////console.debug('--zoombar.positionKnob CurrZoomLevel='+zoomLevel+' levelCount=='+levelCount+' knobTop=='+knobTop);
			Element.setStyle(this.zoomKnob,{top:knobTop+"px"});
		}
	},
	calcKnobZoomLevel: function() {
		var zoomLevel = Math.round((this.zoomKnob.style.top.delPx() - this.config.zoomBarPlusImgHeight) / this.config.knobImgHeight);
		////console.debug("* calcKnobZoomLevel zoomLevel PRE: "+zoomLevel);
		zoomLevel = this.config.agsResolution.length - zoomLevel - 3;
		this.mapManager.zoomTo(zoomLevel);
		////console.debug("* calcKnobZoomLevel zoomLevel POST: "+zoomLevel);
	},
	knobDown: function(e) {
		Event.stop(e);
		this.knobObserver = this.knobMove.bindAsEventListener(this);
		this.knobUpObserver = this.knobUp.bindAsEventListener(this);
		Event.observe(this.container,'mousemove',this.knobObserver,false);
		Event.observe(this.container,'mouseup',this.knobUpObserver,false);
	},
	knobUp: function(e) {
		Event.stop(e);
		Event.stopObserving(this.container,'mousemove',this.knobObserver,false);
		Event.stopObserving(this.container,'mouseup',this.knobUpObserver,false);
		this.calcKnobZoomLevel();
	},
	knobMove: function(e) {
		Event.stop(e);
		var startX = Event.pointerX(e);
		var startY = Event.pointerY(e);
		var elementToDrag = this.zoomKnob;
		var ktop = elementToDrag.style.top;
		
		ktop = ktop.substring(0, ktop.length-2);
		//window.defaultStatus = ktop+"";
		ktop = parseInt(ktop);
		var orig = Position.cumulativeOffset(elementToDrag);
		var deltaX = startX - orig[0];
		var deltaY = startY - orig[1];
		ktop = ktop+deltaY;
		
		var dimensions = elementToDrag.getDimensions();
		var w = dimensions.width;
		var h = dimensions.height;
		ktop = ktop-h/2; 
		
		var ktopmin = this.config.zoomBarPlusImgHeight;
		var ktopmax = this.zoomBarHeight - this.config.zoomBarPlusImgHeight - h;
		
		if (ktop < ktopmin) ktop = ktopmin;
		if (ktop > ktopmax) ktop = ktopmax;
		
		Element.setStyle(elementToDrag,{top:ktop+"px"});
	},
	remove: function() {
		// classical remove routine
		// 1. Event Handler
		Event.stopObserving(this.container,'mousemove',this.knobObserver,false);
		Event.stopObserving(this.container,'mouseup',this.knobUpObserver,false);
		
		if (this.zoomBarCon != null) {

			Event.stopObserving(this.zoomKnob,'mousedown',this.knobDownObserver,false);
			Event.stopObserving(this.zoomPlus,'click',this.triggerZoomInObserver,false);
			Event.stopObserving(this.zoomMinus,'click',this.triggerZoomOutObserver,false);

			// 2. DOM Objects
			try {
				this.zoomBarCon.removeChild(this.zoomKnob);
				this.zoomBarCon.removeChild(this.zoomMinus);
				this.zoomBarCon.removeChild(this.zoomPlus);
				for (var i = 0; i < this.zoomStepImgs.length ; i++) {
					try {
						//var targetZoomLevel = (this.config.agsResolution.length - this.config.minimumAllowedZoomLevel -i);
						Event.stopObserving(this.zoomStepImgs[i],'click', this.triggerZoomTo,false); //TODO: prüfen: gleiche signatur nötig wie bei aufruf, damit es mit deser prototype-version funktioniert?
						Event.stopObserving(this.zoomStepImgs[i],'dblclick', this.triggerZoomTo,false); //TODO: check IE 
						
						this.zoomBarCon.removeChild(this.zoomStepImgs[i]);
					} catch(e) {
						////console.debug("removing child from zoombar icon failed");
					}
				}
				this.container.removeChild(this.zoomBarCon);
			} catch(e) {
				////console.debug("removing zoombarcon failed");
			}
		}

		// 3. Nullify
		this.knobDownObserver = null;
		this.knobObserver = null;
		this.knobUpObserver = null;
		this.triggerZoomInObserver = null;
		this.triggerZoomOutObserver = null;

		this.config = null;
		this.container = null;
//		//debug.writeline("zoomBar removed");
	}
}
/**
 * DataSources sollen die Kommunikation zum Server Kapseln. Bei neuen Sources also hier neue Klasse einbauen.
 * @author
 */
/**
 * POIs vom Server beziehen. (Standard-Verhalten)
 * @author agutheil
 */
ExtentDataSource = Class.create();
ExtentDataSource.prototype = {
	initialize: function() {
		this.parser = new JSONParser();
		this.working=new Array(); //Array hällt jetzt für jede Zoomstufe separat den Requeststatus fest (um Vermischung von POIs aus verschieden Zoomstufen zu vermeiden)		
	},
	init: function(poiManager){
		this.poiManager = poiManager;
		this.config = this.poiManager.config;
		this.coordinates = this.poiManager.coordinates;
		this.serviceIndex = this.poiManager.serviceIndex;
		this.eventLogger = this.poiManager.eventLogger;		
	},
	load: function(poiManager,minX , minY , maxX , maxY, portalClientId){
		this.init(poiManager);
		
		var requestScale = this.coordinates.getCurrentScale();
		////console.debug("ExtentDataSource.load(...) - working "+this.working[requestScale ]);
		this.working[requestScale]=true;
		
		var layers=this.serviceIndexToUrlParam();
		var aggregationMode = "none";
		if(this.config.isAggregation && requestScale >= 250000) aggregationMode = "subset"; //s. Server: ExtentAction
		
		//TODO: client nicht hardcoded
		var params = "minX="+minX+"&minY="+minY+"&maxX="+maxX+"&maxY="+maxY+"&mapScale="+requestScale+"&sessionId="+this.config.sessionId+"&topics="+this.config.activeTopics+"&areas="+this.config.activeAreas+"&targetGroups="+this.config.activeTargetGroups+"&aggregationMode="+aggregationMode+"&portalClientId="+portalClientId+ "&layers="+layers;
		this.parser.load(this.config.poiServletAddress,params,this.processResult.bind(this));
	},
	processResult: function(response) {
		
		//alert("extent? evaluating JSON: "+response.responseText);
		var json = eval("("+response.responseText+")");
		
		//ES, TODO: requestScale über das Request-Objekt abfragen (+ aus JSON rausnemen UGLY!!!). Zugriff auf Request-Obj. geht wohl mit prototype 1.6 ...
	//ES 20100216 IM NEUEN Backend nicht mehr vorhanden
	//var requestScale = json.requestScale;
		delete json.requestScale; //Scale-Objektvariable löschen da es kein POI ist!!!
		////console.debug("ExtentDataSource.processResult(...) scale:"+requestScale );
		
		//if (this.working[requestScale]) { // nur für die aktuelle Zoomstufe AJAX-Response/POIs annehmen
			////console.debug("*** ExtentDataSource.processResult(response) - -this.poiManager.pointBox.length:"+this.poiManager.pointBox.length);
			
			// log paint pois
			this.eventLogger.log(7);
			

			// CK handle poi subset on aggregated zoomlevels
			var portalHasSubsetPois = this.config.portalSettings[this.poiManager.portalClientId].hasSubsetPois;
			if (json["poiSubset"]) {
				for (var i in json["poiSubset"]) {
					var aPOI = json["poiSubset"][i];
					
					if(portalHasSubsetPois) this.poiManager.addSubsetPOI(aPOI["lon"],aPOI["lat"],i,aPOI["type"],aPOI["name"],aPOI["idTash"],false);
					//ES Abprüfung er hier da die forin durchlaufen soll (sonst können die nachfolgenden Aggre-Icons unten nicht ordentlich prozessiert werden)
				}
				// ensure that aggregation points are above subset pois 
				this.poiManager.updatePOIContainer();
			}

			
			var portalHasAggregationPois = this.config.portalSettings[this.poiManager.portalClientId].hasAggregationPois;
			var count = 0;
			for (var i in json) {  //sonst Fehler bei Array-Zugruffen in schleife
				try{			
					if(i != "poiSubset"){ //poiSubset hier auslassen (sonst Fehler bei Array-Zugruff da andere struktur)
						var type = json[i]["type"];
						if (type == "meta") {
							var pxCoord = this.coordinates.rw2px(json[i]["lon"],json[i]["lat"]);
							json[i]["lon"]=pxCoord[0];
							json[i]["lat"]=pxCoord[1];
							if(portalHasAggregationPois) this.poiManager.addMetaPOIInfo(i,json[i]);
						}else{
							this.poiManager.addPOI(json[i]["lon"],json[i]["lat"],i,type,json[i]["name"],json[i]["idTash"], false);
						}
						count++;
					}
				}catch(e){
				//alert(i)
				}
			}
			//console.debug("extent?  JSON syntax OK, "+count+" points added");
		//}
	},
	stop: function(){
		////console.debug("--ExtentDataSource.stop()");
		//ES
		this.parser.abort();
		this.parser.remove(); //nötig?
		
		this.working=new Array(); //alle Request abbrechen
	},
	serviceIndexToUrlParam: function(){
		var urlParam="";
		var idx = $H(this.serviceIndex.idx);
		idx.each(
			function(layer){
				if(layer.value.isVisible){
					urlParam = urlParam + layer.key+",";
				}				
			}
		);
		return urlParam;
	}
	
}

/**
 * POIs vom Server beziehen. (Best-View)
 * 
 * @author agutheil
 */
SearchExtentDataSource = Class.create();
SearchExtentDataSource.prototype = {
	initialize: function() {
		this.parser = new JSONParser();
		this.working=false;
		this.ids=null;
		this.isBubble=false;
		
		this.bubbleIndexStart = 1; 
	},
	init: function(poiManager){
		this.poiManager = poiManager;
		this.config = this.poiManager.config;
		this.coordinates = this.poiManager.coordinates;
		this.serviceIndex = this.poiManager.serviceIndex;		
	},
	getIdsString: function(){
		var idString = "";
		$A(this.ids).each(function(id){idString = idString + id + ","}); 
		return idString;
	},
	setIds: function(ids){
		this.ids = ids;
	},
	/**
	 * Wert, ab dem der Bubble-Nummerierung beginnen soll (für akt. übergeben POI-Liste). -> Paging ist damit möglich
	 * @param ids
	 * @return
	 */
	setBubbleIdxStart: function(startNum){
		//console.debug('##setBubbleIdxStart: '+startNum);
		if(startNum){ //wenn !=null -> sonst soll es 0 bleiben (inti-wert)
			this.bubbleIndexStart = startNum;
		}
	},
	setBubble: function(isBubble){
		this.isBubble = isBubble;
	},
	load: function(poiManager,minX , minY , maxX , maxY){
		this.init(poiManager)
		this.working=true;
		var ids = this.getIdsString();
		var params = "minX="+minX+"&minY="+minY+"&maxX="+maxX+"&maxY="+maxY+"&mapScale="+this.coordinates.getCurrentScale()+"&ids="+ids;
		this.parser.load(this.config.poiSearchExtentAddress,params,this.processResult.bind(this));
	},
	processResult: function(response) {
		if (this.working) {
			//alert("extent? evaluating JSON: "+response.responseText);
			var json = eval("("+response.responseText+")");
			var count = 0;
			for (var i in json) {
				try{			
					var type = json[i]["type"];	
					this.poiManager.addStandalonePOI(json[i]["lon"],json[i]["lat"],i,type,json[i]["name"],json[i]["idTash"],this.isBubble,this.calcBubbleIndex(json[i]["idTash"]));
					count++;
				}catch(e){
				//alert(i)
				}
			}
			//debug.writeline("extent?  JSON syntax OK, "+count+" points added");
		}
	},
	
	stop: function(){
		this.working=false;
	},
	serviceIndexToUrlParam: function(){
		var urlParam="";
		var idx = $H(this.serviceIndex.idx);
		idx.each(
			function(layer){
				if(layer.value.isVisible){
					urlParam = urlParam + layer.key+",";
				}				
			}
		);
		return urlParam;
	},
	calcBubbleIndex: function(tId){
		var cnt= this.bubbleIndexStart-1; //-1 wg. Paging im Portal nötig 
		//console.debug('##calcBubbleIndex: cnt=='+cnt);
		var idx = 0;
		$A(this.ids).each(function(tmpId){
			cnt++;
			if(tmpId==tId){
				idx=cnt;
			}
		});
		return idx;
	}
}

/**
* @author estykow
* 
* POIs vom Server beziehen, nur Response für Teaser-Bilder sieht anders aus.  
*/
SearchExtentTeaserDataSource = Class.create();
SearchExtentTeaserDataSource.prototype = Object.extend(new SearchExtentDataSource(), {
	processResult: function(response) {
		if (this.working) {
			//alert("extent? evaluating JSON: "+response.responseText);
			var json = eval("("+response.responseText+")");
			var count = 0;
			for (var i in json) {
				try{			
					var type = json[i]["type"];	
					this.poiManager.addStandaloneTeaserPOI(json[i]["lon"],json[i]["lat"],i,type,json[i]["name"],json[i]["idTash"],this.isBubble,this.calcBubbleIndex(json[i]["idTash"]));
					count++;
				}catch(e){
				//alert(i)
				}
			}
			//debug.writeline("extent?  JSON syntax OK, "+count+" points added");
		}
	}
});// used to remember the last open popup,
// is used for the state object, when
// transferring the state of the smaller
// map to the bigger map...
lastOpenPopUp=-1;
function setLastOpenPopUp(id) {
	lastOpenPopUp = id;
}

function getLastOpenPopUp() {
	return lastOpenPopUp;
}

// code from http://www.irt.org/script/878.htm
function cloneObject(what) {
    for (i in what) {
        this[i] = what[i];
    }
}

mapOptions = {
	//  ++++++++++ Base Map +++++++++++
	width : 648,//"full", // height and width of the displayed map view in px
	height : 394,//"full",
	top : 0, // offset of this map view from browser window top, left in px
	left : 0,

	mapTileDir : 'http://tash.alta4gis.de/cache3/',
	mapTileImgFormat : "jpg",
	mapTileImgFormatTransparent: "png", //Kacheln mit Transparenz (z.B. Radwege) -> Zwischenlösung
	tileWidth : 256, // width and height of one map tile in px
	tileHeight : 256,
	agsTileXOffset : 0,
	agsTileYOffset : 0,

	//Anzahl Metern eines Pixels für jede Zoomstufe (1,2,...)
	agsResolution: [2645.83862501058,1852.08703750741,793.751587503175,396.875793751588,132.291931250529,66.1459656252646,26.4583862501058,13.2291931250529,6.61459656252646,2.64583862501058],
	agsScale: [10000000,7000000,3000000,1500000,500000,250000,100000,50000,25000,10000],
	//Realwordl-Coord. des Pixel-Karten-Ursprungs. px(0,0) == agsTileOrigin
	agsTileOrigin: [-2122500,10001000],
	//Limitiert sichtbaren Kartenbereich beim pannen
	visibleBounds: {
		ul: [3351210.0, 6194167.0],
		lr: [3749674.0, 5822294.0]
	},
	spacerImg : "http://tash.alta4gis.de/design/spacer_white.gif", // is used for display when no map tile is defined for the requested position		
	borderCache: 2, // count of tiles by which the tilematrix is bigger than the visible extent
	
	minimumAllowedZoomLevel: 3, //gillt nur für Hauptkarte (nicht für OvervieweMap)

	//  ++++++++++ Initial loading cnfiguration +++++++++++
	// will be overridden by the URL parameters! (when implemented)
	zoomLevel : 3, // zoomLevel is the index of the zoomFactor array (in [1,4,8,16] 2 would resemble zoomFactor "8")
				   //ACHTUNG: sollte nicht kleiner als minimumAllowedZoomLevel sein (sonst Zoombar-Knob versetzt angezeigt...)
	lon : 3547000, // map center on start
	lat : 6010000,
			

	//  ++++++++++ Coordinates +++++++++++
	// ALT
	magicNumberRW_Y: 0.0, // ugly magic numbers to account for points offset in the coordinate calculation
	magicNumberPX_Y: 0.4,
	
	//  ++++++++++ Compass Rose +++++++++++
	hasCompassRose : true,
	compassRoseSize : 54, // size in px, is assumed to be quadratic
	compassRoseSrc: "/tash/design/e7/windrose.gif",
	compassRoseSpeed : 5, // in something like px / s
	compassRoseGamestyleSpeed: 0.25, // factor for the gamestyle mover (click, hold and move in the center)
	compassRosePadding: 10, // distance from map border
	compassRosePosition : "top-left", // possible: "bottom-left","bottom-right","top-left"

	//  ++++++++++ ZoomBar +++++++++++
	hasZoomBar : true,
	zoomBarStyle : "full", // if "full", the zoomBar gets a slider to select zoomLevel, otherwise only plus and minus sign is displayed
	zoomBarTop : 0,
	zoomBarLeft: 0,

	plusImg: "/tash/design/e7/zoomplus.gif", // design elements of the zoomBar
	plusImgWidth: 18,
	zoomBarPlusImgHeight: 18,
	minusImg: "/tash/design/e7/zoomminus.gif",
	minusImgWidth: 18,
	minusImgHeight: 18,
	stepImg: "/tash/design/e7/scrollbar.gif",
	stepImgWidth: 18,
	stepImgHeight: 11,
	knobImg: "/tash/design/e7/schieber.gif",
	knobImgWidth: 18,
	knobImgHeight: 11,

	zoomBarPaddingBottom: 0, // if the zoom bar shall not align to map view bottom, add offset here
	zoomBarPaddingHeight: 74,

	//  ++++++++++ POIs +++++++++++
	hasPOIs : true, //OverviewMap hat z.B. keine
	dataSources: {
		"extent":new ExtentDataSource() //default Datasource. laedt die POIs von extent-Servlet		
	},
	poiMinimumZoomLevel : 0,
	poiMaxPrecision: 4, // defines the maximum accuracy of the poiCache. Should be ok for all normal use cases
	
	//Extrawurst....
	poiSearchExtentAddress: "/tash/controller/searchExtent?", //URL zum searchExtent-Servlet

	poiServletAddress: "/tash/controller/extent?", // List of POIs in the Extent (minX,minY,maxX,maxY)
	leavesServletAddress: "/tash/controller/leaves?", // 
	poiTypeServletAddress: "/tash/controller/type?", // all subpoints of a given point of a given type (id,type)
	poiDataServletAddress: "/tash/controller/poi?", // all attributes of one poi (id)
		
	// für einzel POIs, aggregation siehe poicontainer.class.js
	defaultIcon: ["/tash/symbols/tash/meta.png",22,22], // default icon to be used if no icon is defined
	usedIcons: {
		Article: ["/tash/symbols/tash/article.png",22,22],
		Offer: ["/tash/symbols/tash/offer.png",22,22],
		Event: ["/tash/symbols/tash/event.png",22,22],
		Tourismusinformation: ["/tash/symbols/tash/10_icon_info.png",23,23],
		Bahnhof: ["/tash/symbols/tash/20_icon_train.png",23,23],
		HotelPension: ["/tash/symbols/tash/31_icon_bed.png",23,23],
		FerienwohnungHaus: ["/tash/symbols/tash/32_icon_house.png",23,23],
		Campingplatz: ["/tash/symbols/tash/33_icon_camping.png",23,23],
		Jugendherberge: ["/tash/symbols/tash/34_icon_hostel.png",23,23],
		Bauernhof: ["/tash/symbols/tash/35_icon_farm.png",23,23],
		BettBike: ["/tash/symbols/tash/36_icon_bedbike.png",23,23],
		WellnesshotelBeautyfarm: ["/tash/symbols/tash/37_icon_beauty.png",23,23],
		Gastronomie: ["/tash/symbols/tash/40_icon_food.png",23,23],
		MuseumDenkmal: ["/tash/symbols/tash/51_icon_museum.png",23,23],
		Theater: ["/tash/symbols/tash/52_icon_theatre.png",23,23],
		SchlossGarten: ["/tash/symbols/tash/53_icon_castle.png",23,23],
		KlosterKirche: ["/tash/symbols/tash/54_icon_church.png",23,23],
		Freizeitpark: ["/tash/symbols/tash/55_icon_themepark.png",23,23],
		TierparkZoo: ["/tash/symbols/tash/56_icon_zoo.png",23,23],
		StrandBaden: ["/tash/symbols/tash/60_icon_beach.png",23,23],
		Naturerlebnis: ["/tash/symbols/tash/70_icon_nature.png",23,23],
		Segeln: ["/tash/symbols/tash/80_icon_sailing.png",23,23],
		FahrradverleihReparaturservice: ["/tash/symbols/tash/91_icon_bikerepair.png",23,23],
		AbschliessbareFahrradbox: ["/tash/symbols/tash/92_icon_bikelock.png",23,23],
		RastplatzSchutzhuette: ["/tash/symbols/tash/93_icon_bikeshed.png",23,23],
		Golfen: ["/tash/symbols/tash/100_icon_golf.png",23,23],
		Reiten: ["/tash/symbols/tash/110_icon_riding.png",23,23],
		meta: ["/tash/symbols/tash/meta.png",22,22],
		Wetter: ["/tash/design/weather/d_nodata_b.gif",24,24],
		Veranstaltungen: ["/tash/symbols/tash/osg/Events.png",22,22],
		Leuchttuerme: ["/tash/symbols/tash/leuchtturm.png",23,23],
		CmsArtikel: ["/tash/symbols/tash/150_cms_artikel.png",23,23],
		rw1: ["/tash/images/radweg/ico_alte_salzstrasse.png",19,19],
		rw2: ["/tash/images/radweg/ico_elberadweg.png",19,19],
		rw3: ["/tash/images/radweg/ico_eider_treene.png",19,19],
		rw4: ["/tash/images/radweg/ico_grenzroute.png",19,19],
		rw5: ["/tash/images/radweg/ico_hamburg_ruegen.png",19,19],
		rw6: ["/tash/images/radweg/ico_holsteinische_schweiz.png",19,19],
		rw7: ["/tash/images/radweg/ico_moenchsweg.png",19,19],
		rw8: ["/tash/images/radweg/ico_nordostseekanalroute.png",19,19],
		rw9: ["/tash/images/radweg/ico_nordseekuestenradweg.png",19,19],
		rw10: ["/tash/images/radweg/ico_ochsenweg.png",19,19],
		rw11: ["/tash/images/radweg/ico_ostseekuestenradweg.png",19,19],
		rw12: ["/tash/images/radweg/ico_wikinger_friesen.png",19,19],
		//hlms
		rw13: ["/tash/images/radweg/ico_alleen_herrenhaeuser.png",19,19],
		rw14: ["/tash/images/radweg/ico_eiszeittour.png",19,19],
		rw15: ["/tash/images/radweg/ico_kirchentour.png",19,19],
		rw16: ["/tash/images/radweg/ico_seenradtour.png",19,19],
		rw17: ["/tash/images/radweg/ico_techniktour.png",19,19],
		rw18: ["/tash/images/radweg/ico_regionale_routen.png",19,19]
	},
	//Salesguide hat neue POI-Typen und einige POIs habe hier andere Symbole  
	usedIconsOSG: {
		Article: ["/tash/symbols/tash/article.png",22,22],
		Offer: ["/tash/symbols/tash/offer.png",22,22],
		Event: ["/tash/symbols/tash/event.png",22,22],
		Tourismusinformation: ["/tash/symbols/tash/osg/Tourismusinformation.png",22,22],
		Bahnhof: ["/tash/symbols/tash/osg/bahnhof.png",24,24],
		HotelPension: ["/tash/symbols/tash/osg/Hotels.png",22,22],
		FerienwohnungHaus: ["/tash/symbols/tash/32_icon_house.png",24,24],
		Campingplatz: ["/tash/symbols/tash/osg/Campingplaetze.png",22,22],
		Jugendherberge: ["/tash/symbols/tash/osg/Jugendherbergen.png",22,22],
		Bauernhof: ["/tash/symbols/tash/osg/bauerhof.png",24,24],
		BettBike: ["/tash/symbols/tash/36_icon_bedbike.png",24,24],
		WellnesshotelBeautyfarm: ["/tash/symbols/tash/osg/Wellnesshotels.png",22,22],
		Gastronomie: ["/tash/symbols/tash/osg/Gastronomie.png",22,22],
		MuseumDenkmal: ["/tash/symbols/tash/osg/Museum.png",22,22],
		Theater: ["/tash/symbols/tash/osg/Theater.png",22,22],
		SchlossGarten: ["/tash/symbols/tash/osg/Schloesser.png",22,22],
		KlosterKirche: ["/tash/symbols/tash/osg/Kirchen.png",22,22],
		Freizeitpark: ["/tash/symbols/tash/osg/Freizeitparks.png",24,24],
		TierparkZoo: ["/tash/symbols/tash/osg/Zoo.png",22,22],
		StrandBaden: ["/tash/symbols/tash/osg/Strand_und_Baden.png",22,22],
		Naturerlebnis: ["/tash/symbols/tash/osg/Naturerlebnis.png",22,22],
		Segeln: ["/tash/symbols/tash/80_icon_sailing.png",24,24],
		FahrradverleihReparaturservice: ["/tash/symbols/tash/91_icon_bikerepair.png",24,24],
		AbschliessbareFahrradbox: ["/tash/symbols/tash/92_icon_bikelock.png",24,24],
		RastplatzSchutzhuette: ["/tash/symbols/tash/93_icon_bikeshed.png",24,24],
		Golfen: ["/tash/symbols/tash/100_icon_golf.png",24,24],
		Reiten: ["/tash/symbols/tash/110_icon_riding.png",24,24],
		meta: ["/tash/symbols/tash/meta.png",22,22],
		Wetter: ["/tash/design/weather/d_nodata_b.gif",24,24],
		rw1: ["/tash/images/radweg/ico_alte_salzstrasse.png",19,19],
		rw2: ["/tash/images/radweg/ico_elberadweg.png",19,19],
		rw3: ["/tash/images/radweg/ico_eider_treene.png",19,19],
		rw4: ["/tash/images/radweg/ico_grenzroute.png",19,19],
		rw5: ["/tash/images/radweg/ico_hamburg_ruegen.png",19,19],
		rw6: ["/tash/images/radweg/ico_holsteinische_schweiz.png",19,19],
		rw7: ["/tash/images/radweg/ico_moenchsweg.png",19,19],
		rw8: ["/tash/images/radweg/ico_nordostseekanalroute.png",19,19],
		rw9: ["/tash/images/radweg/ico_nordseekuestenradweg.png",19,19],
		rw10: ["/tash/images/radweg/ico_ochsenweg.png",19,19],
		rw11: ["/tash/images/radweg/ico_ostseekuestenradweg.png",19,19],
		rw12: ["/tash/images/radweg/ico_wikinger_friesen.png",19,19],
		//hlms
		rw13: ["/tash/images/radweg/ico_alleen_herrenhaeuser.png",19,19],
		rw14: ["/tash/images/radweg/ico_eiszeittour.png",19,19],
		rw15: ["/tash/images/radweg/ico_kirchentour.png",19,19],
		rw16: ["/tash/images/radweg/ico_seenradtour.png",19,19],
		rw17: ["/tash/images/radweg/ico_techniktour.png",19,19],
		rw18: ["/tash/images/radweg/ico_regionale_routen.png",19,19],
			
		Busunternehmen: ["/tash/symbols/tash/osg/Busbahnhof.png",22,22],
		ReedereiSchiffFaehre: ["/tash/symbols/tash/osg/Haefen.png",22,22],
		Flughafen: ["/tash/symbols/tash/osg/Flughaefen.png",22,22],
		Appartmenthaus: ["/tash/symbols/tash/osg/Hotels.png",22,22],
		Ferienpark: ["/tash/symbols/tash/osg/Freizeitparks.png",22,22],
		Gasthof: ["/tash/symbols/tash/osg/Gastronomie.png",22,22],
		Erlebnisbad: ["/tash/symbols/tash/osg/Freizeitbaeder.png",22,22],
		NaturerlebniszentrumAquarium: ["/tash/symbols/tash/osg/Naturerlebnis.png",22,22],
		Veranstaltungen: ["/tash/symbols/tash/osg/Events.png",22,22],
		Leuchttuerme: ["/tash/symbols/tash/osg/leuchtturm.png",23,23]
	},
	// die icons für die random points in aggregationszoomstufen 
	usedIconsPOISubset: {
		smallSize:{
			/*Article: ["/tash/symbols/tash/article.png",22,22],
			Offer: ["/tash/symbols/tash/offer.png",22,22],
			Event: ["/tash/symbols/tash/event.png",22,22],*/
			Tourismusinformation: ["/tash/symbols/tash/s_information.png",11,11],
			Bahnhof: ["/tash/symbols/tash/s_bahnhof.png",11,11],
			HotelPension: ["/tash/symbols/tash/s_hotels-und-pensionen.png",11,11],
			FerienwohnungHaus: ["/tash/symbols/tash/s_fewos.png",11,11],
			Campingplatz: ["/tash/symbols/tash/s_campingplatz.png",11,11],
			Jugendherberge: ["/tash/symbols/tash/s_jugendherberge.png",11,11],
			Bauernhof: ["/tash/symbols/tash/s_bauerhof.png",11,11],
			BettBike: ["/tash/symbols/tash/s_bett-u-bike.png",11,11],
			WellnesshotelBeautyfarm: ["/tash/symbols/tash/s_wellnesshotels.png",11,11],
			Gastronomie: ["/tash/symbols/tash/s_gastronomie.png",11,11],
			MuseumDenkmal: ["/tash/symbols/tash/s_museen.png",11,11],
			Theater: ["/tash/symbols/tash/s_theater.png",11,11],
			SchlossGarten: ["/tash/symbols/tash/s_schloesser.png",11,11],
			KlosterKirche: ["/tash/symbols/tash/s_kirchen.png",11,11],
			Freizeitpark: ["/tash/symbols/tash/s_freizeitparks.png",11,11],
			TierparkZoo: ["/tash/symbols/tash/s_zoo.png",11,11],
			StrandBaden: ["/tash/symbols/tash/s_strand-und-baden.png",11,11],
			Naturerlebnis: ["/tash/symbols/tash/s_nature.png",11,11],
			Segeln: ["/tash/symbols/tash/s_segeln.png",11,11],
			FahrradverleihReparaturservice: ["/tash/symbols/tash/s_fahrradverleih.png",11,11],
			AbschliessbareFahrradbox: ["/tash/symbols/tash/s_fahrradboxen.png",11,11],
			RastplatzSchutzhuette: ["/tash/symbols/tash/s_schutzhuetten.png",11,11],
			Golfen: ["/tash/symbols/tash/s_golf.png",11,11],
			Reiten: ["/tash/symbols/tash/s_reiten.png",11,11],
			/*meta: ["/tash/symbols/tash/meta.png",22,22],
			Wetter: ["/tash/design/weather/d_nodata_b.gif",24,24],*/
			Veranstaltungen: ["/tash/symbols/tash/osg/s_events.png",11,11],
			Leuchttuerme: ["/tash/symbols/tash/s_leuchtturm.png",11,11],
			CmsArtikel: ["/tash/symbols/tash/s_cms_artikel.png",11,11]
		},
		mediumSize:{
			Tourismusinformation: ["/tash/symbols/tash/m_information.png",15,15],
			Bahnhof: ["/tash/symbols/tash/m_bahnhof.png",15,15],
			HotelPension: ["/tash/symbols/tash/m_hotels-und-pensionen.png",15,15],
			FerienwohnungHaus: ["/tash/symbols/tash/m_fewos.png",15,15],
			Campingplatz: ["/tash/symbols/tash/m_campingplatz.png",15,15],
			Jugendherberge: ["/tash/symbols/tash/m_jugendherberge.png",15,15],
			Bauernhof: ["/tash/symbols/tash/m_bauerhof.png",15,15],
			BettBike: ["/tash/symbols/tash/m_bett-u-bike.png",15,15],
			WellnesshotelBeautyfarm: ["/tash/symbols/tash/m_wellnesshotels.png",15,15],
			Gastronomie: ["/tash/symbols/tash/m_gastronomie.png",15,15],
			MuseumDenkmal: ["/tash/symbols/tash/m_museen.png",15,15],
			Theater: ["/tash/symbols/tash/m_theater.png",15,15],
			SchlossGarten: ["/tash/symbols/tash/m_schloesser.png",15,15],
			KlosterKirche: ["/tash/symbols/tash/m_kirchen.png",15,15],
			Freizeitpark: ["/tash/symbols/tash/m_freizeitparks.png",15,15],
			TierparkZoo: ["/tash/symbols/tash/m_zoo.png",15,15],
			StrandBaden: ["/tash/symbols/tash/m_strand-und-baden.png",15,15],
			Naturerlebnis: ["/tash/symbols/tash/m_nature.png",15,15],
			Segeln: ["/tash/symbols/tash/m_segeln.png",15,15],
			FahrradverleihReparaturservice: ["/tash/symbols/tash/m_fahrradverleih.png",15,15],
			AbschliessbareFahrradbox: ["/tash/symbols/tash/m_fahrradboxen.png",15,15],
			RastplatzSchutzhuette: ["/tash/symbols/tash/m_schutzhuetten.png",15,15],
			Golfen: ["/tash/symbols/tash/m_golf.png",15,15],
			Reiten: ["/tash/symbols/tash/m_reiten.png",15,15],
			/*meta: ["/tash/symbols/tash/meta.png",22,22],
			Wetter: ["/tash/design/weather/d_nodata_b.gif",24,24],*/
			Veranstaltungen: ["/tash/symbols/tash/osg/m_events.png",15,15],
			Leuchttuerme: ["/tash/symbols/tash/m_leuchtturm.png",15,15],
			CmsArtikel: ["/tash/symbols/tash/m_cms_artikel.png",15,15]
		}
	},
	usedIconsPOISubsetOSG: {
		smallSize:{
			Tourismusinformation: ["/tash/symbols/tash/osg/s_tourismusinformation.png",11,11],
			Bahnhof: ["/tash/symbols/tash/osg/s_bahnhof.png",11,11],
			HotelPension: ["/tash/symbols/tash/osg/s_hotels.png",11,11],
			FerienwohnungHaus: ["/tash/symbols/tash/32_icon_house.png",11,11],
			Campingplatz: ["/tash/symbols/tash/osg/s_campingplaetze.png",11,11],
			Jugendherberge: ["/tash/symbols/tash/osg/s_jugendherbergen.png",11,11],
			Bauernhof: ["/tash/symbols/tash/osg/s_bauerhof.png",11,11],
			BettBike: ["/tash/symbols/tash/36_icon_bedbike.png",11,11],
			WellnesshotelBeautyfarm: ["/tash/symbols/tash/osg/s_wellnesshotels.png",11,11],
			Gastronomie: ["/tash/symbols/tash/osg/s_gastronomie.png",11,11],
			MuseumDenkmal: ["/tash/symbols/tash/osg/s_museum.png",11,11],
			Theater: ["/tash/symbols/tash/osg/s_theater.png",11,11],
			SchlossGarten: ["/tash/symbols/tash/osg/s_schloesser.png",11,11],
			KlosterKirche: ["/tash/symbols/tash/osg/s_kirchen.png",11,11],
			Freizeitpark: ["/tash/symbols/tash/osg/s_freizeitparks.png",11,11],
			TierparkZoo: ["/tash/symbols/tash/osg/s_zoo.png",11,11],
			StrandBaden: ["/tash/symbols/tash/osg/s_strand_und_Baden.png",11,11],
			Naturerlebnis: ["/tash/symbols/tash/osg/s_naturerlebnis.png",11,11],
			Segeln: ["/tash/symbols/tash/80_icon_sailing.png",11,11],
			FahrradverleihReparaturservice: ["/tash/symbols/tash/91_icon_bikerepair.png",11,11],
			AbschliessbareFahrradbox: ["/tash/symbols/tash/92_icon_bikelock.png",11,11],
			RastplatzSchutzhuette: ["/tash/symbols/tash/93_icon_bikeshed.png",11,11],
			Golfen: ["/tash/symbols/tash/100_icon_golf.png",11,11],
			Reiten: ["/tash/symbols/tash/110_icon_riding.png",11,11],			
			Busunternehmen: ["/tash/symbols/tash/osg/s_busbahnhof.png",11,11],
			ReedereiSchiffFaehre: ["/tash/symbols/tash/osg/s_haefen.png",11,11],
			Flughafen: ["/tash/symbols/tash/osg/s_flughaefen.png",11,11],
			Appartmenthaus: ["/tash/symbols/tash/osg/s_hotels.png",11,11],
			Ferienpark: ["/tash/symbols/tash/osg/s_freizeitparks.png",11,11],
			Gasthof: ["/tash/symbols/tash/osg/s_gastronomie.png",11,11],
			Erlebnisbad: ["/tash/symbols/tash/osg/s_freizeitbaeder.png",11,11],
			NaturerlebniszentrumAquarium: ["/tash/symbols/tash/osg/s_naturerlebnis.png",11,11],
			Veranstaltungen: ["/tash/symbols/tash/osg/s_events.png",11,11],
			Leuchttuerme: ["/tash/symbols/tash/osg/s_leuchtturm.png",11,11]
		},
		mediumSize:{
			Tourismusinformation: ["/tash/symbols/tash/osg/m_tourismusinformation.png",15,15],
			Bahnhof: ["/tash/symbols/tash/osg/m_bahnhof.png",15,15],
			HotelPension: ["/tash/symbols/tash/osg/m_hotels.png",15,15],
			FerienwohnungHaus: ["/tash/symbols/tash/32_icon_house.png",15,15],
			Campingplatz: ["/tash/symbols/tash/osg/m_campingplaetze.png",15,15],
			Jugendherberge: ["/tash/symbols/tash/osg/m_jugendherbergen.png",15,15],
			Bauernhof: ["/tash/symbols/tash/osg/m_bauerhof.png",15,15],
			BettBike: ["/tash/symbols/tash/36_icon_bedbike.png",15,15],
			WellnesshotelBeautyfarm: ["/tash/symbols/tash/osg/m_wellnesshotels.png",15,15],
			Gastronomie: ["/tash/symbols/tash/osg/m_gastronomie.png",15,15],
			MuseumDenkmal: ["/tash/symbols/tash/osg/m_museum.png",15,15],
			Theater: ["/tash/symbols/tash/osg/m_theater.png",15,15],
			SchlossGarten: ["/tash/symbols/tash/osg/m_schloesser.png",15,15],
			KlosterKirche: ["/tash/symbols/tash/osg/m_kirchen.png",15,15],
			Freizeitpark: ["/tash/symbols/tash/osg/m_freizeitparks.png",15,15],
			TierparkZoo: ["/tash/symbols/tash/osg/m_zoo.png",15,15],
			StrandBaden: ["/tash/symbols/tash/osg/m_strand_und_Baden.png",15,15],
			Naturerlebnis: ["/tash/symbols/tash/osg/m_naturerlebnis.png",15,15],
			Segeln: ["/tash/symbols/tash/80_icon_sailing.png",15,15],
			FahrradverleihReparaturservice: ["/tash/symbols/tash/91_icon_bikerepair.png",15,15],
			AbschliessbareFahrradbox: ["/tash/symbols/tash/92_icon_bikelock.png",15,15],
			RastplatzSchutzhuette: ["/tash/symbols/tash/93_icon_bikeshed.png",15,15],
			Golfen: ["/tash/symbols/tash/100_icon_golf.png",15,15],
			Reiten: ["/tash/symbols/tash/110_icon_riding.png",15,15],			
			Busunternehmen: ["/tash/symbols/tash/osg/m_busbahnhof.png",15,15],
			ReedereiSchiffFaehre: ["/tash/symbols/tash/osg/m_haefen.png",15,15],
			Flughafen: ["/tash/symbols/tash/osg/m_flughaefen.png",15,15],
			Appartmenthaus: ["/tash/symbols/tash/osg/m_hotels.png",15,15],
			Ferienpark: ["/tash/symbols/tash/osg/m_freizeitparks.png",15,15],
			Gasthof: ["/tash/symbols/tash/osg/m_gastronomie.png",15,15],
			Erlebnisbad: ["/tash/symbols/tash/osg/m_freizeitbaeder.png",15,15],
			NaturerlebniszentrumAquarium: ["/tash/symbols/tash/osg/m_naturerlebnis.png",15,15],
			Veranstaltungen: ["/tash/symbols/tash/osg/m_events.png",15,15],
			Leuchttuerme: ["/tash/symbols/tash/osg/m_leuchtturm.png",15,15]
		}		
	},
	//Anzeige-Konfiguration in Aggregations-Listen
	aggregTypesConfDefault:{txt:"Default", img:"meta.png"},
	aggregTypesConf:{
			Tourismusinformation:{txt:"Tourismusinformation", img:"osg/Tourismusinformation.png"}, 	
			Bahnhof:{txt:"Bahnhöfe", img:"osg/bahnhof.png"},					
		  	HotelPension:{txt:"Hotels, Pensionen", img:"osg/Hotels.png"},
	  		FerienwohnungHaus:{txt:"Ferienwohnungen", img:"osg/fewos.png"},
	  		Campingplatz:{txt:"Campingplätze", img:"osg/Campingplaetze.png"},
			Jugendherberge:{txt:"Jugendherbergen", img:"osg/Jugendherbergen.png"},
	  		Bauernhof:{txt:"Bauernhöfe", img:"osg/bauerhof.png"},
	  		BettBike:{txt:"Radlerunterkünfte", img:"36_icon_bedbike.png"},
	  		WellnesshotelBeautyfarm:{txt:"Wellnesshotels", img:"osg/Wellnesshotels.png"},
	  		Gastronomie:{txt:"Gastronomie", img:"osg/Gastronomie.png"},
	  		MuseumDenkmal:{txt:"Museen & Denkmäler", img:"osg/Museum.png"},
	  		Theater:{txt:"Theater", img:"osg/Theater.png"},
	  		SchlossGarten:{txt:"Schlösser & Gärten", img:"osg/Schloesser.png"},
	  		KlosterKirche:{txt:"Kloster & Kirche", img:"osg/Kirchen.png"},
	  		Freizeitpark:{txt:"Freizeitparks", img:"osg/Freizeitparks.png"},
	  		TierparkZoo:{txt:"Tierparks / Zoos", img:"osg/Zoo.png"},
	  		Event:{txt:"Event", img:"osg/Events.png"},
	  		Naturerlebnis:{txt:"Naturerlebnis", img:"osg/Naturerlebnis.png"},
	  		Article:{txt:"Article", img:"article.png"},
	 	 	StrandBaden:{txt:"Strand & Baden", img:"osg/Strand_und_Baden.png"},
	  		Segeln:{txt:"Segeln", img:"80_icon_sailing.png"},
	  		FahrradverleihReparaturservice:{txt:"Radverleih/-reparatur", img:"91_icon_bikerepair.png"},
	  		AbschliessbareFahrradbox:{txt:"Abschliessbare Fahrradbox", img:"92_icon_bikelock.png"},
	  		RastplatzSchutzhuette:{txt:"Rastplatz & Schutzhuette", img:"93_icon_bikeshed.png"},
	  		Reiten:{txt:"Reiten", img:"110_icon_riding.png"},
	  		Golfen:{txt:"Golfen", img:"100_icon_golf.png"},
			
			gray:{txt:"Beförderung/Touristinfos", img:"/tash/symbols/tash/meta/meta-grau.png"},
			orange:{txt:"Unterkunft/Gastronomie", img:"/tash/symbols/tash/meta/meta-orange.png"},
			blue:{txt:"Kultur und Freizeit", img:"/tash/symbols/tash/meta/meta-blau.png"},
			green:{txt:"Veranstaltungen", img:"/tash/symbols/tash/meta/meta-gruen.png"},
	  		
			Busunternehmen:{txt:"Busunternehmen", img:"osg/Busbahnhof.png"},				
			ReedereiSchiffFaehre:{txt:"Reederei / Schiffahrt / Fähre", img:"osg/Haefen.png"},
			Flughafen:{txt:"Flughafen", img:"osg/Flughaefen.png"},
			Appartmenthaus:{txt:"Appartmenthaus", img:"osg/Hotels.png"},
			Ferienpark:{txt:"Freizeitparks", img:"osg/Freizeitparks.png"},
			Gasthof:{txt:"Gasthof", img:"osg/Gastronomie.png"},
			Erlebnisbad:{txt:"Erlebnisbad", img:"osg/Freizeitbaeder.png"},
			NaturerlebniszentrumAquarium:{txt:"Naturerlebniszentrum / Aquarium", img:"osg/Naturerlebnis.png"},
			Veranstaltungen:{txt:"Veranstaltungen", img:"osg/Events.png"},
			Leuchttuerme:{txt:"Leuchttürme", img:"osg/leuchtturm.png"}				
	},
	//Anzeige-Konfiguration in Aggregations-Listen für Salesguide (Portal)
	aggregTypesConfOSG: {
			Tourismusinformation:{txt:"Tourismusinformation",img:"10_icon_info.png"}, 	
			Bahnhof:{txt:"Bahnhöfe",img:"20_icon_train.png"},					
		  	HotelPension:{txt:"Hotels, Pensionen", img:"31_icon_bed.png"},
	  		FerienwohnungHaus:{txt:"Ferienwohnungen", img:"32_icon_house.png"},
	  		Campingplatz:{txt:"Campingplätze", img:"33_icon_camping.png"},
			Jugendherberge:{txt:"Jugendherbergen", img:"34_icon_hostel.png"},
	  		Bauernhof:{txt:"Bauernhöfe", img:"35_icon_farm.png"},
	  		BettBike:{txt:"Radlerunterkünfte", img:"36_icon_bedbike.png"},
	  		WellnesshotelBeautyfarm:{txt:"Wellnesshotels", img:"37_icon_beauty.png"},
	  		Gastronomie:{txt:"Gastronomie", img:"40_icon_food.png"},
	  		MuseumDenkmal:{txt:"Museen & Denkmäler", img:"51_icon_museum.png"},
	  		Theater:{txt:"Theater", img:"52_icon_theatre.png"},
	  		SchlossGarten:{txt:"Schlösser & Gärten", img:"53_icon_castle.png"},
	  		KlosterKirche:{txt:"Kloster & Kirche", img:"54_icon_church.png"},
	  		Freizeitpark:{txt:"Freizeitparks", img:"55_icon_themepark.png"},
	  		TierparkZoo:{txt:"Tierparks / Zoos", img:"56_icon_zoo.png"},
	  		Event:{txt:"Event", img:"event.png"},
	  		Naturerlebnis:{txt:"Naturerlebnis", img:"70_icon_nature.png"},
	  		Article:{txt:"Article", img:"article.png"},
	 	 	StrandBaden:{txt:"Strand & Baden", img:"60_icon_beach.png"},
	  		Segeln:{txt:"Segeln", img:"80_icon_sailing.png"},
	  		FahrradverleihReparaturservice:{txt:"Radverleih/-reparatur", img:"91_icon_bikerepair.png"},
	  		AbschliessbareFahrradbox:{txt:"Abschliessbare Fahrradbox", img:"92_icon_bikelock.png"},
	  		RastplatzSchutzhuette:{txt:"Rastplatz & Schutzhuette", img:"93_icon_bikeshed.png"},
	  		Reiten:{txt:"Reiten", img:"110_icon_riding.png"},
	  		Golfen:{txt:"Golfen", img:"100_icon_golf.png"},
	  		Veranstaltungen:{txt:"Veranstaltungen", img:"osg/Events.png"},
			
			gray:{txt:"Infrastruktur", img:"/tash/symbols/tash/meta/meta-grau.png"},
			orange:{txt:"Übernachten/Essen/Kultur", img:"/tash/symbols/tash/meta/meta-orange.png"},
			blue:{txt:"Meer & Natur", img:"/tash/symbols/tash/meta/meta-blau.png"},
			green:{txt:"Rad, Golf, Reiten", img:"/tash/symbols/tash/meta/meta-gruen.png"}		
	},
	
	//ALT	
	typeMap: { // defines translations for the POI types, order: FR,DE,EN
		Article: ["Artikel","Artikel","Artikel"],
		Offer: ["Offer","Offer","Offer"],
		Event: ["Event","Event","Event"],
		Tourismusinformation: ["Tourismusinformation","Tourismusinformation","Tourismusinformation"],
		Bahnhof: ["Bahnhöfe","Bahnhöfe","Bahnhöfe"],
		HotelPension: ["Hotels, Pensionen","Hotels, Pensionen","Hotels, Pensionen"],
		FerienwohnungHaus: ["Ferienwohnungen/-häuser","Ferienwohnungen/-häuser","Ferienwohnungen/-häuser"],
		Campingplatz: ["Campingplätze","Campingplätze","Campingplätze"],
		Jugendherberge: ["Jugendherbergen","Jugendherbergen","Jugendherbergen"],
		Bauernhof: ["Bauernhöfe","Bauernhöfe","Bauernhöfe"],
		BettBike: ["Bett & Bike","Bett & Bike","Bett & Bike"],
		WellnesshotelBeautyfarm: ["Wellnesshotels & Beautyfarmen","Wellnesshotels & Beautyfarmen","Wellnesshotels & Beautyfarmen"],
		Gastronomie: ["Gastronomie","Gastronomie","Gastronomie"],
		MuseumDenkmal: ["Museen & Denkmäler","Museen & Denkmäler","Museen & Denkmäler"],
		Theater: ["Theater","Theater","Theater"],
		SchlossGarten: ["Schlösser & Gärten","Schlösser & Gärten","Schlösser & Gärten"],
		KlosterKirche: ["Klöster & Kirchen","Klöster & Kirchen","Klöster & Kirchen"],
		Freizeitpark: ["Freizeitparks","Freizeitparks","Freizeitparks"],
		TierparkZoo: ["Tierparks/Zoos","Tierparks/Zoos","Tierparks/Zoos"],
		StrandBaden: ["Strand & Baden","Strand & Baden","Strand & Baden"],
		Naturerlebnis: ["Naturerlebnis","Naturerlebnis","Naturerlebnis"],
		Segeln: ["Segeln","Segeln","Segeln"],
		FahrradverleihReparaturservice: ["Fahrradverleih & Reparaturservice","Fahrradverleih & Reparaturservice","Fahrradverleih & Reparaturservice"],
		AbschliessbareFahrradbox: ["abschließbare Fahrradboxen","abschließbare Fahrradboxen","abschließbare Fahrradboxen"],
		RastplatzSchutzhuette: ["Rastplätze & Schutzhütten","Rastplätze & Schutzhütten","Rastplätze & Schutzhütten"],
		Golfen: ["Golfen","Golfen","Golfen"],
		Reiten: ["Reiten","Reiten","Reiten"],
		Wetter: ["Wetter","Wetter","Wetter"],
		meta: ["meta","meta","meta"]
	},
	
	//Infomax-ID 2 type (für externe Kommunikation)
	//Für alle Portale, zentral
	typeMapMapping: { 
		1:"Article",
		2:"Offer",
		3:"Event",
		10:"Tourismusinformation",
		20:"Bahnhof",
		31:"HotelPension",
		32:"FerienwohnungHaus",
		33:"Campingplatz",
		34:"Jugendherberge",
		35:"Bauernhof",
		36:"BettBike",
		37:"WellnesshotelBeautyfarm",
		40:"Gastronomie",
		51:"MuseumDenkmal",
		52:"Theater",
		53:"SchlossGarten",
		54:"KlosterKirche",
		55:"Freizeitpark",
		56:"TierparkZoo",
		60:"StrandBaden",
		70:"Naturerlebnis",
		80:"Segeln",
		91:"FahrradverleihReparaturservice",
		92:"AbschliessbareFahrradbox",
		93:"RastplatzSchutzhuette",
		100:"Golfen",
		110:"Reiten",
		120:"Wetter",
		999:"meta",
		1996:"Radweg",
		1997:"rw_anhaenger",
		1998:"rw_belag",
		1999:"rw_gesamt",		
		1986:"RadwegHLMS",
		1987:"rw_hlms_anhaenger",
		1988:"rw_hlms_belag",
		1989:"rw_hlms_gesamt",
		1976:"RadwegRegio",
		1977:"rw_regio_anhaenger",
		1978:"rw_regio_belag",
		1979:"rw_regio_gesamt",
		22:"Busunternehmen",
		23:"ReedereiSchiffFaehre",
		24:"Flughafen",
		38:"Appartmenthaus",
		39:"Ferienpark",
		391:"Gasthof",
		57:"Erlebnisbad",
		58:"NaturerlebniszentrumAquarium",
		130:"Veranstaltungen",
		140:"Leuchttuerme",
		150:"CmsArtikel"
	},
	
	typeWithLowLayerPrio: ["Tourismusinformation", "Bahnhof" ],  //POI-Typen die unterhalb anderer Liegen sollen (z-Index) da wenigiger wichtig (0002995)
	rw_mapping: {
		
	},

	// ALT ab hier vvvvvvvvvvvvvvvv
	
	langs: ["fr","de","en"],

	metaPointXOff : 0,
	metaPointYOff : 0,
	subPointXOff: 0,
	subPointYOff: 0,
	
	luxInterfaceAddress: "http://www.luxembourg2007.org/manif.php?map=", // jump back address for the event types
	
	// search results:
	
	showOnlySearchResults: false, // defines if only search result pois are displayed, the searchResult servlet is used...
	searchResultIds: [], // containes the IDs
	searchResultServletAddress: "http://luxembourg2007.alta4gis.de/luxembourg2007/tash/controller/searchExtent?", // List of search results in the Extent (replaces normal servlet)

	// ALT bis hier ^^^^^^^^^^^^^^^^

	// edit
	
	editMode: false, // defines if points can be edited, so the edit bar will be displayed and they can be moved
	//editServletAddress: "/alta4_servlets/noticeCoordinates?", // send edit commands to
	editServletAddress: "/tash/controller/noticeCoordinates?", // send edit commands to


	editObject: { // prepares the object to be edited
		recode: false,
		id: 0,
		lon: 0,
		lat: 0,
		origLon: 0,
		origLat: 0,
		type: null,
		name: "",
		successfullyGeocoded: false
	},
	// contains the parameters which are passed through the geocoding process
	editPassThrough: "",
			
	//  ++++++++++ PopUps +++++++++++	
	// ASK AG
	showPopUpMinWidth: 300,
	showPopUpMinHeight: 300,
	
	//ES: Flag - ob es die Minmap (kleine Karte auf Einzelseite und Angebotsuche). In der MapIntern wird "ermittelt", ob dies zutrift und der Flag gesetzt. 
	isMiniMap: false, 
	
	// using this template the popups can be customized, just add the fields in the DB at the position where they should be displayed,
	// all HTML content is parsed into a div by using innerHTML
	
	//TASH
	// die strings die durch variablen erstetzt werden...
	popUpTagNames: ["name","street","streetNumber","zipCode","zip","city","address1Street","address1ZipCode","address1City","contactName","email","homepage","phone1","phone","fax","previewImage","imageUrl","shortDescription","detailLink","region","lonWGS84","latWGS84","underlineTitle", "certifiedBnB", "link", "offerDetailLinks", "addressbaseName"],

	popUpTemplateGray: '<div class="overlay-window" style="left: 0px; top: 0px;"><div class="gray-titlebar"><img src="/tash/design/e7/overlay_corner_gray.gif" alt="" /><h3>_name_</h3></div><div class="body"><p class="address-left"><div>_street_ _streetNumber_</div>_zipCode_ _city_</p></div></div>',	
	popUpTemplateGray10: '<div class="overlay-window" style="left: 0px; top: 0px;"><div class="gray-titlebar"><img src="/tash/design/e7/overlay_corner_gray.gif" alt="" /><h3>_name_</h3></div><div class="body"><div class="info_block"><p class="address-left"><div>_street_ _streetNumber_</div>_zipCode_ _city__phone1_</p></div><div style="clear:both;"></div><p class="copy">_shortDescription_</p></div></div>',
	popUpTemplateGray20: '<div class="overlay-window" style="left: 0px; top: 0px;"><div class="gray-titlebar"><img src="/tash/design/e7/overlay_corner_gray.gif" alt="" /><h3>_name_</h3></div><div class="body"><p class="address-left"><div>_street_ _streetNumber_</div>_zipCode_ _city_</p><p class="morelink"><a href="http://reiseauskunft.bahn.de" target="_blank">&gt; Bahn-Reiseauskuft</a></p></div></div>',
	
	
	//mit Fax: popUpTemplateOrange: '<div class="overlay-window" style="left: 0px; top: 0px;"><div class="orange-titlebar"><img src="/tash/design/e7/overlay_corner_orange.gif" alt="" /><h3>_name_</h3></div><div class="body"><div class="info_block"><img src="_previewImage_" alt="" class="thumbnail" /><p class="address">_address1Street__address1ZipCode_ _address1City__phone1_</p></div><div style="clear:both;"></div><p class="copy">_shortDescription_</p>_detailLink__offerDetailLinks_</div></div>',
	//TODO: gruppierung foto+ adresse auf andere Templates übertragen
	popUpTemplateOrange: '<div class="overlay-window" style="left: 0px; top: 0px;"><div class="orange-titlebar"><img src="/tash/design/e7/overlay_corner_orange.gif" alt="" /><h3>_name_</h3></div><div class="body"><div class="info_block">_previewImage_<div class="address"><table border="0"><tr><td>_addressbaseName__address1Street__address1ZipCode_ _address1City__phone1__email_</td></tr></table></div></div><div style="clear:both;"></div><p class="copy">_shortDescription_</p>_detailLink__offerDetailLinks_</div></div>',
	
	popUpTemplateBlue: '<div class="overlay-window" style="left: 0px; top: 0px;"><div class="blue-titlebar"><img src="/tash/design/e7/overlay_corner_blue.gif" alt="" /><h3>_name_</h3></div><div class="body"><div class="info_block">_previewImage_<div class="address"><table border="0"><tr><td>_address1Street__address1ZipCode_ _address1City__phone1_</td></tr></table></div></div><div style="clear:both;"></div><p class="copy">_shortDescription_</p>_detailLink__offerDetailLinks_</div></div>',
	popUpTemplateBlue60: '<div class="overlay-window" style="left: 0px; top: 0px;"><div class="blue-titlebar"><img src="/tash/design/e7/overlay_corner_blue.gif" alt="" /><h3>_name_</h3></div><div class="body"><p class="address-left">_address1Street__zipCode_ _address1City_</p></div></div>',
	popUpTemplateBlue80: '<div class="overlay-window" style="left: 0px; top: 0px;"><div class="blue-titlebar"><img src="/tash/design/e7/overlay_corner_blue.gif" alt="" /><h3>_name_</h3></div><div class="body"><div class="info_block"><p class="address-left">_address1Street__address1ZipCode_ _address1City_</p></div><div style="clear:both;"></div><p class="copy"><br />_shortDescription_</p>_detailLink_</div></div>',
	
	popUpTemplateGreen: '<div class="overlay-window" style="left: 0px; top: 0px;"><div class="green-titlebar"><img src="/tash/design/e7/overlay_corner_green.gif" alt="" /><h3>_name_</h3></div><div class="body"><div class="info_block">_previewImage_<div class="address"><table border="0"><tr><td>_address1Street__address1ZipCode_ _address1City__phone1_</td></tr></table></div></div><div style="clear:both;"></div><p class="copy">_shortDescription_</p>_detailLink__offerDetailLinks_</div></div>',
	popUpTemplateGreen91: '<div class="overlay-window" style="left: 0px; top: 0px;"><div class="green-titlebar"><img src="/tash/design/e7/overlay_corner_green.gif" alt="" /><h3>_name_</h3></div><div class="body">_previewImage_<div class="address"><table border="0"><tr><td>_address1Street__address1ZipCode_ _address1City_<div>_street_ _streetNumber_</div>_zipCode_ _city__phone1_</td></tr></table></div><p class="copy">_shortDescription_</p>_detailLink__offerDetailLinks_</div></div>',
	popUpTemplateGreen92: '<div class="overlay-window" style="left: 0px; top: 0px;"><div class="green-titlebar"><img src="/tash/design/e7/overlay_corner_green.gif" alt="" /><h3>_name_</h3></div><div class="body"><p class="address-left">_address1Street__address1ZipCode_ _address1City_</p><div></div>',
	popUpTemplateGreen130: '<div class="overlay-window" style="left: 0px; top: 0px;"><div class="green-titlebar"><img src="/tash/design/e7/overlay_corner_green.gif" alt="" /><h3>_name_</h3></div><div class="body"><div class="info_block">_previewImage_<div class="address"><table border="0"><tr><td><div>_street_ _streetNumber_</div>_zipCode_ _city__phone1_</td></tr></table></div></div><div style="clear:both;"></div><p class="copy">_shortDescription_</p><p class="">_underlineTitle_</p>_detailLink__offerDetailLinks_</div></div>',
	
	popUpTemplateRW: '<div class="overlay-window" style="left: 0px; top: 0px;"><div class="gray-titlebar"><img src="/tash/design/e7/overlay_corner_gray.gif" alt="" /><h3>_name_</h3></div><div class="body"><table border="0">	<tr><td>_imageUrl_</td>	<td><div class="address">_contactName_<br /><p>_street_ _streetNumber_</p>_zip_ _city_</div>_email__homepage_</td></tr></table>	<p class="copy">_shortDescription_</p>_link_</div></div>',
	
	//7.6em wie die Bild-Breite
	plainTeaser: '<div class="overlay-window" style="left: 0px; top: 0px;width:7.6em"><div class="info_block"><a href="_detailLink_" title="_name_" >_previewImage_</a></div></div>',
	
	popUpHideDelay: 250, // how long should the popup (or name tag) stay open after leaving (in ms)

	certifiedBnBLogo: "/tash/symbols/tash/certified_bnb_logo.jpg",
	
	//ALT
	linesVisibleInAggregatedPopUp:10, // after x lines, the popup is cut and a scrollbar is drawn.

	maxLinkLength: 30, // after 30 letters, "..." will be displayed and the link is cut.
	maxNameLength: 30, // after 30 letters, "..." will be displayed and the name (_name_) is cut.
	
	weatherStationsTemplate : '<span>#{name}<span><img src="#{img}">#{minTmp}°/#{maxTmp}°',
	
	//  ++++++++++ MapManager +++++++++++
	//ALT? (LUX)
	zoomSpeed: 75, // speed of the zoom animation
	moveSpeed: 10, // step size of the move animation (translate the tiles by ?)
	
	//  ++++++++++ Copyright +++++++++++
	hasCopyrightInfo: true,
	copyrightInfos: [["powered by alta4","http://www.alta4.com"],["&copy; 2008 LVermA-SH, ATKIS &reg;","http://lverma.schleswig-holstein.de"]],
	copyrightInfosOffsetX: 20,
	copyrightInfosOffsetY: 20,

	//  ++++++++++ Logging +++++++++++
	loggingUserId: 3,
	loggingProject: 3,
	loggingURL: "/tash/logging/index.jsp",
	loggingActive: true,

	googleAnalyticsLoggingActive: false,
	
	//  ++++++++++ OverviewMap +++++++++++
	overviewMapZoomlevelDifference: 3, // number of zoomlevels between overview map and main map
	hasInteractions: true,
	isOverviewMap: false,
	hasConnectedMap: false,
	connectedMap: null,
	moveObserver: null,
	centerObserver: null,
	overviewMapBorderStyle: "1px solid white",
	
	//  ++++++++++ Authentification +++++++++++
	//ALT
	sessionId: 0, // will be used to store the current sessionId
	
	editGetPOIServlet: "/tash/controller/getPOI?",	
	bestViewServlet: "/tash/controller/getBestView?",
	
	//  ++++++++++ TASH specific +++++++++++
	
	// OA Kram, wenn notwendig im Server nachsehen...
	isArea:false,
	activeAreas:"0",
	activeTopics:"0",
	activeTargetGroups:"0",
	
	wetterInfos: {
	},
	wetterMapping:{
		0:'/tash/design/weather/d_0_b.gif',
		1:'/tash/design/weather/d_1_b.gif',
		2:'/tash/design/weather/d_2_b.gif',
		3:'/tash/design/weather/d_3_b.gif',
		4:'/tash/design/weather/d_4_b.gif',
		5:'/tash/design/weather/d_5_b.gif',
		6:'/tash/design/weather/d_6_b.gif',
		7:'/tash/design/weather/d_7_b.gif',
		8:'/tash/design/weather/d_8_b.gif',
		9:'/tash/design/weather/d_9_b.gif',
		10:'/tash/design/weather/d_nodata_b.gif',
		20:'/tash/design/weather/n_0_b.gif',
		21:'/tash/design/weather/n_1_b.gif',
		22:'/tash/design/weather/n_2_b.gif',
		23:'/tash/design/weather/n_3_b.gif',
		24:'/tash/design/weather/n_4_b.gif',
		25:'/tash/design/weather/n_5_b.gif',
		26:'/tash/design/weather/n_6_b.gif',
		27:'/tash/design/weather/n_7_b.gif',
		28:'/tash/design/weather/n_8_b.gif',
		29:'/tash/design/weather/n_9_b.gif',
		30:'/tash/design/weather/n_nodata_b.gif'	
	},
	
	//  ++++++++++ Minimizeability +++++++++++
	hasMinimizer: false,
	minimizerMinimizeImageSrc: "/tash/design/ov_map_close.png",
	minimizerMaximizeImageSrc: "/tash/design/ov_map_open.png",
	minimizerImageSize: [15,15],

	//  ++++++++++ Bounding box marker (for ovmap) +++++++++++
	hasBoundingBoxMarker: false,

	
	//  ++++++++++ Map-History +++++++++++
	/*Zurzeit wird nur das öffnen eines POI-Popups historiesiert*/
	hasHistory: true,  		//ob Historisierung überhaupt erwünscht ist
	history: new Array(),	//hält die Schritte fest (State-Objekte)
	historyCursor: null, 	//merkt sich die navigation innerhalb der history ("wo stehen wir gerade in der Histrory")
	historyMax: 10, 		//viele Schritte maximal germerkt werden sollen
	historyInitMapLat: null, //SH-Start-Extent merken (auch für back2Start-Funktionalität)
	historyInitMapLon: null, //SH-Start-Extent merken (auch für back2Start-Funktionalität)
	historyInitMapZoomLevel: null, //SH-Start-Extent merken (auch für back2Start-Funktionalität)
		
	// no map updates when true!!!	
	// wichtig wenn OVMap minimized... --> kein Neuzeichnen der Karte (mapIntern.repaint())
	suspendRedraw: false,
	
	vectors : {
		polygons: {
			defaultStroke: {color: "black", width: 2, cap: "butt", join: 4},
			defaultFill: [255, 128, 0, 0.5]
		},
		polylines: {
			defaultStroke: {color: "black", width: 2, cap: "butt", join: 4}
		},
		points: {
			defaultStroke: {color: "black", width: 2, cap: "butt", join: 4},
			defaultFill: [0, 128, 255, 0.5],
			defaultRadius: 5
		}
	},
	radwegeLayerConf:{ 
		fernradwege:{
			0: {layername:'rw_gesamt',	path: "200908/tash_rw_g/Digitaler Atlas SH/_alllayers/L"},
			1: {layername:'rw_belag',	path: "200908/tash_rw_b/Digitaler Atlas SH/_alllayers/L"},
			2: {layername:'rw_anhaenger',path: "200908/tash_rw_a/Digitaler Atlas SH/_alllayers/L"}
		},
		regioradwege:{
			0: {layername:'rw_regio_gesamt',	path: "200908/tash_rw_regio_g/Digitaler Atlas SH/_alllayers/L"},
			1: {layername:'rw_regio_belag',		path: "200908/tash_rw_regio_b/Digitaler Atlas SH/_alllayers/L"},
			2: {layername:'rw_regio_anhaenger',	path: "200908/tash_rw_regio_a/Digitaler Atlas SH/_alllayers/L"}
		},
		hlmsradwege:{
			0: {layername:'rw_hlms_gesamt',	path: "200908/tash_rw_hlms_g/Digitaler Atlas SH/_alllayers/L"},
			1: {layername:'rw_hlms_belag',		path: "200908/tash_rw_hlms_b/Digitaler Atlas SH/_alllayers/L"},
			2: {layername:'rw_hlms_anhaenger',	path: "200908/tash_rw_hlms_a/Digitaler Atlas SH/_alllayers/L"}
		}
	},
	//Portal-Spezifische Einstellungen (für TASH, OSG, HMLS etc)
	// Achtung: Ist hasPOIs untergeordnet!
	portalSettings: {
		2: {hasSubsetPois: true, hasAggregationPois: false}, //TASH (+ Riegel auf Serverseite für Aggreg-POIs!)
		3: {hasSubsetPois: true, hasAggregationPois: false}, //HLMS
		4: {hasSubsetPois: true, hasAggregationPois: false}, //OSG
		5: {hasSubsetPois: false, hasAggregationPois: true} //MaKS
	}
};

overviewMapOptions = {	
	vectors : {
		polygons: {
			defaultStroke: {color: "black", width: 1, cap: "butt", join: 4},
			defaultFill: [255, 128, 0, 1.0]
		},
		polylines: {
			defaultStroke: {color: "black", width: 1, cap: "butt", join: 4}
		},
		points: {
			defaultStroke: {color: "black", width: 1, cap: "butt", join: 4},
			defaultFill: [255, 128, 0, 1.0],
			defaultRadius: 2
		}
	},

	//  ++++++++++ Base Map +++++++++++
	width : 250,//"full", // height and width of the displayed map view in px
	height : 250,//"full",
	top : 0, // offset of this map view from browser window top, left in px
	left : 0,

	/*mapTileDir : "http://localhost/cache/_alllayers/L",
	mapTileImgFormat : "png",
	tileWidth : 1024, // width and height of one map tile in px
	tileHeight : 1024,
	agsTileXOffset : 0,
	agsTileYOffset : 0,
    agsResolution: [6.61459656252646,2.64583862501058],
	agsScale: [25000,10000],
	//agsScale: [25000,1],
	agsTileOrigin: [3523712.88370742,6084826.88698353],

	spacerImg : "http://tash.alta4gis.de/design/spacer_white.gif", // is used for display when no map tile is defined for the requested position		
	borderCache: 2, // count of tiles by which the tilematrix is bigger than the visible extent
	
	minimumAllowedZoomLevel: 0,

	//  ++++++++++ Initial loading cnfiguration +++++++++++
	// will be overridden by the URL parameters! (when implemented)
	zoomLevel : 0, // zoomLevel is the index of the zoomFactor array (in [1,4,8,16] 2 would resemble zoomFactor "8")
	lon : 3611201, // map center on start
	lat : 5973283,
	*/
	
	mapTileDir : 'http://tash.alta4gis.de/cache3/',
	mapTileImgFormat : "jpg",
	mapTileImgFormatTransparent: "png", //Kacheln mit Transparenz (z.B. Radwege) -> Zwischenlösung

	//TODO
	tileCOntainerSourceConfisgGanzLangVariable :  { 
		radwege : {
			sourcePath: "..._alllayers/",
			mapTileImageFormat : "jpg"
		},
		hintergrund: {
			sourcePath: "..._alllayers2/",
			mapTileImageFormat : "png"
		}
	},

	tileWidth : 256, // width and height of one map tile in px
	tileHeight : 256,
	agsTileXOffset : 0,
	agsTileYOffset : 0,

	agsResolution: [2645.83862501058,1852.08703750741,793.751587503175,396.875793751588,132.291931250529,66.1459656252646,26.4583862501058,13.2291931250529,6.61459656252646,2.64583862501058],
	agsScale: [10000000,7000000,3000000,1500000,500000,250000,100000,50000,25000,10000],
	agsTileOrigin: [-2122500,10001000],
	visibleBounds: {
		ul: [3351210.0, 6194167.0],
		lr: [3749674.0, 5822294.0]
	},
	spacerImg : "http://tash.alta4gis.de/design/spacer_white.gif", // is used for display when no map tile is defined for the requested position		
	borderCache: 2, // count of tiles by which the tilematrix is bigger than the visible extent
	
	minimumAllowedZoomLevel: 0,

	//  ++++++++++ Initial loading cnfiguration +++++++++++
	// will be overridden by the URL parameters! (when implemented)
	zoomLevel : 0, // zoomLevel is the index of the zoomFactor array (in [1,4,8,16] 2 would resemble zoomFactor "8")
	lon : 3547000, // map center on start
	lat : 6010000,

	//  ++++++++++ Coordinates +++++++++++
	magicNumberRW_Y: 0.0, // ugly magic numbers to account for points offset in the coordinate calculation
	magicNumberPX_Y: 0.4,
	
	//  ++++++++++ Compass Rose +++++++++++
	hasCompassRose : false,
	compassRoseSize : 54, // size in px, is assumed to be quadratic
	compassRoseSrc: "/tash/design/e7/windrose.gif",
	compassRoseSpeed : 5, // in something like px / s
	compassRoseGamestyleSpeed: 0.25, // factor for the gamestyle mover
	compassRosePadding: 10, // distance from map border
	compassRosePosition : "top-left", // possible: "bottom-left","bottom-right","top-left"

	//  ++++++++++ ZoomBar +++++++++++
	hasZoomBar : false,
	zoomBarStyle : "full", // if "full", the zoomBar gets a slider to select zoomLevel, otherwise only plus and minus sign is displayed
	zoomBarTop : 0,
	zoomBarLeft: 0,

	plusImg: "/tash/design/e7/zoomplus.gif", // design elements of the zoomBar
	plusImgWidth: 18,
	zoomBarPlusImgHeight: 18,
	minusImg: "/tash/design/e7/zoomminus.gif",
	minusImgWidth: 18,
	minusImgHeight: 18,
	stepImg: "/tash/design/e7/scrollbar.gif",
	stepImgWidth: 18,
	stepImgHeight: 11,
	knobImg: "/tash/design/e7/schieber.gif",
	knobImgWidth: 18,
	knobImgHeight: 11,

	zoomBarPaddingBottom: 0, // if the zoom bar shall not align to map view bottom, add offset here
	zoomBarPaddingHeight: 74,

	//  ++++++++++ POIs +++++++++++
	hasPOIs : false,
	poiMinimumZoomLevel : 0,
	poiMaxPrecision: 4, // defines the maximum accuracy of the poiCache. Should be ok for all normal use cases
	
	poiSearchExtentAddress: "/tash/controller/searchExtent?", //URL zum searchExtent-Servlet
	poiServletAddress: "/tash/controller/extent?", // List of POIs in the Extent (minX,minY,maxX,maxY)
	leavesServletAddress: "/tash/controller/leaves?", // 
	poiTypeServletAddress: "/tash/controller/type?", // all subpoints of a given point of a given type (id,type)
	poiDataServletAddress: "/tash/controller/poi?", // all attributes of one poi (id)
		
	defaultIcon: ["/tash/symbols/tash/meta.png",22,22], // default icon to be used if no icon is defined
	usedIcons: {
		Article: ["/tash/symbols/tash/article.png",22,22],
		Offer: ["/tash/symbols/tash/offer.png",22,22],
		Event: ["/tash/symbols/tash/event.png",22,22],
		Tourismusinformation: ["/tash/symbols/tash/10_icon_info.png",23,23],
		Bahnhof: ["/tash/symbols/tash/20_icon_train.png",23,23],
		HotelPension: ["/tash/symbols/tash/31_icon_bed.png",23,23],
		FerienwohnungHaus: ["/tash/symbols/tash/32_icon_house.png",23,23],
		Campingplatz: ["/tash/symbols/tash/33_icon_camping.png",23,23],
		Jugendherberge: ["/tash/symbols/tash/34_icon_hostel.png",23,23],
		Bauernhof: ["/tash/symbols/tash/35_icon_farm.png",23,23],
		BettBike: ["/tash/symbols/tash/36_icon_bedbike.png",23,23],
		WellnesshotelBeautyfarm: ["/tash/symbols/tash/37_icon_beauty.png",23,23],
		Gastronomie: ["/tash/symbols/tash/40_icon_food.png",23,23],
		MuseumDenkmal: ["/tash/symbols/tash/51_icon_museum.png",23,23],
		Theater: ["/tash/symbols/tash/52_icon_theatre.png",23,23],
		SchlossGarten: ["/tash/symbols/tash/53_icon_castle.png",23,23],
		KlosterKirche: ["/tash/symbols/tash/54_icon_church.png",23,23],
		Freizeitpark: ["/tash/symbols/tash/55_icon_themepark.png",23,23],
		TierparkZoo: ["/tash/symbols/tash/56_icon_zoo.png",23,23],
		StrandBaden: ["/tash/symbols/tash/60_icon_beach.png",23,23],
		Naturerlebnis: ["/tash/symbols/tash/70_icon_nature.png",23,23],
		Segeln: ["/tash/symbols/tash/80_icon_sailing.png",23,23],
		FahrradverleihReparaturservice: ["/tash/symbols/tash/91_icon_bikerepair.png",23,23],
		AbschliessbareFahrradbox: ["/tash/symbols/tash/92_icon_bikelock.png",23,23],
		RastplatzSchutzhuette: ["/tash/symbols/tash/93_icon_bikeshed.png",23,23],
		Golfen: ["/tash/symbols/tash/100_icon_golf.png",23,23],
		Reiten: ["/tash/symbols/tash/110_icon_riding.png",23,23],
		meta: ["/tash/symbols/tash/meta.png",22,22],
		Leuchttuerme: ["/tash/symbols/tash/leuchtturm.png",23,23],
		CmsArtikel: ["/tash/symbols/tash/150_cms_artikel.png",23,23]
	},	
		//Salesguide hat neue POI-Typen und einige POIs habe hier andere Symbole  
	usedIconsOSG: {
		Article: ["/tash/symbols/tash/article.png",22,22],
		Offer: ["/tash/symbols/tash/offer.png",22,22],
		Event: ["/tash/symbols/tash/event.png",22,22],
		Tourismusinformation: ["/tash/symbols/tash/osg/Tourismusinformation.png",22,22],
		Bahnhof: ["/tash/symbols/tash/osg/bahnhof.png",24,24],
		HotelPension: ["/tash/symbols/tash/osg/Hotels.png",22,22],
		FerienwohnungHaus: ["/tash/symbols/tash/32_icon_house.png",24,24],
		Campingplatz: ["/tash/symbols/tash/osg/Campingplaetze.png",22,22],
		Jugendherberge: ["/tash/symbols/tash/osg/Jugendherbergen.png",22,22],
		Bauernhof: ["/tash/symbols/tash/osg/bauerhof.png",24,24],
		BettBike: ["/tash/symbols/tash/36_icon_bedbike.png",24,24],
		WellnesshotelBeautyfarm: ["/tash/symbols/tash/osg/Wellnesshotels.png",22,22],
		Gastronomie: ["/tash/symbols/tash/osg/Gastronomie.png",22,22],
		MuseumDenkmal: ["/tash/symbols/tash/osg/Museum.png",22,22],
		Theater: ["/tash/symbols/tash/osg/Theater.png",22,22],
		SchlossGarten: ["/tash/symbols/tash/osg/Schloesser.png",22,22],
		KlosterKirche: ["/tash/symbols/tash/osg/Kirchen.png",22,22],
		Freizeitpark: ["/tash/symbols/tash/osg/Freizeitparks.png",24,24],
		TierparkZoo: ["/tash/symbols/tash/osg/Zoo.png",22,22],
		StrandBaden: ["/tash/symbols/tash/osg/Strand_und_Baden.png",22,22],
		Naturerlebnis: ["/tash/symbols/tash/osg/Naturerlebnis.png",22,22],
		Segeln: ["/tash/symbols/tash/80_icon_sailing.png",24,24],
		FahrradverleihReparaturservice: ["/tash/symbols/tash/91_icon_bikerepair.png",24,24],
		AbschliessbareFahrradbox: ["/tash/symbols/tash/92_icon_bikelock.png",24,24],
		RastplatzSchutzhuette: ["/tash/symbols/tash/93_icon_bikeshed.png",24,24],
		Golfen: ["/tash/symbols/tash/100_icon_golf.png",24,24],
		Reiten: ["/tash/symbols/tash/110_icon_riding.png",24,24],
		meta: ["/tash/symbols/tash/meta.png",22,22],
		Wetter: ["/tash/design/weather/d_nodata_b.gif",24,24],
		rw1: ["/tash/images/radweg/ico_alte_salzstrasse.png",19,19],
		rw2: ["/tash/images/radweg/ico_elberadweg.png",19,19],
		rw3: ["/tash/images/radweg/ico_eider_treene.png",19,19],
		rw4: ["/tash/images/radweg/ico_grenzroute.png",19,19],
		rw5: ["/tash/images/radweg/ico_hamburg_ruegen.png",19,19],
		rw6: ["/tash/images/radweg/ico_holsteinische_schweiz.png",19,19],
		rw7: ["/tash/images/radweg/ico_moenchsweg.png",19,19],
		rw8: ["/tash/images/radweg/ico_nordostseekanalroute.png",19,19],
		rw9: ["/tash/images/radweg/ico_nordseekuestenradweg.png",19,19],
		rw10: ["/tash/images/radweg/ico_ochsenweg.png",19,19],
		rw11: ["/tash/images/radweg/ico_ostseekuestenradweg.png",19,19],
		rw12: ["/tash/images/radweg/ico_wikinger_friesen.png",19,19],	
		//hlms
		rw13: ["/tash/images/radweg/ico_alleen_herrenhaeuser.png",19,19],
		rw14: ["/tash/images/radweg/ico_eiszeittour.png",19,19],
		rw15: ["/tash/images/radweg/ico_kirchentour.png",19,19],
		rw16: ["/tash/images/radweg/ico_seenradtour.png",19,19],
		rw17: ["/tash/images/radweg/ico_techniktour.png",19,19],
		rw18: ["/tash/images/radweg/ico_regionale_routen.png",19,19],
		
		Busunternehmen: ["/tash/symbols/tash/osg/Busbahnhof.png",22,22],
		ReedereiSchiffFaehre: ["/tash/symbols/tash/osg/Haefen.png",22,22],
		Flughafen: ["/tash/symbols/tash/osg/Flughaefen.png",22,22],
		Appartmenthaus: ["/tash/symbols/tash/osg/Hotels.png",22,22],
		Ferienpark: ["/tash/symbols/tash/osg/Freizeitparks.png",22,22],
		Gasthof: ["/tash/symbols/tash/osg/Gastronomie.png",22,22],
		Erlebnisbad: ["/tash/symbols/tash/osg/Freizeitbaeder.png",22,22],
		NaturerlebniszentrumAquarium: ["/tash/symbols/tash/osg/Naturerlebnis.png",22,22],
		Veranstaltungen: ["/tash/symbols/tash/osg/Events.png",22,22],
		Leuchttuerme: ["/tash/symbols/tash/osg/150_cms_artikel.png",23,23]
	},
	// die icons für die random points in aggregationszoomstufen
	usedIconsPOISubset: {
		smallSize:{
			/*Article: ["/tash/symbols/tash/article.png",22,22],
			Offer: ["/tash/symbols/tash/offer.png",22,22],
			Event: ["/tash/symbols/tash/event.png",22,22],*/
			Tourismusinformation: ["/tash/symbols/tash/s_information.png",11,11],
			Bahnhof: ["/tash/symbols/tash/s_bahnhof.png",11,11],
			HotelPension: ["/tash/symbols/tash/s_hotels-und-pensionen.png",11,11],
			FerienwohnungHaus: ["/tash/symbols/tash/s_fewos.png",11,11],
			Campingplatz: ["/tash/symbols/tash/s_campingplatz.png",11,11],
			Jugendherberge: ["/tash/symbols/tash/s_jugendherberge.png",11,11],
			Bauernhof: ["/tash/symbols/tash/s_bauerhof.png",11,11],
			BettBike: ["/tash/symbols/tash/s_bett-u-bike.png",11,11],
			WellnesshotelBeautyfarm: ["/tash/symbols/tash/s_wellnesshotels.png",11,11],
			Gastronomie: ["/tash/symbols/tash/s_gastronomie.png",11,11],
			MuseumDenkmal: ["/tash/symbols/tash/s_museen.png",11,11],
			Theater: ["/tash/symbols/tash/s_theater.png",11,11],
			SchlossGarten: ["/tash/symbols/tash/s_schloesser.png",11,11],
			KlosterKirche: ["/tash/symbols/tash/s_kirchen.png",11,11],
			Freizeitpark: ["/tash/symbols/tash/s_freizeitparks.png",11,11],
			TierparkZoo: ["/tash/symbols/tash/s_zoo.png",11,11],
			StrandBaden: ["/tash/symbols/tash/s_strand-und-baden.png",11,11],
			Naturerlebnis: ["/tash/symbols/tash/s_nature.png",11,11],
			Segeln: ["/tash/symbols/tash/s_segeln.png",11,11],
			FahrradverleihReparaturservice: ["/tash/symbols/tash/s_fahrradverleih.png",11,11],
			AbschliessbareFahrradbox: ["/tash/symbols/tash/s_fahrradboxen.png",11,11],
			RastplatzSchutzhuette: ["/tash/symbols/tash/s_schutzhuetten.png",11,11],
			Golfen: ["/tash/symbols/tash/s_golf.png",11,11],
			Reiten: ["/tash/symbols/tash/s_reiten.png",11,11],
			/*meta: ["/tash/symbols/tash/meta.png",22,22],
			Wetter: ["/tash/design/weather/d_nodata_b.gif",24,24],*/
			Veranstaltungen: ["/tash/symbols/tash/osg/s_events.png",11,11],
			Leuchttuerme: ["/tash/symbols/tash/s_leuchtturm.png",11,11],
			CmsArtikel: ["/tash/symbols/tash/s_cms_artikel.png",11,11]
		},
		mediumSize:{
			Tourismusinformation: ["/tash/symbols/tash/m_information.png",15,15],
			Bahnhof: ["/tash/symbols/tash/m_bahnhof.png",15,15],
			HotelPension: ["/tash/symbols/tash/m_hotels-und-pensionen.png",15,15],
			FerienwohnungHaus: ["/tash/symbols/tash/m_fewos.png",15,15],
			Campingplatz: ["/tash/symbols/tash/m_campingplatz.png",15,15],
			Jugendherberge: ["/tash/symbols/tash/m_jugendherberge.png",15,15],
			Bauernhof: ["/tash/symbols/tash/m_bauerhof.png",15,15],
			BettBike: ["/tash/symbols/tash/m_bett-u-bike.png",15,15],
			WellnesshotelBeautyfarm: ["/tash/symbols/tash/m_wellnesshotels.png",15,15],
			Gastronomie: ["/tash/symbols/tash/m_gastronomie.png",15,15],
			MuseumDenkmal: ["/tash/symbols/tash/m_museen.png",15,15],
			Theater: ["/tash/symbols/tash/m_theater.png",15,15],
			SchlossGarten: ["/tash/symbols/tash/m_schloesser.png",15,15],
			KlosterKirche: ["/tash/symbols/tash/m_kirchen.png",15,15],
			Freizeitpark: ["/tash/symbols/tash/m_freizeitparks.png",15,15],
			TierparkZoo: ["/tash/symbols/tash/m_zoo.png",15,15],
			StrandBaden: ["/tash/symbols/tash/m_strand-und-baden.png",15,15],
			Naturerlebnis: ["/tash/symbols/tash/m_nature.png",15,15],
			Segeln: ["/tash/symbols/tash/m_segeln.png",15,15],
			FahrradverleihReparaturservice: ["/tash/symbols/tash/m_fahrradverleih.png",15,15],
			AbschliessbareFahrradbox: ["/tash/symbols/tash/m_fahrradboxen.png",15,15],
			RastplatzSchutzhuette: ["/tash/symbols/tash/m_schutzhuetten.png",15,15],
			Golfen: ["/tash/symbols/tash/m_golf.png",15,15],
			Reiten: ["/tash/symbols/tash/m_reiten.png",15,15],
			/*meta: ["/tash/symbols/tash/meta.png",22,22],
			Wetter: ["/tash/design/weather/d_nodata_b.gif",24,24],*/
			Veranstaltungen: ["/tash/symbols/tash/osg/m_events.png",15,15],
			Leuchttuerme: ["/tash/symbols/tash/m_leuchtturm.png",15,15],
			CmsArtikel: ["/tash/symbols/tash/m_cms_artikel.png",15,15]
		}
	},
	usedIconsPOISubsetOSG: {
		smallSize:{
			Tourismusinformation: ["/tash/symbols/tash/osg/s_tourismusinformation.png",11,11],
			Bahnhof: ["/tash/symbols/tash/osg/s_bahnhof.png",11,11],
			HotelPension: ["/tash/symbols/tash/osg/s_hotels.png",11,11],
			FerienwohnungHaus: ["/tash/symbols/tash/32_icon_house.png",11,11],
			Campingplatz: ["/tash/symbols/tash/osg/s_campingplaetze.png",11,11],
			Jugendherberge: ["/tash/symbols/tash/osg/s_jugendherbergen.png",11,11],
			Bauernhof: ["/tash/symbols/tash/osg/s_bauerhof.png",11,11],
			BettBike: ["/tash/symbols/tash/36_icon_bedbike.png",11,11],
			WellnesshotelBeautyfarm: ["/tash/symbols/tash/osg/s_wellnesshotels.png",11,11],
			Gastronomie: ["/tash/symbols/tash/osg/s_gastronomie.png",11,11],
			MuseumDenkmal: ["/tash/symbols/tash/osg/s_museum.png",11,11],
			Theater: ["/tash/symbols/tash/osg/s_theater.png",11,11],
			SchlossGarten: ["/tash/symbols/tash/osg/s_schloesser.png",11,11],
			KlosterKirche: ["/tash/symbols/tash/osg/s_kirchen.png",11,11],
			Freizeitpark: ["/tash/symbols/tash/osg/s_freizeitparks.png",11,11],
			TierparkZoo: ["/tash/symbols/tash/osg/s_zoo.png",11,11],
			StrandBaden: ["/tash/symbols/tash/osg/s_strand_und_Baden.png",11,11],
			Naturerlebnis: ["/tash/symbols/tash/osg/s_naturerlebnis.png",11,11],
			Segeln: ["/tash/symbols/tash/80_icon_sailing.png",11,11],
			FahrradverleihReparaturservice: ["/tash/symbols/tash/91_icon_bikerepair.png",11,11],
			AbschliessbareFahrradbox: ["/tash/symbols/tash/92_icon_bikelock.png",11,11],
			RastplatzSchutzhuette: ["/tash/symbols/tash/93_icon_bikeshed.png",11,11],
			Golfen: ["/tash/symbols/tash/100_icon_golf.png",11,11],
			Reiten: ["/tash/symbols/tash/110_icon_riding.png",11,11],			
			Busunternehmen: ["/tash/symbols/tash/osg/s_busbahnhof.png",11,11],
			ReedereiSchiffFaehre: ["/tash/symbols/tash/osg/s_haefen.png",11,11],
			Flughafen: ["/tash/symbols/tash/osg/s_flughaefen.png",11,11],
			Appartmenthaus: ["/tash/symbols/tash/osg/s_hotels.png",11,11],
			Ferienpark: ["/tash/symbols/tash/osg/s_freizeitparks.png",11,11],
			Gasthof: ["/tash/symbols/tash/osg/s_gastronomie.png",11,11],
			Erlebnisbad: ["/tash/symbols/tash/osg/s_freizeitbaeder.png",11,11],
			NaturerlebniszentrumAquarium: ["/tash/symbols/tash/osg/s_naturerlebnis.png",11,11],
			Veranstaltungen: ["/tash/symbols/tash/osg/s_events.png",11,11],
			Leuchttuerme: ["/tash/symbols/tash/osg/s_leuchtturm.png",11,11]
		},
		mediumSize:{
			Tourismusinformation: ["/tash/symbols/tash/osg/m_tourismusinformation.png",15,15],
			Bahnhof: ["/tash/symbols/tash/osg/m_bahnhof.png",15,15],
			HotelPension: ["/tash/symbols/tash/osg/m_hotels.png",15,15],
			FerienwohnungHaus: ["/tash/symbols/tash/32_icon_house.png",15,15],
			Campingplatz: ["/tash/symbols/tash/osg/m_campingplaetze.png",15,15],
			Jugendherberge: ["/tash/symbols/tash/osg/m_jugendherbergen.png",15,15],
			Bauernhof: ["/tash/symbols/tash/osg/m_bauerhof.png",15,15],
			BettBike: ["/tash/symbols/tash/36_icon_bedbike.png",15,15],
			WellnesshotelBeautyfarm: ["/tash/symbols/tash/osg/m_wellnesshotels.png",15,15],
			Gastronomie: ["/tash/symbols/tash/osg/m_gastronomie.png",15,15],
			MuseumDenkmal: ["/tash/symbols/tash/osg/m_museum.png",15,15],
			Theater: ["/tash/symbols/tash/osg/m_theater.png",15,15],
			SchlossGarten: ["/tash/symbols/tash/osg/m_schloesser.png",15,15],
			KlosterKirche: ["/tash/symbols/tash/osg/m_kirchen.png",15,15],
			Freizeitpark: ["/tash/symbols/tash/osg/m_freizeitparks.png",15,15],
			TierparkZoo: ["/tash/symbols/tash/osg/m_zoo.png",15,15],
			StrandBaden: ["/tash/symbols/tash/osg/m_strand_und_Baden.png",15,15],
			Naturerlebnis: ["/tash/symbols/tash/osg/m_naturerlebnis.png",15,15],
			Segeln: ["/tash/symbols/tash/80_icon_sailing.png",15,15],
			FahrradverleihReparaturservice: ["/tash/symbols/tash/91_icon_bikerepair.png",15,15],
			AbschliessbareFahrradbox: ["/tash/symbols/tash/92_icon_bikelock.png",15,15],
			RastplatzSchutzhuette: ["/tash/symbols/tash/93_icon_bikeshed.png",15,15],
			Golfen: ["/tash/symbols/tash/100_icon_golf.png",15,15],
			Reiten: ["/tash/symbols/tash/110_icon_riding.png",15,15],			
			Busunternehmen: ["/tash/symbols/tash/osg/m_busbahnhof.png",15,15],
			ReedereiSchiffFaehre: ["/tash/symbols/tash/osg/m_haefen.png",15,15],
			Flughafen: ["/tash/symbols/tash/osg/m_flughaefen.png",15,15],
			Appartmenthaus: ["/tash/symbols/tash/osg/m_hotels.png",15,15],
			Ferienpark: ["/tash/symbols/tash/osg/m_freizeitparks.png",15,15],
			Gasthof: ["/tash/symbols/tash/osg/m_gastronomie.png",15,15],
			Erlebnisbad: ["/tash/symbols/tash/osg/m_freizeitbaeder.png",15,15],
			NaturerlebniszentrumAquarium: ["/tash/symbols/tash/osg/m_naturerlebnis.png",15,15],
			Veranstaltungen: ["/tash/symbols/tash/osg/m_events.png",15,15],
			Leuchttuerme: ["/tash/symbols/tash/osg/m_leuchtturm.png",15,15]
		}		
	},
	//Anzeige-Konfiguration in Aggregations-Listen
	aggregTypesConfDefault:{txt:"Default", img:"meta.png"},
	aggregTypesConf:{
			Tourismusinformation:{txt:"Tourismusinformation", img:"osg/Tourismusinformation.png"}, 	
			Bahnhof:{txt:"Bahnhöfe", img:"osg/bahnhof.png"},					
		  	HotelPension:{txt:"Hotels, Pensionen", img:"osg/Hotels.png"},
	  		FerienwohnungHaus:{txt:"Ferienwohnungen", img:"osg/fewos.png"},
	  		Campingplatz:{txt:"Campingplätze", img:"osg/Campingplaetze.png"},
			Jugendherberge:{txt:"Jugendherbergen", img:"osg/Jugendherbergen.png"},
	  		Bauernhof:{txt:"Bauernhöfe", img:"osg/bauerhof.png"},
	  		BettBike:{txt:"Radlerunterkünfte", img:"36_icon_bedbike.png"},
	  		WellnesshotelBeautyfarm:{txt:"Wellnesshotels", img:"osg/Wellnesshotels.png"},
	  		Gastronomie:{txt:"Gastronomie", img:"osg/Gastronomie.png"},
	  		MuseumDenkmal:{txt:"Museen & Denkmäler", img:"osg/Museum.png"},
	  		Theater:{txt:"Theater", img:"osg/Theater.png"},
	  		SchlossGarten:{txt:"Schlösser & Gärten", img:"osg/Schloesser.png"},
	  		KlosterKirche:{txt:"Kloster & Kirche", img:"osg/Kirchen.png"},
	  		Freizeitpark:{txt:"Freizeitparks", img:"osg/Freizeitparks.png"},
	  		TierparkZoo:{txt:"Tierparks / Zoos", img:"osg/Zoo.png"},
	  		Event:{txt:"Event", img:"osg/Events.png"},
	  		Naturerlebnis:{txt:"Naturerlebnis", img:"osg/Naturerlebnis.png"},
	  		Article:{txt:"Article", img:"article.png"},
	 	 	StrandBaden:{txt:"Strand & Baden", img:"osg/Strand_und_Baden.png"},
	  		Segeln:{txt:"Segeln", img:"80_icon_sailing.png"},
	  		FahrradverleihReparaturservice:{txt:"Radverleih/-reparatur", img:"91_icon_bikerepair.png"},
	  		AbschliessbareFahrradbox:{txt:"Abschliessbare Fahrradbox", img:"92_icon_bikelock.png"},
	  		RastplatzSchutzhuette:{txt:"Rastplatz & Schutzhuette", img:"93_icon_bikeshed.png"},
	  		Reiten:{txt:"Reiten", img:"110_icon_riding.png"},
	  		Golfen:{txt:"Golfen", img:"100_icon_golf.png"},
			
			gray:{txt:"Beförderung/Touristinfos", img:"/tash/symbols/tash/meta/meta-grau.png"},
			orange:{txt:"Unterkunft/Gastronomie", img:"/tash/symbols/tash/meta/meta-orange.png"},
			blue:{txt:"Kultur und Freizeit", img:"/tash/symbols/tash/meta/meta-blau.png"},
			green:{txt:"Veranstaltungen", img:"/tash/symbols/tash/meta/meta-gruen.png"},
	  		
			Busunternehmen:{txt:"Busunternehmen", img:"osg/Busbahnhof.png"},				
			ReedereiSchiffFaehre:{txt:"Reederei / Schiffahrt / Fähre", img:"osg/Haefen.png"},
			Flughafen:{txt:"Flughafen", img:"osg/Flughaefen.png"},
			Appartmenthaus:{txt:"Appartmenthaus", img:"osg/Hotels.png"},
			Ferienpark:{txt:"Freizeitparks", img:"osg/Freizeitparks.png"},
			Gasthof:{txt:"Gasthof", img:"osg/Gastronomie.png"},
			Erlebnisbad:{txt:"Erlebnisbad", img:"osg/Freizeitbaeder.png"},
			NaturerlebniszentrumAquarium:{txt:"Naturerlebniszentrum / Aquarium", img:"osg/Naturerlebnis.png"},
			Veranstaltungen:{txt:"Veranstaltungen", img:"osg/Events.png"},
			Leuchttuerme:{txt:"Leuchttürme", img:"osg/leuchtturm.png"}				
	},
	//Anzeige-Konfiguration in Aggregations-Listen für Salesguide (Portal)
	aggregTypesConfOSG: {
			Tourismusinformation:{txt:"Tourismusinformation",img:"10_icon_info.png"}, 	
			Bahnhof:{txt:"Bahnhöfe",img:"20_icon_train.png"},					
		  	HotelPension:{txt:"Hotels, Pensionen", img:"31_icon_bed.png"},
	  		FerienwohnungHaus:{txt:"Ferienwohnungen", img:"32_icon_house.png"},
	  		Campingplatz:{txt:"Campingplätze", img:"33_icon_camping.png"},
			Jugendherberge:{txt:"Jugendherbergen", img:"34_icon_hostel.png"},
	  		Bauernhof:{txt:"Bauernhöfe", img:"35_icon_farm.png"},
	  		BettBike:{txt:"Radlerunterkünfte", img:"36_icon_bedbike.png"},
	  		WellnesshotelBeautyfarm:{txt:"Wellnesshotels", img:"37_icon_beauty.png"},
	  		Gastronomie:{txt:"Gastronomie", img:"40_icon_food.png"},
	  		MuseumDenkmal:{txt:"Museen & Denkmäler", img:"51_icon_museum.png"},
	  		Theater:{txt:"Theater", img:"52_icon_theatre.png"},
	  		SchlossGarten:{txt:"Schlösser & Gärten", img:"53_icon_castle.png"},
	  		KlosterKirche:{txt:"Kloster & Kirche", img:"54_icon_church.png"},
	  		Freizeitpark:{txt:"Freizeitparks", img:"55_icon_themepark.png"},
	  		TierparkZoo:{txt:"Tierparks / Zoos", img:"56_icon_zoo.png"},
	  		Event:{txt:"Event", img:"event.png"},
	  		Naturerlebnis:{txt:"Naturerlebnis", img:"70_icon_nature.png"},
	  		Article:{txt:"Article", img:"article.png"},
	 	 	StrandBaden:{txt:"Strand & Baden", img:"60_icon_beach.png"},
	  		Segeln:{txt:"Segeln", img:"80_icon_sailing.png"},
	  		FahrradverleihReparaturservice:{txt:"Radverleih/-reparatur", img:"91_icon_bikerepair.png"},
	  		AbschliessbareFahrradbox:{txt:"Abschliessbare Fahrradbox", img:"92_icon_bikelock.png"},
	  		RastplatzSchutzhuette:{txt:"Rastplatz & Schutzhuette", img:"93_icon_bikeshed.png"},
	  		Reiten:{txt:"Reiten", img:"110_icon_riding.png"},
	  		Golfen:{txt:"Golfen", img:"100_icon_golf.png"},
	  		Veranstaltungen:{txt:"Veranstaltungen", img:"osg/Events.png"},
			
			gray:{txt:"Infrastruktur", img:"/tash/symbols/tash/meta/meta-grau.png"},
			orange:{txt:"Übernachten/Essen/Kultur", img:"/tash/symbols/tash/meta/meta-orange.png"},
			blue:{txt:"Meer & Natur", img:"/tash/symbols/tash/meta/meta-blau.png"},
			green:{txt:"Rad, Golf, Reiten", img:"/tash/symbols/tash/meta/meta-gruen.png"}		
	},
	typeMap: { // defines translations for the POI types, order: FR,DE,EN
		Article: ["Artikel","Artikel","Artikel"],
		Offer: ["Offer","Offer","Offer"],
		Event: ["Event","Event","Event"],
		Tourismusinformation: ["Tourismusinformation","Tourismusinformation","Tourismusinformation"],
		Bahnhof: ["Bahnhöfe","Bahnhöfe","Bahnhöfe"],
		HotelPension: ["Hotels, Pensionen","Hotels, Pensionen","Hotels, Pensionen"],
		FerienwohnungHaus: ["Ferienwohnungen/-häuser","Ferienwohnungen/-häuser","Ferienwohnungen/-häuser"],
		Campingplatz: ["Campingplätze","Campingplätze","Campingplätze"],
		Jugendherberge: ["Jugendherbergen","Jugendherbergen","Jugendherbergen"],
		Bauernhof: ["Bauernhöfe","Bauernhöfe","Bauernhöfe"],
		BettBike: ["Bett & Bike","Bett & Bike","Bett & Bike"],
		WellnesshotelBeautyfarm: ["Wellnesshotels & Beautyfarmen","Wellnesshotels & Beautyfarmen","Wellnesshotels & Beautyfarmen"],
		Gastronomie: ["Gastronomie","Gastronomie","Gastronomie"],
		MuseumDenkmal: ["Museen & Denkmäler","Museen & Denkmäler","Museen & Denkmäler"],
		Theater: ["Theater","Theater","Theater"],
		SchlossGarten: ["Schlösser & Gärten","Schlösser & Gärten","Schlösser & Gärten"],
		KlosterKirche: ["Klöster & Kirchen","Klöster & Kirchen","Klöster & Kirchen"],
		Freizeitpark: ["Freizeitparks","Freizeitparks","Freizeitparks"],
		TierparkZoo: ["Tierparks/Zoos","Tierparks/Zoos","Tierparks/Zoos"],
		StrandBaden: ["Strand & Baden","Strand & Baden","Strand & Baden"],
		Naturerlebnis: ["Naturerlebnis","Naturerlebnis","Naturerlebnis"],
		Segeln: ["Segeln","Segeln","Segeln"],
		FahrradverleihReparaturservice: ["Fahrradverleih & Reparaturservice","Fahrradverleih & Reparaturservice","Fahrradverleih & Reparaturservice"],
		AbschliessbareFahrradbox: ["abschließbare Fahrradboxen","abschließbare Fahrradboxen","abschließbare Fahrradboxen"],
		RastplatzSchutzhuette: ["Rastplätze & Schutzhütten","Rastplätze & Schutzhütten","Rastplätze & Schutzhütten"],
		Golfen: ["Golfen","Golfen","Golfen"],
		Reiten: ["Reiten","Reiten","Reiten"],
		Wetter: ["Wetter","Wetter","Wetter"],
		meta: ["meta","meta","meta"]
	},
	//Für alle Portale, zentral
	typeMapMapping: { 
		1:"Article",
		2:"Offer",
		3:"Event",
		10:"Tourismusinformation",
		20:"Bahnhof",
		31:"HotelPension",
		32:"FerienwohnungHaus",
		33:"Campingplatz",
		34:"Jugendherberge",
		35:"Bauernhof",
		36:"BettBike",
		37:"WellnesshotelBeautyfarm",
		40:"Gastronomie",
		51:"MuseumDenkmal",
		52:"Theater",
		53:"SchlossGarten",
		54:"KlosterKirche",
		55:"Freizeitpark",
		56:"TierparkZoo",
		60:"StrandBaden",
		70:"Naturerlebnis",
		80:"Segeln",
		91:"FahrradverleihReparaturservice",
		92:"AbschliessbareFahrradbox",
		93:"RastplatzSchutzhuette",
		100:"Golfen",
		110:"Reiten",
		120:"Wetter",
		999:"meta",
		1996:"Radweg",
		1997:"rw_anhaenger",
		1998:"rw_belag",
		1999:"rw_gesamt",
		1986:"RadwegHLMS",
		1987:"rw_hlms_anhaenger",
		1988:"rw_hlms_belag",
		1989:"rw_hlms_gesamt",		
		1976:"RadwegRegio",
		1977:"rw_regio_anhaenger",
		1978:"rw_regio_belag",
		1979:"rw_regio_gesamt",
		22:"Busunternehmen",
		23:"ReedereiSchiffFaehre",
		24:"Flughafen",
		38:"Appartmenthaus",
		39:"Ferienpark",
		391:"Gasthof",
		57:"Erlebnisbad",
		58:"NaturerlebniszentrumAquarium",
		130:"Veranstaltungen",
		140:"Leuchttuerme",		
		150:"CmsArtikel"		
	},

	typeWithLowLayerPrio: ["Tourismusinformation", "Bahnhof" ],  //POI-Typen die unterhalb anderer Liegen sollen (z-Index) da wenigiger wichtig (0002995)
	
	nonToggleTypes: ["meta","Wetter"],
	
	langs: ["fr","de","en"],

	metaPointXOff : 0,
	metaPointYOff : 0,
	subPointXOff: 0,
	subPointYOff: 0,
	
	luxInterfaceAddress: "http://www.luxembourg2007.org/manif.php?map=", // jump back address for the event types
	
	// search results:
	
	showOnlySearchResults: false, // defines if only search result pois are displayed, the searchResult servlet is used...
	searchResultIds: [], // containes the IDs
	searchResultServletAddress: "http://luxembourg2007.alta4gis.de/luxembourg2007/tash/controller/searchExtent?", // List of search results in the Extent (replaces normal servlet)

	// edit
	
	editMode: false, // defines if points can be edited, so the edit bar will be displayed and they can be moved
	//editServletAddress: "/alta4_servlets/noticeCoordinates?", // send edit commands to
	editServletAddress: "/tash/controller/noticeCoordinates?", // send edit commands to
	editObject: { // prepares the object to be edited
		recode: false,
		id: 0,
		lon: 0,
		lat: 0,
		origLon: 0,
		origLat: 0,
		type: null,
		name: "",
		successfullyGeocoded:false
	},
	// contains the parameters which are passed through the geocoding process
	editPassThrough: "",
			
	//  ++++++++++ PopUps +++++++++++
	showPopUpMinWidth: 300,
	showPopUpMinHeight: 300,
	
	//ES: Flag - ob es die Minmap (kleine Karte auf Einzelseite und Angebotsuche). In der MapIntern wird "ermittelt", ob dies zutrift und der Flag gesetzt. 
	isMiniMap: false,
	
	// using this template the popups can be customized, just add the fields in the DB at the position where they should be displayed,
	// all HTML content is parsed into a div by using innerHTML
	
	//Lux07
	//popUpTagNames: ["name","street","streetNumber","countryCode","zipCode","city","tel","fax","email","webSite","desc","niceWebSite","niceEmail"],
	//popUpTemplate: '<table class="popUpContent"><tr><td colspan="2" class="title">_name_</td></tr><tr><td class="addressCell"><div>_street_ _streetNumber_</div><br />_countryCode_-_zipCode_ _city_<br />_tel_<br />_fax_<br /><a href="mailto:_email_">_niceEmail_</a><br /><a href="_webSite_" target="blank">_niceWebSite_</a><br /></td><td class="descCell"><div class="desc">_desc_</div></td></tr></table>',
	
	//TASH
	popUpTagNames: ["name","street","streetNumber","zipCode","zip","city","address1Street","address1ZipCode","address1City","contactName","email","homepage","phone1","phone","fax","previewImage","imageUrl","shortDescription","detailLink","region","lonWGS84","latWGS84","underlineTitle", "certifiedBnB", "link", "offerDetailLinks"],

	popUpTemplateGray: '<div class="overlay-window" style="left: 0px; top: 0px;"><div class="gray-titlebar"><img src="/tash/design/e7/overlay_corner_gray.gif" alt="" /><h3>_name_</h3></div><div class="body"><p class="address-left"><div>_street_ _streetNumber_</div>_zipCode_ _city_</p></div></div>',	
	popUpTemplateGray10: '<div class="overlay-window" style="left: 0px; top: 0px;"><div class="gray-titlebar"><img src="/tash/design/e7/overlay_corner_gray.gif" alt="" /><h3>_name_</h3></div><div class="body"><div class="info_block"><p class="address-left"><div>_street_ _streetNumber_</div>_zipCode_ _city__phone1_</p></div><div style="clear:both;"></div><p class="copy">_shortDescription_</p></div></div>',
	popUpTemplateGray20: '<div class="overlay-window" style="left: 0px; top: 0px;"><div class="gray-titlebar"><img src="/tash/design/e7/overlay_corner_gray.gif" alt="" /><h3>_name_</h3></div><div class="body"><p class="address-left"><div>_street_ _streetNumber_</div>_zipCode_ _city_</p><p class="morelink"><a href="http://reiseauskunft.bahn.de" target="_blank">&gt; Bahn-Reiseauskuft</a></p></div></div>',
	
	
	//mit Fax: popUpTemplateOrange: '<div class="overlay-window" style="left: 0px; top: 0px;"><div class="orange-titlebar"><img src="/tash/design/e7/overlay_corner_orange.gif" alt="" /><h3>_name_</h3></div><div class="body"><div class="info_block"><img src="_previewImage_" alt="" class="thumbnail" /><p class="address">_address1Street__address1ZipCode_ _address1City__phone1_</p></div><div style="clear:both;"></div><p class="copy">_shortDescription_</p>_detailLink_</div></div>',
	//TODO: gruppierung foto+ adresse auf andere Templates übertragen
	popUpTemplateOrange: '<div class="overlay-window" style="left: 0px; top: 0px;"><div class="orange-titlebar"><img src="/tash/design/e7/overlay_corner_orange.gif" alt="" /><h3>_name_</h3></div><div class="body"><div class="info_block">_previewImage_<div class="address"><table border="0"><tr><td>_address1Street__address1ZipCode_ _address1City__phone1__email_</td></tr></table></div></div><div style="clear:both;"></div><p class="copy">_shortDescription_</p>_detailLink_</div></div>',
	
	popUpTemplateBlue: '<div class="overlay-window" style="left: 0px; top: 0px;"><div class="blue-titlebar"><img src="/tash/design/e7/overlay_corner_blue.gif" alt="" /><h3>_name_</h3></div><div class="body"><div class="info_block">_previewImage_<div class="address"><table border="0"><tr><td>_address1Street__address1ZipCode_ _address1City__phone1_</td></tr></table></div></div><div style="clear:both;"></div><p class="copy">_shortDescription_</p>_detailLink_</div></div>',
	popUpTemplateBlue60: '<div class="overlay-window" style="left: 0px; top: 0px;"><div class="blue-titlebar"><img src="/tash/design/e7/overlay_corner_blue.gif" alt="" /><h3>_name_</h3></div><div class="body"><p class="address-left">_address1Street__zipCode_ _address1City_</p></div></div>',
	popUpTemplateBlue80: '<div class="overlay-window" style="left: 0px; top: 0px;"><div class="blue-titlebar"><img src="/tash/design/e7/overlay_corner_blue.gif" alt="" /><h3>_name_</h3></div><div class="body"><div class="info_block"><p class="address-left">_address1Street__address1ZipCode_ _address1City_</p></div><div style="clear:both;"></div><p class="copy"><br />_shortDescription_</p>_detailLink_</div></div>',
	
	popUpTemplateGreen: '<div class="overlay-window" style="left: 0px; top: 0px;"><div class="green-titlebar"><img src="/tash/design/e7/overlay_corner_green.gif" alt="" /><h3>_name_</h3></div><div class="body"><div class="info_block">_previewImage_<div class="address"><table border="0"><tr><td>_address1Street__address1ZipCode_ _address1City__phone1_</td></tr></table></div></div><div style="clear:both;"></div><p class="copy">_shortDescription_</p>_detailLink_</div></div>',
	popUpTemplateGreen91: '<div class="overlay-window" style="left: 0px; top: 0px;"><div class="green-titlebar"><img src="/tash/design/e7/overlay_corner_green.gif" alt="" /><h3>_name_</h3></div><div class="body">_previewImage_<div class="address"><table border="0"><tr><td>_address1Street__address1ZipCode_ _address1City_<div>_street_ _streetNumber_</div>_zipCode_ _city__phone1_</td></tr></table></div>_detailLink_</div></div>',
	popUpTemplateGreen92: '<div class="overlay-window" style="left: 0px; top: 0px;"><div class="green-titlebar"><img src="/tash/design/e7/overlay_corner_green.gif" alt="" /><h3>_name_</h3></div><div class="body"><p class="address-left">_address1Street__address1ZipCode_ _address1City_</p><div></div>',
	popUpTemplateGreen130: '<div class="overlay-window" style="left: 0px; top: 0px;"><div class="green-titlebar"><img src="/tash/design/e7/overlay_corner_green.gif" alt="" /><h3>_name_</h3></div><div class="body"><div class="info_block">_previewImage_<div class="address"><table border="0"><tr><td><div>_street_ _streetNumber_</div>_zipCode_ _city__phone1_</td></tr></table></div></div><div style="clear:both;"></div><p class="copy">_shortDescription_</p><p class="">_underlineTitle_</p>_detailLink_</div></div>',
	
	plainTeaser: '<div class="overlay-window" style="left: 0px; top: 0px;width:7.6em"><div class="info_block"><a href="_detailLink_" title="_name_" >_previewImage_</a></div></div>',
		
	popUpTemplateRW: '<div class="overlay-window" style="left: 0px; top: 0px;"><div class="gray-titlebar"><img src="/tash/design/e7/overlay_corner_gray.gif" alt="" /><h3>_name_</h3></div><div class="body"><table border="0">	<tr><td><img src="_imageUrl_" alt="" class="thumbnail" /></td>	<td><div class="address">_contactName_<br /><p>_street_ _streetNumber_</p>_zip_ _city_</div>_email__homepage_</td></tr></table>	<p class="copy">_shortDescription_</p>_link_</div></div>',

	certifiedBnBLogo: "/tash/symbols/tash/certified_bnb_logo.jpg",
			
	popUpHideDelay: 250, // how long should the popup stay open after leaving (in ms)
	linesVisibleInAggregatedPopUp:10, // after x lines, the popup is cut and a scrollbar is drawn.
	maxLinkLength: 30, // after 30 letters, "..." will be displayed and the link is cut.
	maxNameLength: 30, // after 30 letters, "..." will be displayed and the name (_name_) is cut.
	
	weatherStationsTemplate : '<span>#{name}<span><img src="#{img}">#{minTmp}°/#{maxTmp}°',
		
	//  ++++++++++ LayerSelector +++++++++++
	hasLayerSelector:true,
	layerSelectorPosX: 0, // offset of the layer selector from window border in px
	layerSelectorPosY: 0,
	
	//  ++++++++++ MapManager +++++++++++
	zoomSpeed: 75, // speed of the zoom animation
	moveSpeed: 10, // step size of the move animation (translate the tiles by ?)
	
	//  ++++++++++ Copyright +++++++++++
	hasCopyrightInfo: false,
	copyrightInfos: [["powered by alta4","http://www.alta4.com"],["&copy; 2007 alta4","disclaimer.html"]],
	copyrightInfosOffsetX: 50,
	copyrightInfosOffsetY: 30,

	//  ++++++++++ Logging +++++++++++
	loggingUserId: 0,
	loggingProject: 0,
	loggingURL: "/tash/logging/index.jsp",
	loggingActive: false,

	googleAnalyticsLoggingActive: false,
	
	//  ++++++++++ OverviewMap +++++++++++
	overviewMapZoomlevelDifference: 3, // number of zoomlevels between overview map and main map
	hasInteractions: true,
	isOverviewMap: true,
	hasConnectedMap: false,
	connectedMap: null,
	moveObserver: null,
	centerObserver: null,
	overviewMapBorderStyle: "2px solid white",
	
	//  ++++++++++ Authentification +++++++++++
	sessionId: 0, // will be used to store the current sessionId
	//editGetPOIServlet: "/alta4_servlets/getPOI?",
	
	editGetPOIServlet: "/tash/controller/getPOI?",
	
	bestViewServlet: "/tash/controller/getBestView?",
	
	//  ++++++++++ TASH specific +++++++++++
	isArea:false,
	activeAreas:"0",
	activeTopics:"0",
	activeTargetGroups:"0",
	
	wetterInfos: {
	},
	wetterMapping:{
		0:'/tash/design/weather/d_0_b.gif',
		1:'/tash/design/weather/d_1_b.gif',
		2:'/tash/design/weather/d_2_b.gif',
		3:'/tash/design/weather/d_3_b.gif',
		4:'/tash/design/weather/d_4_b.gif',
		5:'/tash/design/weather/d_5_b.gif',
		6:'/tash/design/weather/d_6_b.gif',
		7:'/tash/design/weather/d_7_b.gif',
		8:'/tash/design/weather/d_8_b.gif',
		9:'/tash/design/weather/d_9_b.gif',
		10:'/tash/design/weather/d_nodata_b.gif'	
	},
	
	//  ++++++++++ Minimizeability +++++++++++
	hasMinimizer: true,
	minimizerMinimizeImageSrc: "/tash/design/ov_map_close.png",
	minimizerMaximizeImageSrc: "/tash/design/ov_map_open.png",
	minimizerImageSize: [15,15],

	//  ++++++++++ Bounding box marker (for ovmap) +++++++++++
	hasBoundingBoxMarker: true,
	
	//  ++++++++++ Map-History +++++++++++
	/*Zurzeit wird nur das öffnen eines POI-Popups historiesiert*/
	hasHistory: false,
	history: new Array(),
	historyCursor: null, //merkt sich die navigation innerhalb der history (integer)
	historyMax: 10, 		//viele Schritte maximal germerkt werden sollen
	historyInitMapLat: null, //SH-Start-Extent merken (auch für back2Start-Funktionalität)
	historyInitMapLon: null, //SH-Start-Extent merken (auch für back2Start-Funktionalität)
	historyInitMapZoomLevel: null, //SH-Start-Extent merken (auch für back2Start-Funktionalität)	

	// no map updates when true!!!	
	suspendRedraw: false,
	
	radwegeLayerConf:{ 
		fernradwege:{
			0: {layername:'rw_gesamt',	path: "200908/tash_rw_g/Digitaler Atlas SH/_alllayers/L"},
			1: {layername:'rw_belag',	path: "200908/tash_rw_b/Digitaler Atlas SH/_alllayers/L"},
			2: {layername:'rw_anhaenger',path: "200908/tash_rw_a/Digitaler Atlas SH/_alllayers/L"}
		},
		regioradwege:{
			0: {layername:'rw_regio_gesamt',	path: "200908/tash_rw_regio_g/Digitaler Atlas SH/_alllayers/L"},
			1: {layername:'rw_regio_belag',		path: "200908/tash_rw_regio_b/Digitaler Atlas SH/_alllayers/L"},
			2: {layername:'rw_regio_anhaenger',	path: "200908/tash_rw_regio_a/Digitaler Atlas SH/_alllayers/L"}
		},
		hlmsradwege:{
			0: {layername:'rw_hlms_gesamt',	path: "200908/tash_rw_hlms_g/Digitaler Atlas SH/_alllayers/L"},
			1: {layername:'rw_hlms_belag',		path: "200908/tash_rw_hlms_b/Digitaler Atlas SH/_alllayers/L"},
			2: {layername:'rw_hlms_anhaenger',	path: "200908/tash_rw_hlms_a/Digitaler Atlas SH/_alllayers/L"}
		}
	},

	
	//Portal-Spezifische Einstellungen (für TASH, OSG, HMLS etc)
	// Achtung: Ist hasPOIs untergeordnet!
	portalSettings: {
		2: {hasSubsetPois: false, hasAggregationPois: false}, //TASH
		3: {hasSubsetPois: false, hasAggregationPois: false}, //HLMS
		4: {hasSubsetPois: false, hasAggregationPois: false}, //OSG
		5: {hasSubsetPois: false, hasAggregationPois: false} //MaKS
	}

};