1 if (Garmin == undefined) var Garmin = {};
  2 /** Copyright � 2007 Garmin Ltd. or its subsidiaries.
  3  *
  4  * Licensed under the Apache License, Version 2.0 (the 'License')
  5  * you may not use this file except in compliance with the License.
  6  * You may obtain a copy of the License at
  7  *
  8  *    http://www.apache.org/licenses/LICENSE-2.0
  9  *
 10  * Unless required by applicable law or agreed to in writing, software
 11  * distributed under the License is distributed on an 'AS IS' BASIS,
 12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  * See the License for the specific language governing permissions and
 14  * limitations under the License.
 15  * 
 16  * @fileoverview GarminDevicePlugin wraps the Garmin ActiveX/Netscape plugin that should be installed on your machine inorder to talk to a Garmin Gps Device.
 17  * The plugin is available for download from http://www8.garmin.com/support/download_details.jsp?id=3608
 18  * More information is available about this plugin from http://www8.garmin.com/products/communicator/
 19  * 
 20  * @author Diana Chow diana.chow[at]garmin.com, Carlo Latasa carlo.latasa@garmin.com
 21  * @version 1.0
 22  */
 23 
 24 /** This api provides a set of functions to accomplish the following tasks with a Gps Device:
 25  * <br/>
 26  * <br/>  1) Unlocking devices allowing them to be found and accessed.
 27  * <br/>  2) Finding avaliable devices plugged into this machine.
 28  * <br/>  3) Reading from the device.
 29  * <br/>  4) Writing gpx files to the device.
 30  * <br/>  5) Downloading data to the device.
 31  * <br/>	 6) Geting messages, getting transfer status/progress and version information from the device.
 32  * <br/><br/>
 33  * Note that the GarminPluginAPIV1.xsd is referenced throughout this API. Please find more information about the GarminPluginAPIV1.xsd from http://
 34  *  
 35  * @class
 36  * requires Prototype
 37  * @param pluginElement element that references the Garmin GPS Control Web Plugin that should be installed.
 38  * 
 39  * constructor 
 40  * @return a new GarminDevicePlugin
 41  **/
 42 Garmin.DevicePlugin = function(pluginElement){};  //just here for jsdoc
 43 Garmin.DevicePlugin = Class.create();
 44 Garmin.DevicePlugin.prototype = {
 45 
 46     /** Constructor.
 47      * @private
 48      */
 49 	initialize: function(pluginElement) {        
 50 	    this.plugin = pluginElement;
 51 	    this.unlocked = false;
 52 	    //console.debug("DevicePlugin constructor supportsFitnessWrite="+this.supportsFitnessWrite)
 53 	},
 54 	
 55 	/** Unlocks the GpsControl object to be used at the given web address.  
 56      * More than one set of path-key pairs my be passed in, for example:
 57      * ['http://myDomain.com/', 'xxx','http://www.myDomain.com/', 'yyy']
 58      * See documentation site for more info on getting a key. <br/>
 59      * <br/>
 60      * Minimum plugin version 2.0.0.4
 61      * 
 62      * @param pathKeyPairsArray {Array}- baseURL and key pairs.  
 63      * @type Boolean
 64      * @return true if successfully unlocked or undefined otherwise
 65      */
 66 	unlock: function(pathKeyPairsArray) {
 67 	    var len = pathKeyPairsArray ? pathKeyPairsArray.length / 2 : 0;
 68 	    for(var i=0;i<len;i++) {
 69 	    	if (this.plugin.Unlock(pathKeyPairsArray[i*2], pathKeyPairsArray[i*2+1])){
 70 	    		this.unlocked = true;
 71 	    		return this.unlocked;
 72 	    	}
 73 	    }
 74 	    
 75 	    // Unlock codes for local development
 76 	    this.tryUnlock = this.plugin.Unlock("file:///","cb1492ae040612408d87cc53e3f7ff3c")
 77         	|| this.plugin.Unlock("http://localhost","45517b532362fc3149e4211ade14c9b2")
 78         	|| this.plugin.Unlock("http://127.0.0.1","40cd4860f7988c53b15b8491693de133");
 79         
 80         this.unlocked = !this.plugin.Locked;
 81         	
 82 	    return this.unlocked;
 83 	},
 84 	
 85 	/** Returns true if the plug-in is unlocked.
 86 	 */
 87 	isUnlocked: function() {
 88 		return this.unlocked;
 89 	},
 90 	
 91 	/**
 92 	* Check to see if plugin supports this function.  We are having to pass in the string due
 93 	* to IE evaluating the function when passed in as a parameter.
 94 	*
 95 	* @param pluginFunctionName {String} - name of the plugin function.
 96 	* @return true - if function is available in the plugin.  False otherwise.
 97 	*/
 98 	_getPluginFunctionExists: function(pluginFunctionName) {
 99 		var pluginFunction = "this.plugin." + pluginFunctionName;
100 		
101 	    try {
102 		    if( typeof eval(pluginFunction) == "function" ) {
103 		        return true;
104 		    }
105 		    else if(eval(pluginFunction)) {
106 		        return true;
107 		    }
108 		    else {
109 		        return false;
110 		    }
111 		}
112 		catch( e ) {
113 		    // For a supported function Internet Explorer says type is undefined but
114 		    // throws when the call is made.
115 		    return true;
116     	}
117 	},
118 
119 	/**
120 	* Check to see if plugin supports this field.
121 	*
122 	* @param pluginField {String} - name of the plugin field.
123 	* @return true - if the field is available in the plugin.  False otherwise.
124 	*/
125 	_getPluginFieldExists: function(pluginField) {
126 	    try {
127 		    if( typeof pluginField == "string" ) {
128 		        return true;
129 		    }
130 		    else if( pluginField ) {
131 		        return true;
132 		    }
133 		    else {
134 		        return false;
135 		    }
136 		}
137 		catch( e ) {
138 		    // For a supported function Internet Explorer says type is undefined but
139 		    // throws when the call is made.
140 		    return true;
141     	}
142 	},
143 	
144 	/** Lazy-logic accessor to fitness write support var.
145 	 * This is used to detect whether the user's installed plugin supports fitness writing.
146 	 * Fitness writing capability has a minimum requirement of plugin version 2.2.0.1.
147 	 * This should NOT be called until the plug-in has been unlocked.
148 	 */
149 	getSupportsFitnessWrite: function() {
150 	    return this._getPluginFunctionExists("StartWriteFitnessData"); 
151 	},
152 	
153 	/** Lazy-logic accessor to fitness write support var.
154 	 * This is used to detect whether the user's installed plugin supports fitness directory reading,
155 	 * which has a minimum requirement of plugin version 2.2.0.2.
156 	 * This should NOT be called until the plug-in has been unlocked.
157 	 */
158 	getSupportsFitnessDirectoryRead: function() {	
159 		return this._getPluginFunctionExists("StartReadFitnessDirectory");
160 	},
161 
162 	/** Lazy-logic accessor to FIT read support var.
163 	 * This is used to detect whether the user's installed plugin supports FIT directory reading,
164 	 * which has a minimum requirement of plugin version 2.8.x.x (TBD)
165 	 * This should NOT be called until the plug-in has been unlocked.
166 	 */
167 	getSupportsFitDirectoryRead: function() {		
168 			return this._getPluginFunctionExists("StartReadFITDirectory");
169 	},
170 	
171 	/** Lazy-logic accessor to fitness read compressed support var.
172 	 * This is used to detect whether the user's installed plugin supports fitness reading in compressed format,
173 	 * which has a minimum requirement of plugin version 2.2.0.2.
174 	 * This should NOT be called until the plug-in has been unlocked.
175 	 */
176 	getSupportsFitnessReadCompressed: function() {
177 	    return this._getPluginFieldExists(this.plugin.TcdXmlz);
178 	},
179 	
180 	/** Initiates a find Gps devices action on the plugin. 
181 	 * Poll with finishFindDevices to determine when the plugin has completed this action.
182 	 * Use getDeviceXmlString to inspect xml contents for and array of Device nodes.<br/>
183 	 * <br/>
184 	 * Minimum plugin version 2.0.0.4
185 	 * 
186 	 * @see #finishFindDevices
187 	 * @see #cancelFindDevices
188 	 */
189 	startFindDevices: function() {
190 		this.plugin.StartFindDevices();
191 	},
192 
193 	/** Cancels the current find devices interaction. <br/>
194 	 * <br/>
195 	 * Minimum plugin version 2.0.0.4
196 	 * 
197 	 * @see #startFindDevices
198 	 * @see #finishFindDevices
199 	 */
200 	cancelFindDevices: function() {
201         this.plugin.CancelFindDevices();
202 	},
203 
204 	/** Poll - with this function to determine completion of startFindDevices. Used after 
205 	 * the call to startFindDevices(). <br/>
206 	 * <br/>
207 	 * Minimum plugin version 2.0.0.4
208 	 * 
209 	 * @type Boolean
210 	 * @return Returns true if completed finding devices otherwise false.
211 	 * @see #startFindDevices
212 	 * @see #cancelFindDevices
213 	 */
214 	finishFindDevices: function() {
215     	return this.plugin.FinishFindDevices();
216 	},
217 	
218 	/** Returns information about the number of devices connected to this machine as 
219 	 * well as the names of those devices.  Refer to the 
220 	 * <a href="http://developer.garmin.com/schemas/device/v2/xmlspy/index.html#Link04DDFE88">Devices_t</a>
221 	 * element in the Device XML schema for what is included.
222 	 * The xml returned should contain a 'Device' element with 'DisplayName' and 'Number'
223 	 * if there is a device actually connected. <br/>
224 	 * <br/>
225 	 * Minimum plugin version 2.0.0.4
226 	 * 
227 	 * @type String
228 	 * @return Xml string with detailed device info
229 	 * @see #getDeviceDescriptionXml
230 	 */
231 	getDevicesXml: function(){
232 		return this.plugin.DevicesXmlString();
233 	},
234 
235 	/** Returns information about the specified Device indicated by the device Number. 
236 	 * See the getDevicesXml function to get the actual deviceNumber assigned.
237 	 * Refer to the 
238 	 * <a href="http://developer.garmin.com/schemas/device/v2/xmlspy/index.html#Link04DDFE88">Devices_t</a>
239 	 * element in the Device XML schema for what is included in the XML. <br/>
240 	 * <br/>
241 	 * Minimum plugin version 2.0.0.4
242 	 * 
243 	 * @param deviceNumber {Number} Assigned by the plugin, see getDevicesXml for 
244 	 * assignment of that number.
245 	 * @type String
246 	 * @return Xml string with detailed device info
247 	 * @see #getDevicesXml
248 	 */
249 	getDeviceDescriptionXml: function(deviceNumber){
250 		return this.plugin.DeviceDescription(deviceNumber);
251 	},
252 	
253 	// Read Methods
254 	
255 	/** Initiates the read from the gps device conneted. Use finishReadFromGps and getGpsProgressXml to 
256 	 * determine when the plugin is done with this operation. Also, use getGpsXml to extract the
257 	 * actual data from the device. <br/>
258 	 * <br/>
259 	 * Minimum plugin version 2.0.0.4
260 	 * 
261 	 * @param deviceNumber {Number} assigned by the plugin, see getDevicesXml for 
262 	 * assignment of that number.
263 	 * @see #finishReadFromGps
264 	 * @see #cancelReadFromGps
265 	 * @see #getDevicesXml
266 	 */
267 	startReadFromGps: function(deviceNumber) {
268 		 this.plugin.StartReadFromGps( deviceNumber );
269 	},
270 
271 	/** Indicates the status of the read process. It will return an integer
272 	 * know as the completion state.  The purpose is to show the 
273  	 * user information about what is happening to the plugin while it 
274  	 * is servicing your request. Used after startReadFromGps(). <br/>
275  	 * <br/>
276  	 * Minimum plugin version 2.0.0.4
277  	 * 
278 	 * @type Number
279 	 * @return Completion state - The completion state can be one of the following: <br/>
280 	 *  <br/>
281 	 *	0 = idle <br/>
282  	 * 	1 = working <br/>
283  	 * 	2 = waiting <br/>
284  	 * 	3 = finished <br/>
285  	 * @see #startReadFromGps
286 	 * @see #cancelReadFromGps
287 	 */
288 	finishReadFromGps: function() {
289 		return this.plugin.FinishReadFromGps();
290 	},
291 	
292 	/** Cancels the current read from the device. <br/>
293 	 * <br/>
294 	 * Minimum plugin version 2.0.0.4
295 	 * @see #startReadFromGps
296 	 * @see #finishReadFromGps
297      */	
298 	cancelReadFromGps: function() {
299 		this.plugin.CancelReadFromGps();
300 	},
301 	
302 	/** Start the asynchronous ReadFitnessData operation. <br/>
303 	 * <br/>
304 	 * Minimum plugin version 2.1.0.3 for FitnessHistory type<br/>
305      * Minimum plugin version 2.2.0.1 for FitnessWorkouts, FitnessUserProfile, FitnessCourses
306 	 * 
307 	 * @param deviceNumber {Number} assigned by the plugin, see getDevicesXmlString for 
308 	 * assignment of that number.
309 	 * @param dataTypeName {String} a fitness datatype from the 
310 	 * <a href="http://developer.garmin.com/schemas/device/v2">Garmin Device XML</a> 
311 	 * retrieved with getDeviceDescriptionXml
312 	 * @see #finishReadFitnessData  
313 	 * @see #cancelReadFitnessData
314 	 * @see #getDeviceDescriptionXml
315 	 * @see Garmin.DeviceControl#FILE_TYPES
316 	 */
317 	startReadFitnessData: function(deviceNumber, dataTypeName) {
318 		if( !this.checkPluginVersionSupport([2,1,0,3]) ) {
319 			throw new Error("Your Communicator Plug-in version (" + this.getPluginVersionString() + ") does not support reading this type of fitness data.");
320 		}
321 
322 		 this.plugin.StartReadFitnessData( deviceNumber, dataTypeName );
323 	},
324 
325 	/** Poll for completion of the asynchronous ReadFitnessData operation. <br/>
326      * <br/>
327      * If the CompletionState is eMessageWaiting, call MessageBoxXml
328      * to get a description of the message box to be displayed to
329      * the user, and then call RespondToMessageBox with the value of the
330      * selected button to resume operation.<br/>
331      * <br/>
332      * Minimum plugin version 2.1.0.3 for FitnessHistory type <br/>
333      * Minimum plugin version 2.2.0.1 for FitnessWorkouts, FitnessUserProfile, FitnessCourses
334 	 * 
335 	 * @type Number
336 	 * @return Completion state - The completion state can be one of the following: <br/>
337 	 *  <br/>
338 	 *	0 = idle <br/>
339  	 * 	1 = working <br/>
340  	 * 	2 = waiting <br/>
341  	 * 	3 = finished <br/>
342  	 * @see #startReadFitnessData  
343 	 * @see #cancelReadFitnessData
344 	 */
345 	finishReadFitnessData: function() {
346 	 	 return  this.plugin.FinishReadFitnessData();
347 	},
348 	
349 	/** Cancel the asynchronous ReadFitnessData operation. <br/>
350 	 * <br/>
351 	 * Minimum plugin version 2.1.0.3 for FitnessHistory type <br/>
352      * Minimum plugin version 2.2.0.1 for FitnessWorkouts, FitnessUserProfile, FitnessCourses
353      * 
354      * @see #startReadFitnessData  
355 	 * @see #finishReadFitnessData
356      */	
357 	cancelReadFitnessData: function() {
358 		this.plugin.CancelReadFitnessData();
359 	},
360 	
361 	/**
362 	 * List all of the FIT files on the device. Starts an asynchronous directory listing operation for the device.
363 	 * Poll for finished with FinishReadFitDirectory. The result is stored in ______.
364 	 * 
365 	 * Minimum plugin version 2.7.2.0
366 	 * @see #finishReadFitDirectory
367 	 */
368 	startReadFitDirectory: function(deviceNumber) {
369 	    if( !this.getSupportsFitDirectoryRead() ) {
370 			throw new Error("Your Communicator Plug-in version (" + this.getPluginVersionString() + ") does not support reading directory listing data.");
371 		}
372 	    this.plugin.StartReadFITDirectory(deviceNumber);
373 	},
374 	
375 	/** Poll for completion of the asynchronous startReadFitDirectory operation. <br/>
376      * <br/>
377 	 * Minimum plugin version 2.7.2.0
378 	 * 
379 	 * @type Number
380 	 * @return Completion state - The completion state can be one of the following: <br/>
381 	 *  <br/>
382 	 *	0 = idle <br/>
383  	 * 	1 = working <br/>
384  	 * 	2 = waiting <br/>
385  	 * 	3 = finished <br/>
386 	 * 
387 	 * @see #startReadFitDirectory
388 	 * @see #cancelReadFitDirectory
389 	 * @see #getMessageBoxXml
390 	 * @see #respondToMessageBox
391 	 */
392 	finishReadFitDirectory: function() {
393 		return this.plugin.FinishReadFITDirectory();
394 	},
395 	
396 	/** Start the asynchronous ReadFitnessDirectory operation. <br/>
397 	 * <br/>
398 	 * Minimum plugin version 2.2.0.2
399 	 * 
400 	 * @param deviceNumber {Number} assigned by the plugin, see getDevicesXmlString for 
401 	 * assignment of that number.
402 	 * @param dataTypeName a Fitness DataType from the GarminDevice.xml retrieved with DeviceDescription
403 	 * @see #finishReadFitnessDirectory
404 	 * @see #cancelReadFitnessDirectory
405 	 * @see Garmin.DeviceControl#FILE_TYPES
406 	 */
407 	startReadFitnessDirectory: function(deviceNumber, dataTypeName) {
408 		if( !this.getSupportsFitnessDirectoryRead() ) {
409 			throw new Error("Your Communicator Plug-in version (" + this.getPluginVersionString() + ") does not support reading fitness directory data.");
410 		}
411 		this.plugin.StartReadFitnessDirectory( deviceNumber, dataTypeName);
412 	},
413 	
414 	/** Poll for completion of the asynchronous ReadFitnessDirectory operation. <br/>
415      * <br/>
416      * If the CompletionState is eMessageWaiting, call getMessageBoxXml
417      * to get a description of the message box to be displayed to
418      * the user, and then call respondToMessageBox with the value of the
419      * selected button to resume operation.<br/>
420 	 * <br/>
421 	 * Minimum plugin version 2.2.0.2
422 	 * 
423 	 * @type Number
424 	 * @return Completion state - The completion state can be one of the following: <br/>
425 	 *  <br/>
426 	 *	0 = idle <br/>
427  	 * 	1 = working <br/>
428  	 * 	2 = waiting <br/>
429  	 * 	3 = finished <br/>
430 	 * 
431 	 * @see #startReadFitnessDirectory
432 	 * @see #cancelReadFitnessDirectory
433 	 * @see #getMessageBoxXml
434 	 * @see #respondToMessageBox
435 	 */
436 	finishReadFitnessDirectory: function() {
437 		return this.plugin.FinishReadFitnessDirectory();
438 	},
439 	
440 	/** Cancel the asynchronous ReadFitnessDirectory operation. <br/>
441 	 * <br/>
442 	 * Minimum plugin version 2.2.0.2
443 	 * 
444 	 * @see #startReadFitnessDirectory
445 	 * @see #finishReadFitnessDirectory
446      */	
447 	cancelReadFitnessDirectory: function() {
448 		this.plugin.CancelReadFitnessDirectory();
449 	},
450 
451 	/** Cancel the asynchronous ReadFitDirectory operation. <br/>
452 	 * <br/>
453 	 * Minimum plugin version 2.7.2.0
454 	 * 
455 	 * @see #startReadFitDirectory
456 	 * @see #finishReadFitDirectory
457      */	
458 	cancelReadFitDirectory: function() {
459 		this.plugin.CancelReadFitDirectory();
460 	},
461 	
462 	/** Start the asynchronous ReadFitnessDetail operation. <br/>
463 	 * <br/>
464 	 * Minimum plugin version 2.2.0.2
465 	 * 
466 	 * @param deviceNumber assigned by the plugin, see getDevicesXmlString for 
467 	 * assignment of that number.
468 	 * @param dataTypeName a Fitness DataType from the GarminDevice.xml retrieved with DeviceDescription
469 	 * @see #finishReadFitnessDetail
470 	 * @see #cancelReadFitnessDetail
471 	 * @see Garmin.DeviceControl#FILE_TYPES
472 	 */
473 	startReadFitnessDetail: function(deviceNumber, dataTypeName, dataId) {
474 		if( !this.checkPluginVersionSupport([2,2,0,2]) ) {
475 			throw new Error("Your Communicator Plug-in version (" + this.getPluginVersionString() + ") does not support reading fitness detail.");
476 		}
477 		
478 		this.plugin.StartReadFitnessDetail(deviceNumber, dataTypeName, dataId);
479 	},
480 	
481 	/** Poll for completion of the asynchronous ReadFitnessDetail operation. <br/>
482      * <br/>
483      * If the CompletionState is eMessageWaiting, call MessageBoxXml
484      * to get a description of the message box to be displayed to
485      * the user, and then call RespondToMessageBox with the value of the
486      * selected button to resume operation.<br/>
487      * <br/>
488      * Minimum plugin version 2.2.0.2
489 	 * 
490 	 * @type Number
491 	 * @return Completion state - The completion state can be one of the following: <br/>
492 	 *  <br/>
493 	 *	0 = idle <br/>
494  	 * 	1 = working <br/>
495  	 * 	2 = waiting <br/>
496  	 * 	3 = finished <br/>
497 	 * 
498 	 */
499 	finishReadFitnessDetail: function() {
500 		return this.plugin.FinishReadFitnessDetail();
501 	},
502 	
503 	/** Cancel the asynchronous ReadFitnessDirectory operation. <br/>
504 	 * <br/>
505 	 * Minimum version 2.2.0.2
506 	 * 
507 	 * @see #startReadFitnessDetail
508 	 * @see #finishReadFitnessDetail
509      */	
510 	cancelReadFitnessDetail: function() {
511 		this.plugin.CancelReadFitnessDetail();
512 	},
513 	
514 	// Write Methods
515 	
516 	/** Initates writing the gpsXml to the device specified by deviceNumber with a filename set by filename.
517 	 * The gpsXml is typically in GPX fomat and the filename is only the name without the extension. The 
518 	 * plugin will append the .gpx extension automatically.<br/>
519 	 * <br/>
520 	 * Use finishWriteToGps to poll when the write operation/plugin is complete.<br/>
521 	 * <br/>
522 	 * Uses the helper functions to set the xml info and the filename.  <br/>
523 	 * <br/>
524 	 * Minimum plugin version 2.0.0.4<br/>
525      * Minimum plugin version 2.2.0.1 for writes of GPX to SD Card
526 	 * 
527 	 * @param gpsXml {String} the gps/gpx information that should be transferred to the device.
528 	 * @param filename {String} the desired filename for the gpsXml that shall end up on the device.
529 	 * @param deviceNumber {Number} the device number assigned by the plugin.
530 	 * @see #finishWriteToGps
531 	 * @see #cancelWriteToGps  
532 	 */
533 	startWriteToGps: function(gpsXml, filename, deviceNumber) {
534 		this._setWriteGpsXml(gpsXml);
535 		this._setWriteFilename(filename);
536 	    this.plugin.StartWriteToGps(deviceNumber);
537 	},
538 
539 	/** Sets the gps xml content that will end up on the device once the transfer is complete.
540 	 * Use in conjunction with startWriteToGps to initiate the actual write.
541 	 *
542 	 * @private 
543 	 * @param gpsXml {String} xml data that is to be written to the device. Must be in GPX format.
544 	 */
545 	_setWriteGpsXml: function(gpsXml) {
546     	this.plugin.GpsXml = gpsXml;
547 	},
548 
549 	/** This the filename that wil contain the gps xml once the transfer is complete. Use with 
550 	 * setWriteGpsXml to set what the file contents will be. Also, use startWriteToGps to 
551 	 * actually make the write happen.
552 	 * 
553 	 * @private
554 	 * @param filename {String} the actual filename that will end up on the device. Should only be the
555 	 * name and not the extension. The plugin will append the extension portion to the file name--typically .gpx.
556 	 * @see #setWriteGpsXml, #startWriteToGps, #startWriteFitnessData
557 	 */
558 	_setWriteFilename: function(filename) {
559     	this.plugin.FileName = filename;
560 	},
561 
562 	/** This is used to indicate the status of the write process. It will return an integer
563 	 * know as the completion state.  The purpose is to show the 
564  	 * user information about what is happening to the plugin while it 
565  	 * is servicing your request. <br/>
566  	 * <br/>
567  	 * Minimum plugin version 2.0.0.4<br/>
568      * Minimum plugin version 2.2.0.1 for writes of GPX to SD Card 
569  	 * 
570 	 * @type Number
571 	 * @return Completion state - The completion state can be one of the following: <br/>
572 	 *  <br/>
573 	 *	0 = idle <br/>
574  	 * 	1 = working <br/>
575  	 * 	2 = waiting <br/>
576  	 * 	3 = finished <br/>
577  	 * @see #startWriteToGps
578 	 * @see #cancelWriteToGps  
579  	 */
580 	finishWriteToGps: function() {
581 		//console.debug("Plugin.finishWriteToGps");
582 	   	return  this.plugin.FinishWriteToGps();
583 	},
584     
585 	/** Cancels the current write operation to the gps device. <br/>
586 	 * <br/>
587 	 * Minimum plugin version 2.0.0.4<br/>
588      * Minimum plugin version 2.2.0.1 for writes of GPX to SD Card
589      * 
590      * @see #startWriteToGps
591 	 * @see #finishWriteToGps  
592      */	
593 	cancelWriteToGps: function() {
594 		this.plugin.CancelWriteToGps();
595 	},
596 
597 	/** Start the asynchronous StartWriteFitnessData operation. <br/>
598 	 * <br/>
599 	 * Minimum plugin version 2.2.0.1
600 	 * 
601 	 * @param tcdXml {String} XML of TCD data
602 	 * @param deviceNumber {Number} the device number, assigned by the plugin. See getDevicesXmlString for 
603 	 * assignment of that number.
604 	 * @param filename {String} the filename to write to on the device.
605 	 * @param dataTypeName {String} a Fitness DataType from the GarminDevice.xml retrieved with DeviceDescription
606 	 * @see #finishWriteFitnessData  
607 	 * @see #cancelWriteFitnessData
608 	 * @see Garmin.DeviceControl#FILE_TYPES
609 	 */
610 	startWriteFitnessData: function(tcdXml, deviceNumber, filename, dataTypeName) {	
611 		if( !this.checkPluginVersionSupport([2,2,0,1]) ) {
612 			throw new Error("Your Communicator Plug-in version (" + this.getPluginVersionString() + ") does not support writing fitness data.");
613 		}
614 		
615 		this._setWriteTcdXml(tcdXml);
616 		this._setWriteFilename(filename);
617 		this.plugin.StartWriteFitnessData(deviceNumber, dataTypeName);
618 	},
619 	
620 	/** This is used to indicate the status of the write process for fitness data. It will return an integer
621 	 * know as the completion state.  The purpose is to show the 
622  	 * user information about what is happening to the plugin while it 
623  	 * is servicing your request. <br/>
624  	 * <br/>
625  	 * Minimum plugin version 2.2.0.1
626  	 * 
627 	 * @type Number
628 	 * @return Completion state - The completion state can be one of the following: <br/>
629 	 *  <br/>
630 	 *	0 = idle <br/>
631  	 * 	1 = working <br/>
632  	 * 	2 = waiting <br/>
633  	 * 	3 = finished <br/>
634  	 * @see #startWriteFitnessData  
635 	 * @see #cancelWriteFitnessData
636 	 */
637 	finishWriteFitnessData: function() {
638 	 	return  this.plugin.FinishWriteFitnessData();
639 	},
640 	
641 	/** Cancel the asynchronous ReadFitnessData operation. <br/>
642 	 * <br/>
643 	 * Minimum plugin version 2.2.0.1
644 	 * 
645 	 * @see #startWriteFitnessData  
646 	 * @see #finishWriteFitnessData
647      */	
648 	cancelWriteFitnessData: function() {
649 		this.plugin.CancelWriteFitnessData();
650 	},
651 	
652 	/** Sets the tcd xml content that will end up on the device once the transfer is complete.
653 	 * Use in conjunction with startWriteFitnessData to initiate the actual write.
654 	 *
655 	 * @private 
656 	 * @param tcdXml {String} xml data that is to be written to the device. Must be in TCX format.
657 	 */
658 	_setWriteTcdXml: function(tcdXml) {
659     	this.plugin.TcdXml = tcdXml;
660 	},
661 	
662 	/**
663 	 * Determine the amount of space available on a Mass Storage Mode Device Volume.
664 	 * 
665 	 * @param {Number} deviceNumber - the device number assigned by the plugin. See {@link getDevicesXmlString} for 
666 	 * assignment of that number.
667 	 * @param {String} relativeFilePath - if a file is being replaced, set to relative path on device, otherwise set to empty string.
668 	 * @return -1 for non-mass storage mode devices.  
669 	 */
670 	bytesAvailable: function(deviceNumber, relativeFilePath) {
671 	    return this.plugin.BytesAvailable(deviceNumber, relativeFilePath);
672 	},
673 
674     /** Responds to a message box on the device. <br/>
675      * <br/>
676      * Minimum plugin version 2.0.0.4
677      *   
678      * @param response should be an int which corresponds to a button value from this.plugin.MessageBoxXml
679      */
680     respondToMessageBox: function(response) {
681         this.plugin.RespondToMessageBox(response);
682     },
683 
684 	/** Initates downloading the gpsDataString to the device specified by deviceNumber.
685 	 * The gpsDataString is typically in GPI fomat and the filename is only the name without the extension. The 
686 	 * plugin will append the .gpx extension automatically.<br/>
687 	 * <br/>
688 	 * Use finishWriteToGps to poll when the write operation/plugin is complete.<br/>
689 	 * <br/>
690 	 * Uses the helper functions to set the xml info and the filename.  <br/>
691 	 * <br/>
692 	 * Minimum plugin version 2.0.0.4
693 	 *  
694 	 * @param gpsDataString {String} the gpi information that should be transferred to the device.
695 	 * @param filename {String} the filename to write to on the device.
696 	 * @param deviceNumber {Number} the device number assigned by the plugin. 
697 	 * @see #finishDownloadData  
698 	 * @see #cancelDownloadData
699 	 */
700 	startDownloadData: function(gpsDataString, deviceNumber) {
701 		//console.debug("Plugin.startDownloadData gpsDataString="+gpsDataString);
702 		this.plugin.StartDownloadData(gpsDataString, deviceNumber);
703 	},
704 
705 	/** This is used to indicate the status of the download process. It will return an integer
706 	 * know as the completion state.  The purpose is to show the 
707  	 * user information about what is happening to the plugin while it 
708  	 * is servicing your request.<br/>
709 	 * <br/>
710 	 * Minimum plugin version 2.0.0.4
711 	 * 
712 	 * @type Number
713 	 * @return Completion state - The completion state can be one of the following: <br/>
714 	 *  <br/>
715 	 *	0 = idle <br/>
716  	 * 	1 = working <br/>
717  	 * 	2 = waiting <br/>
718  	 * 	3 = finished <br/>
719  	 * @see #startDownloadData  
720 	 * @see #cancelDownloadData
721 	 */
722 	finishDownloadData: function() {
723 		//console.debug("Plugin.finishDownloadData");
724 		return this.plugin.FinishDownloadData();
725 	},
726 
727 	/** Cancel the asynchronous Download Data operation. <br/>
728 	 * <br/>
729 	 * Minimum plugin version 2.0.0.4
730 	 * 
731 	 * @see #startDownloadData  
732 	 * @see #finishDownloadData
733 	 */
734 	cancelDownloadData: function() {
735 		this.plugin.CancelDownloadData();
736 	},
737 
738     /** Indicates success of StartDownloadData operation. <br/>
739      * <br/>
740      * Minimum plugin version 2.0.0.4
741      * 
742      * @type Boolean
743      * @return True if the last StartDownloadData operation was successful
744      */
745     downloadDataSucceeded: function() {
746 		return this.plugin.DownloadDataSucceeded;
747     },
748 
749     /** Download and install a list of unit software updates.  Start the asynchronous 
750      * StartUnitSoftwareUpdate operation.
751      * 
752      * Check for completion with the FinishUnitSoftwareUpdate() method.  After
753      * completion check the DownloadDataSucceeded property to make sure that all of the downloads 
754      * were successfully placed on the device. 
755      * 
756      * See the Schema UnitSoftwareUpdatev3.xsd for the format of the UpdateResponsesXml description
757      *
758      * @see Garmin.DevicePlugin.finishUnitSoftwareUpdate
759      * @see Garmin.DevicePlugin.cancelUnitSoftwareUpdate
760      * @see Garmin.DevicePlugin.downloadDataSucceeded
761      * @version plugin v2.6.2.0
762      */
763     startUnitSoftwareUpdate: function(updateResponsesXml, deviceNumber) {
764         this.plugin.StartUnitSoftwareUpdate(updateResponsesXml, deviceNumber);
765     },
766     
767     /** Poll for completion of the asynchronous Unit Software Update operation. It will return an integer
768 	 * know as the completion state.  The purpose is to show the 
769  	 * user information about what is happening to the plugin while it 
770  	 * is servicing your request.<br/>
771  	 * @type Number 
772      * @version plugin v2.6.2.0
773      * @return Completion state - The completion state can be one of the following: <br/>
774 	 *  <br/>
775 	 *	0 = idle <br/>
776  	 * 	1 = working <br/>
777  	 * 	2 = waiting <br/>
778  	 * 	3 = finished <br/>
779  	 * @see Garmin.DevicePlugin.startUnitSoftwareUpdate
780  	 * @see Garmin.DevicePlugin.cancelUnitSoftwareUpdate
781      */
782     finishUnitSoftwareUpdate: function() {
783         return this.plugin.FinishUnitSoftwareUpdate();  
784     },
785     
786     /** Cancel the asynchrous Download Data operation
787      * @version plugin v2.6.2.0
788      */
789     cancelUnitSoftwareUpdate: function() {
790         this.plugin.CancelUnitSoftwareUpdate();
791     },
792     
793     /** Get the UnitSoftwareUpdateRequests for a given device.
794      * This request retrieves the main system software (system region only.)
795      * @param deviceNumber {Number} the device number to retrieve unit software information for. 
796      * @return {String} XML string of the document format in the namespace below, or
797      * the most current version of that xms namespace
798      * http://www.garmin.com/xmlschemas/UnitSoftwareUpdate/v3
799      * @version plugin v2.6.2.0
800      * @see Garmin.DevicePlugin.getAdditionalSoftwareUpdateRequests
801      */
802 //    getUnitSoftwareUpdateRequests: function(deviceNumber) {
803 //        return this.plugin.UnitSoftwareUpdateRequests(deviceNumber);
804 //    },
805     
806     /** Get the AdditionalSoftwareUpdateRequests for a given device.
807      * This request retrieves the additional system software (all software except for system region.)
808      * @param deviceNumber {Number} the device number to retrieve unit software information for.
809      * @return {String} XML string of the document format in the namespace below, or
810      * the most current version of that xms namespace
811      * http://www.garmin.com/xmlschemas/UnitSoftwareUpdate/v3
812      * @version plugin v2.6.2.0
813      * @see Garmin.DevicePlugin.getUnitSoftwareUpdateRequests
814      */
815 //    getAdditionalSoftwareUpdateRequests: function(deviceNumber) {
816 //        return this.plugin.AdditionalSoftwareUpdateRequests(deviceNumber);
817 //    },
818     
819     /** Indicates success of WriteToGps operation. <br/>
820      * <br/>
821      * Minimum plugin version 2.0.0.4
822      * 
823      * @type Boolean
824      * @return True if the last ReadFromGps or WriteToGps operation was successful
825      */
826     gpsTransferSucceeded: function() {
827 		return this.plugin.GpsTransferSucceeded;
828     },
829 
830     /** Indicates success of ReadFitnessData or WriteFitnessData operation. <br/>
831      * <br/>
832      * Minimum plugin version 2.1.0.3
833      * 
834      * @type Boolean
835      * @return True if the last ReadFitnessData or WriteFitnessData operation succeeded
836      */
837     fitnessTransferSucceeded: function() {
838 		return this.plugin.FitnessTransferSucceeded;
839     },
840     
841     /** Return the specified file as a UU-Encoded string
842      * <br/>
843      * Minimum version 2.6.3.1
844      * 
845      * If the file is known to be compressed, compressed should be
846      * set to false. Otherwise, set compressed to true to retrieve a
847      * gzipped and uuencoded file.
848      * 
849      * @param relativeFilePath {String} path relative to the Garmin folder on the device
850      */
851     getBinaryFile: function(deviceNumber, relativeFilePath, compressed) {
852         return this.plugin.GetBinaryFile(deviceNumber, relativeFilePath, compressed);
853     },
854     
855     /** This is the GpsXml information from the device. Typically called after a read operation.
856      * 
857      * @see #finishReadFromGps
858      */
859 	getGpsXml: function(){
860 		return this.plugin.GpsXml;
861 	},
862 
863     /** This is the fitness data Xml information from the device. Typically called after a ReadFitnessData operation. <br/>
864 	 * <br/>
865      * Schemas for the TrainingCenterDatabase format are available at
866      * <a href="http://developer.garmin.com/schemas/tcx/v2/">http://developer.garmin.com/schemas/tcx/v2/</a><br/>
867      * <br/>
868      * Minimum plugin version 2.1.0.3
869      * 
870      * @see #finishReadFitnessData
871      * @see #finishReadFitnessDirectory
872      * @see #finishReadFitnessDetail
873      */
874 	getTcdXml: function(){
875 		return this.plugin.TcdXml;
876 	},
877 	
878 	 /** Returns last read fitness xml data in compressed format.  The xml is compressed as gzp and base64 expanded. <br/>
879 	  * <br/>
880 	  * Minimum plugin version 2.2.0.2
881 	  * 
882 	  * @return The read xml data in compressed gzp and base64 expanded format.
883 	  * @see #finishReadFitnessData
884       * @see #finishReadFitnessDirectory
885       * @see #finishReadFitnessDetail
886 	  */
887 	getTcdXmlz: function() {
888 		return this.plugin.TcdXmlz;
889 	},
890 
891 	 /** Returns last read directory xml data.<br/>
892 	  * <br/>
893 	  * 
894 	  * @return The directory xml data
895 	  * @see #finishReadFitDirectory
896 	  */
897 	getDirectoryXml: function() {
898 		return this.plugin.DirectoryListingXml;
899 	},
900 
901     /** Returns the xml describing the message when the plug-in is waiting for input from the user.
902      * @type String
903      * @return The xml describing the message when the plug-in is waiting for input from the user.
904      */
905 	getMessageBoxXml: function(){
906 		return this.plugin.MessageBoxXml;
907 	},
908     
909 	/** Get the status/progress of the current state or transfer.
910      * @type String
911      * @return The xml describing the current progress state of the plug-in.
912      */	
913 	getProgressXml: function() {
914 		return this.plugin.ProgressXml;
915 	},
916 
917 	/** Returns metadata information about the plugin version. 
918      * @type String
919      * @return The xml describing the user's version of the plug-in.
920 	 */
921 	getVersionXml: function() {
922 		return this.plugin.VersionXml;
923 	},
924 	
925 	/** Gets a string of the version number for the plugin the user has currently installed.
926      * @type String 
927      * @return A string of the format "versionMajor.versionMinor.buildMajor.buildMinor", ex: "2.0.0.4"
928      */	
929 	getPluginVersionString: function() {
930 		var versionArray = this.getPluginVersion();
931 	
932 		var versionString = versionArray[0] + "." + versionArray[1] + "." + versionArray[2] + "." + versionArray[3];
933 	    return versionString;
934 	},
935 	
936 	/** Gets the version number for the plugin the user has currently installed.
937      * @type Array 
938      * @return An array of the format: [versionMajor, versionMinor, buildMajor, buildMinor].
939      */	
940 	getPluginVersion: function() {
941     	var versionMajor = parseInt(this._getElementValue(this.getVersionXml(), "VersionMajor"));
942     	var versionMinor = parseInt(this._getElementValue(this.getVersionXml(), "VersionMinor"));
943     	var buildMajor = parseInt(this._getElementValue(this.getVersionXml(), "BuildMajor"));
944     	var buildMinor = parseInt(this._getElementValue(this.getVersionXml(), "BuildMinor"));
945 
946 	    var versionArray = [versionMajor, versionMinor, buildMajor, buildMinor];
947 	    return versionArray;
948 	},
949 	
950 	/** Sets the required plugin version number for the application.
951 	 * @param reqVersionArray {Array} The required version to set to.  In the format [versionMajor, versionMinor, buildMajor, buildMinor]
952 	 * 			i.e. [2,2,0,1]
953 	 */
954 	setPluginRequiredVersion: function(reqVersionArray) {
955 		Garmin.DevicePlugin.REQUIRED_VERSION.versionMajor = reqVersionArray[0];
956 		Garmin.DevicePlugin.REQUIRED_VERSION.versionMinor = reqVersionArray[1];
957 		Garmin.DevicePlugin.REQUIRED_VERSION.buildMajor = reqVersionArray[2];
958 		Garmin.DevicePlugin.REQUIRED_VERSION.buildMinor = reqVersionArray[3];
959 	},
960 	
961 	/** Sets the latest plugin version number.  This represents the latest version available for download at Garmin.
962 	 * We will attempt to keep the default value of this up to date with each API release, but this is not guaranteed,
963 	 * so set this to be safe or if you don't want to upgrade to the latest API.
964 	 * 
965 	 * @param reqVersionArray {Array} The latest version to set to.  In the format [versionMajor, versionMinor, buildMajor, buildMinor]
966 	 * 			i.e. [2,2,0,1]
967 	 */
968 	setPluginLatestVersion: function(reqVersionArray) {
969 		Garmin.DevicePlugin.LATEST_VERSION.versionMajor = reqVersionArray[0];
970 		Garmin.DevicePlugin.LATEST_VERSION.versionMinor = reqVersionArray[1];
971 		Garmin.DevicePlugin.LATEST_VERSION.buildMajor = reqVersionArray[2];
972 		Garmin.DevicePlugin.LATEST_VERSION.buildMinor = reqVersionArray[3];
973 	},
974 	
975 	/** Used to check if the user's installed plugin version meets the required version for feature support purposes.
976 	 *  
977 	 * @param {Array} reqVersionArray An array representing the required version, in the format: [versionMajor, versionMinor, buildMajor, buildMinor]. 
978 	 * @return {boolean} true if the passed in required version is met by the user's plugin version (user's version is equal to or greater), false otherwise.
979 	 * @see setPluginRequiredVersion
980 	 */
981 	checkPluginVersionSupport: function(reqVersionArray) {
982 		
983 		var pVersion = this._versionToNumber(this.getPluginVersion());
984    		var rVersion = this._versionToNumber(reqVersionArray);
985         return (pVersion >= rVersion);
986 	},
987 	
988 	/**
989 	 * @private
990 	 */
991 	_versionToNumber: function(versionArray) {
992 		if (versionArray[1] > 99 || versionArray[2] > 99 || versionArray[3] > 99)
993 			throw new Error("version segment is greater than 99: "+versionArray);
994 		return 1000000*versionArray[0] + 10000*versionArray[1] + 100*versionArray[2] + versionArray[3];
995 	},
996 	
997 	/** Determines if the Garmin plugin is at least the required version for the application.
998      * @type Boolean
999      * @see setPluginRequiredVersion
1000 	 */
1001 	isPluginOutOfDate: function() {
1002     	var pVersion = this._versionToNumber(this.getPluginVersion());
1003    		var rVersion = this._versionToNumber(Garmin.DevicePlugin.REQUIRED_VERSION.toArray());
1004         return (pVersion < rVersion);
1005 	},
1006 	
1007 	/** Checks if plugin is the most recent version released, for those that want the latest and greatest.
1008      */
1009     isUpdateAvailable: function() {
1010     	var pVersion = this._versionToNumber(this.getPluginVersion());
1011    		var cVersion = this._versionToNumber(Garmin.DevicePlugin.LATEST_VERSION.toArray());
1012         return (pVersion < cVersion);
1013     },
1014 	
1015 	/** Pulls value from xml given an element name or null if no tag exists with that name.
1016 	 * @private
1017 	 */
1018 	_getElementValue: function(xml, tagName) {
1019 		var start = xml.indexOf("<"+tagName+">");
1020 		if (start == -1)
1021 			return null;
1022 		start += tagName.length+2;
1023 		var end = xml.indexOf("</"+tagName+">");
1024 		var result = xml.substring(start, end);
1025 		return result;
1026 	}
1027 	
1028 };
1029 
1030 /** Latest version (not required) of the Garmin Communicator Plugin, and a complementary toString function to print it out with
1031  */
1032 Garmin.DevicePlugin.LATEST_VERSION = {
1033     versionMajor: 2,
1034     versionMinor: 7,
1035     buildMajor: 3,
1036     buildMinor: 0,
1037     
1038     toString: function() {
1039         return this.versionMajor + "." + this.versionMinor + "." + this.buildMajor + "." + this.buildMinor;
1040     },
1041     
1042     toArray: function() {
1043         return [this.versionMajor, this.versionMinor, this.buildMajor, this.buildMinor];
1044     }	
1045 }; 
1046  
1047  
1048 /** Latest required version of the Garmin Communicator Plugin, and a complementary toString function to print it out with. 
1049  */
1050 Garmin.DevicePlugin.REQUIRED_VERSION = {
1051     versionMajor: 2,
1052     versionMinor: 1,
1053     buildMajor: 0,
1054     buildMinor: 1,
1055     
1056     toString: function() {
1057         return this.versionMajor + "." + this.versionMinor + "." + this.buildMajor + "." + this.buildMinor;
1058     },
1059     
1060     toArray: function() {
1061         return [this.versionMajor, this.versionMinor, this.buildMajor, this.buildMinor];
1062     }	
1063 };