﻿/*
	carto.js : a simple map toolkit.
	

*/

/* the carto */
var Carto =  function (){
    this.cartoId= 'carto';
    this.previousMousePosX = 0;
	this.previousMousePosY = 0 ;
	this._oX=0;
	this._oY=0;
	this.cartoElt = $('#'+this.cartoId);
	
	//making markers layer
	var marlayer = $ ("<div id = 'markers'></div>")
	this.cartoElt.append(marlayer);
	this.markersLayer = marlayer;
	
	//making popup layer
	var pplayer = $ ("<div id = 'popups'></div>")
	this.cartoElt.append(pplayer);
	this.popupslayer = pplayer;
	
	this._markers= new Array();
	this._tiles= new Array();
	this._tilesCoords = new Array();
	this._popup = null;// only one popup on map...
	this.addMarkerCallBack = null;
	this.delMarkerCallBack = null;
	this.currentZoomFactor=1;
	this.maxXRange = 450;
	this.maxYRange = 250;
	this.minXRange = -450;
	this.minYRange = -450;
	this.mediaPath="";
	this.XYFields = null;
	this._usermarker=null;
	this.tmpHeight=0;
	this.tmpWidth=0;
	this.canAdd=true;
	this.zoomSmoothFactor = 0.1;
	this.currentZoomLevel=0;
	this.ZoomLevelsOffsets = [1,2];
	this.logElt = $('#carto #log');
	this.preventMove=false;
	this.count=0;
	this.touchTrace = null;
	this.touches = null;
	//settings
	this.mapNameRoot = 'plan-futuroscope';
	this.tileHeight = 308;	
	this.tileWidth = 600;
	this.maxZoomExtent = 4;	
	this.minZoomExtent = 0.2;
	//
	this.modeDebug=false;
	this.debugSquares = null;
	
	//
	return this;
};

