/*function makeDatum(name, unit, value)
{
	var datum = {};
	
	datum.name = name;
	datum.unit = unit;
	datum.value = value;
		
	return datum;
}*/

function makeDatums(specificDatums, record)
{
	var datums = new Array();

	for (var i = 0; i < specificDatums.length; i++) {
	
		var datum = {};
		
		datum.title = specificDatums[i].datumTitle;
		datum.name = specificDatums[i].datumName;
		datum.unit = specificDatums[i].datumUnit;
		
		if (datums.name == "Coverage") {
			datum.value = record.properties[specificDatums[i].datumProperty];
		} else			
			datum.value = convertToLocaleString(record.properties[specificDatums[i].datumProperty]);
		
		datums[i] = datum;
	}

	return datums;
}

/*function drawPopup(lat, lon, datetime, speed, datum, index)
{	
	var text = '<table border="0">';
	text += '<tr><th align="left">Record:</th><td>' + index + '</td></tr>';
	text += '<tr><th align="left">Lat:</th><td>' + lat + '</td></tr>';
	text += '<tr><th align="left">Lon:</th><td>' + lon + '</td></tr>';
	text += '<tr><th align="left">Speed:</th><td>' + (speed < 0 ? 'N/A' : speed.toFixed(2)) 
			+ ' km/h' + '</td></tr>';
	
	if (datum.name.match("speed") == null) {
		text += '<tr><th align="left">' + datum.name.slice(0,1).toUpperCase() + datum.name.slice(1) + ':</th><td>' 
				+ (datum.value < 0 ? 'N/A' : datum.value.toFixed(2)) + ' ' 
				+ datum.unit + '</td></tr>';
	}
	text += '<tr><th align="left">Date:</th><td>' + datetime + '</td></tr>';
	text += '</table>';	

	var lonlat = new OpenLayers.LonLat(lon, lat);
	lonlat.transform(proj, map.getProjectionObject());

	var popup = new OpenLayers.Popup.FramedCloud(null,
					   lonlat,
					   new OpenLayers.Size(200,200),
					   text,
					   null,
					   true,
					   null);	
	map.addPopup(popup);		

	popup.autoSize = true;		
}*/

function drawPopup(lat, lon, latString, lonString, datetime, speed, datums, index, device)
{	
	var text = '<table border="0">';
	text += '<tr><th align="left">' + popupDeviceTitleText + '</th><td>' + device + '</td></tr>';
	text += '<tr><th align="left">' + popupRecordTitleText + '</th><td>' + index + '</td></tr>';
	text += '<tr><th align="left">' + popupLatTitleText + '</th><td>' + latString + '</td></tr>';
	text += '<tr><th align="left">' + popupLonTitleText + '</th><td>' + lonString + '</td></tr>';
	/*text += '<tr><th align="left">Speed:</th><td>' + (speed < 0 ? 'N/A' : speed.toFixed(2)) 
			+ ' km/h' + '</td></tr>';*/
	
	/*if (datum.name.match("speed") == null) {
		text += '<tr><th align="left">' + datum.name.slice(0,1).toUpperCase() + datum.name.slice(1) + ':</th><td>' 
				+ (datum.value < 0 ? 'N/A' : datum.value.toFixed(2)) + ' ' 
				+ datum.unit + '</td></tr>';
	}*/
	for (var i = 0; i < datums.length; i++) {
		/*if (datums[i].name == "Coverage") {
			text += '<tr><th align="left">' + datums[i].name + ':</th><td>' 
			+ (datums[i].value < 0 ? 'N/A' : datums[i].value) + ' ' 
			+ datums[i].unit + '</td></tr>';
			continue;
		}*/		
				
		text += '<tr><th align="left">' + datums[i].title + ':</th><td>' 
		+ ((datums[i].value == undefined || datums[i].value < 0) ? 'N/A' : ((datums[i].name == 'Speed') ? speed : datums[i].value)) + ' ' 
		+ datums[i].unit + '</td></tr>';
	}
	
	text += '<tr><th align="left">' + popupDateTitleText + '</th><td>' + datetime + '</td></tr>';
	text += '</table>';	

	var lonlat = new OpenLayers.LonLat(lon, lat);
	lonlat.transform(proj, map.getProjectionObject());

	var popup = new OpenLayers.Popup.FramedCloud(null,
					   lonlat,
					   new OpenLayers.Size(200,200),
					   text,
					   null,
					   true,
					   null);	
	map.addPopup(popup);		

	popup.autoSize = true;		
}

function drawDevicePopup(device, latLocaleString, lonLocaleString, statusLocaleString)
{	
	var text = '<table border="0">';
	text += '<tr><th align="left">' + popupDeviceNameTitleText + '</th><td>' + device.name + '</td></tr>';
	text += '<tr><th align="left">' + popupDeviceRecTitleText + '</th><td>' + ((device.records != -1) ? device.records : "unknown")  + '</td></tr>';
	text += '<tr><th align="left">' + popupDeviceLastLatTitleText + '</th><td>' + latLocaleString + '</td></tr>';
	text += '<tr><th align="left">' + popupDeviceLastLonTitleText + '</th><td>' + lonLocaleString + '</td></tr>';
	
	text += '<tr><th align="left">' + popupDeviceStatusTitleText + '</th><td>' + statusLocaleString + '</td></tr>';	
	
	text += '<tr><th align="left">' + popupDeviceDateTitleText + '</th><td>' + device.lastTime + '</td></tr>';
	text += '</table>';	

	// Fijate que a veces de va al carajo el mapa porque currentLongitude y currentLatitude no son numeros sino strings.
	var lonlat = new OpenLayers.LonLat(device.currentLongitude, device.currentLatitude);
	lonlat.transform(proj, map.getProjectionObject());

	var popup = new OpenLayers.Popup.FramedCloud(null,
					   lonlat,
					   new OpenLayers.Size(200,200),
					   text,
					   null,
					   true,
					   null);	
	map.addPopup(popup);		

	popup.autoSize = true;		
}

