function xmlFromString(body)
{
	if (typeof(body) != 'object')
	{
        // code for IE
        if (window.ActiveXObject)
        {
          var doc=new ActiveXObject("Microsoft.XMLDOM");
          doc.async="false";
          doc.loadXML(body);
        }
        // code for Mozilla, Firefox, Opera, etc.
        else
        {
          var parser=new DOMParser();
          var doc=parser.parseFromString(body,"text/xml");
        }
        return doc;
	}
	else
	{
		return body;
	}
}

maps = {
	
	/**
	 * Start parameters
	 */
	startLat: 47.084478,
	startLon: 2.351828,
	startZoom : 5,
	startImage : "http://www.toc-toc.fr/images/flag_green.gif",
	endImage : "http://www.toc-toc.fr/images/flag_red.gif",
	err620: 0,
	err620max: 10,
	err620time: 2,
	err620incr: 2,
	clearCallback: null,
	lastWaypoint : null,
	firstWaypoint: null,
	
	/**
	 * Instances for maps
	 */
	activeMap : null,
	activeDirection : null,
	
	/**
	 * Multi-direction computing
	 */
	
	afterAllCompute: null,
	afterWhileCompute: null,
	directions: null,
	directionsContainer: null,
	directionsCursor: null,
	
	/**
	 * Direction computing parameters
	 */
	afterCompute: null,
	currentDirection: null,
	currentDirectionCursor: null,
	currentDirectionDistance: null,
	drawInactiveSteps : false,
	/**
	 * Start the map (create the object). If already created, it will replace it to initial position
	 * @param string name The ID of the map 
	 */
	startMap: function (name)
	{
		if (maps.activeMap == null){
			maps.activeMap = new GMap2(document.getElementById(name));
			maps.activeMap.addControl(new GSmallMapControl());
			maps.activeDirection = new GDirections();
			GEvent.addListener(maps.activeDirection, "load", maps.newDirection);
			GEvent.addListener(maps.activeDirection, "error", maps.newDirection);
			maps.activeMap.setCenter(new GLatLng(maps.startLat, maps.startLon), maps.startZoom);
		}
	},
	
	/**
	 * Compute a direction, with a specific format
	 * @param string element The XML element
	 * @param string container The container ID
	 * @param function callback The function called after computing the direction
	 */
	computeDirection: function (element, container, callback){
		// return callback(Math.round(Math.random()*25000));
		maps.startMap(container);
		maps.afterCompute = callback;
		maps.currentDirection = [];
		maps.currentDirectionCursor = 0;
		maps.currentDirectionDistance = 0;
		
		element = xmlFromString(element);
		$(element).find('checkpoint').each(function (i,e){
			maps.currentDirection.push({
				lat: $(e).attr('lat'),
				lon: $(e).attr('lon'),
				active: $(e).attr('active')
			});
		});
		maps.calculateDirection();
	},
	
	computeDirections: function (element, container, callbackU, callback){
		maps.startMap(container);
		maps.directions = [];
		maps.directionsCursor = 0;
		maps.afterAllCompute = callback;
		maps.afterWhileCompute = callbackU;
		$(element).find('directions').children().each(function (i,e){
			maps.directions.push($(e));
		});
		maps.calculateDirections(0);
	},
	
	/**
	 * Draw the direction on the map
	 */
	drawDirection: function (){
		var i = 0;
		maps.activeMap.clearOverlays();
		if (maps.activeMap.clearCallback){
			maps.activeMap.clearCallback();
		}
		for (i = 0; i < maps.currentDirection.length - 1; i++)
		{
			if (maps.currentDirection[i].active == '1' && maps.currentDirection[i+1].active == '1'){
				polyline = maps.currentDirection[i].polyline;
				polyline.setStrokeStyle({
					color: "#00ff00",
					opacity: 0.8
				});
				maps.activeMap.addOverlay(polyline);
				
			    var baseIcon = new GIcon(G_DEFAULT_ICON);
			    baseIcon.iconSize = new GSize(16, 16);
			    baseIcon.iconAnchor = new GPoint(14, 14);
			    baseIcon.shadow = null;
			    baseIcon.shadowSize = new GSize(0, 0);			    
			    
			    latlng1 = new GLatLng(maps.currentDirection[i].lat,maps.currentDirection[i].lon);
				icon1 = new GIcon(baseIcon);
				icon1.image = maps.startImage;
				marker1 = new GMarker(latlng1, {
					icon: icon1
				});
				
				latlng2 = new GLatLng(maps.currentDirection[i+1].lat,maps.currentDirection[i+1].lon);
				icon2 = new GIcon(baseIcon);
				icon2.image = maps.endImage;
				marker2 = new GMarker(latlng2, {
					icon: icon2
				});
				
				maps.activeMap.addOverlay(marker1);
				maps.activeMap.addOverlay(marker2);
				
				l1 = new GLatLng(
						Math.min(latlng1.lat(),latlng2.lat()),
						Math.min(latlng1.lng(),latlng2.lng())
					);
				l2 = new GLatLng(
						Math.max(latlng1.lat(),latlng2.lat()),
						Math.max(latlng1.lng(),latlng2.lng())
					);
				middle = new GLatLngBounds(l1,l2);
				
				maps.activeMap.setCenter(middle.getCenter());
				maps.activeMap.setZoom(maps.activeMap.getBoundsZoomLevel(middle)-2);
				maps.lastWaypoint = latlng2;
				maps.firstWaypoint = latlng1;
				
				

			} else if (maps.drawInactiveSteps) {
				polyline = maps.currentDirection[i].polyline;
				polyline.setStrokeStyle({
					color: "#ff0000",
					opacity: 0.4
				});
				maps.activeMap.addOverlay(polyline);
			}
		}
		
		maps.afterCompute(maps.currentDirectionDistance);
	},
	
	getLastWaypoint : function (){
		return maps.lastWaypoint;
	},
	
	getFirstWaypoint : function (){
		return maps.firstWaypoint;
	},
	
	/**
	 * Execute next iteration on direction calculating.
	 */
	calculateDirection: function (){
		if (maps.currentDirectionCursor == maps.currentDirection.length - 1){
			maps.drawDirection();
		} else {
			i = maps.currentDirectionCursor;
			if (maps.currentDirection[i])
			{	
				start_lat = maps.currentDirection[i].lat;
				start_lon = maps.currentDirection[i].lon;
				end_lat = maps.currentDirection[i+1].lat;
				end_lon = maps.currentDirection[i+1].lon;
				maps.activeDirection.load("from: "+start_lat+","+start_lon+" to: "+end_lat+","+end_lon, {
					getPolyline: true
				});
			}
			else
			{
			}
		}
	},
	
	calculateDirections: function (i){
		if (maps.directionsCursor == maps.directions.length - 1){
			maps.afterWhileCompute($(maps.directions[maps.directionsCursor]).attr('id'),i);
			maps.afterAllCompute();
		} else {
			 if (i == 0){
				maps.directionsCursor = 0;
			 } else {
				 maps.afterWhileCompute($(maps.directions[maps.directionsCursor]).attr('id'),i);
				 maps.directionsCursor++;
			 }
			 maps.computeDirection(maps.directions[maps.directionsCursor], maps.directionsContainer, maps.calculateDirections);
		}
	},
	
	getDirectionProgress : function (){
		if ( !maps.currentDirection){
			return 0;
		}
		if (maps.currentDirection.length == 0){
			return 0;
		}
		return (maps.currentDirectionCursor + 1) / (maps.currentDirection.length);
	},
	
	getDirectionsProgress : function (){
		if (!maps.directions){
			return 0;
		}
		if (maps.directions.length == 0){
			return 0;
		}
		biggest = (maps.directionsCursor) / (maps.directions.length);
		smallest = maps.getDirectionProgress();
		if (biggest < 1){
			return biggest + smallest / maps.directions.length;
		} else {
			return biggest;
		}

	},
	
	
	
	errorDirection: function(message)
	{
		message = "Erreur du serveur !\nMerci de réessayer votre requête. En cas de problème, contactez l'équipe TOC-TOC pour réaliser cet itinéraire.\n\nMessage : " + message;
		alert(message);
		return false;
	},
	
	/**
	 * Callback when a inter-direction is computed
	 */
	newDirection: function (){
		i = maps.currentDirectionCursor;
		code = maps.activeDirection.getStatus().code;
		if (code == 620){
			if (maps.err620 == maps.err620max){
				return maps.errorDirection("Trop de requêtes");
			} else {
				maps.err620 ++;
				maps.err620time += maps.err620incr;
			}
		} else {
			if (code == 400){ return maps.errorDirection("Requête GM incorrecte"); }
			if (code == 500){ return maps.errorDirection("Erreur serveur"); }
			if (code == 601){ return maps.errorDirection("Requête GM incorrecte"); }
			if (code == 602){ return maps.errorDirection("Impossible de localiser l'adresse"); }
			if (code == 603){ return maps.errorDirection("L'emplacement GPS pour cette addresse n'est pas disponible"); }
			if (code == 604){ return maps.errorDirection("Aucun itinéraire trouvé entre les 2 adresses"); }
			if (code == 610){ return maps.errorDirection("Mauvaise clé API"); }
		}

		maps.currentDirection[i].polyline = maps.activeDirection.getPolyline();
		maps.currentDirectionDistance += maps.activeDirection.getDistance().meters;
		maps.currentDirectionCursor++;
		setTimeout("maps.calculateDirection();",maps.err620time * 1000);
//		return true;
	}
};