Carto.prototype = {
	//element:def,
	init:function(args){
		var myself = this;
		//alert(screen.availHeight+" "+screen.availWidth);
		var height=0;

		if(args['mapNameRoot']!=undefined){
			this.mapNameRoot = args['mapNameRoot'];
		}
		if(args['tileHeight']!=undefined){
			this.tileHeight = parseInt(args['tileHeight']);		
		}
		if(args['tileWidth']!=undefined){
			this.tileWidth = parseInt(args['tileWidth']);		
		}

		if(args['maxZoomExtent']!=undefined){
			this.maxZoomExtent = parseFloat(args['maxZoomExtent']);		
		}if(args['minZoomExtent']!=undefined){
			this.minZoomExtent = parseFloat(args['minZoomExtent']);		
		}
		
		
		
		if(screen.availHeight>screen.availWidth){
		
			height=screen.availWidth-30;
		}
		else if(screen.availHeight<screen.availWidth){
			height=screen.availHeight-30;
		}
		this.cartoElt.get(0).style.heigh=height;//+'px');
		//setting params
		if(args!=undefined){
			if(args['mediaPath']!=undefined){
				this.setMediaPath(args['mediaPath']);
			}
			if((args['XTarget']!=undefined)&&(args['YTarget']!=undefined)){
				this.XYFields={
					"XTarget":args['XTarget'],
					"YTarget":args['YTarget']
				};
				
			}
		}
		
		if(args['debug']!=undefined){
			this.modeDebug=true;
		}
		this.cartoElt.bind("dragstart", function() {
			return false;
		});

		
		
		
		//building tiles
		this.makeTiles();

		//compatibility and bindings between touch and clic
		if (document.getElementById(this.cartoId).addEventListener) {
			document.getElementById(this.cartoId).addEventListener("touchstart", myself.touchHandler, true);
			document.getElementById(this.cartoId).addEventListener("touchmove", myself.touchHandler, true);
			document.getElementById(this.cartoId).addEventListener("touchend", myself.touchHandler, true);
			document.getElementById(this.cartoId).addEventListener("touchcancel", myself.touchHandler, true); 
		} else if (document.getElementById(this.cartoId).attachEvent) {//And a special case for ... ? for ? IE of course...
			document.getElementById(this.cartoId).attachEvent("touchstart", myself.touchHandler);
			document.getElementById(this.cartoId).attachEvent("touchmove", myself.touchHandler);
			document.getElementById(this.cartoId).attachEvent("touchend", myself.touchHandler);
			document.getElementById(this.cartoId).attachEvent("touchcancel", myself.touchHandler); 
			//el.attachEvent('onclick', modifieTexte);
		}
		
		//
		$('#btnleft').click(function(){myself.move(10,0,{'delP':true});});
		$('#btndown').click(function(){myself.move(0,-10,{'delP':true});});
		$('#btnright').click(function(){myself.move(-10,0,{'delP':true});});
		$('#btnup').click(function(){myself.move(0,10,{'delP':true});});		
		//removing default scroll on carto div
		this.cartoElt.bind('touchmove', function(e) {
			e.preventDefault();
		});
		
		
		this.cartoElt.delegate('a','click',function(){location.href=$(this).attr('href');});
		//------
		
		if(this.XYFields!=null){
			//alert($('#'+args['XTarget']).attr('value'));
			this.addMarker(-1,$('#'+args['XTarget']).attr('value'),$('#'+args['YTarget']).attr('value'),this,true,0);
		}

	},
	getCurrentZoomFactor:function(){
		return this.currentZoomFactor;
	},
	setMediaPath:function(mPath){
		this.mediaPath = mPath;
	},
	getMediaPath:function(){
		return this.mediaPath;
	},

	
	//we need to smooth the scaling value we get from gesture event, 
	// otherwise maps zoom/dezoom are WAY to quick...
	getSmoothedScale:function(e){
		return 1 + (e.scale-1) * this.zoomSmoothFactor;
	},
	
	//getting css properties for tiles based on map origin position, current zoom levels, "absolute" positions, etc.
	getTileCSSX:function(tileNum){
		return this.getOX () + parseInt ( this._tilesCoords[tileNum]['left'] ) * this.getCurrentZoomFactor()/this.ZoomLevelsOffsets[this.currentZoomLevel];
	},
	
	getTileCSSY:function(tileNum){
		return this.getOY () + parseInt ( this._tilesCoords[tileNum]['top'] ) * this.getCurrentZoomFactor()/this.ZoomLevelsOffsets[this.currentZoomLevel];
	},
	//TODO : height and width computation should include zoom level also...
	getTileCSSHeight:function(tileNum){
		return parseInt ( this._tilesCoords [tileNum]['height'] ) * (this.getCurrentZoomFactor()/this.ZoomLevelsOffsets[this.currentZoomLevel]) ; 
	},
	
	getTileCSSWidth:function(tileNum){
		return parseInt ( this._tilesCoords [tileNum]['width'] ) * (this.getCurrentZoomFactor()/this.ZoomLevelsOffsets[this.currentZoomLevel]) ;
	},

	zoomPlus:function(factor){
		//alert("zoom plus");
		//TODO : 
		if (this.currentZoomFactor*factor<this.maxZoomExtent){
			if((this.currentZoomFactor<=2)&&(this.currentZoomFactor*factor>2)){
				this.currentZoomLevel=1;
				this.makeTiles();
			}
			
			//befor zooming : deleting popups
			this.delPopups();
			
			this.currentZoomFactor=this.currentZoomFactor*factor;
			//this.log(this.currentZoomFactor);		
			
			this._oX*=factor;
			this._oY*=factor;
			for( var i = 0 ; i < this._tiles.length;i++){
				//increasing top/left values
				
				this._tiles[i].css( 'top', this.getTileCSSY(i)+"px" );
				this._tiles[i].css( 'left', this.getTileCSSX(i)+"px" );
				
				this._tiles[i].css( 'height',this.getTileCSSHeight(i)+"px" );
				this._tiles[i].css( 'width', this.getTileCSSWidth(i)+"px" );
				
			}
			// - modifier leurs top/left,
			// - modifier les top/left des pictos.
			for(var i =  0 ; i < this._markers.length ; i ++){
				this._markers[i].updatePos(0,0);
			}
		}		
		
		//return (this.getOX()+this._tilesCoords[i]['width']*this.getCurrentZoomFactor());
		//return (this.getOY()+this._tilesCoords[i]['height']*this.getCurrentZoomFactor());
	},
	//zoomminus and zoomplus clearly perform the same thing. Should we merge them ?
	zoomMinus:function(factor){
		if (this.currentZoomFactor/factor>this.minZoomExtent){
			if((this.currentZoomFactor>=2)&&(this.currentZoomFactor/factor<2)){
				this.currentZoomLevel=0;
				this.makeTiles();
			}

			//befor zooming : deleting popups
			this.delPopups();
			
			this.currentZoomFactor=this.currentZoomFactor/factor;
			//this.log(this.currentZoomFactor);
			this._oX/=factor;
			this._oY/=factor;
			for( var i = 0 ; i < this._tiles.length;i++){
					
				this._tiles[i].css( 'top', this.getTileCSSY(i)+"px" );
				this._tiles[i].css( 'left', this.getTileCSSX(i)+"px" );
				
				this._tiles[i].css( 'height',this.getTileCSSHeight(i)+"px" );
				this._tiles[i].css( 'width', this.getTileCSSWidth(i)+"px" );
				
			}
			// - modifier leurs top/left,
			// - modifier les top/left des pictos.

			for(var i =  0 ; i < this._markers.length ; i ++){
				this._markers[i].updatePos(0,0);
			}
		}
	},
	
	setZoom:function(newZoomfactor){
	
		if((this.currentZoomFactor>=2)&&(newZoomfactor<2)){
			this.currentZoomLevel=0;
			this.makeTiles();
		}else if((this.currentZoomFactor<=2)&&(newZoomfactor>2)){
			this.currentZoomLevel=1;
			this.makeTiles();

		}

		this._oX/=this.currentZoomFactor/newZoomfactor;		
		this._oY/=this.currentZoomFactor/newZoomfactor;
		this.currentZoomFactor=newZoomfactor;
		//this.log(this.currentZoomFactor);

		
		for( var i = 0 ; i < this._tiles.length;i++){
				
			this._tiles[i].css( 'top', this.getTileCSSY(i)+"px" );
			this._tiles[i].css( 'left', this.getTileCSSX(i)+"px" );
			
			this._tiles[i].css( 'height',this.getTileCSSHeight(i)+"px" );
			this._tiles[i].css( 'width', this.getTileCSSWidth(i)+"px" );
			
		}
		// - modifier leurs top/left,
		// - modifier les top/left des pictos.

		for(var i =  0 ; i < this._markers.length ; i ++){
			this._markers[i].updatePos(0,0);
		}
	
	},
	
	//building tiles. For now, a single tile.
	makeTiles : function(){
		var Xpos  ;
		var Ypos =  0 ;		
		
		//if we had tiles before
		if (this._tiles.length!=0){
			//bye bye tiles
			while(this._tiles.length>0){
				this._tiles[0].remove();
				this._tiles.splice(0,1);
				//this.delMarker(this,0,this._tiles[0]);
			}
			
			//	
			this._tiles = new Array();
			this._tilesCoords = new Array();
		}
		
		for (var j = 0 ; j <= this.currentZoomLevel ; j ++ ){
			Xpos =  0 ;
			for (var i = 0 ; i <= this.currentZoomLevel ; i ++){
	
				var tile = $("<div class='tile'></div>");
				
				var img = $('<img src="'+this.getMediaPath()+'map/'+this.currentZoomLevel+'/'+this.mapNameRoot+'-'+i+'-'+j+'.jpg"/>');
				tile.html (img);
				//tile.css('top',Ypos+"px");
				//tile.css('left',Xpos+"px");	
				
				//top, left, height, and width initial values are stored and considered as references values
				// for zoom
				this._tilesCoords.push({'top':Ypos,'left':Xpos,'height':this.tileHeight,'width':this.tileWidth});
				//TODO: put this value as an object member...
				Xpos+=this.tileWidth;
				this.cartoElt.append(tile);
				this._tiles.push(tile);
				var myself = this;
				tile.mousedown(function(e){
					myself.dragStart(e,myself);
			
				});
			}
			//TODO: put this value as an object member...
			Ypos+=this.tileHeight;
		}
		
		//gesture 
		//TODO : attach event on a to be added container for all tiles
		var self = this;
		for (var i = 0 ; i < this._tiles.length ; i ++){
			
			var node = this._tiles[i].get(0);
			
			//first need to store values...
			node.style.width = this.getTileCSSWidth(i)+"px";//_tiles[i].css("width");
			node.style.height = this.getTileCSSHeight(i)+"px";			
			
			node.ontouchstart = function (e){
			
				//self.touchTrace =[{'x1':e.touches[0].pageX,'y1':e.touches[0].pageY,'x2':e.touches[1].pageX,'y2':e.touches[1].pageY}] ;
				if(e.touches.length>1){
					self.preventMove=true;
					
					//storing centroid for two first fingers as an equivalent for mousepos
					self.previousMousePosX = -self.cartoElt.offset().left+(e.touches[0].pageX+e.touches[1].pageX)/2;
					self.previousMousePosY = -self.cartoElt.offset().top+(e.touches[0].pageY+e.touches[1].pageY)/2;
				}else{
					self.previousMousePosX = -self.cartoElt.offset().left+(e.touches[0].pageX);
					self.previousMousePosY = -self.cartoElt.offset().top+(e.touches[0].pageY);
				}
			};
			node.ontouchmove = function (e) { self.zoomAndMove(e,self); }
 
			node.ontouchend = function(e){
				
				self.preventMove=false;
				var logstring = JSON.stringify(self.touchTrace,replacer);
				//alert (logstring);

				$.ajax({
						type : 'POST',
						data : {'str':logstring},
						url:'webservices/log.php',
						
						success: function(xml){
							//alert (xml);
						}
					}
				);
				
			};
		}
		
		//just drawing tiles
		

	},
	log:function(msg){
		this.logElt.html(msg);
	},
	
	/* function associated to touchmove...*/
	zoomAndMove:function(evt,self){
		//var self = this;
		//event contains a scale value. depending on it, zoom+ or zoom-...				
		if(evt.touches.length>1){
			//alert('-->'+evt.scale);
			if(evt.scale>1){
				self.zoomPlus(self.getSmoothedScale(evt));
			}else{
				self.zoomMinus(1/self.getSmoothedScale(evt));
			}
			
			if (this.modeDebug == true){
				if(self.debugSquares == undefined){
					self.debugSquares = new Array();
				}
				for ( var i = 0 ; i < self.debugSquares.length ; i ++ ) {
					//self.debugSquares[i].
					self.debugSquares[i].remove();
					
				}
				self.debugSquares.length = 0;
				
				for ( var i = 0 ; i < evt.touches.length ; i ++ ) {
					var square = $('<div style="width:10px;height:10px;background-color:pink;"></div>')
					square.css("position","absolute");
					square.css('top',evt.touches[i].pageY+'px');
					square.css('left',evt.touches[i].pageX+'px');
					//alert ( evt.touches[i].pageX + ' - ' + evt.touches[i].pageY );
					$('body').append(square);
					self.debugSquares.push(square);
				}
			}
			//alert("mvd2"+node.className);				
			//computing new mousepositions
			// based on two first fingers centroids.
			// formulas are taken directly from "dragTiles" func...
			var Xcentroid = (evt.touches[0].pageX+evt.touches[1].pageX)/2;
			var newX = -self.cartoElt.offset().left+Xcentroid - self.previousMousePosX + self._oX; 
			//alert(self.previousMousePosX+"||"+evt.touches[0].pageX+"~~"+evt.touches[0].pageX+"newX:"+newX+"; oX"+self._oX);
			self.previousMousePosX = -self.cartoElt.offset().left+Xcentroid;
			var dx=newX-self._oX;


			var Ycentroid = (evt.touches[0].pageY+evt.touches[1].pageY)/2;
			var newY = -self.cartoElt.offset().top + Ycentroid - self.previousMousePosY + self._oY;
			self.previousMousePosY = -self.cartoElt.offset().top + Ycentroid;
			var dy=newY-self._oY;
			//self.touchTrace.push({'x1':evt.touches[0].pageX,'y1':evt.touches[0].pageY,'x2':evt.touches[1].pageX,'y2':evt.touches[1].pageY});
			
			//then we move.
			var myArgs = {'force':true};
			
			
			//MOVING
			if(evt.touches[0].pageX>evt.touches[1].pageX){
				if(evt.touches[0].pageY>evt.touches[1].pageY){
					self.move(-Math.abs(Xcentroid-evt.touches[1].pageX)/4,-Math.abs(Ycentroid-evt.touches[1].pageY)/4,myArgs);
				}else{
					self.move(-Math.abs(Xcentroid-evt.touches[1].pageX)/4,-Math.abs(Ycentroid-evt.touches[0].pageY)/4,myArgs);
				}
			}
			else{
				if(evt.touches[0].pageY>evt.touches[1].pageY){
					self.move(-Math.abs(Xcentroid-evt.touches[0].pageX)/4,-Math.abs(Ycentroid-evt.touches[1].pageY)/4,myArgs);
				}else{
					self.move(-Math.abs(Xcentroid-evt.touches[0].pageX)/4,-Math.abs(Ycentroid-evt.touches[0].pageY)/4,myArgs);
				}				
			}
		}	
	},
	
	//sort touches : sets current touches 
	sortTouches:function(evt){
		
	},
	
	//on touchstart/mousedown, beginning drag mode.
	dragStart:function(e,self){
	
			// storing initial position
			self.previousMousePosX = e.pageX-self.cartoElt.offset().left;
			self.previousMousePosY = e.pageY-self.cartoElt.offset().top;		
			self.cartoElt.mousemove(function(e){self.dragTiles(e,self);});
	
			//what to do when stopping drag movement
			$('body').mouseup(function(){
				self.cartoElt.unbind('mousemove');
				$(this).unbind('mouseup');
				//alert('mup');
			});

	},
	
	touchHandler:function(event){
		var touches = event.changedTouches,
			first = touches[0],
			type = "";
		switch(event.type)
		{
			case "touchstart": type = "mousedown"; break;
			case "touchmove":  type = "mousemove"; break;        
			case "touchend":   type = "mouseup"; break;
			default: return;
		}
		
		var simulatedEvent = document.createEvent("MouseEvent");
		simulatedEvent.initMouseEvent(type, true, true, window, 1, 
								  first.screenX, first.screenY, 
								  first.clientX, first.clientY, false, 
								  false, false, false, 0, null);

		first.target.dispatchEvent(simulatedEvent);
		if (type=="mousemove"){//keeping the ability to click...
			event.preventDefault();
		}
	},
	
	
	
	//mousemouve/touchmove : moving tiles and popups accordingly to 
	dragTiles:function(e,self){
		var myself = self;
		self.canAdd=false;
		if(self._popup!=null){
			self.delPopups();
		}

		var moveX = true;
		var moveY = true;
		//movement delta

		// making hard hard computation to get new positions and deltas
		// TODO : should be simplified...
		var newX = -myself.cartoElt.offset().left+e.pageX - this.previousMousePosX + this._oX; 
		self.previousMousePosX = -myself.cartoElt.offset().left+e.pageX;
		var dx=newX-myself._oX;

		var newY = -myself.cartoElt.offset().top+e.pageY - this.previousMousePosY + this._oY;
		self.previousMousePosY = -myself.cartoElt.offset().top+e.pageY;
		var dy=newY-myself._oY;

		
		//and then move !
		//if (e.touches.length<2)
		self.move(dx,dy);
		
	},
	
	//getters
	getOX:function(){
		return this._oX;
	},
	getOY:function(){
		return this._oY;
	},
	
	
	move:function(Xmove,Ymove,myArgs){
		//alert (myArgs!=undefined && myArgs['delP']==true);
		this.log(Xmove+" "+Ymove);
		//clearing popups if asked
		if((this._popup!=null)&&(myArgs!=undefined)&&(myArgs["delP"]!=undefined)&&(myArgs['delP']==true)){
			//alert(myArgs["delP"]);		
			this.delPopups();
		}
		//this.count++;
		var isdef = ((myArgs!=undefined)&&(myArgs["force"]!=undefined))?true:false;
		//this.log(this.count+"-"+isdef);
		//if(isdef){alert('isedf !!');}
		//mving if not preventing move and/or forcing move... (case of zoom with two fingers)
		if((this.preventMove==false)||((this.preventMove==true)&&(myArgs!=undefined)&&(myArgs["force"]!=undefined)&&(myArgs['force']==true))){
		
	
			//if(myArgs!=undefined)
			//{this.log(this.preventMove+"-"+Xmove);alert('sdf');}
			
			//yes we move
			var moveX = true;
			var moveY = true;
			
			//movement delta
			var newX = this._oX+Xmove;
			var dx=Xmove;
			var newY = this._oY+Ymove;
			var dy=Ymove;

			//possibly out of bounds ... 
			if ((newX>=this.maxXRange*this.getCurrentZoomFactor())||(newX<=this.minXRange*this.getCurrentZoomFactor())){
				moveX = false;
			}
			if ((newY<=this.minYRange*this.getCurrentZoomFactor())||(newY>=this.maxYRange*this.getCurrentZoomFactor())){
				moveY = false;
			}
			//alert(Xmove+'--'+Ymove);
			// if not out of bounds, we can do the move
			this._oX = (moveX)?newX:this._oX;
			this._oY = (moveY)?newY:this._oY;
			
			//moving tiles
			for( var i = 0 ; i < this._tiles.length;i++){
				// for X and Y, getting new positions 
				if( moveY ){
					
					this._tiles[i].css( 'top', this.getTileCSSY(i) );
				}
				if( moveX ){

					this._tiles[i].css( 'left', this.getTileCSSX(i) );
				}
			}
			
			//moving markers also
			for(var i =  0 ; i < this._markers.length ; i ++){

				var mydx = (moveX)?dx:0;
				var mydy = (moveY)?dy:0;		
				this._markers[i].updatePos(mydx,mydy);		
				
			}
			$('#logDelta').html(dx+','+dy+' ['+this.currentZoomFactor+'] <br/>');
			//myself._oX = myself.previousCartoPosX;
		
		
		}
	},
	
	centerTo:function(args){
		var self = this;
		var centerX=parseInt(this.cartoElt.css('width').replace(/[^-\d\.]/g, ''))/2;
		var centerY=parseInt(this.cartoElt.css('height').replace(/[^-\d\.]/g, ''))/2; 		
		if(args['target']=='coords'){
			//TODO : centrage carte
			this.move(centerX-args['x'],
			centerY-args['y']);
			//alert('centerTo coords'+args['x']+','+args['y']);
		}else if(args['target']=='markerId'){
		
			
			var myUrl='webservices/xmlAttractions.php';
			var myLoc='Attraction';
			
			if (args['catId']!=undefined && ( args['catId'] == '400' || args['catId'] == 400)){
				myUrl = 'webservices/xmlRestaurants.php' ;
				myLoc = 'Restaurant';
			}else if(args['catId']!=undefined && ( args['catId'] == '200' || args['catId'] == 200)){
				myUrl = 'webservices/xmlBoutiques.php' ;
				myLoc = 'Shop';			
			}
			
			//TODO : centrage carte
			$.ajax({
				type : 'GET',
				data : {'attractionid':args['id']},
				url:myUrl,//'webservices/xmlAttractions.php',
				dataType: "xml",
				success: function(xml){

					var myxml = $(xml);
					
					var markerXmlElt = $('LocalizationsList '+myLoc, myxml).get(0);//each(function(){

					/*self.addMarker(myxml.find('Id').text(),
									parseInt(myxml.find('MapX').text()),
									parseInt(myxml.find('MapY').text()),
									self,
									false,
									1); */
					self.move(centerX-parseInt(myxml.find('MapX').text())* (self.getCurrentZoomFactor()),
						centerY-parseInt(myxml.find('MapY').text())* (self.getCurrentZoomFactor()));
					//alert((centerY-parseInt(myxml.find('MapY').text()))+'||'+(self.getCurrentZoomFactor()));
				}
			});
		}
	},
	
	// enable adding markers functionnality
	// 
	enableAddMode:function(){

		var self = this;

		self.addMarkerCallBack = function(e){
			if(self.canAdd==true){
				//alert('yes');
				self.addMarker(0,e.pageX-self.cartoElt.offset().left-self.getOX(),
				e.pageY-self.cartoElt.offset().top-self.getOY(),self,true);
							//self.noAdd=true;	
			}else{
				//alert('no');
				self.canAdd=true;
			}
		}; 
		this.cartoElt.click(self.addMarkerCallBack);
	},
	
	//disabling adding markers
	disableAddMode:function(self){

		self.cartoElt.unbind('click',self.addMarkerCallBack);
		self.addMarkerCallBack = null;
		$('#admarker a').html("| Cliquez pour ajouter un marqueur");		
		
	},
	
	// adding marker
	addMarker:function(id,x,y,self,userCreated,catId){

		
		var marker = new Marker();
		
		marker.ID = id;
		
		marker.init(self,x,y,catId);
	
	
		if( (userCreated!=undefined)&&userCreated == true ){
		
			if(self._usermarker!=null){
				self._usermarker.deleteMarker();
				self._usermarker=null;
			}
				
			self._usermarker = marker;
		
		}//else{
			self._markers.push(marker);		
		//}
		//self.disableAddMode(self);
	
		if(self.XYFields!=undefined){
			//alert(self.XYFields['XTarget']+","+self.XYFields['YTarget']);
			$('#'+self.XYFields['XTarget']).attr('value',x);
			$('#'+self.XYFields['YTarget']).attr('value',y);
		}
	},
	
	addMarkersFromXml:function(xmlFile,categoryId,delmarkers){
		var myself = this;
		var myxml = $(xmlFile);
		if (delmarkers==undefined || delmarkers == true){
			this.delMarkers();
		}
		var myLoc = 'Attraction';
		
		if ((categoryId == 400) ||(categoryId == '400')){
			myLoc = 'Restaurant';
		}else if((categoryId == 200) ||(categoryId == '200')){
			myLoc = 'Shop';
		}
		else if((categoryId == 300) ||(categoryId == '300')){
			myLoc = 'Service';
		}
		else if((categoryId == 600) ||(categoryId == '600')){
			myLoc = 'Attraction';
		}
		
		
		//alert($('LocalizationsList '+myLoc, myxml).length);
		$('LocalizationsList '+myLoc, myxml).each(function(){
			//alert('!'+$(this).find('Id').text());
			if ((myLoc != 'Service')||((myLoc == 'Service')&&($(this).find('ServiceType Id').text()=="1"))){
			myself.addMarker($(this).find('Id').text(),
								parseInt($(this).find('MapX').text()),
								parseInt($(this).find('MapY').text()),
								myself,
								false,
								categoryId);
			}
			//alert(myLoc+" --> "+$(this).find('MapX').text()+" "+parseInt($(this).find('MapY').text()));
		});
	},
	// deleting marker
	delMarker:function(self,i,m){

		m.deleteMarker();
		for( var i = 0 ; i < self._markers.length;i++){
			if(self._markers[i]==m){
				self._markers.splice(i,1);
				self.disableDeleteMode(self);			
				break;
			}
		}

	},
	
	delMarkers:function(){
		while(this._markers.length>0){
			this.delMarker(this,0,this._markers[0]);
		}
		this.delPopups();
	},
	
	disableDeleteMode:function(self){

		self.delMarkerCallBack = function (){alert("non");};
		$('#delmarker a').html("| Cliquez pour supprimer un marqueur");	
	},
	
	enableDeleteMode:function(){

		var self = this;
		self.delMarkerCallBack = self.delMarker; 
		for (var i = 0 ; i < self._markers.length ; i ++){
			var deleteMe = self._markers[i];
			deleteMe.markerElt.unbind("click");
			var number = i ;
			self._markers[i].markerElt.click(function(){self.delMarkerCallBack(self,number,deleteMe);});

		}
	},
	insertPopup : function(popup){
		this.popupslayer.append(popup.popupElt);
		if (this._popup != null){		
		this._popup.close();
		}
		this._popup = popup;
	},
	delPopups: function(){
		if (this._popup != null){
			this._popup.close();
			this._popup = null;
		}
	}
}; 