function addImageLayer(layerName, url, width, height, minLat, maxLat, minLon, maxLon)
{
	// HACER: los bounds usarlos en otro momento, no cada vez que agrego
	// una capa
	var bounds = new OpenLayers.Bounds();
	bounds.extend(new OpenLayers.LonLat(minLon,minLat));
	bounds.extend(new OpenLayers.LonLat(maxLon,maxLat));
	bounds.transform(proj, map.getProjectionObject());
	map.zoomToExtent(bounds, false);

	globalBounds = bounds;

	var size = new OpenLayers.Size(width, height);

	var options = { isBaseLayer: false, alwaysInRange: true };

	imageLayers[layerName] = new OpenLayers.Layer.Image(layerName,
		url,
		bounds,
		size,
		options
	);

	map.addLayer(imageLayers[layerName]);
}

function setImageLayerVisibility(layerName, visibility)
{
	if (typeof(imageLayers[layerName].setVisibility) != 'undefined')
		imageLayers[layerName].setVisibility(visibility);
}

function toggleImageLayer(layerName)
{
	if (typeof(imageLayers[layerName].setVisibility) != 'undefined')
		imageLayers[layerName].setVisibility(
			!imageLayers[layerName].getVisibility());
}

function featureSelect(feature)
{
	// HACER: sacar lonlat porque no es necesario
	var lonlat = feature.geometry.getBounds().getCenterLonLat().clone();
	lonlat.transform(map.getProjectionObject(), proj);

	var id = feature.attributes.featureId;
	
	// Si status es -1 entonces el feature es un punto, si no, un dispositivo.
	if (feature.attributes.status == -1)
		getFeatureInfoById(lonlat.lat, lonlat.lon, id);
	else
		getDeviceInfoById(feature.attributes.device_id);
}

function createMarkerLayer()
{	
	var styleMap = new OpenLayers.StyleMap({
		"default": new OpenLayers.Style({
			pointRadius: "${radius}",
			//fillColor: "#000000",
			//fill: false,
			fillOpacity: 0.5,
			strokeColor: "#ffffff",
			strokeWidth: 2,
			externalGraphic: "img/status/marker.png",
			graphicYOffset: -45,
			graphicWidth: 35,
			graphicHeight: 80,
			/*label: "${device_id}",*/
			label: "${device_label}",
			labelYOffset: 28,
            fontSize: "16px",
            fontFamily: "Droid Sans",
            fontWeight: "bold",
            display: "${visible}" 
		})
	});

	markerLayer = new OpenLayers.Layer.Vector("markers", { styleMap: styleMap });
	markerLayer.setZIndex(350);
	map.addLayer(markerLayer);
}

function destroyMarkerLayer()
{
	markerLayer.destroyFeatures();
	
	delete markerLayer;
	
	markerLayer = null;
}

function setMapZoom(minLat, maxLat, minLon, maxLon, currentLat, currentLon)
{	
	if (!(minLat == 90 && maxLat == -90 && maxLon == -180 && minLon == 180)) {
		var bounds = new OpenLayers.Bounds();
		bounds.extend(new OpenLayers.LonLat(minLon,minLat));
		bounds.extend(new OpenLayers.LonLat(maxLon,maxLat));
		bounds.transform(proj, map.getProjectionObject());
		map.zoomToExtent(bounds, false);	
	}	
	
	map.setCenter( new OpenLayers.LonLat(currentLon,
			currentLat).transform(map.displayProjection, map.projection));
}

function setMapCenter(lat, lon, zoom)
{	
	map.setCenter( new OpenLayers.LonLat(lon,
			lat).transform(map.displayProjection, map.projection),zoom);
}

/* 
 * Layer for device status only, destroyed when retrieving features from
 * the server.
 */
