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.TcxActivityFactory - A factory for producing tcx 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 tcx xml and produce tcx xml given an
 23  * array of activity.
 24  * many other types of data.
 25  * @class Garmin.TcxActivityFactory
 26  * @constructor 
 27  */
 28 Garmin.TcxActivityFactory = function(){};
 29 Garmin.TcxActivityFactory = {
 30 	
 31 	parseString: function(tcxString) {
 32 		var tcxDocument = Garmin.XmlConverter.toDocument(tcxString);		
 33 		return Garmin.TcxActivityFactory.parseDocument(tcxDocument);		
 34 	},
 35 	
 36 	/* Creates and returns an array of activities from the document. */
 37 	parseDocument: function(tcxDocument) {
 38 		
 39 		// Not TCX parseable
 40 		if( tcxDocument.getElementsByTagName(Garmin.TcxActivityFactory.SCHEMA_TAGS.activities).length == 0
 41 			&& tcxDocument.getElementsByTagName(Garmin.TcxActivityFactory.SCHEMA_TAGS.courses).length == 0) {
 42 			throw new Error("ERROR: Unable to parse TCX document.");
 43 		}
 44 		
 45 		var parsedDocument;
 46 		
 47 		// Activities		
 48 		if( tcxDocument.getElementsByTagName(Garmin.TcxActivityFactory.SCHEMA_TAGS.activity).length >= 0) {
 49 			
 50 			if( tcxDocument.getElementsByTagName(Garmin.TcxActivityFactory.SCHEMA_TAGS.track).length >= 0) { 
 51 				// Complete activity
 52 				parsedDocument = Garmin.TcxActivityFactory._parseTcxActivities(tcxDocument);
 53 			}
 54 			else {
 55 				// Directory listing
 56 				parsedDocument = Garmin.TcxActivityFactory._parseTcxHistoryDirectory(tcxDocument);
 57 			}
 58 		} 
 59 		// Courses
 60 		else if(tcxDocument.getElementsByTagName(Garmin.TcxActivityFactory.SCHEMA_TAGS.course).length >= 0) {
 61 		
 62 			if( tcxDocument.getElementsByTagName(Garmin.TcxActivityFactory.SCHEMA_TAGS.lap).length >= 0) {
 63 				// Complete course
 64 				parsedDocument = Garmin.TcxActivityFactory._parseTcxCourses(tcxDocument);
 65 			}
 66 			else {
 67 				// Directory listing
 68 				parsedDocument = Garmin.TcxActivityFactory._parseTcxCourseDirectory(tcxDocument);
 69 			}
 70 		}
 71 		
 72 		return parsedDocument;
 73 	},
 74 	
 75 	produceString: function(activities) {
 76 		var tcxString = "";
 77 		
 78 		// header tags
 79 		tcxString += '<?xml version="1.0" encoding="UTF-8" standalone="no" ?>';
 80 		tcxString += '\n<TrainingCenterDatabase xmlns="http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2 http://www.garmin.com/xmlschemas/TrainingCenterDatabasev2.xsd http://www.garmin.com/xmlschemas/FatCalories/v1 http://www.garmin.com/xmlschemas/fatcalorieextensionv1.xsd">';
 81 		tcxString += '\n  <Activities>';		
 82 		
 83 		if (activities != null && activities.length > 0) {			
 84 			// activity tags
 85 			for (var i = 0; i < activities.length; i++) {
 86 				tcxString += "\n    " + Garmin.TcxActivityFactory._produceActivityString(activities[i]);
 87 			}
 88 			tcxString += '\n  </Activities>';
 89 			
 90 			// author tag
 91 			var activityDom = activities[0].getAttribute(Garmin.Activity.ATTRIBUTE_KEYS.dom);
 92 			if (activityDom != null) {
 93 				var authorDom = activityDom.ownerDocument.getElementsByTagName(Garmin.TcxActivityFactory.SCHEMA_TAGS.author);
 94 				if (authorDom.length > 0) {
 95 					tcxString += "\n  " + Garmin.XmlConverter.toString(authorDom[0]);
 96 				}
 97 			}
 98 		}
 99 
100 		// footer tags
101 		tcxString += '\n</TrainingCenterDatabase>';
102 				
103 		return tcxString;
104 	},
105 	
106 	/** Fully load the sample, assume sample was previously lazy-loaded
107 	 */	
108 	finishLoadingSample: function(domNode, sample) {
109 		Garmin.TcxActivityFactory._parseTcxTrackPoint(domNode, sample);
110 		sample.isLazyLoaded = false;
111 	},	
112 	
113 	_produceActivityString: function(activity) {
114 		var activityString = "";
115 		
116 		if (activity != null) {
117 			// converting the dom back into string
118 			// this is the lazy way, this will not work if 
119 			// converting between file types or activity data
120 			// has been modified.
121 			var activityDom = activity.getAttribute(Garmin.Activity.ATTRIBUTE_KEYS.dom);			
122 			if (activityDom != null) {
123 				activityString = Garmin.XmlConverter.toString(activityDom);
124 			}
125 		}
126 		
127 		return activityString;
128 	},
129 	
130 	_parseTcxHistoryDirectory: function(tcxDocument) {
131 		var activities = new Array();
132 		var activityNodes;
133 
134 		// Grab the activity/course nodes, depending on document		
135 		activityNodes = tcxDocument.getElementsByTagName(Garmin.TcxActivityFactory.SCHEMA_TAGS.activity);
136 		
137 		// loop through all activities in the document
138 		for (var i = 0; i < activityNodes.length; i++) {
139 			
140 			if( activityNodes[i].parentNode.tagName != Garmin.TcxActivityFactory.SCHEMA_TAGS.nextSport ){
141 				// create new activity object
142 				var activity = Garmin.TcxActivityFactory._parseTcxActivity(activityNodes[i], Garmin.TcxActivityFactory.SCHEMA_TAGS.activity);
143 				
144 				// grab all the lap nodes in the dom			
145 				var lapNodes = activityNodes[i].getElementsByTagName(Garmin.TcxActivityFactory.SCHEMA_TAGS.lap);
146 				
147 				// grab start time from the first lap and set duration to 0
148 				if (lapNodes.length > 0) {
149 					var activityStartTimeMS = lapNodes[0].getAttribute(Garmin.TcxActivityFactory.SCHEMA_TAGS.lapStartTime);
150 					var activityDurationMS = 0;	// in ms
151 				}			
152 				
153 				// loop through all laps in this activity
154 				for (var j = 0; j < lapNodes.length; j++) {
155 					
156 					// update the duration of this activity
157 					var lapTotalTime = Garmin.TcxActivityFactory._tagValue(lapNodes[j], Garmin.TcxActivityFactory.SCHEMA_TAGS.lapTotalTime);
158 					activityDurationMS += parseFloat(lapTotalTime + "e+3");
159 				}
160 				
161 				if ( lapNodes.length > 0) {
162 					// set the start and end time summary data for the activity if possible
163 					activityStartTimeObj = (new Garmin.DateTimeFormat()).parseXsdDateTime(activityStartTimeMS);
164 					activityEndTimeObj	=  new Garmin.DateTimeFormat();
165 					// NOTE: switch to using setDate() once it is implemented in Garmin.DateTimeFormat
166 					activityEndTimeObj.date = new Date(activityStartTimeObj.getDate().getTime() + activityDurationMS);
167 					activity.setSummaryValue(Garmin.Activity.SUMMARY_KEYS.startTime, activityStartTimeObj);
168 					activity.setSummaryValue(Garmin.Activity.SUMMARY_KEYS.endTime, activityEndTimeObj);
169 				}
170 				
171 				// Add the populated activity to the list of activities.  This activity may not have laps (if it's a directory listing entry).
172 				activities.push(activity);
173 			}
174 		}
175 		
176 		return activities;
177 	},
178 	
179 	_parseTcxCourseDirectory: function(tcxDocument) {
180 		var activities = new Array();
181 		var activityNodes;
182 
183 		// Grab the activity/course nodes, depending on document		
184 		activityNodes = tcxDocument.getElementsByTagName(Garmin.TcxActivityFactory.SCHEMA_TAGS.course);
185 		
186 		// loop through all activities in the document
187 		for (var i = 0; i < activityNodes.length; i++) {
188 			
189 			// create new activity object
190 			var activity = Garmin.TcxActivityFactory._parseTcxActivity(activityNodes[i], Garmin.TcxActivityFactory.SCHEMA_TAGS.course);
191 			
192 			// Add the populated activity to the list of activities.  This activity will not have laps.
193 			activities.push(activity);
194 		}
195 		
196 		return activities;
197 	},
198 	
199 	_parseTcxActivities: function(tcxDocument) {
200 		var activities = new Array();
201 		var activityNodes;
202 
203 		// Grab the activity/course nodes, depending on document		
204 		activityNodes = tcxDocument.getElementsByTagName(Garmin.TcxActivityFactory.SCHEMA_TAGS.activity);
205 		
206 		// loop through all activities in the document
207 		for (var i = 0; i < activityNodes.length; i++) {
208 			
209 			if( activityNodes[i].parentNode.tagName == Garmin.TcxActivityFactory.SCHEMA_TAGS.nextSport ){
210 				continue;
211 				}
212 				
213 			// create new activity object
214 			var activity = Garmin.TcxActivityFactory._parseTcxActivity(activityNodes[i], Garmin.TcxActivityFactory.SCHEMA_TAGS.activity);
215 			
216 			// create a history series for all the trackpoints in this activity
217 			var historySeries = new Garmin.Series(Garmin.Series.TYPES.history);
218 			
219 			// grab all the lap nodes in the dom			
220 			var lapNodes = activityNodes[i].getElementsByTagName(Garmin.TcxActivityFactory.SCHEMA_TAGS.lap);
221 			
222 			// grab start time from the first lap and set duration to 0
223 			if (lapNodes.length > 0) {
224 				var activityStartTimeMS = lapNodes[0].getAttribute(Garmin.TcxActivityFactory.SCHEMA_TAGS.lapStartTime);
225 				var activityDurationMS = 0;	// in ms
226 			}			
227 			
228 			// loop through all laps in this activity
229 			for (var j = 0; j < lapNodes.length; j++) {
230 				
231 				// update the duration of this activity
232 				var lapTotalTime = Garmin.TcxActivityFactory._tagValue(lapNodes[j], Garmin.TcxActivityFactory.SCHEMA_TAGS.lapTotalTime);
233 				activityDurationMS += parseFloat(lapTotalTime + "e+3");
234 				
235 				/* not implemented until sections are in place
236 				// create lap section
237 				// set start time				
238 				// set total time				
239 				// set distance				
240 				// set max speed				
241 				// set calories				
242 				// set intensity				
243 				// set trigger method
244 				*/
245 				
246 				// loop through all the tracks in this lap
247 				var trackNodes = lapNodes[j].getElementsByTagName(Garmin.TcxActivityFactory.SCHEMA_TAGS.track);			
248 				for (var k = 0; k < trackNodes.length; k++) {
249 					
250 					/* not implemented until sections are in place
251 					// create track section
252 					*/					
253 					
254 					// loop through all the trackpoints in this track
255 					var trackPointNodes = trackNodes[k].getElementsByTagName(Garmin.TcxActivityFactory.SCHEMA_TAGS.trackPoint);
256 					for (var l = 0; l < trackPointNodes.length; l++) {
257 						//historySeries.addSample(Garmin.TcxActivityFactory._parseTcxTrackPoint(trackPointNodes[l]));
258 						var trackPoint = new Garmin.Sample();
259 						trackPoint.setLazyLoading(true, Garmin.TcxActivityFactory, trackPointNodes[l]);
260 						historySeries.addSample(trackPoint);
261 						//historySeries.addSample(new Garmin.Sample());
262 					}					
263 				}
264 			}
265 			
266 			if ( lapNodes.length > 0) {
267 				// set the start and end time summary data for the activity if possible
268 				activityStartTimeObj = (new Garmin.DateTimeFormat()).parseXsdDateTime(activityStartTimeMS);
269 				activityEndTimeObj	=  new Garmin.DateTimeFormat();
270 				// NOTE: switch to using setDate() once it is implemented in Garmin.DateTimeFormat
271 				activityEndTimeObj.date = new Date(activityStartTimeObj.getDate().getTime() + activityDurationMS);
272 				activity.setSummaryValue(Garmin.Activity.SUMMARY_KEYS.startTime, activityStartTimeObj);
273 				activity.setSummaryValue(Garmin.Activity.SUMMARY_KEYS.endTime, activityEndTimeObj);
274 			}
275 			
276 			if (historySeries.getSamplesLength() > 0) {				
277 				// add the populated series to the activity
278 				activity.addSeries(historySeries);
279 			}
280 			
281 			// Add the populated activity to the list of activities.  This activity may not have laps (if it's a directory listing entry).
282 			activities.push(activity);
283 		}
284 		
285 		return activities;
286 	},
287 	
288 	_parseTcxCourses: function(tcxDocument) {
289 		var activities = new Array();
290 		var activityNodes;
291 
292 		// Grab the course nodes, depending on document		
293 		activityNodes = tcxDocument.getElementsByTagName(Garmin.TcxActivityFactory.SCHEMA_TAGS.course);
294 		
295 		// loop through all activities in the document
296 		for (var i = 0; i < activityNodes.length; i++) {
297 			
298 			// create new activity object
299 			var activity = Garmin.TcxActivityFactory._parseTcxActivity(activityNodes[i], Garmin.TcxActivityFactory.SCHEMA_TAGS.course);
300 			
301 			// create a history series for all the trackpoints in this activity
302 			var historySeries = new Garmin.Series(Garmin.Series.TYPES.course);
303 			
304 			// grab all the lap nodes in the dom			
305 			var lapNodes = activityNodes[i].getElementsByTagName(Garmin.TcxActivityFactory.SCHEMA_TAGS.lap);
306 			
307 			// grab start time from the first lap and set duration to 0
308 			if (lapNodes.length > 0) {
309 				var activityDurationMS = 0;	// in ms
310 			}		
311 			
312 			// loop through all laps in this activity
313 			for (var j = 0; j < lapNodes.length; j++) {
314 				
315 				// update the duration of this activity
316 				var lapTotalTime = Garmin.TcxActivityFactory._tagValue(lapNodes[j], Garmin.TcxActivityFactory.SCHEMA_TAGS.lapTotalTime);
317 				activityDurationMS += parseFloat(lapTotalTime + "e+3");
318 				
319 				/* not implemented until sections are in place
320 				// create lap section
321 				// set start time				
322 				// set total time				
323 				// set distance				
324 				// set max speed				
325 				// set calories				
326 				// set intensity				
327 				// set trigger method
328 				*/
329 			}
330 			
331 			// loop through all the tracks in this lap
332 			var trackNodes = activityNodes[i].getElementsByTagName(Garmin.TcxActivityFactory.SCHEMA_TAGS.track);			
333 			for (var k = 0; k < trackNodes.length; k++) {
334 				
335 				/* not implemented until sections are in place
336 				// create track section
337 				*/					
338 				
339 				// loop through all the trackpoints in this track
340 				var trackPointNodes = trackNodes[k].getElementsByTagName(Garmin.TcxActivityFactory.SCHEMA_TAGS.trackPoint);
341 				for (var l = 0; l < trackPointNodes.length; l++) {
342 					//historySeries.addSample(Garmin.TcxActivityFactory._parseTcxTrackPoint(trackPointNodes[l]));
343 					var trackPoint = new Garmin.Sample();
344 					trackPoint.setLazyLoading(true, Garmin.TcxActivityFactory, trackPointNodes[l]);
345 					historySeries.addSample(trackPoint);
346 					//historySeries.addSample(new Garmin.Sample());
347 				}					
348 			}
349 			
350 			if (historySeries.getSamplesLength() > 0) {				
351 				// add the populated series to the activity
352 				activity.addSeries(historySeries);
353 			}
354 			
355 			// Add the populated activity to the list of activities.  This activity may not have laps (if it's a directory listing entry).
356 			activities.push(activity);
357 		}
358 		
359 		return activities;
360 	},
361 	
362 	_parseTcxActivity: function(activityNode, activityType) {
363 		// create new activity object
364 		var activity = new Garmin.Activity();
365 		
366 		// set lazy loaded
367 		activity.setAttribute(Garmin.Activity.ATTRIBUTE_KEYS.isLazyLoaded, true);
368 		
369 		// set factory
370 		activity.setAttribute(Garmin.Activity.ATTRIBUTE_KEYS.factory, Garmin.TcxActivityFactory);
371 		
372 		// set dom
373 		activity.setAttribute(Garmin.Activity.ATTRIBUTE_KEYS.dom, activityNode);
374 		
375 		// set id
376 		var id;
377 		if(activityType == Garmin.TcxActivityFactory.SCHEMA_TAGS.activity) {
378 			id = Garmin.TcxActivityFactory._tagValue(activityNode, Garmin.TcxActivityFactory.SCHEMA_TAGS.activityId);
379 		} else {
380 			id = Garmin.TcxActivityFactory._tagValue(activityNode, Garmin.TcxActivityFactory.SCHEMA_TAGS.courseName);
381 		}
382 		activity.setAttribute(Garmin.Activity.ATTRIBUTE_KEYS.activityName, id)		
383 		
384 		// set sport
385 		var sport = activityNode.getAttribute(Garmin.TcxActivityFactory.SCHEMA_TAGS.activitySport);
386 		activity.setAttribute(Garmin.Activity.ATTRIBUTE_KEYS.activitySport, sport);	
387 		
388 		// set creator information, optional in schema
389 		var creator = activityNode.getElementsByTagName(Garmin.TcxActivityFactory.SCHEMA_TAGS.creator);
390 		if (creator != null && creator.length > 0) {
391 			// set creator name
392 			var creatorName = Garmin.TcxActivityFactory._tagValue(creator[0], Garmin.TcxActivityFactory.SCHEMA_TAGS.creatorName);
393 			activity.setAttribute(Garmin.Activity.ATTRIBUTE_KEYS.creatorName, creatorName);
394 			
395 			// set creator unit id
396 			var unitId = Garmin.TcxActivityFactory._tagValue(creator[0], Garmin.TcxActivityFactory.SCHEMA_TAGS.creatorUnitID);
397 			activity.setAttribute(Garmin.Activity.ATTRIBUTE_KEYS.creatorUnitId, unitId);
398 							
399 			// set creator product id
400 			var prodId = Garmin.TcxActivityFactory._tagValue(creator[0], Garmin.TcxActivityFactory.SCHEMA_TAGS.creatorProductID);
401 			activity.setAttribute(Garmin.Activity.ATTRIBUTE_KEYS.creatorProdId, prodId);
402 							
403 			// set creator version
404 			var version = Garmin.TcxActivityFactory._parseTcxVersion(creator[0]);
405 			if (version != null) {
406 				activity.setAttribute(Garmin.Activity.ATTRIBUTE_KEYS.creatorVersion, version);
407 			}
408 		}
409 		
410 		return activity;
411 	},
412 	
413 	
414 	
415 	_parseTcxTrackPoint: function(trackPointNode, trackPointSample) {
416 		// create a sample for this trackpoint if needed
417 		if (trackPointSample == null) {
418 			trackPointSample = new Garmin.Sample();
419 		}
420 		/*
421 		var trackPointValueNodes = trackPointNode.childNodes;
422 		for (var i = 1; i < trackPointValueNodes.length; i += 2) {
423 			if (trackPointValueNodes[i].nodeType == 1 && trackPointValueNodes[i].hasChildNodes()) {
424 				var nodeValue = trackPointValueNodes[i].childNodes[0].nodeValue;
425 				if (nodeValue != null) {
426 					switch(trackPointValueNodes[i].nodeName) {
427 						case Garmin.TcxActivityFactory.SCHEMA_TAGS.trackPointTime:
428 							trackPointSample.setMeasurement(Garmin.Sample.MEASUREMENT_KEYS.time, (new Garmin.DateTimeFormat()).parseXsdDateTime(nodeValue));						
429 							break;						
430 						case Garmin.TcxActivityFactory.SCHEMA_TAGS.position:
431 							//var latitude = Garmin.TcxActivityFactory._tagValue(trackPointValueNodes[i], Garmin.TcxActivityFactory.SCHEMA_TAGS.positionLatitude);		
432 							//var longitude = Garmin.TcxActivityFactory._tagValue(trackPointValueNodes[i], Garmin.TcxActivityFactory.SCHEMA_TAGS.positionLongitude);
433 							var latitude = trackPointValueNodes[i].childNodes[1].childNodes[0].nodeValue;
434 							var longitude = trackPointValueNodes[i].childNodes[3].childNodes[0].nodeValue;
435 							trackPointSample.setMeasurement(Garmin.Sample.MEASUREMENT_KEYS.latitude, latitude);
436 							trackPointSample.setMeasurement(Garmin.Sample.MEASUREMENT_KEYS.longitude, longitude);						
437 							break;						
438 						case Garmin.TcxActivityFactory.SCHEMA_TAGS.trackPointElevation:
439 							trackPointSample.setMeasurement(Garmin.Sample.MEASUREMENT_KEYS.elevation, nodeValue);
440 							break;
441 						case Garmin.TcxActivityFactory.SCHEMA_TAGS.trackPointDistance:
442 							trackPointSample.setMeasurement(Garmin.Sample.MEASUREMENT_KEYS.distance, nodeValue);
443 							break;
444 						case Garmin.TcxActivityFactory.SCHEMA_TAGS.trackPointHeartRate:
445 							//var heartRate = Garmin.TcxActivityFactory._tagValue(trackPointValueNodes[i], Garmin.TcxActivityFactory.SCHEMA_TAGS.trackPointHeartRateValue);
446 							var heartRate = trackPointValueNodes[i].childNodes[1].childNodes[0].nodeValue;
447 							trackPointSample.setMeasurement(Garmin.Sample.MEASUREMENT_KEYS.heartRate, heartRate);
448 							break;
449 						case Garmin.TcxActivityFactory.SCHEMA_TAGS.trackPointCadence:
450 							trackPointSample.setMeasurement(Garmin.Sample.MEASUREMENT_KEYS.cadence, nodeValue);
451 							break;
452 						case Garmin.TcxActivityFactory.SCHEMA_TAGS.trackPointSensorState:
453 							trackPointSample.setMeasurement(Garmin.Sample.MEASUREMENT_KEYS.sensorState, nodeValue);
454 							break;																																				
455 						default:
456 					}
457 				}
458 			}
459 		}
460 		*/
461 		
462 		// set time
463 		var time = Garmin.TcxActivityFactory._tagValue(trackPointNode, Garmin.TcxActivityFactory.SCHEMA_TAGS.trackPointTime);
464 		trackPointSample.setMeasurement(Garmin.Sample.MEASUREMENT_KEYS.time, (new Garmin.DateTimeFormat()).parseXsdDateTime(time));	
465 
466 		// set latitude and longitude, optional in schema (signal loss, create signal section);					
467 		var position = trackPointNode.getElementsByTagName(Garmin.TcxActivityFactory.SCHEMA_TAGS.position);
468 		if (position.length > 0) {
469 			var latitude = Garmin.TcxActivityFactory._tagValue(position[0], Garmin.TcxActivityFactory.SCHEMA_TAGS.positionLatitude);		
470 			var longitude = Garmin.TcxActivityFactory._tagValue(position[0], Garmin.TcxActivityFactory.SCHEMA_TAGS.positionLongitude);
471 			trackPointSample.setMeasurement(Garmin.Sample.MEASUREMENT_KEYS.latitude, latitude);
472 			trackPointSample.setMeasurement(Garmin.Sample.MEASUREMENT_KEYS.longitude, longitude);						
473 		}
474 					
475 		// set elevation, optional in schema
476 		var elevation = Garmin.TcxActivityFactory._tagValue(trackPointNode, Garmin.TcxActivityFactory.SCHEMA_TAGS.trackPointElevation);
477 		if (elevation != null) {
478 			trackPointSample.setMeasurement(Garmin.Sample.MEASUREMENT_KEYS.elevation, elevation);
479 		}
480 		
481 		// set distance, optional in schema
482 		var distance = Garmin.TcxActivityFactory._tagValue(trackPointNode, Garmin.TcxActivityFactory.SCHEMA_TAGS.trackPointDistance);
483 		if (distance != null) {
484 			trackPointSample.setMeasurement(Garmin.Sample.MEASUREMENT_KEYS.distance, distance);
485 		}
486 
487 		// set heart rate, optional in schema
488 		var heartRateNode = trackPointNode.getElementsByTagName(Garmin.TcxActivityFactory.SCHEMA_TAGS.trackPointHeartRate);
489 		if (heartRateNode.length > 0) {
490 			var heartRate = Garmin.TcxActivityFactory._tagValue(heartRateNode[0], Garmin.TcxActivityFactory.SCHEMA_TAGS.trackPointHeartRateValue);
491 			trackPointSample.setMeasurement(Garmin.Sample.MEASUREMENT_KEYS.heartRate, heartRate);
492 		}
493 
494 		// set cadence, optional in schema
495 		var cadence = Garmin.TcxActivityFactory._tagValue(trackPointNode, Garmin.TcxActivityFactory.SCHEMA_TAGS.trackPointCadence);
496 		if (cadence != null) {
497 			trackPointSample.setMeasurement(Garmin.Sample.MEASUREMENT_KEYS.cadence, cadence);
498 		}
499 
500 		// set sensor state, optional in schema
501 		var sensorState = Garmin.TcxActivityFactory._tagValue(trackPointNode, Garmin.TcxActivityFactory.SCHEMA_TAGS.trackPointSensorState);
502 		if (sensorState != null) {
503 			trackPointSample.setMeasurement(Garmin.Sample.MEASUREMENT_KEYS.sensorState, sensorState);
504 		}
505 		
506 		return trackPointSample;
507 	},
508 	
509 	_parseTcxVersion: function(parentNode) {
510 		// find the version node
511 		var versionNodes = parentNode.getElementsByTagName(Garmin.TcxActivityFactory.SCHEMA_TAGS.version);
512 		
513 		// if there is a version node
514 		if (versionNodes.length > 0) {					
515 			// get version major and minor
516 			var vMajor = Garmin.TcxActivityFactory._tagValue(versionNodes[0], Garmin.TcxActivityFactory.SCHEMA_TAGS.versionMajor);
517 			var vMinor = Garmin.TcxActivityFactory._tagValue(versionNodes[0], Garmin.TcxActivityFactory.SCHEMA_TAGS.versionMinor);
518 			
519 			// get buid major and minor, optional in schema
520 			var bMajor = Garmin.TcxActivityFactory._tagValue(versionNodes[0], Garmin.TcxActivityFactory.SCHEMA_TAGS.versionBuildMajor);
521 			var bMinor = Garmin.TcxActivityFactory._tagValue(versionNodes[0], Garmin.TcxActivityFactory.SCHEMA_TAGS.versionBuildMinor);
522 			
523 			// return version
524 			if ((bMajor != null) && (bMinor != null)) {
525 				return { versionMajor: vMajor, versionMinor: vMinor, buildMajor: bMajor, buildMinor: bMinor };
526 			} else {
527 				return { versionMajor: vMajor, versionMinor: vMinor };
528 			}
529 		} else {
530 			return null;
531 		}
532 	},	
533 	
534 	_tagValue: function(parentNode, tagName) {
535 		var subNode = parentNode.getElementsByTagName(tagName);
536 		return subNode.length > 0 ? subNode[0].childNodes[0].nodeValue : null;
537 	},	
538 	
539     toString: function() {
540         return "[TcxActivityFactory]";
541     }	
542 };
543 
544 Garmin.TcxActivityFactory.DETAIL = {
545 	creator:			"Garmin Communicator Plugin API - http://www.garmin.com/"
546 };
547 
548 Garmin.TcxActivityFactory.SCHEMA_TAGS = {
549 	activities:					"Activities",
550 	activity:					"Activity",
551 	activityId:					"Id",
552 	activitySport:				"Sport",
553 	author:						"Author",
554 	course:						"Course",
555 	courses:					"Courses",
556 	courseName:					"Name",
557 	creator:					"Creator",
558 	creatorName:				"Name",
559 	creatorUnitID:				"UnitId",
560 	creatorProductID:			"ProductID",
561 	lap:						"Lap",
562 	lapAverageHeartRate:		"AverageHeartRateBpm",
563 	lapCadence:					"Cadence",
564 	lapCalories:				"Calories",
565 	lapDistance:				"DistanceMeters",
566 	lapIntensity:				"Intensity",
567 	lapMaxHeartRate:			"MaximumHeartRateBpm",
568 	lapMaxSpeed:				"MaximumSpeed",
569 	lapNotes:					"Notes",
570 	lapStartTime:				"StartTime",
571 	lapTotalTime:				"TotalTimeSeconds",
572 	lapTriggerMethod:			"TriggerMethod",
573 	multiSportSession:			"MultiSportSession",
574 	nextSport:					"NextSport",
575 	position:					"Position",
576 	positionLatitude:			"LatitudeDegrees",
577 	positionLongitude:			"LongitudeDegrees",
578 	track:						"Track",
579 	trackPoint:					"Trackpoint",
580 	trackPointCadence:			"Cadence",
581 	trackPointDistance:			"DistanceMeters",
582 	trackPointElevation:		"AltitudeMeters",	
583 	trackPointHeartRate:		"HeartRateBpm",
584 	trackPointHeartRateValue:	"Value",
585 	trackPointSensorState:		"SensorState",
586 	trackPointTime:				"Time",
587 	version:					"Version",
588 	versionBuildMajor:			"BuildMajor",
589 	versionBuildMinor:			"BuildMinor",	
590 	versionMajor:				"VersionMajor",
591 	versionMinor:				"VersionMinor"
592 };
593 /*
594 // Dynamic include of required libraries and check for Prototype
595 // Code taken from scriptaculous
596 // TODO: put this code in a library and reuse is instead of copying it to new files
597 var TcxActivityFactory = {
598 	require: function(libraryName) {
599 		// inserting via DOM fails in Safari 2.0, so brute force approach
600 		document.write('<script type="text/javascript" src="'+libraryName+'"></script>');
601 	},
602 
603 	load: function() {
604 		if((typeof Prototype=='undefined') || 
605 			(typeof Element == 'undefined') || 
606 			(typeof Element.Methods=='undefined') ||
607 			parseFloat(Prototype.Version.split(".")[0] + "." +
608 			Prototype.Version.split(".")[1]) < 1.5) {
609 			throw("TcxActivityFactory requires the Prototype JavaScript framework >= 1.5.0");
610 		}
611 
612 		$A(document.getElementsByTagName("script"))
613 		.findAll(
614 			function(s) {
615 				return (s.src && s.src.match(/TcxActivityFactory\.js(\?.*)?$/))
616 			}
617 		)
618 		.each(
619 			function(s) {
620 				var path = s.src.replace(/TcxActivityFactory\.js(\?.*)?$/,'../../');
621 				var includes = s.src.match(/\?.*load=([a-z,]*)/);
622 				var dependencies = 'garmin/util/Util-XmlConverter' +
623 									',garmin/util/Util-DateTimeFormat' +
624 									',garmin/activity/GarminMeasurement' +
625 									',garmin/activity/GarminSample' +
626 									',garmin/activity/GarminSerie' +
627 									',garmin/activity/GarminActivity';
628 			    (includes ? includes[1] : dependencies).split(',').each(
629 					function(include) {
630 						TcxActivityFactory.require(path+include+'.js') 
631 					}
632 				);
633 			}
634 		);
635 	}	
636 }
637 
638 TcxActivityFactory.load();*/