/* Tile objects are not used right now. TODO for next versions, all the code more or less exists in 
 Carto object... */
var Tile = function(){
	return this;
}

Tile.prototype = {
	init:function(){
	
	}

}


/* Marker : objects managing markers on map*/
var Marker = function(){
	this.ID = 4440;
	this._x;
	this._y;
	this.deltaPX = 10;
	this.deltaPY = 40 ;
	this.markerElt = null;
	this._carto = null;
	this.type = 1;
	return this;
};

Marker.prototype = {
	init:function( carto, posX, posY, type ){
		var self = this;
		this._carto = carto;
			
		var markerelt = $( "<div class='marker'></div>" );
		
		if (type!=undefined && !isNaN( parseInt( type ) ) ){
		
			markerelt.html( "<img src='"+carto.getMediaPath()+"markr-"+type+".png'/>" );
		}else {
			markerelt.html( "<img src='"+carto.getMediaPath()+"markr.png'/>" );		
		}
		if (type>100){
			this.type = type;
		}else{
			this.type = 1;
		}
		//posX = posX - this.deltaPX;
		//posY = posY - this.deltaPY;

		this._x=posX ;
		this._y=posY ;	
		
		markerelt.css( 'top', this.getCSSY() + 'px' );
		markerelt.css( 'left', this.getCSSX() + 'px' );
		this.markerElt = markerelt;
		var ID = this.ID;
		if(parseInt(type)!=300){
		markerelt.click ( function(){ self.openPopup(self);} );
		}
		carto.markersLayer.append(markerelt);
	},
	deleteMarker:function(){
		this.markerElt.remove();
	},
	getX:function(){
		return (this._x);
	},
	getY:function(){
		return (this._y);
	},
	
	//getCSS* : top/left positions for elems placed in relative position
	getCSSX:function(){
		return (this._carto.getOX()+this._x*this._carto.getCurrentZoomFactor()-this.deltaPX);
	},
	getCSSY:function(){
		return (this._carto.getOY()+this._y*this._carto.getCurrentZoomFactor()-this.deltaPY);
	},
	
	updatePos:function(dx,dy){
		
		this.markerElt.css( 'top', ( this.getCSSY () ) );
		this.markerElt.css( 'left', ( this.getCSSX () ) );
	},
	openPopup:function(self){
		var myPopup = new Popup ();
		$.ajax({
			url:'webservices/xhtmlpopup-'+self.type+'.php?ID='+self.ID,
			data:{ID:self.ID},
			success:function(data){
				myPopup.init(self._carto,self,data,self.type);//'Je suis le popup du picto '+self.ID+'<br />Le détail est visible <a href="http://futuroscope.dev.artefacto.fr/attraction.php?id='+self.ID+'">ici</a>');
			}
		});
	
	
	}

};