function createDeviceLayer(minLat, maxLat, minLon, maxLon)
{
	/*var minLongitude = (minLon > Math.abs(-73.5833333)) ? minLon : -73.5833333;
	var minLatitude = (minLat > Math.abs(-55.0500000)) ? minLat : -55.0500000;
	var maxLongitude = (maxLon > Math.abs(-53.6333333)) ? maxLon : -53.6333333;
	var maxLatitude = (maxLat > Math.abs(-21.7666667)) ? maxLat : -21.7666667;*/
	
	var minLongitude = minLon;
	var minLatitude = minLat;
	var maxLongitude = maxLon;
	var maxLatitude = maxLat;
		
	var bounds = new OpenLayers.Bounds();
	bounds.extend(new OpenLayers.LonLat(minLongitude,minLatitude));
	bounds.extend(new OpenLayers.LonLat(maxLongitude,maxLatitude));
	bounds.transform(proj, map.getProjectionObject());
	map.zoomToExtent(bounds, false);
	
	if (minLon == maxLon && minLat == maxLat)
		map.zoomTo(map.getZoom() - 2);

	globalBounds = bounds;
	
	var style = new OpenLayers.Style(
	        // the first argument is a base symbolizer
	        // all other symbolizers in rules will extend this one
	        {
	        	pointRadius: "${radius}",
	        	fillOpacity: 1,
				strokeColor: "#ffffff",
				strokeWidth: 2
				//label: "${device_id}" // label will be foo attribute value
	        },
	        // the second argument will include all rules
	        {
	            rules: [
	                new OpenLayers.Rule({
	                    // a rule contains an optional filter
	                    filter: new OpenLayers.Filter.Comparison({
	                        type: OpenLayers.Filter.Comparison.EQUAL_TO,
	                        property: "status", // the "foo" feature attribute
	                        value: 0
	                    }),
	                    // if a feature matches the above filter, use this symbolizer
	                    symbolizer: {
	                        externalGraphic: "img/status/inactive.png",
	                        label: "${device_label}",
	                        fontSize: "16px",
	                        fontFamily: "Droid Sans",
	                        fontWeight: "bold"     
	                    }
	                }),
	                new OpenLayers.Rule({
	                    filter: new OpenLayers.Filter.Comparison({
	                        type: OpenLayers.Filter.Comparison.EQUAL_TO,
	                        property: "status",
	                        value: 1
	                    }),
	                    symbolizer: {
	                        externalGraphic: "img/status/stopped.png",
	                        label: "${device_label}",
	                        fontSize: "16px",
	                        fontFamily: "Droid Sans",
	                        fontWeight: "bold"     
	                    }
	                }),
	                new OpenLayers.Rule({
	                    filter: new OpenLayers.Filter.Comparison({
	                        type: OpenLayers.Filter.Comparison.EQUAL_TO,
	                        property: "status",
	                        value: 2	                        
	                    }),
	                    symbolizer: {
	                        externalGraphic: "img/status/working.png",
	                        label: "${device_label}",
	                        fontSize: "16px",
	                        fontFamily: "Droid Sans",
	                        fontWeight: "bold"     
	                    }
	                }),
	                new OpenLayers.Rule({
	                    filter: new OpenLayers.Filter.Comparison({
	                        type: OpenLayers.Filter.Comparison.EQUAL_TO,
	                        property: "status",
	                        value: 3	                        
	                    }),
	                    symbolizer: {	                    	
	                        externalGraphic: "img/status/transporting.png",
	                        label: "${device_label}",
	                        fontSize: "16px",
	                        fontFamily: "Droid Sans",
	                        fontWeight: "bold"     	                        
	                    }
	                })
	            ]
	        }
	    );
	    
	var select_style = new OpenLayers.Style(
	        // the first argument is a base symbolizer
	        // all other symbolizers in rules will extend this one
	        {
	        	pointRadius: "${select_radius}",
	        	fillOpacity: 1,
				strokeColor: "#ffffff",
				strokeWidth: 2
	            //label: "${status}" // label will be foo attribute value
	        },
	        // the second argument will include all rules
	        {
	            rules: [					
	                new OpenLayers.Rule({
	                    // a rule contains an optional filter
	                    filter: new OpenLayers.Filter.Comparison({
	                        type: OpenLayers.Filter.Comparison.EQUAL_TO,
	                        property: "status", // the "foo" feature attribute
	                        value: 0
	                    }),
	                    // if a feature matches the above filter, use this symbolizer
	                    symbolizer: {	                    		        	        	
	                        externalGraphic: "img/status/inactive_select.png",
	                        label: "${device_label}",
	                        fontSize: "16px",
	                        fontFamily: "Droid Sans",
	                        fontWeight: "bold"                        
	                    }
	                }),
	                new OpenLayers.Rule({
	                    filter: new OpenLayers.Filter.Comparison({
	                        type: OpenLayers.Filter.Comparison.EQUAL_TO,
	                        property: "status",
	                        value: 1
	                    }),
	                    symbolizer: {	                    	
	                        externalGraphic: "img/status/stopped_select.png",
	                        label: "${device_label}",
	                        fontSize: "16px",
	                        fontFamily: "Droid Sans",
	                        fontWeight: "bold"
	                    }
	                }),
	                new OpenLayers.Rule({
	                    filter: new OpenLayers.Filter.Comparison({
	                        type: OpenLayers.Filter.Comparison.EQUAL_TO,
	                        property: "status",
	                        value: 2	                        
	                    }),
	                    symbolizer: {
	                        externalGraphic: "img/status/working_select.png",
	                        label: "${device_label}",
	                        fontSize: "16px",
	                        fontFamily: "Droid Sans",
	                        fontWeight: "bold"
	                    }
	                }),
	                new OpenLayers.Rule({
	                    filter: new OpenLayers.Filter.Comparison({
	                        type: OpenLayers.Filter.Comparison.EQUAL_TO,
	                        property: "status",
	                        value: 3	                        
	                    }),
	                    symbolizer: {	                    	
	                        externalGraphic: "img/status/transporting_select.png",
	                        label: "${device_label}",
	                        fontSize: "16px",
	                        fontFamily: "Droid Sans",
	                        fontWeight: "bold"                      
	                    }
	                })
	            ]
	        }
	    );	        
	
	styleMap = new OpenLayers.StyleMap({
		"default": style,
		"select": select_style
	});
	
	deviceLayer =  new OpenLayers.Layer.Vector("absolute_markers", { styleMap: styleMap });
	map.addLayer(deviceLayer);
	selectFeature = new OpenLayers.Control.SelectFeature(
			deviceLayer,
			{ onSelect: featureSelect }
		);
	
	map.addControl(selectFeature);
	selectFeature.activate();
}

