1 if (Garmin == undefined) var Garmin = {};
  2 /**
  3  * Copyright � 2007 Garmin Ltd. or its subsidiaries.
  4  *
  5  * Licensed under the Apache License, Version 2.0 (the 'License')
  6  * you may not use this file except in compliance with the License.
  7  * You may obtain a copy of the License at
  8  *
  9  *    http://www.apache.org/licenses/LICENSE-2.0
 10  *
 11  * Unless required by applicable law or agreed to in writing, software
 12  * distributed under the License is distributed on an 'AS IS' BASIS,
 13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 14  * See the License for the specific language governing permissions and
 15  * limitations under the License.
 16  * 
 17  * @fileoverview Garmin.GpxActivityFactory - A factory for producing gpx activity and data.
 18  * 
 19  * @author Bobby Yang bobby.yang.at.garmin.com
 20  * @version 1.0
 21  */
 22 /**A factory that can produce an array activity given gpx xml and produce gps xml given an
 23  * array of activity.
 24  * many other types of data.
 25  * @class Garmin.GpxActivityFactory
 26  * @constructor 
 27  */
 28 Garmin.GpxActivityFactory = function(){};
 29 Garmin.GpxActivityFactory = {
 30 	
 31 	parseString: function(gpxString) {
 32 		var gpxDocument = Garmin.XmlConverter.toDocument(gpxString);		
 33 		return Garmin.GpxActivityFactory.parseDocument(gpxDocument);	
 34 	},
 35 	
 36 	parseDocument: function(gpxDocument) {
 37         return this.parseDocumentByType(gpxDocument, Garmin.GpxActivityFactory.GPX_TYPE.all);
 38 	},
 39 	
 40 	parseDocumentByType: function(gpxDocument, type) {
 41 		var activities = new Array();
 42         var routes = new Array();
 43         var tracks = new Array();
 44         var waypoints = new Array();        
 45         
 46         switch(type) {
 47           case Garmin.GpxActivityFactory.GPX_TYPE.routes:
 48               activities = Garmin.GpxActivityFactory._parseGpxRoutes(gpxDocument);
 49               break;
 50           case Garmin.GpxActivityFactory.GPX_TYPE.waypoints:
 51               activities = Garmin.GpxActivityFactory._parseGpxWaypoints(gpxDocument);
 52               break;
 53           case Garmin.GpxActivityFactory.GPX_TYPE.tracks:
 54               activities = Garmin.GpxActivityFactory._parseGpxTracks(gpxDocument);
 55               break;
 56           case Garmin.GpxActivityFactory.GPX_TYPE.all:
 57               routes = Garmin.GpxActivityFactory._parseGpxRoutes(gpxDocument);
 58               tracks = Garmin.GpxActivityFactory._parseGpxTracks(gpxDocument);
 59               waypoints = Garmin.GpxActivityFactory._parseGpxWaypoints(gpxDocument);
 60               activities = waypoints.concat(routes).concat(tracks);
 61               break;    
 62         }
 63          
 64         return activities;
 65 	},
 66 	
 67 	produceString: function(activities) {
 68 		var gpxString = "";
 69 		
 70 		// default creator information incase we can't find the creator info in the dom
 71 		var creator = Garmin.GpxActivityFactory.DETAIL.creator;
 72 		
 73 		// default metadata information incase we can't find the metadata node in the dom
 74 		var metadata = "\n  <metadata>";
 75 		metadata += "\n    <link href=\"http://www.garmin.com\">";
 76 		metadata += "\n      <text>Garmin International</text>";
 77 		metadata += "\n    </link>";						
 78 		metadata += "\n  </metadata>";
 79 		
 80 		// try to find creator and metadata info in the dom
 81 		if (activities != null && activities.length > 0) {
 82 			var activityDom = activities[0].getAttribute(Garmin.Activity.ATTRIBUTE_KEYS.dom);
 83 			var gpxNode = activityDom.ownerDocument.getElementsByTagName(Garmin.GpxActivityFactory.SCHEMA_TAGS.gpx);
 84 			if (gpxNode.length > 0) {
 85 				// grab creator information from the dom if possible
 86 				var creatorStr = gpxNode[0].getAttribute(Garmin.GpxActivityFactory.SCHEMA_TAGS.creator);
 87 				if (creatorStr != null && creatorStr != "") {
 88 					creator = creatorStr;
 89 				}
 90 				// grab metadata info
 91 				var metadataNode = gpxNode[0].getElementsByTagName(Garmin.GpxActivityFactory.SCHEMA_TAGS.metadata);
 92 				if (metadataNode.length > 0) {
 93 					metadata = Garmin.XmlConverter.toString(metadataNode[0]);
 94 				}
 95 			}
 96 		}
 97 
 98 		// header tags
 99 		gpxString += "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\" ?>";	
100 		gpxString += "\n<gpx xmlns=\"http://www.topografix.com/GPX/1/1\" creator=\"" + creator + "\" version=\"1.1\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd http://www.garmin.com/xmlschemas/GpxExtensions/v3 http://www.garmin.com/xmlschemas/GpxExtensions/v3/GpxExtensionsv3.xsd\">";
101 	
102 		//metadata tag
103 		gpxString += "\n  " + metadata;
104 		
105 		if (activities != null) {
106 			// waypoint and track tags
107 			for(var i = 0; i < activities.length; i++) {		
108 				gpxString += "\n  " + Garmin.GpxActivityFactory._produceActivityString(activities[i]);
109 			}
110 		}
111 		
112 		// footer tags
113 		gpxString += "\n</gpx>";
114 		
115 		return gpxString;
116 	},
117 	
118 	/** Fully load the sample, assume sample was previously lazy-loaded
119 	 */	
120 	finishLoadingSample: function(domNode, sample) {
121 		if (domNode.nodeName == Garmin.GpxActivityFactory.SCHEMA_TAGS.routePoint) {
122 			Garmin.GpxActivityFactory._parseGpxRoutePoint(domNode, sample);
123 			sample.isLazyLoaded = false;
124 		} else if (domNode.nodeName == Garmin.GpxActivityFactory.SCHEMA_TAGS.trackPoint) {
125 			Garmin.GpxActivityFactory._parseGpxTrackPoint(domNode, sample);
126 			sample.isLazyLoaded = false;
127 		}
128 	},		
129 	
130 	_produceActivityString: function(activity) {
131 		var activityString = "";
132 		if (activity != null) {
133 			var series = activity.getSeries();
134 			for (var i = 0; i < series.length; i++) {
135 				var currentSeries = series[i];
136 				if (currentSeries.getSeriesType() == Garmin.Series.TYPES.history) {
137 					// converting the dom back into string
138 					// this is the lazy way, this will not work if 
139 					// converting between file types or activity data
140 					// has been modified.
141 					var activityDom = activity.getAttribute(Garmin.Activity.ATTRIBUTE_KEYS.dom);			
142 					if (activityDom != null) {
143 						activityString = Garmin.XmlConverter.toString(activityDom);
144 					}
145 				} else if (currentSeries.getSeriesType() == Garmin.Series.TYPES.waypoint) {
146 					// converting the dom back into string
147 					// this is the lazy way, this will not work if 
148 					// converting between file types or activity data
149 					// has been modified.
150 					var activityDom = activity.getAttribute(Garmin.Activity.ATTRIBUTE_KEYS.dom);			
151 					if (activityDom != null) {
152 						activityString = Garmin.XmlConverter.toString(activityDom);
153 					}						
154 				}
155 			}
156 		}		
157 		return activityString;
158 	},
159 	
160 	_parseGpxRoutes: function(gpxDocument) {
161 		var routes = new Array();
162     	var routeNodes = gpxDocument.getElementsByTagName(Garmin.GpxActivityFactory.SCHEMA_TAGS.route);
163 
164 		for( var i=0; i < routeNodes.length; i++ ) {
165 			var route = new Garmin.Activity();
166 			
167 			var routeName = Garmin.GpxActivityFactory._tagValue(routeNodes[i], Garmin.GpxActivityFactory.SCHEMA_TAGS.routeName);
168 			if (routeName == null) {
169 				routeName = "";
170 			}
171 			
172 			route.setAttribute(Garmin.Activity.ATTRIBUTE_KEYS.dom, routeNodes[i]);
173 			route.setAttribute(Garmin.Activity.ATTRIBUTE_KEYS.activityName, routeName);
174 
175 			var series = new Garmin.Series(Garmin.Series.TYPES.route);
176 			route.addSeries(series);
177 
178 			var routePoints = routeNodes[i].getElementsByTagName(Garmin.GpxActivityFactory.SCHEMA_TAGS.routePoint);					
179 			if (routePoints.length > 0) {					
180 				for( var j=0; j < routePoints.length; j++ ) {
181 					var routePoint = new Garmin.Sample();
182 					routePoint.setLazyLoading(true, Garmin.GpxActivityFactory, routePoints[j]);
183 					series.addSample(routePoint);
184 				}
185 			}
186 			
187 			if (series.getSamplesLength() > 0) {
188 				routes.push(route);
189 			}
190 		}
191 		
192     	return routes;			
193 	},
194 	
195 	_parseGpxRoutePoint: function(routePointNode, routePointSample) {
196 		if (routePointSample == null) {
197 			routePointSample = new Garmin.Sample();
198 		}
199 
200 		routePointSample.setMeasurement(Garmin.Sample.MEASUREMENT_KEYS.latitude, routePointNode.getAttribute(Garmin.GpxActivityFactory.SCHEMA_TAGS.waypointLatitude));
201 		routePointSample.setMeasurement(Garmin.Sample.MEASUREMENT_KEYS.longitude, routePointNode.getAttribute(Garmin.GpxActivityFactory.SCHEMA_TAGS.waypointLongitude));
202 		
203 		var elevation =  Garmin.GpxActivityFactory._tagValue(routePointNode,Garmin.GpxActivityFactory.SCHEMA_TAGS.waypointElevation);
204 		if (elevation != null) {
205 			routePointSample.setMeasurement(Garmin.Sample.MEASUREMENT_KEYS.elevation, elevation);
206 		}		
207 		
208 		return routePointSample;		
209 	},
210 	
211 	_parseGpxTracks: function(gpxDocument) {
212 		var tracks = new Array();
213 		
214     	var trackNodes = gpxDocument.getElementsByTagName(Garmin.GpxActivityFactory.SCHEMA_TAGS.track);
215 		for( var i=0; i < trackNodes.length; i++ ) {
216 			var track = new Garmin.Activity();
217 			
218 			var trackName = Garmin.GpxActivityFactory._tagValue(trackNodes[i], Garmin.GpxActivityFactory.SCHEMA_TAGS.trackName);
219 			if (trackName == null) {
220 				trackName = "";
221 			}
222 			
223 			track.setAttribute(Garmin.Activity.ATTRIBUTE_KEYS.dom, trackNodes[i]);
224 			track.setAttribute(Garmin.Activity.ATTRIBUTE_KEYS.activityName, trackName);
225 
226 			var series = new Garmin.Series(Garmin.Series.TYPES.history);
227 			track.addSeries(series);
228 
229 			var trackSegments = trackNodes[i].getElementsByTagName(Garmin.GpxActivityFactory.SCHEMA_TAGS.trackSegment);	
230 			for( var j=0; j < trackSegments.length; j++ ) {
231 				
232 				// grab all the trackpoints
233 				var trackPoints = trackSegments[j].getElementsByTagName(Garmin.GpxActivityFactory.SCHEMA_TAGS.trackPoint);											
234 				if (trackPoints.length > 0) {
235 					
236 					// set the start and end time summary values		
237 					var startTime = Garmin.GpxActivityFactory._tagValue(trackPoints[0], Garmin.GpxActivityFactory.SCHEMA_TAGS.waypointTime);
238 					var endTime = Garmin.GpxActivityFactory._tagValue(trackPoints[trackPoints.length - 1], Garmin.GpxActivityFactory.SCHEMA_TAGS.waypointTime);					
239 					if (startTime != null && endTime != null) {
240 						track.setSummaryValue(Garmin.Activity.SUMMARY_KEYS.startTime, (new Garmin.DateTimeFormat()).parseXsdDateTime(startTime));
241 						track.setSummaryValue(Garmin.Activity.SUMMARY_KEYS.endTime, (new Garmin.DateTimeFormat()).parseXsdDateTime(endTime));
242 					} else {
243 						// can't find timestamps, must be a route reported as a track (GPSMap does this)
244 						series.setSeriesType(Garmin.Series.TYPES.route);
245 					}
246 				
247 					// loop through all the trackpoints in this segment				
248 					for( var k=0; k < trackPoints.length; k++ ) {
249 						var trackPoint = new Garmin.Sample();
250 						trackPoint.setLazyLoading(true, Garmin.GpxActivityFactory, trackPoints[k]);
251 						series.addSample(trackPoint);						
252 					}
253 					
254 					// add the track to the list of tracks
255 					tracks.push(track);
256 				}
257 			}
258 		}
259 
260     	return tracks;	
261 	},
262 	
263 	_parseGpxTrackPoint: function(trackPointNode, trackPointSample) {
264 		if (trackPointSample == null) {
265 			trackPointSample = new Garmin.Sample();	
266 		}
267 		
268 		trackPointSample.setMeasurement(Garmin.Sample.MEASUREMENT_KEYS.latitude, trackPointNode.getAttribute(Garmin.GpxActivityFactory.SCHEMA_TAGS.waypointLatitude));
269 		trackPointSample.setMeasurement(Garmin.Sample.MEASUREMENT_KEYS.longitude, trackPointNode.getAttribute(Garmin.GpxActivityFactory.SCHEMA_TAGS.waypointLongitude));
270 		
271 		var elevation =  Garmin.GpxActivityFactory._tagValue(trackPointNode,Garmin.GpxActivityFactory.SCHEMA_TAGS.waypointElevation);
272 		if (elevation != null) {
273 			trackPointSample.setMeasurement(Garmin.Sample.MEASUREMENT_KEYS.elevation, elevation);
274 		}
275 
276 		var time = Garmin.GpxActivityFactory._tagValue(trackPointNode, Garmin.GpxActivityFactory.SCHEMA_TAGS.waypointTime);
277 		if (time != null) {
278 			trackPointSample.setMeasurement(Garmin.Sample.MEASUREMENT_KEYS.time, (new Garmin.DateTimeFormat()).parseXsdDateTime(time));
279 		}			
280 		
281 		return trackPointSample;
282 	},
283 	
284 	_parseGpxWaypoints: function(gpxDocument) {
285 		var waypoints = new Array();
286     	var waypointNodes = gpxDocument.getElementsByTagName(Garmin.GpxActivityFactory.SCHEMA_TAGS.waypoint);
287     	
288 		for( var i=0; i < waypointNodes.length; i++ ) {
289 			waypoints.push(Garmin.GpxActivityFactory._parseGpxWaypoint(waypointNodes[i]));
290 		}
291     	
292     	return waypoints;
293 	},
294 	
295 	_parseGpxWaypoint: function(waypointNode) {
296 		var waypoint = new Garmin.Activity();
297 		var waypointSeries = new Garmin.Series(Garmin.Series.TYPES.waypoint);
298 		var waypointSample = new Garmin.Sample();
299 		
300 		waypoint.setAttribute(Garmin.Activity.ATTRIBUTE_KEYS.dom, waypointNode);			
301 
302 		waypointSample.setMeasurement(Garmin.Sample.MEASUREMENT_KEYS.latitude, waypointNode.getAttribute(Garmin.GpxActivityFactory.SCHEMA_TAGS.waypointLatitude)); 
303 		waypointSample.setMeasurement(Garmin.Sample.MEASUREMENT_KEYS.longitude, waypointNode.getAttribute(Garmin.GpxActivityFactory.SCHEMA_TAGS.waypointLongitude));
304 				
305 		var elevation =  Garmin.GpxActivityFactory._tagValue(waypointNode,Garmin.GpxActivityFactory.SCHEMA_TAGS.waypointElevation);
306 		if (elevation != null) {
307 			waypointSample.setMeasurement(Garmin.Sample.MEASUREMENT_KEYS.elevation, elevation);
308 		}
309 		
310 		var wptName =  Garmin.GpxActivityFactory._tagValue(waypointNode,Garmin.GpxActivityFactory.SCHEMA_TAGS.waypointName);
311 		if (wptName != null) {
312 			waypoint.setAttribute(Garmin.Activity.ATTRIBUTE_KEYS.activityName, wptName);
313 		}
314 		
315 		waypointSeries.addSample(waypointSample);
316 		waypoint.addSeries(waypointSeries);		
317    		return waypoint;
318 	},
319 	
320 	_tagValue: function(parentNode, tagName) {
321 		var subNode = parentNode.getElementsByTagName(tagName);
322 		return subNode.length > 0 ? subNode[0].childNodes[0].nodeValue : null;
323 	},	
324 	
325     toString: function() {
326         return "[GpxActivityFactory]";
327     }	
328 };
329 
330 /** Constants defining GPX type
331  */
332 Garmin.GpxActivityFactory.GPX_TYPE = {
333 	routes:    "routes",
334 	waypoints: "waypoints",
335 	tracks:    "tracks",
336 	all:       "all"
337 }
338 
339 /** Constants defining details about the factory
340  */
341 Garmin.GpxActivityFactory.DETAIL = {
342 	creator:			"Garmin Communicator Plug-In API"
343 };
344 
345 /** Constants defining tags used by the gpx schema. This is used
346  *  by the factory when converting between the xml and datastructure.
347  */
348 Garmin.GpxActivityFactory.SCHEMA_TAGS = {
349 	creator:					"creator",
350 	gpx:						"gpx",
351 	metadata:					"metadata",
352 	route:						"rte",
353 	routeName:					"name",
354 	routePoint:					"rtept",
355 	track:						"trk",
356 	trackName:					"name",
357 	trackPoint:					"trkpt",
358 	trackSegment:				"trkseg",
359 	waypoint:					"wpt",
360 	waypointComment:			"cmt",
361 	waypointDGPSAge:			"ageofdgpsdata",
362 	waypointDGPSID:				"dgpsid",
363 	waypointDescription:		"desc",
364 	waypointGeoIdHeight:		"geoidheight",
365 	waypointHDOP:				"hdop",
366 	waypointMagVar:				"magvar",
367 	waypointName:				"name",
368 	waypointLatitude:			"lat",
369 	waypointLink:				"link",
370 	waypointLongitude:			"lon",
371 	waypointElevation:			"ele",
372 	waypointPDOP:				"pdop",
373 	waypointSatellites:			"sat",
374 	waypointSource:				"src",
375 	waypointSymbol:				"sym",
376 	waypointTime:				"time",
377 	waypointType:				"type",
378 	waypointVDOP:				"vdop"
379 };
380 /*
381 // Dynamic include of required libraries and check for Prototype
382 // Code taken from scriptaculous
383 // TODO: put this code in a library and reuse is instead of copying it to new files
384 var GpxActivityFactory = {
385 	require: function(libraryName) {
386 		// inserting via DOM fails in Safari 2.0, so brute force approach
387 		document.write('<script type="text/javascript" src="'+libraryName+'"></script>');
388 	},
389 
390 	load: function() {
391 		if((typeof Prototype=='undefined') || 
392 			(typeof Element == 'undefined') || 
393 			(typeof Element.Methods=='undefined') ||
394 			parseFloat(Prototype.Version.split(".")[0] + "." +
395 			Prototype.Version.split(".")[1]) < 1.5) {
396 			throw("GpxActivityFactory requires the Prototype JavaScript framework >= 1.5.0");
397 		}
398 
399 		$A(document.getElementsByTagName("script"))
400 		.findAll(
401 			function(s) {
402 				return (s.src && s.src.match(/GpxActivityFactory\.js(\?.*)?$/))
403 			}
404 		)
405 		.each(
406 			function(s) {
407 				var path = s.src.replace(/GpxActivityFactory\.js(\?.*)?$/,'../../');
408 				var includes = s.src.match(/\?.*load=([a-z,]*)/);
409 				var dependencies = 'garmin/util/Util-XmlConverter' +
410 									',garmin/util/Util-DateTimeFormat' +
411 									',garmin/activity/GarminMeasurement' +
412 									',garmin/activity/GarminSample' +
413 									',garmin/activity/GarminSeries' +
414 									',garmin/activity/GarminActivity';
415 			    (includes ? includes[1] : dependencies).split(',').each(
416 					function(include) {
417 						GpxActivityFactory.require(path+include+'.js') 
418 					}
419 				);
420 			}
421 		);
422 	}	
423 }
424 
425 GpxActivityFactory.load();*/
426