/* Popup manage objects that are created when clicking on a marker */
var Popup = function(){
	this.popupElt = null;
	this.decalageX = 20;
	this.decalageY = -5;
	this._carto = null;
};

Popup.prototype={
	init:function(carto,markerRef,htmlContent,catId){
	//parseInt(markerRef.markerElt.css('top').replace(/[^-\d\.]/g, ''));
	
	
		var popupelt = $('<div class="popup cat-'+catId+'">'+htmlContent+'</div>');

		this.popupElt = popupelt;
		
		popupelt.css({
			height:'114px',
			width:'210px',
			padding:'0px'
		
		});

		var XPos=parseInt(markerRef.markerElt.css('left').replace(/[^-\d\.]/g, ''))+this.decalageX;
		var YPos=parseInt(markerRef.markerElt.css('top').replace(/[^-\d\.]/g, ''))-(parseInt(popupelt.css('height').replace(/[^-\d\.]/g, ''))-
								parseInt(popupelt.css('padding-top').replace(/[^-\d\.]/g, ''))-
								parseInt(popupelt.css('padding-bottom').replace(/[^-\d\.]/g, '')))+
								this.decalageY;

		this._carto = carto;
		popupelt.css('top',YPos+'px');		
		popupelt.css('left',XPos+'px');

		carto.insertPopup(this);

		var toto = parseInt(popupelt.css('width').replace(/[^-\d\.]/g, ''))+XPos ;
	
		if(parseInt(popupelt.css('width').replace(/[^-\d\.]/g, ''))+XPos>parseInt(carto.cartoElt.css('width').replace(/[^-\d\.]/g, ''))+20){
			carto.move(-(parseInt(popupelt.css('width').replace(/[^-\d\.]/g, ''))+
						 parseInt(popupelt.css('padding-left').replace(/[^-\d\.]/g, ''))+
						 parseInt(popupelt.css('padding-right').replace(/[^-\d\.]/g, ''))+
						 XPos-
						 parseInt(carto.cartoElt.css('width').replace(/[^-\d\.]/g, '')))-20,0);
						
						
			var npx = XPos - (parseInt(popupelt.css('width').replace(/[^-\d\.]/g, ''))+
								parseInt(popupelt.css('padding-left').replace(/[^-\d\.]/g, ''))+
								parseInt(popupelt.css('padding-right').replace(/[^-\d\.]/g, ''))+
								XPos-
								parseInt(carto.cartoElt.css('width').replace(/[^-\d\.]/g, ''))
							)-20;
			popupelt.css('left',npx+'px');		
		}
		if(YPos<10){
			carto.move( 0, (10-YPos) );
			var npy = 10;
			popupelt.css('top',npy+'px');		
		}
		
		

	},
	close:function(){
		this.popupElt.remove();
	}
};









function replacer(key, value) {
    if (typeof value === 'number' && !isFinite(value)) {
        return String(value);
    }
    return value;
}