function fillDeviceMarkers(id, lon, lat, value, label)
{
	var point = new OpenLayers.Geometry.Point(lon, lat);
	point.transform(proj, map.getProjectionObject());	
	
	for (var i = 0; i < deviceLayer.features.length; i++) {
		var feature = deviceLayer.features[i];
		if (feature.attributes.device_id == id) {
			feature.layer.removeFeatures([ feature ]);
			break;
		}
	}
	
	deviceLayer.addFeatures([ new OpenLayers.Feature.Vector(point.clone(), { device_label: label, device_id: id, status : value, radius: 20, select_radius: 24 } ) ]);
}

function destroyDeviceLayer()
{
	deviceLayer.destroyFeatures();
		
	delete deviceLayer;
	
	deviceLayer = null;
}

function addVectorLayer(layerName, isNew, minLat, maxLat, minLon, maxLon)
{
	// HACER: los bounds usarlos en otro momento, no cada vez que agrego
	// una capa

	if (!isNew) {
		var bounds = new OpenLayers.Bounds();
		bounds.extend(new OpenLayers.LonLat(minLon,minLat));
		bounds.extend(new OpenLayers.LonLat(maxLon,maxLat));
		bounds.transform(proj, map.getProjectionObject());
		map.zoomToExtent(bounds, false);
	
		globalBounds = bounds;
	}
	
	var style = new OpenLayers.Style(
	        // the first argument is a base symbolizer
	        // all other symbolizers in rules will extend this one
	        {
	        	pointRadius: 4,
				fillColor: "${color}",
				//strokeColor: "#ff0000",
				strokeColor: "black",
				strokeWidth: 1,
	            display: "${visible}"
	            //label: "${status}" // label will be foo attribute value
	        },
	        // the second argument will include all rules
	        {
	            rules: [
					new OpenLayers.Rule({
					    // a rule contains an optional filter
					    filter: new OpenLayers.Filter.Comparison({
					        type: OpenLayers.Filter.Comparison.EQUAL_TO,
					        property: "status", // the "foo" feature attribute
					        value: -1
					    }),
					    // if a feature matches the above filter, use this symbolizer
					    symbolizer: {
					    	pointRadius: 4,
							fillColor: "${color}",
							//strokeColor: "#ff0000",
							strokeColor: "black",
							strokeWidth: 1,
	                        graphicZIndex: "${featureId}"
					    }
					}),
	                new OpenLayers.Rule({
	                    // a rule contains an optional filter
	                    filter: new OpenLayers.Filter.Comparison({
	                        type: OpenLayers.Filter.Comparison.EQUAL_TO,
	                        property: "status", // the "foo" feature attribute
	                        value: 0
	                    }),
	                    // if a feature matches the above filter, use this symbolizer
	                    symbolizer: {
	                    	pointRadius: "${radius}",
	        	        	fillOpacity: 1,
	        				strokeColor: "#ffffff",
	        				strokeWidth: 2,
	                        externalGraphic: "img/status/inactive.png",
	                        graphicZIndex: "${featureId}",
	                        label: "${device_label}",
	                        fontSize: "16px",
	                        fontFamily: "Droid Sans",
	                        fontWeight: "bold"
	                    }
	                }),
	                new OpenLayers.Rule({
	                    filter: new OpenLayers.Filter.Comparison({
	                        type: OpenLayers.Filter.Comparison.EQUAL_TO,
	                        property: "status",
	                        value: 1
	                    }),
	                    symbolizer: {
	                    	pointRadius: "${radius}",
	        	        	fillOpacity: 1,
	        				strokeColor: "#ffffff",
	        				strokeWidth: 2,
	                        externalGraphic: "img/status/stopped.png",
	                        graphicZIndex: "${featureId}",
	                        label: "${device_label}",
	                        fontSize: "16px",
	                        fontFamily: "Droid Sans",
	                        fontWeight: "bold"
	                    }
	                }),
	                new OpenLayers.Rule({
	                    filter: new OpenLayers.Filter.Comparison({
	                        type: OpenLayers.Filter.Comparison.EQUAL_TO,
	                        property: "status",
	                        value: 2	                        
	                    }),
	                    symbolizer: {
	                    	pointRadius: "${radius}",
	        	        	fillOpacity: 1,
	        				strokeColor: "#ffffff",
	        				strokeWidth: 2,
	                        externalGraphic: "img/status/working.png",
	                        graphicZIndex: "${featureId}",
	                        label: "${device_label}",
	                        fontSize: "16px",
	                        fontFamily: "Droid Sans",
	                        fontWeight: "bold"
	                    }
	                }),
	                new OpenLayers.Rule({
	                    filter: new OpenLayers.Filter.Comparison({
	                        type: OpenLayers.Filter.Comparison.EQUAL_TO,
	                        property: "status",
	                        value: 3	                        
	                    }),
	                    symbolizer: {
	                    	pointRadius: "${radius}",
	        	        	fillOpacity: 1,
	        				strokeColor: "#ffffff",
	        				strokeWidth: 2,
	                        externalGraphic: "img/status/transporting.png",
	                        graphicZIndex: "${featureId}",
	                        label: "${device_label}",
	                        fontSize: "16px",
	                        fontFamily: "Droid Sans",
	                        fontWeight: "bold"
	                    }
	                })
	            ]
	        }
	    );
	
	var select_style = new OpenLayers.Style(
	        // the first argument is a base symbolizer
	        // all other symbolizers in rules will extend this one
	        {
	        	pointRadius: 4,
				fillColor: "${color}",
				//strokeColor: "#ff0000",
				strokeColor: "black",
				strokeWidth: 1
	            //label: "${status}" // label will be foo attribute value
	        },
	        // the second argument will include all rules
	        {
	            rules: [
					new OpenLayers.Rule({
					    // a rule contains an optional filter
					    filter: new OpenLayers.Filter.Comparison({
					        type: OpenLayers.Filter.Comparison.EQUAL_TO,
					        property: "status", // the "foo" feature attribute
					        value: -1
					    }),
					    // if a feature matches the above filter, use this symbolizer
					    symbolizer: {
					    	pointRadius: 4,
							//fillColor: "${color}",
							strokeColor: "blue",
							strokeWidth: 2
					    }
					}),
	                new OpenLayers.Rule({
	                    // a rule contains an optional filter
	                    filter: new OpenLayers.Filter.Comparison({
	                        type: OpenLayers.Filter.Comparison.EQUAL_TO,
	                        property: "status", // the "foo" feature attribute
	                        value: 0
	                    }),
	                    // if a feature matches the above filter, use this symbolizer
	                    symbolizer: {
	                    	pointRadius: "${select_radius}",
	        	        	fillOpacity: 1,
	        				strokeColor: "#ffffff",
	        				strokeWidth: 2,
	                        externalGraphic: "img/status/inactive_select.png",
	                        graphicZIndex: 0,
	                        label: "${device_label}",
	                        fontSize: "16px",
	                        fontFamily: "Droid Sans",
	                        fontWeight: "bold"
	                    }
	                }),
	                new OpenLayers.Rule({
	                    filter: new OpenLayers.Filter.Comparison({
	                        type: OpenLayers.Filter.Comparison.EQUAL_TO,
	                        property: "status",
	                        value: 1
	                    }),
	                    symbolizer: {
	                    	pointRadius: "${select_radius}",
	        	        	fillOpacity: 1,
	        				strokeColor: "#ffffff",
	        				strokeWidth: 2,
	                        externalGraphic: "img/status/stopped_select.png",
	                        graphicZIndex: 0,
	                        label: "${device_label}",
	                        fontSize: "16px",
	                        fontFamily: "Droid Sans",
	                        fontWeight: "bold"
	                    }
	                }),
	                new OpenLayers.Rule({
	                    filter: new OpenLayers.Filter.Comparison({
	                        type: OpenLayers.Filter.Comparison.EQUAL_TO,
	                        property: "status",
	                        value: 2	                        
	                    }),
	                    symbolizer: {
	                    	pointRadius: "${select_radius}",
	        	        	fillOpacity: 1,
	        				strokeColor: "#ffffff",
	        				strokeWidth: 2,
	                        externalGraphic: "img/status/working_select.png",
	                        graphicZIndex: 0,
	                        label: "${device_label}",
	                        fontSize: "16px",
	                        fontFamily: "Droid Sans",
	                        fontWeight: "bold"
	                    }
	                }),
	                new OpenLayers.Rule({
	                    filter: new OpenLayers.Filter.Comparison({
	                        type: OpenLayers.Filter.Comparison.EQUAL_TO,
	                        property: "status",
	                        value: 3	                        
	                    }),
	                    symbolizer: {
	                    	pointRadius: "${select_radius}",
	        	        	fillOpacity: 1,
	        				strokeColor: "#ffffff",
	        				strokeWidth: 2,
	                        externalGraphic: "img/status/transporting_select.png",
	                        label: "${device_label}",
	                        graphicZIndex: 0,
	                        fontSize: "16px",
	                        fontFamily: "Droid Sans",
	                        fontWeight: "bold"
	                    }
	                })
	            ]
	        }
	    );	
	        
	// Poner también borde de style al absolute marker.
	styleMap = new OpenLayers.StyleMap({
		"default": style,
		"select": select_style
	});

	// HACER: ver si le agrego las mismas opciones que a la imageLayer

	
	if (isNew) 		
		for (var layer in vectorLayers) {
			var zIndex = vectorLayers[layer].getZIndex();
			vectorLayers[layer].setZIndex(parseInt(zIndex) + 1);
		}
	
	vectorLayers[layerName] = new OpenLayers.Layer.Vector(layerName, { styleMap: styleMap, rendererOptions: { zIndexing: true } /* , renderers: ["Canvas", "SVG", "VML"]*/ });
	map.addLayer(vectorLayers[layerName]);	
	
	vectorLayers[layerName].setVisibility(false);
	selectFeature = new OpenLayers.Control.SelectFeature(
		vectorLayers[layerName],
		{ onSelect: featureSelect }
	);

	map.addControl(selectFeature);
	selectFeature.activate();
}

function setVectorLayerVisibility(layerName, visibility)
{
	if (typeof(vectorLayers[layerName]) != 'undefined' &&
		typeof(vectorLayers[layerName].setVisibility) != 'undefined')
		vectorLayers[layerName].setVisibility(visibility);
}

function checkBoxClick(id)
{
	var checked = $("#" + id).attr('value');
	if (checked == "on") {
		$("#" + id).attr("value", "off");
	} else {
		$("#" + id).attr("value", "on");
	}
};

function checkVectorLayerVisibility(layerName)
{
	if (typeof(vectorLayers[layerName]) != 'undefined' &&
		typeof(vectorLayers[layerName].getVisibility) != 'undefined')
		return vectorLayers[layerName].getVisibility();
	
	return false;
}

function toggleVectorLayer(layerName)
{
	if (typeof(vectorLayers[layerName]) != 'undefined' &&
		typeof(vectorLayers[layerName].setVisibility) != 'undefined')
		vectorLayers[layerName].setVisibility(
			!vectorLayers[layerName].getVisibility());
}



/*function toggleAbsoluteMarkerLayer()
{
	if (typeof(absoluteMarkerLayer) != 'undefined' &&
		typeof(absoluteMarkerLayer.setVisibility) != 'undefined')
		absoluteMarkerLayer.setVisibility(
			!absoluteMarkerLayer.getVisibility());
}*/

// HACER: usar esta paleta para crear dinamicamente los estilos CSS

// http://colorbrewer2.org/
/*palette = [
	"#9E0142",
	"#D53E4F",
	"#F46D43",
	"#FDAE61",
	"#FEE08B",
	"#E6F598",
	"#ABDDA4",
	"#66C2A5",
	"#3288BD",
	"#5E4FA2",
	"#BABDB6"
];*/

palette = [     	
       	"#660000",
       	"#FF0000",
       	"#FF6600",
       	"#FF9900",
       	"#FFFF00",
    	"#00FF00",
       	"#00FFFF",
     	"#0099FF",
       	"#0000FF",
       	"#000066",
       	"#BABDB6" // This is for undefined data
 ];

function color(value, layerName)
{
	if (value < 0)
		//return palette[10]; // Gray
		return "#BABDB6";

	var ref = layerReferences[layerName];

	for (var i = 0; i < ref.length; i++)
	{
		if (ref[i].beginUnbounded && value <= ref[i].end)
			//return palette[ref[i].color];
			return ref[i].color;
		else if (ref[i].endUnbounded && value >= ref[i].begin)
			//return palette[ref[i].color];
			return ref[i].color;
		else if (ref[i].begin <= value && value <= ref[i].end)
			//return palette[ref[i].color];
			return ref[i].color;
	}

	//return palette[10]; // Gray
	return "#BABDB6";
}

function changeMarkerStatus(value)
{
	if (markerLayer.features.length == 0)
		return;	
	
	if (markerLayer.features[0].status == value)
		return;
	
	var lon = markerLayer.features[0].geometry.x;
	var lat = markerLayer.features[0].geometry.y;
	
	var point = new OpenLayers.Geometry.Point(lon, lat);
	//point.transform(proj, map.getProjectionObject());
	
	markerLayer.destroyFeatures();	
	markerLayer.addFeatures([ new OpenLayers.Feature.Vector(point.clone(), { status : value } ) ]);	
}

function destroyAbsoluteMarkerFeatures()
{
	//absoluteMarkerLayer.destroyFeatures();	
	for (var layerName in vectorLayers)
	{
		for (var i = 0; i < vectorLayers[layerName].features.length; i++) {
			if (vectorLayers[layerName].features[i].attributes.status >= 0) {
				vectorLayers[layerName].features[i].destroy();
				break;
			}		
		}
	}
}

function drawAbsoluteMarker(id, lon, lat, value, label)
{
	var point = new OpenLayers.Geometry.Point(lon, lat);
	point.transform(proj, map.getProjectionObject());	

	//absoluteMarkerLayer.addFeatures([ new OpenLayers.Feature.Vector(point.clone(), { device_id: id, status : value, radius: 20 } ) ]);
	
	for (var layerName in vectorLayers)
	{		
		var feature = new OpenLayers.Feature.Vector(point.clone(), { color: color(value, layerName), device_label: label, device_id: id, status : value, select_radius: 24, radius: 20, featureId: -1, visible: "true" });
		vectorLayers[layerName].addFeatures([ feature ]);
		feature.layer.drawFeature(feature);
	}
}

function redrawAbsoluteMarker(id, lon, lat, value, radius, label)
{
	var point = new OpenLayers.Geometry.Point(lon, lat);
	point.transform(proj, map.getProjectionObject());	

	//absoluteMarkerLayer.addFeatures([ new OpenLayers.Feature.Vector(point.clone(), { device_id: id, status : value, radius: 20 } ) ]);

	
	for (var layerName in vectorLayers)
	{
		var hasMarker = false;
		for (var i = 0; i < vectorLayers[layerName].features.length; i++) {
			var feature = vectorLayers[layerName].features[i];
			if (feature.attributes.status >= 0 && feature.attributes.device_id == id) {
				hasMarker = true;
				/*feature.attributes.radius = radius;
				feature.attributes.select_radius = radius + 4;
				feature.attributes.value = value;*/				
				
				feature.layer.removeFeatures([ feature ]);
				//vectorLayers[layerName].drawFeature(feature, style);
				
				var visible;
				var checkbox = "vehicle_device" + id;
				var checked = $("#" + checkbox).attr('value')
				if (checked == "on")					
					visible = "true";
				else 
					visible = "none";
					
				
				vectorLayers[layerName].addFeatures([ new OpenLayers.Feature.Vector(point.clone(), { device_label: label, device_id: id, status : value, radius: 20, select_radius: 24 , featureId: -1, visible: visible } ) ]);
				//feature.move(new OpenLayers.LonLat(point.x, point.y));
				break;
			}			
		}
		
		if (!hasMarker) 
			vectorLayers[layerName].addFeatures([ new OpenLayers.Feature.Vector(point.clone(), { device_label: label, device_id: id, status : value, radius: 20, select_radius: 24, featureId: -1, visible: "true" } ) ]);		
	}
}

function drawMarker(record, radius, label)
{
	var point = new OpenLayers.Geometry.Point(record.longitude, record.latitude);
	point.transform(proj, map.getProjectionObject());
	
	/*if (markerLayer.features.length == 0)
		//markerLayer.addFeatures([ new OpenLayers.Feature.Vector(point.clone(), { status : 0 } ) ]);
		markerLayer.addFeatures([ new OpenLayers.Feature.Vector(point.clone(), { device_id : record.deviceId, radius: 20, visible: "true" } ) ]);
	else
		markerLayer.features[0].move(new OpenLayers.LonLat(point.x, point.y));*/
	
	var id =  record.deviceId;
	var markers = [];
	
	for (var i=0; i < markerLayer.features.length; i++)
		if (markerLayer.features[i].attributes.device_id == id)
			markers.push(markerLayer.features[i]);
	
	if (markers.length == 0)
		markerLayer.addFeatures([ new OpenLayers.Feature.Vector(point.clone(), { device_label: label, device_id : record.deviceId, radius: radius, visible: "true" } ) ]);
	else {		
		markers[0].move(new OpenLayers.LonLat(point.x, point.y));
	}
}

function redrawMarker(id)
{
	for (var i=0; i < markerLayer.features.length; i++)
		if (markerLayer.features[i].attributes.device_id == id) {
			var point = markerLayer.features[i].attributes.prev;
			if (point != null) {
				alert(point.x);
				alert(point.y);
				markerLayer.features[i].move(new OpenLayers.LonLat(point.x, point.y));
			} else 
				markerLayer.removeFeatures([ markerLayer.features[i] ]);
		}
	
}

function destroyMarker()
{
	if (markerLayer != null)
		markerLayer.destroyFeatures();	
}

function toggleMarker(id)
{
	var checkbox = "virt_vehicle_device" + id;
	
	var checked = $("#" + checkbox).attr('value')
	if (checked == "on") {
		$("#" + checkbox).attr("value", "off");
		radius = 0;
		visible = "none";
	} else {
		$("#" + checkbox).attr("value", "on");
		radius = 20;
		visible = "true";
	}	
		
	for (var i = 0; i < markerLayer.features.length; i++) {
		if (markerLayer.features[i].attributes.device_id == id) {
			markerLayer.features[i].attributes.visible = visible;
			resizeFeature(markerLayer.features[i], radius);
			break;
		}		
	}
}

function toggleAbsoluteMarker(id)
{
	var radius = 20;
	var checkbox = "vehicle_device" + id;
	
	var checked = $("#" + checkbox).attr('value')
	if (checked == "on") {
		$("#" + checkbox).attr("value", "off");
		radius = 0;
		visible = "none";
	} else {
		$("#" + checkbox).attr("value", "on");
		radius = 20;
		visible = "true";
	}
	
	for (var layerName in vectorLayers)
	{
		for (var i = 0; i < vectorLayers[layerName].features.length; i++) {
			if (vectorLayers[layerName].features[i].attributes.featureId == -1 &&
				vectorLayers[layerName].features[i].attributes.device_id == id) {
				vectorLayers[layerName].features[i].attributes.visible = visible;
				resizeFeature(vectorLayers[layerName].features[i], radius);
				break;
			}		
		}
	}
}

function resizeFeature(feature, radius)
{
	feature.attributes.radius = radius;	
	
	feature.layer.drawFeature(feature);	
}


/*
 * No confundir con la deviceLayer que dibuja los estados de los dispositivos
 * al principio. Esta funcion sirve para mostrar/ocultar los features de un
 * dispositivo dado en el mapa.
 */ 
function toggleDeviceLayers(id)
{
	var checkbox = "data_device" + id;
	var visible = "true";
	
	var checked = $("#" + checkbox).attr('value')
	if (checked == "on") {
		$("#" + checkbox).attr("value", "off");
		visible = "none";
	} else {
		$("#" + checkbox).attr("value", "on");
		visible = "true";
	}
	
	// El status < 0 simboliza que no es el absoluteMarker
	for (var layerName in vectorLayers)
	{
		for (var i = 0; i < vectorLayers[layerName].features.length; i++) {
			var feature = vectorLayers[layerName].features[i];			
			if (feature.attributes.device_id == id && feature.attributes.status < 0) {
				feature.attributes.visible = visible;										
				feature.layer.drawFeature(feature);	
			}		
		}
	}
}

function drawPoint(record, deviceId, featureId, visible, markerRadius, markerLabel)
{
	var point = new OpenLayers.Geometry.Point(record.longitude, record.latitude);
	point.transform(proj, map.getProjectionObject());

	for (var layerName in vectorLayers)
	{
		var value = -1;

		if (typeof(record.properties[layerName]) != 'undefined')
			value = record.properties[layerName];
		else
			continue;

		var attributes = { color: color(value, layerName), featureId: featureId, status: -1, visible: visible, device_id: deviceId };
		
		vectorLayers[layerName].addFeatures([
			new OpenLayers.Feature.Vector(
				point.clone(), attributes
			)
		]);
	}

	/* Este es el marcador fantasma al dibujar los mapas */
	
	var id =  record.deviceId;
	var markers = [];
	
	for (var i=0; i < markerLayer.features.length; i++) 		
		if (markerLayer.features[i].attributes.device_id == id)
			markers.push(markerLayer.features[i]);

	
	if (markers.length == 0)
	//if (markerLayer.features.length == 0)
		markerLayer.addFeatures([ new OpenLayers.Feature.Vector(point.clone(), { device_label: markerLabel, device_id : record.deviceId, radius: markerRadius, visible: "true" } ) ]);
		//markerLayer.addFeatures([ new OpenLayers.Feature.Vector(point.clone(), { status: 0 }) ]);
	else
	{
		markers[0].move(new OpenLayers.LonLat(point.x, point.y));
	}
}

function clearAllLayers()
{
// HACER: revisar si esta funcion hace todo lo que debe

	// HACER: que no borre los marcadores cuando esten

	destroyAllFeatures();

	// HACER: tambien lo tengo que sacar de OpenLayers
	for (var layerName in vectorLayers) 
		delete vectorLayers[layerName];

	for (var layerName in imageLayers)
		delete imageLayers[layerName];

	if (map.popups != null)  	
		for (var pop=map.popups.length - 1; pop >= 0; pop--) {
			var popup = map.popups[pop];
			map.removePopup(popup);
			delete popup;
		}
	
	if (deviceLayer != null)
		destroyDeviceLayer();
	
	if (markerLayer != null)
		destroyMarkerLayer();
	
	/* Comentado para ver si esto era lo que tiraba error
	// Parece que si, esta aca el problema
	for (var i = 0; i < map.layers.length; i++)
		if (map.layers[i].name != "google")
		{
			map.layers[i].destroy();

			//map.removeLayer(map.layers[i]., false); // Parece que no hace falta, puede ser que tire error
		}
	*/
}

function cleanFeatures()
{
	for (var layerName in vectorLayers) {
		var features = [];
		
		for (var i = 0; i < vectorLayers[layerName].features.length; i++) {			
			var feature = vectorLayers[layerName].features[i];
			if (feature.attributes.featureId != -1) 
				features.push(feature);
		}
		
		vectorLayers[layerName].destroyFeatures(features);
	}
	
	if (markerLayer != null && typeof(markerLayer.destroyFeatures) != 'undefined')
		markerLayer.destroyFeatures(); 
}

function destroyAllFeatures()
{
	// HACER: el 'if' no deberia ser necesario, probar de sacarlo

	for (var layerName in vectorLayers)
		if (typeof(vectorLayers[layerName].destroyFeatures) != 'undefined')
			vectorLayers[layerName].destroyFeatures();
	
	if (markerLayer != null && typeof(markerLayer.destroyFeatures) != 'undefined')
		markerLayer.destroyFeatures(); 
	
	/*if (typeof(deviceLayer.destroyFeatures) != 'undefined')
		deviceLayer.destroyFeatures();*/ 	
}

function setReferences(layerName, intervals)
{
	layerReferences[layerName] = intervals;
}

function setSliderPlaying(b)
{
	if (b)
		$('#playerSlider > .ui-widget-header').css('background-color', '#08DD30');
	else
		$('#playerSlider > .ui-widget-header').css('background', '#FD4403');
}

function setProgressBarValue(value)
{	
	if ($('#progress_bar .ui-progress').css('width') == '100%')
		$('#progress_bar .ui-progress').css('width', '7%');
	
	$('#progress_bar .ui-progress').animate({
        width: value+'%'
      }, {
        duration: 1000, 
        
        // swing or linear
        easing: 'swing',

        // this gets called every step of the animation, and updates the label
        step: function( value ){
          var labelEl = $('#progress_bar .ui-progress .ui-label .value'),
              valueEl = $('#progress_bar .ui-progress .ui-label .value');
          
          if (Math.ceil(value) < 15 && $('#progress_bar .ui-progress .ui-label .value').is(":visible")) {
            labelEl.hide();
          } else {
            if (labelEl.is(":hidden")) {
              labelEl.fadeIn();
            };
          }
          
          if (Math.ceil(value) == 100) {
            labelEl.text(progressBarDoneLabelText);            
          }else{
            valueEl.text(Math.ceil(value) + '%');
          }
        },
        complete: function() {
        	if (value == 100) 
        		setTimeout(function() { hideLoadIndicator(); }, 1000);
        }
      });
}

function setProgressBarLabel(label)
{
	$('#progress_bar .ui-progress .ui-label .value').html(label);
}

function initProgressBar()
{
	$('#progress_bar .ui-progress').css('width', '0%');
}

