var activity_uploader;
var contact_list = [];

jQuery.fn.exists = function(func){
    if(jQuery(this).length>0) {
        if(func) {
            return func();
        }
        return true;
    }
    return false;
}

function buttonstyleOver(e)
{
	e.className = "buttonstyleOver";
}

function buttonstyleOut(e)
{
	e.className = "buttonstyleOut";
}

// Anonymous function
(function($)
{			
	
	$.loading.maskCss.background = "#FFF";
	$.loading.maskCss.opacity = .50;
	
	var newActivities = new Array();
	var activityQueue = new Array();
	var processedCount = 0;
	var newCount = 0;
	var opperation = "";
	
	var ActivityUploader = function(options) {
		this.initialize(options);
	};
	
	ActivityUploader.prototype = {
		initialize: function(options)
		{
			
			
			this.key = options.key;
			this.check_url = options.check_url;
			this.post_url = options.post_url;

			try {
			  
			  this.controller = new ActivityController();
				this.gc = new Garmin.DeviceControl();
				this.gc.register(this.controller);
				this.gc.unlock(this.key);
				this.gc.setPluginRequiredVersion([2,6,3,1]);
				// this.gc.setPluginLatestVersion([2,5,1,0]);
				this.gc.validatePlugin();
				
			} catch(e) {
				this.controller.onException(e);
			}

		},
		
		start: function(opp) {
			opperation = opp;
			
			if(this.gc != undefined) {
				this.gc.findDevices();
			}
		},
		
		reset: function() {
			
			this.gc.cancelFindDevices();
			this.gc.cancelReadFromDevice();
			newActivities = new Array();
			activityQueue = new Array();
			processedCount = 0;
			newCount = 0;
			$('#upload-progress-bar').hide();
			$("#tracks").hide();
		},
		
		read_from : function(device_number,r) {
			r.controller.deviceNumber = device_number;
			$('#upload-messages').text("Found Device... " + r.controller.devices[device_number].displayName);
			$("#tracks").children().remove();
			$("#tracks").hide();
			this.controller.set_type((this.gc.checkDeviceReadSupport(Garmin.DeviceControl.FILE_TYPES.tcxDir))? "TCX" : "FIT");
			this.controller.read(r);
			// r.controller.readDataFromDevice(Garmin.DeviceControl.FILE_TYPES.tcxDir);
		},
		
		write_to : function(device_number,r) {
			r.controller.deviceNumber = device_number;
			$('#upload-messages').text("Found Device... " + r.controller.devices[device_number].displayName);
			$("#tracks").children().remove();
			$("#tracks").hide();
			$.get('/routes/crs/' + activity_id, {}, function(data, status) {
				if(status == "success") {
					
					r.controller.writeFitnessToDevice(data, "course.crs");
				}
			},"text");
			
		} // END function write_to()
	}; // END ActivityUpload class
	
	var ActivityMapController = Class.create({
	  initialize: function(container, activity) {
	    this.activity = activity;
	    this.alternate = 1;
	    this.all_tracks = new Array();
	    try {
	      var map = new GMap2(document.getElementById(container));
	      map.addMapType(G_PHYSICAL_MAP);
	      map.setMapType(G_PHYSICAL_MAP);
        map.addControl(new GLargeMapControl());
        var mapControl = new GHierarchicalMapTypeControl();
		
        // Set up map type menu relationships
        mapControl.clearRelationships();
        mapControl.addRelationship(G_SATELLITE_MAP, G_HYBRID_MAP, "Labels", false);

        // Add control after you've specified the relationships
        map.addControl(mapControl);
        var last_point;
        for(var n=0;n<activity.laps.length;n++) {
          var tracks = new Array();
          var icon = new GIcon();
          icon.image = '/images/numbers/' + (n+1) + '.png';
          icon.iconSize = new GSize(13,13);
          icon.iconAnchor = new GPoint(6,6);
          var first_point = false;
    	    for(var i=0;i<activity.laps[n].tracks.length;i++) {
    	      if(Math.abs(activity.laps[n].tracks[i].latitude_degrees)) {
    	        last_point = new GLatLng(activity.laps[n].tracks[i].latitude_degrees, activity.laps[n].tracks[i].longitude_degrees);
    	        if(first_point == false) {
    	          first_point = last_point;
  	          }
    	        tracks.push(last_point);
      	      this.all_tracks.push(last_point);
    	      }
    	    }
    	    var marker = new GMarker(first_point, {icon:icon});
    	    var polyline = new GPolyline(tracks, (this.alternate)? "#FF0000" : "#990000", 2, 1);
    	    map.addOverlay(polyline);
    	    map.addOverlay(marker);
    	    this.alternate = (this.alternate == 0)? 1 : 0;
        }
        
        var finish = new GIcon();
        finish.image = '/images/numbers/finish.png';
        finish.iconSize = new GSize(13,13);
        finish.iconAnchor = new GPoint(6,-6);
        finish_marker = new GMarker(last_point, {icon:finish});
        map.addOverlay(finish_marker);
        
        // Zoom Hack!
        var polyline = new GPolyline(this.all_tracks, "#FFFFFF", 3, 1);
        map.setCenter(polyline.getBounds().getCenter(), map.getBoundsZoomLevel(polyline.getBounds()));
        //map.addOverlay(polyline);
        window.unload = GUnload;
	    } catch(e) {
	      alert("Somthing bad happened... " + e);
	    }
	  } // END function intitalize()
	});
	
	var BaseActivityController = {
	  _processTracks: function(r)
		{
			
			var obj = this;
			$.post(this.check_url, {xml:r.controller.gpsDataString}, function(data,status) {
				if(status == 'success') {
					if(data.activities) {
						newActivities = newActivities.concat(data.activities);
						activityQueue = activityQueue.concat(data.activities);
					}
					
					
					$('#upload-messages').text('Processing ' + newActivities.length + ' track(s)');
					if(newActivities.length < 1) {
						$("#tracks").show();
						$('<li>All the available tracks have been processed. You should probably go out and ride.</li>').appendTo("#tracks");
					}
					$('#upload-progress-bar').hide();
					obj._processTrack(r);
					processedCount++;
				}
			}, 'json');
		},// END function _processTracks()
		
		_getActivity: function(id)
		{
			for(i=0;i<newActivities.length; i++) {
				if(id == newActivities[i].id) {
					return newActivities[i];
				}
			}
			return null;
		}, // END function _getActivity()
		
		_createTrackUpload: function(r) 
		{
			var id = r.controller.gpsData.getElementsByTagName('Id')[0].firstChild.nodeValue;
			var activity = this._getActivity(id);
			var post_url = this.post_url; // Need to set the post url because of this scope gets overidden.


			var series = Garmin.TcxActivityFactory.parseDocument(r.controller.gpsData)[0].getSeries();

			if(series.length == 0) {
				return false;
			}

			var url = this.activity_post_url;
			var xml = r.controller.gpsDataString;

			if(activity != null) {
				var li = $('<li id="' + activity.md5 + '"/>');
				var div = $('<div class="upload-form"/>');
				var button = $('<p><div id="upload-an-activity" class="button ui-state-default ui-corner-all"><span class="ui-icon ui-icon-transferthick-e-w"></span>Upload Activity</div></p>');
				var name = $('<p><label>Name: </label><input type="text" name="name" class="input-text" id="' + activity.md5 + '-name"/></p>');
				var desc = $('<p><label>Description: </label><textarea id="' + activity.md5 + '-desc"></textarea></p>');
				var priv = $('<p><label><input type="checkbox" value="yes" id="' + activity.md5 + '-private"/> Keep this private!</label></p>');
				var tags = $('<p><label>Tags (comma separated): </label><input type="text" name="tags"  class="input-text" id="' + activity.md5 + '-tags"/></p>');
				var sports = $('<p/>');
				var sports_label = $('<label> Sport: </label>').appendTo(sports);
				var sports_pulldown = $("#sport_pulldown").clone().appendTo(sports);
				$(sports_pulldown).attr('id', activity.md5 + '-sport');
				
				$(div).append(sports);
				$(div).append(name);
				$(div).append(desc);
				$(div).append(tags);
				$(div).append(priv);
				$(div).append(button);
				
				$(button).click(function() {
					$('#' + activity.md5).loading({
						mask:true,
						align:"center",
						img: "/images/bigWaiting.gif"
					});
					var fields = {
						xml: xml,
						name: $("#" + activity.md5 + "-name").val(),
						sport_id: $("#" + activity.md5 + "-sport").val(),
						tag_list: $("#" + activity.md5 + "-tags").val(),
						description: $("#" + activity.md5 + "-desc").val(),
						is_private: $("#" + activity.md5 + "-private:checked").val()
					};
					$.post(post_url, fields, function(data,status) {
						$('#' + activity.md5).loading();
						$("#" + activity.md5).html('<a href="' + data.link + '">' + data.name + '</a> uploaded successfuly. ' + data.sponsor + ' moved another <strong>$' + data.dollars_raised + '</strong> to ' + data.cause + '.');
						refresh_activities();
					}, 'json');
				});

				if(series.length > 0) {
					var route = $('<div class="route"><div id="' + activity.md5 + '-map" class="chooser-map"/></div>').appendTo(li);
				}
				
				$('<strong>Date:</strong><span> ' + activity.date_ft + ' </span>').appendTo(route);
				$('<strong>Dist:</strong><span> ' + activity.dist + ' </span>').appendTo(route);
				$('<strong>Time:</strong><span> ' + activity.time_ft + ' </span>').appendTo(route);
				
				
				$(li).append(div);
				$("#tracks").show();
				$('#tracks').prepend(li);
				
				if(series.length > 0) {
					var mapController = new Garmin.MapController(activity.md5 + '-map');
					mapController.drawTrack(series[0]);
				}

				newCount++;
				$('#upload-messages').text(newCount + ' new track(s) found');

				return true;
			}
		} // END _createTrackUpload();
	}

  var TCXActivityController = Class.create(BaseActivityController,{
    initialize: function() 
    {
        this.check_url = "/garmin/tcx_check"; 
				this.post_url = "/garmin/tcx_upload";
    }, // END function initialize
    
    read: function(r)
    {
      r.controller.readDataFromDevice(Garmin.DeviceControl.FILE_TYPES.tcxDir);
    }, // END function read
    
    onFinishReadFromDevice: function(r)
		{
			if(r.success) {
				switch(r.controller.gpsDataType) {
					case Garmin.DeviceControl.FILE_TYPES.tcxDir:
						this._processTracks(r);
						break;
					case Garmin.DeviceControl.FILE_TYPES.tcxDetail: 
						this._createTrackUpload(r);
						if(activityQueue.length > 0) {
							if(this._processTrack(r)) {
								processedCount++;
							}
						} else {
							if(processedCount == 0) {
								$("#tracks").show();
								$("<li>Hmmm. We can't find anything to upload -- See if it's already uploaded, then go out and have some fun!</li>").appendTo("#tracks");
							}
							$('#upload-messages').text('Finished processing.');
							$('#upload-progress-bar').hide();
							// $(".ui-widget-overlay").height($('#dialog-upload').height() + $('#dialog-upload').scrollTop() + 50);
						}
						break;
					default:
						break;
				}
			}
		}, // END function on FinishReadFromDevice()
    
		_processTrack: function(r)
		{
			var activity = activityQueue.pop();
			if(activity) {
				r.controller.readDetailFromDevice(Garmin.DeviceControl.FILE_TYPES.tcxDetail, activity.id);
			}
			
		} // END function _processTrack()
  }); // END FITActivityController class
  
  
  var FITActivityController = Class.create(BaseActivityController,{
    initialize: function() 
    {
      this.check_url = "/garmin/fit_check"; 
			this.post_url = "/garmin/fit_upload";
			this.convert_url = "/garmin/fit_convert";
			this.activities = new Array();
			this.total_available = 0;
    }, // END function initialize
    
    read: function(r)
    { 
      var obj = this;
      $('#upload-messages').text("We've been working hard to support FIT based devices (like the Garmin 500). Currently the Garmin plugin doesn't support this device. But have no fear because we've come up with a work around solution! Use the browse button bellow to choose a FIT data file from you mounted Garmin device. On Windows, they should be located at e:/GARMIN/Garmin/Activities/. On Mac OS X, they are located at /GARMIN/Garmin/Activities/.");
      var li = $('<li/>');
      var p = $('<div style="text-align: center;"/>');
      var upload = $('<a class="btn" id="fit-upload-btn">Choose FIT Data File to Process</a>');
      p.append(upload);
      li.append(p);
      $('#tracks').append(li);
      $('#tracks').show();
      
      new AjaxUpload(upload, {
        // Location of the server-side upload script
        // NOTE: You are not allowed to upload files to another domain
        action: '/garmin/fit_file_upload',
        // File upload name
        name: 'fitfile',
        // Submit file after selection
        autoSubmit: true,
        // The type of data that you're expecting back from the server.
        // HTML (text) and XML are detected automatically.
        // Useful when you are using JSON data as a response, set to "json" in that case.
        // Also set server response type to text/html, otherwise it will not work in IE6
        responseType: 'json',
        // Fired after the file is selected
        // Useful when autoSubmit is disabled
        // You can return false to cancel upload
        // @param file basename of uploaded file
        // @param extension of that file
        onChange: function(file, extension){},
        // Fired before the file is uploaded
        // You can return false to cancel upload
        // @param file basename of uploaded file
        // @param extension of that file
        onSubmit: function(file, extension) {},
        // Fired when file upload is completed
        // WARNING! DO NOT USE "FALSE" STRING AS A RESPONSE!
        // @param file basename of uploaded file
        // @param response server response
        onComplete: function(file, response) { 
          if(response.status == 'ok') {
            var post_url = obj.post_url; // Need to set the post url because of this scope gets overidden

      			if(response.activity != null) {
      			  var activity = response.activity;
      				var li = $('<li id="' + activity.md5_sig + '"/>');
      				var div = $('<div class="upload-form"/>');
      				var button = $('<p><div id="upload-an-activity" class="button ui-state-default ui-corner-all"><span class="ui-icon ui-icon-transferthick-e-w"></span>Upload Activity</div></p>');
      				var name = $('<p><label>Name: </label><input type="text" name="name" class="input-text" id="' + activity.md5_sig + '-name"/></p>');
      				var desc = $('<p><label>Description: </label><textarea id="' + activity.md5_sig + '-desc"></textarea></p>');
      				var priv = $('<p><label><input type="checkbox" value="yes" id="' + activity.md5_sig + '-private"/> Keep this private!</label></p>');
      				var tags = $('<p><label>Tags (comma separated): </label><input type="text" name="tags"  class="input-text" id="' + activity.md5_sig + '-tags"/></p>');
      				var sports = $('<p/>');
      				var sports_label = $('<label> Sport: </label>').appendTo(sports);
      				var sports_pulldown = $("#sport_pulldown").clone().appendTo(sports);
      				$(sports_pulldown).attr('id', activity.md5_sig + '-sport');

      				$(div).append(sports);
      				$(div).append(name);
      				$(div).append(desc);
      				$(div).append(tags);
      				$(div).append(priv);
      				$(div).append(button);

      				$(button).click(function() {
      					$('#' + activity.md5_sig).loading({
      						mask:true,
      						align:"center",
      						img: "/images/bigWaiting.gif"
      					});
      					var fields = {
      						data: JSON.stringify(activity.data),
      						md5_sig: activity.md5_sig,
      						name: $("#" + activity.md5_sig + "-name").val(),
      						sport_id: $("#" + activity.md5_sig + "-sport").val(),
      						tag_list: $("#" + activity.md5_sig + "-tags").val(),
      						description: $("#" + activity.md5_sig + "-desc").val(),
      						is_private: $("#" + activity.md5_sig + "-private:checked").val()
      					};
      					$.post(post_url, fields, function(data,status) {
      						$('#' + activity.md5_sig).loading();
      						$("#" + activity.md5_sig).html('<a href="' + data.link + '">' + data.name + '</a> uploaded successfuly. ' + data.sponsor + ' moved another <strong>$' + data.dollars_raised + '</strong> to ' + data.cause + '.');
      						refresh_activities();
      					}, 'json');
      				});

      				var route = $('<div class="route"><div id="' + activity.md5_sig + '-map" class="chooser-map"/></div>').appendTo(li);

      				$('<strong>Date:</strong><span> ' + activity.date_ft + ' </span>').appendTo(route);
      				$('<strong>Dist:</strong><span> ' + activity.dist + ' </span>').appendTo(route);
      				$('<strong>Time:</strong><span> ' + activity.time_ft + ' </span>').appendTo(route);


      				$(li).append(div);
      				$("#tracks").show();
      				$('#tracks').append(li);

              //// PUT MAP CALL HERE!
              var map = new ActivityMapController(activity.md5_sig + '-map',activity.data);
      			}
          } else {
            alert(response.message);
          }
          
        }
      });
      
      return;
      r.controller.readDataFromDevice(Garmin.DeviceControl.FILE_TYPES.fitDir);
    }, // END function read()
    
    onFinishReadFromDevice: function(r) {
      var this_alias = this;
      if(r.success) {
        // Send the FITBinary to the server for processing.
        this.activities.push(r.controller.gpsDataString);
        $("#upload-progress-bar").progressbar('option', 'value', (this.activities.length/this.total_available)*100);
        if(this.activities.length == this.total_available) {
          $.post(this.convert_url, {"data[]":this.activities}, function(data, status) {
            if(status == 'success') {
              $('#upload-progress-bar').hide();
              for(i=data.activities.length;i>=0;i--) {
                this_alias._createTrackUpload(data.activities[i]);
              }
            }
          }, 'json');
        }
      } else if(r.controller.gpsDataType == 'FitDirectory') {
        // Send the GPS Data String to the server for processing. 
        $.post(this.check_url, {xml:r.controller.gpsDataString}, function(data, status) {
          if(status == 'success') {
            $('#upload-progress-bar').show();
            $('#upload-messages').text('Processing tracks.');
						$("#upload-progress-bar").progressbar('option', 'value', 0);
            this_alias.total_available = data.activities.length;
            for(i=0;i<this_alias.total_available;i++) {
              var current_activity = data.activities[i];
              r.controller.getBinaryFile(r.controller.deviceNumber, current_activity.filename);
            }
          }
        }, 'json');
      }
      
      
    }, // END function onFinishReadFromDevice()
    
    _createTrackUpload: function(activity) 
		{
			var post_url = this.post_url; // Need to set the post url because of this scope gets overidden

			if(activity != null) {
				var li = $('<li id="' + activity.md5_sig + '"/>');
				var div = $('<div class="upload-form"/>');
				var button = $('<p><div id="upload-an-activity" class="button ui-state-default ui-corner-all"><span class="ui-icon ui-icon-transferthick-e-w"></span>Upload Activity</div></p>');
				var name = $('<p><label>Name: </label><input type="text" name="name" class="input-text" id="' + activity.md5_sig + '-name"/></p>');
				var desc = $('<p><label>Description: </label><textarea id="' + activity.md5_sig + '-desc"></textarea></p>');
				var priv = $('<p><label><input type="checkbox" value="yes" id="' + activity.md5_sig + '-private"/> Keep this private!</label></p>');
				var tags = $('<p><label>Tags (comma separated): </label><input type="text" name="tags"  class="input-text" id="' + activity.md5_sig + '-tags"/></p>');
				var sports = $('<p/>');
				var sports_label = $('<label> Sport: </label>').appendTo(sports);
				var sports_pulldown = $("#sport_pulldown").clone().appendTo(sports);
				$(sports_pulldown).attr('id', activity.md5_sig + '-sport');
				
				$(div).append(sports);
				$(div).append(name);
				$(div).append(desc);
				$(div).append(tags);
				$(div).append(priv);
				$(div).append(button);
				
				$(button).click(function() {
					$('#' + activity.md5_sig).loading({
						mask:true,
						align:"center",
						img: "/images/bigWaiting.gif"
					});
					var fields = {
						data: JSON.stringify(activity.data),
						md5_sig: activity.md5_sig,
						name: $("#" + activity.md5_sig + "-name").val(),
						sport_id: $("#" + activity.md5_sig + "-sport").val(),
						tag_list: $("#" + activity.md5_sig + "-tags").val(),
						description: $("#" + activity.md5_sig + "-desc").val(),
						is_private: $("#" + activity.md5_sig + "-private:checked").val()
					};
					$.post(post_url, fields, function(data,status) {
						$('#' + activity.md5_sig).loading();
						$("#" + activity.md5_sig).html('<a href="' + data.link + '">' + data.name + '</a> uploaded successfuly. ' + data.sponsor + ' moved another <strong>$' + data.dollars_raised + '</strong> to ' + data.cause + '.');
						refresh_activities();
					}, 'json');
				});

				var route = $('<div class="route"><div id="' + activity.md5_sig + '-map" class="chooser-map"/></div>').appendTo(li);
				
				$('<strong>Date:</strong><span> ' + activity.date_ft + ' </span>').appendTo(route);
				$('<strong>Dist:</strong><span> ' + activity.dist + ' </span>').appendTo(route);
				$('<strong>Time:</strong><span> ' + activity.time_ft + ' </span>').appendTo(route);
				
				
				$(li).append(div);
				$("#tracks").show();
				$('#tracks').prepend(li);
				
        //// PUT MAP CALL HERE!
        var map = new ActivityMapController(activity.md5_sig + '-map',activity.data);
        
				newCount++;
				$('#upload-messages').text(newCount + ' new track(s) found');

				return true;
			}
		} // END _createTrackUpload();
  }); // END ActivityController class


  // This is a dummy controller. It's used to get us past the activity finder.
  var ActivityController = Class.create({
    initialize: function() 
    {
      this.target = null;
    }, // END function initialize
    
    set_type: function(type)
    {
      switch(type) {
        case 'FIT':
          this.target = new FITActivityController();
          break;
        default:
          this.target = new TCXActivityController();
          break;
      }
    },
    
    onStartFindDevices: function(r) { },
  	onCancelFindDevices: function(r) { },
  	onInteractionWithNoDevice: function(r) { },
  	onStartReadFromDevice: function(r) { },
  	onFinishReadFromDevice: function(r) { this.target.onFinishReadFromDevice(r); },
  	onWaitingReadFromDevice: function(xml_message, r) { },
  	onCancelReadFromDevice: function(r) { },
  	
  	read: function(r) { this.target.read(r); },

  	onFinishFindDevices: function(r)
  	{

  		if(r.controller.numDevices == 0) {
  			$("#dialog-upload").html("We were unable to find any devices.");
  		} else if(r.controller.numDevices == 1) {
  			$('#upload-messages').text("Found Device... " + r.controller.devices[0].displayName);

  			if(opperation == 'read') {
  				activity_uploader.read_from(r.controller.deviceNumber,r);
  			} else if(opperation == "write") {
  				activity_uploader.write_to(r.controller.deviceNumber,r);
  			}

  		} else {
  			for(n=0;n<r.controller.numDevices;n++) {
  				$("<li>" + r.controller.devices[n].displayName + " <div id=\"device-" + n + "\"class=\"button-right ui-state-default ui-corner-all\"><span class=\"ui-icon ui-icon-play\"></span>Use this Device</div></li>").appendTo('#tracks');
  				$("#device-" + n).click(function() {
  					var number = this.id.replace(/device-/, '');
  					if(opperation == "read") {
  						activity_uploader.read_from(number,r);
  					} else if (opperation == "write") {
  						activity_uploader.write_to(number,r);
  					}

  				});
  			}
  			$('#upload-messages').html('Please choose a device to use.');
  			$("#tracks").show();

  		}
  	}, // END function onFinishFindDevices()

  	onProgressReadFromDevice: function(r)
  	{
  		try {
  			if(r.progress != undefined) {
  				if(r.progress.text != undefined) {
  					if(r.progress.text[0] != undefined) {
  						if(r.progress.percentage != undefined) {
  							if(r.progress.percentage < 100) {
  								if(r.progress.text[0] != undefined) {
  									$('#upload-messages').text(r.progress.text[0]);
  								}
  							} else {
  								$('#upload-messages').text('Processing tracks.');
  							}
  						} 

  						$('#upload-progress-bar').show();

  						if(r.progress.percentage != undefined) {
  							$("#upload-progress-bar").progressbar('option', 'value', r.progress.percentage);
  						}

  						if(r.progress != undefined) {
  							if(r.progress.text[0] != undefined && r.progress.text.length > 1) {
  								var message = r.progress.text[0] + '... ';
  								message += r.progress.text[1];
  								$('#upload-messages').text(message);

  								if(r.progress.text[0].match(/^100/)) {
  									$("#upload-progress-bar").progressbar('option', 'value', 100);
  								}
  							}
  						}
  					}
  				}
  			}
  		} catch(e) {
  			// Do nothing!
  		}
  	}, // END function onProgressReadFromDevice()

  	onProgressWriteToDevice: function(r)
  	{
  		this.onProgressReadFromDevice(r);
  	}, // END function onProgressWriteToDevice()

  	onException: function(error)
  	{
  	  // console.log(error);
  	  var errorStatus;
  		var hideFromBrowser = false;
  		if(error.name == "BrowserNotSupportedException") {
  			errorStatus = "<h1>Oops!</h1><p>It appears your browser is not supported with this version of the Garmin plugin. If you have the latest version of the Garmin Plugin then you will need to try a different browser. Otherwise you should download the latest version from <a href=\"http://www8.garmin.com/products/communicator/\">Garmin's Website</a>.</p>";
  		} else if (error.name == "PluginNotInstalledException" || error.name == "OutOfDatePluginException") {
  			errorStatus = "<h1>Oops!</h1><p>It appears you either don't have the Garmin Communicator Plugin installed or it's out of date. Please visit <a href=\"http://www8.garmin.com/products/communicator/\">Garmin's Website</a> to download the latest Communicator plug-in.</p>";
  			errorStatus += "<p>" + error.message + "</p>";
  		} else if (Garmin.PluginUtils.isDeviceErrorXml(error)) {
  			errorStatus = "<h1>Oops!</h1>";
  			errorStatus += "<p>" + Garmin.PluginUtils.getDeviceErrorMessage(error) + "</p>";	
  		} else {
  			errorStatus = "<h1>Oops!</h1>";
  			errorStatus += "<p>Something terrible happened... </p>";	
  		}						
  		$('#upload-messages').html(errorStatus);
  	},

  	onFinishWriteToDevice: function(r) {
  		$('#upload-progress-bar').hide();
  		$('#upload-messages').text('Congratulations! The course was successfully saved to your device.');
  	} // END function onFinishWriteToDevice()
  }); // END ActivityControllerBase class
	
	$.fn.wait = function(time, type) {
	    time = time || 1000;
	    type = type || "fx";
	    return this.queue(type, function() {
	        var self = this;
	        setTimeout(function() {
	            $(self).dequeue();
	        }, time);
	    });
	};

    

	
	function inArray(val, arr) {
		for(i=0;i<arr.length;i++) {
			if(val == arr[i]) {
				return true
			}
		}
		return false;
	}
	
	var errors = $('<ul/>');
	
	function clear_entry_form() {
		allFields = $([]).add("#activity_name").add("activity_sport").add("#activity_description").add("#activity_hrs").add("#activity_mins").add("#activity_secs").add("#activity_distance").add("#activity_tag_list");
		$("#activity_private").attr('checked', false);
		allFields.val("").removeClass('ui-state-error');
		$('#dialog-entry-form div.errors').remove();
		$('#activity_hrs').val('00');
		$('#activity_mins').val('00');
		$('#activity_secs').val('00');
		errors.empty();
	}
		
	function check_not_null(field, label) {
		if(field.val().length <= 0) {
			field.addClass('ui-state-error');
			errors.append("<li>" + label + " is required.</li>");
			return false;
		}
		field.removeClass('ui-state-error');
		return true;
	}
	
	function check_date_not_future(field)
	{
		var now = new Date();
		var target = Date.parse(field.val());
		
		if(now.getTime() < target) {
			field.addClass('ui-state-error');
			errors.append("<li>The start time can not be in the future.</li>");
			return false;
		}
		return true;
	}
	
	function check_less_than(field, value, message)
	{
		if(field.val() > value) {
			field.addClass('ui-state-error');
			errors.append("<li>" + message + "</li>");
			return false;
		}
		
		return true;
	}
	
	function show_errors(dialog_id) {
		$(dialog_id).prepend('<div class="errors ui-state-error"/>');
		$(dialog_id + " div.errors").append('<h4>Please fix the following errors:</h4>');
		$(dialog_id + " div.errors").append(errors);
	}
	
	function show_confirmation(dialog_id, message) {
		$(dialog_id).prepend('<div class="info-message">' + message + '</div>');
		$(dialog_id + " div.info-message").wait(6000).fadeOut(500);
	}
	
	function refresh_activities() {
		if($('#activities').hasClass('home')) {
			$.get('/api/get_activities', {view:$("#current_view").val(), page:1}, function(data, status) {
				if(status = 'success') {
					$('#activities > ul').replaceWith("<ul>"+data+"</ul>");
				}
			}, 'html');
		} else if ($("#my-routes-content").length > 0) {
			updateMyRoutes(1,true);
		}
	}
	
	function submit_entry_form(type) {
		var valid = true;
		$('#dialog-entry-form div.errors').remove();
		errors.empty();

		valid = check_not_null($("#activity_name"), "Activity name") && valid;
		valid = check_date_not_future($("#timestamp_of_run")) && valid;
		valid = check_less_than($("#activity_hrs"), 10, "Wow! Are you sure you exercised for " + $("#activity_hrs").val() + " hours?") && valid;
		valid = check_less_than($("#activity_mins"), 59, "You can't enter more then 59 minutes.") && valid;
		valid = check_less_than($("#activity_secs"), 59, "You can't enter more then 59 seconds.") && valid;
		if($("#activity_distance_units").val() == 'miles') {
			valid = check_less_than($("#activity_distance"), 210, "You can only enter up to 210 miles on a hand enter activity.") && valid;
		} else if ($("#activity_distance_units").val() == 'meters') {
			valid = check_less_than($("#activity_distance"), 16093, "You can only enter up to 16,093 meters on a hand enter activity.") && valid;
		}
		

		if(valid) {
			allFields = $([]).add("#activity_name").add("#activity_sport").add("#activity_description").add("#timestamp_of_run").add("#activity_hrs").add("#activity_mins").add("#activity_secs").add("#activity_distance").add('#activity_private').add('#activity_distance_units').add("#activity_tag_list");
			$.post('/api/activity', allFields.serialize(), function(data, text_status) {
				refresh_activities();
				clear_entry_form();
				var message = 'Right on! ' + data.sponsor + ' will move another <strong>$' + data.dollars_raised + '</strong> to ' + data.cause + '. Every day, you and all of Plus 3 are Making It Count.';
				if(type == "done") {
					show_confirmation('#main', message);
				} else {
					show_confirmation('#dialog-entry-form', message);
				}
				
			}, 'json');
			return true;
		} else {
			show_errors("#dialog-entry-form");
			return false;
		}
	}
	
	$("div.info-message").ready(function() {
		$("div.info-message").wait(6000).fadeOut(500);
	});
	
	
   	$('#dialog-entry-form').ready(function() {
		
		$('#dialog-entry-form').dialog({
			bgiframe: true,
			autoOpen: false,
			modal: true,
			draggable: false,
			width: 625,
			resizable: false,
			title: "Hand Enter an Activity",
			buttons: {
				"Enter and Add Another Activity" : function() {
					submit_entry_form("another");
				},

				"Enter and Done" : function() {
					if(submit_entry_form("done")) {
						$(this).dialog('close');
					}
				}

			},
			close: function() {
				clear_entry_form();
			}
		});
	});
	
	$(".date-select").ready(function() {
		$(".date-select").change(function() {
			var month = $("#date_month").val();
			if(month < 10) {
				month = "0" + month;
			}
			var day = $("#date_day").val();
			if(day < 10) {
				day = "0" + day;
			}
			var year = $("#date_year").val();
			var hour = $("#date_hour").val();
			var minute = $("#date_minute").val();
			var ampm = $("#date_ampm").val();
			
			$("#timestamp_of_run").val(month+"/"+day+"/"+year+" "+hour+":"+minute+" "+ampm);
		});
	});
	
	$('#dialog-edit-details').ready(function() {
		
		$('#dialog-edit-details').dialog({
			bgiframe: true,
			autoOpen: false,
			modal: true,
			draggable: false,
			width: 625,
			resizable: false,
			title: "Edit Activity Details",
			buttons: {
				"Save Details" : function() {
					var valid = true;
					$('#dialog-edit-details div.errors').remove();
					errors.empty();

					valid = check_not_null($("#activity_name"), "Activity name") && valid;
					valid = check_date_not_future($("#timestamp_of_run")) && valid;

					if(valid) {
						allFields = $([]).add("#id").add("#activity_name").add("#activity_sport").add("#activity_description").add('#activity_private').add("#timestamp_of_run");
						$.post('/api/update_activity', allFields.serialize(), function(data, status) {
							if(status = 'success') {
								$("#" + $("#id").val() + "-title").html($("#activity_name").val());
								$("#" + $("#id").val() + "-description").html($("#activity_description").val().replace(/\n/g, '<br/>'));
								$("#sport").html(data.sport);
								$("#amount").html("$" + data.dollars_raised);
								$("#timestamp_of_run-sum").html(data.timestamp);
								$("#dollars-raised").html("$" + data.dollars_raised);
								if($("#activity_private:checked").val() == "yes") {
									$("#privacy").text("Only you can see this.");
								} else {
									$("#privacy").text("Anyone can see this.");
								}
								show_confirmation('#main', 'Right on! ' + data.sponsor + ' will move another <strong>$' + data.dollars_raised + '</strong> to ' + data.cause + '. Every day, you and all of Plus 3 are Making It Count.');
								$('#dialog-edit-details').dialog('close');
							}
						}, 'json');
					} else {
						show_errors("#dialog-edit-details-form");
					}
				},

				"Cancel" : function() {
					$('#dialog-edit-details').dialog('close');
				}

			}
		});
	});
	
	$("#edit-details-btn").ready(function() {
		$("#edit-details-btn").click(function() {
			$('#dialog-edit-details').dialog('open');
		});
	});
	
	$('#dialog-upload').ready(function() {
		$('#dialog-upload').dialog({
			/* bgiframe: true, */
			autoOpen: false,
			modal: true,
			position: "top",
			draggable: false,
			width: 800,
			minHeight: 50,
			resizable: true,
			title: "Upload an Activity",
			close: function() {
				activity_uploader.reset();
				$('#upload-messages').text("Searching for devices...");
				$("#upload-progress-bar").progressbar('option', 'value', 0);
				$("#tracks").children().remove();
			},
			open: function(event,ui) {
				$("#upload-progress-bar").progressbar({ value: 0 });
			}
		});
	});
	
	$('#dialog-email-route').ready(function() {
		
		$('#dialog-email-route').dialog({
			bgiframe: true,
			autoOpen: false,
			modal: true,
			draggable: false,
			width: 600,
			resizable: false,
			title: "Email a Friend",
			buttons: {
				"Send" : function() {
					var users = $.map($('.user-token'), function(item,index) {
						return $(item).val();
					});
					
					var groups = $.map($('.group-token'), function(item,index) {
						return $(item).val();
					});
					
					var emails = $.map($('.email-only-token'), function(item,index) {
						return $(item).val();
					});
					
					var fields = {
						"users[]" : users,
						"groups[]" : groups,
						"emails[]" : emails,
						"id" : $('input[name=id]').val(),
						"message": $('textarea[name=message]').val()
					}
					
					
					$.post('/api/email_activity', fields, function(data,status) {
						if(status == 'success') {
							$('#dialog-email-route').dialog('close');
							show_confirmation('#main', 'Your email, eloquent and pithy, was sent.');
						}
					}, 'json');
				},

				"Cancel" : function() {
					$('#dialog-email-route').dialog('close');
				}

			},
			close: function() {
				$('.email-token').remove();
				$("#message").val("");
			}
		});
	});
	
	$('#dialog-email-route form').ready(function() {
		$('#dialog-email-route form').submit(function() {
			return false;
		});
	});
	
	$("#email-to-friend").ready(function() {
		$("#email-to-friend").click(function() {
			$("#dialog-email-route").dialog("open");
		});
	})
	
	function resize_token() {
		$("#token").width($("#token").val().length*.5 + 2.4 + "em");
	}
	
	function add_email_only_token() {
		if($("#token").val().match(/(.+)@(.+)\.(.+)/)) {
			$("#token-borderless").before('<div class="email-token ui-corner-all"><span class="remove-token ui-icon ui-icon-close"></span>' + $("#token").val() + '<input type="hidden" name="email" class="email-only-token" value="' + $("#token").val() + '"/></div>');
			$(".remove-token").click(function() {
				$(this).parent().fadeOut();
				$(this).parent().remove();
			});
			$("#token").val("");
			resize_token();
		} else {
			$("#token").val("");
		}
	}
	
	$("#email-field").ready(function() {
		$("#email-field").click(function() {
			$("#token").focus();
		});
	});
	
	$("#token").ready(function() {
		$("#token").keydown(function(){
			resize_token();
		});
		
		$("#token").blur(function() {
			add_email_only_token();
		});
		
		$("#token").keyup(function(event) {
			if(event.keyCode == 13) {
				add_email_only_token();
			}
		});
		
		
		$("#token").autocomplete(contact_list, {
			minChars: 0,
			width: 210,
			matchContains: "word",
			autoFill: false,
			formatItem: function(row, i, max) {
				return row.name + "<span class=\"ac_email\">" + row.to + "</span>";
			},
			formatMatch: function(row, i, max) {
				return row.name + " " + row.to;
			}
		}).result(function(event,item) {	
			if(item.to == "Send to group") {
				$("#token-borderless").before('<div class="email-token ui-corner-all"><span class="remove-token ui-icon ui-icon-close"></span>'+item.name+'<input name="group" type="hidden" class="group-token" value="' + item.id + '"/></div>');
			} else {
				$("#token-borderless").before('<div class="email-token ui-corner-all"><span class="remove-token ui-icon ui-icon-close"></span>'+item.name+'<input name="user" type="hidden" class="user-token" value="' + item.id + '"/></div>');
			}
			$(".remove-token").click(function() {
				$(this).parent().fadeOut();
				$(this).parent().remove();
			});
			$("#token").val("");
			resize_token();
		});
	});
	
	$("#hand-enter-an-activity").ready(function() {
		$("#hand-enter-an-activity").click(function() {
			$('#dialog-entry-form').dialog("open");
		})
	});
	
	$("#upload-an-activity").ready(function() {
		$("#upload-an-activity").click(function() {
			$('#dialog-upload').dialog("open");
			activity_uploader = new ActivityUploader({
				key: garmin_key, 
				check_url:"/api/check_activities", 
				post_url:"/api/upload_activity"
			});
			activity_uploader.start("read");
		})
	});
	
	$("#use-in-event").ready(function() {
		$("#use-in-event").click(function() {
			$('#dialog-event').dialog("open");
		})
	});
	
	$('#dialog-event').ready(function() {
		
		$('#dialog-event').dialog({
			bgiframe: true,
			autoOpen: false,
			modal: true,
			draggable: false,
			width: 400,
			resizable: false,
			title: "Use in event",
			buttons: {
				"Attach to Event" : function() {
					$("#dialog-event form").validate();
					if($("#dialog-event form").valid()) {
						$.post('/routes/use_in_event', $('#dialog-event form').serialize(), function(data,status) {
							if(status == 'success') {
								$("#dialog-event").dialog("close");
								show_confirmation('#main', 'The route has been added to the selected event. Nicely done!');
							}
						}, 'json');
					}
				},

				"Cancel" : function() {
					$("#dialog-event form select").val("");
					$('#dialog-event').dialog('close');
				}

			}
		});
		
	});
	
	$("#save-to-device").ready(function() {
		$("#save-to-device").click(function() {
			$('#dialog-upload').dialog('option', 'title', 'Save to Device');
			$('#dialog-upload').dialog('option', 'width', 500);
			$('#dialog-upload').dialog("open");
			activity_uploader = new ActivityUploader({
				key: garmin_key, 
				check_url:"/api/check_activities", 
				post_url:"/api/upload_activity"
			});
			activity_uploader.start('write');
		})
	});
	
	$("div.button,div.button-right").ready(function() {
		$("div.button,div.button-right").hover(
			function() { $(this).addClass('ui-state-hover'); }, 
			function() { $(this).removeClass('ui-state-hover'); }
		);
	});
	
	$("#start-address-map-btn").ready(function() {
		$("#start-address-map-btn").click(function() {
			ResetMap();
			$("#pace-controls").show();
		});
	});
	
	$("form#start-map-form").ready(function() {
		$("form#start-map-form").submit(function() {
			ResetMap();
			$("#pace-controls").show();
			return false;
		});
	});
	
	$("#save-map-btn").ready(function() {
		$("#save-map-btn").click(function() {
			save_route(activity_id,timestamp_of_activity);
		});
	});
	
	$("#reset-map-btn").ready(function() {
		$("#reset-map-btn").click(function() {
			$("#map").html('<div class="ui-overlay"><div class="ui-widget-overlay"></div><div id="map-controls" class="ui-dialog-content ui-widget-content ui-corner-all"><h3>Would you like draw your route on a map?</h3><p>Enter a staring address in the field below and click the "Get&nbsp;Started!" button. Once the map appears, click once on the map for the starting point. Then continue to click to create your route.</p><form id="start-map-form"><p><label>Address (or just city, state):</label> <input type="text" id="city_state" name="city_state"/></p></form><div id="start-address-map-btn" class="button-right ui-state-default ui-corner-all"><span class="ui-icon ui-icon-play"></span>Get Started!</div></div></div>');
			$("#distance_span").text('0.00 miles');
			$("#pace-controls").hide();
			$("form#start-map-form").submit(function() {
				ResetMap();
				$("#pace-controls").show();
				return false;
			});
			$("#start-address-map-btn").click(function() {
				ResetMap();
				$("#pace-controls").show();
			});
		});
	});
	
	$("div#map.gps-data").ready(function() {
    if($("div#map.gps-data")[0]) {
      $.get('/routes/data?id=' + activity_id, function(data, status) {
  	    var map = new ActivityMapController("map", JSON.parse(data));
  	  }, 'json');
    }
	});
	
	$('#activity_sport.entry-form-sports').ready(function() {
		$('#activity_sport.entry-form-sports').change(function() {
			if(inArray(this.value, time_based_sports)) {
				$("#activity-distance-field").hide();
			} else {
				$("#activity-distance-field").show();
			}
		});
	});
	
	$('span.editable').ready(function() {
		$('span.editable').editable({
			type: "text",
			submit: "Save",
			cancel: "Cancel",
			onSubmit: function (content) {
				id = $(this)[0].id.replace(/\-title/,"");
				$.get("/api/save_activity_attribute", {name:"name", value:content.current, id:id});
				$(this).addClass('highlight');
			},
			onEdit: function() { $(this).removeClass('highlight'); },
			onCancel: function() { $(this).addClass('highlight'); }
		});
	});
	
	$('div.description.editable').ready(function() {
		$("div.description.editable").editable({
			type: "textarea",
			submit: "Save",
			cancel: "Cancel",
			onSubmit: function (content) {
				id = $(this)[0].id.replace(/\-description/,"");
				$.get("/api/save_activity_attribute", {name:"description", value:content.current, id:id});
				$(this).addClass('highlight');
				$(this).removeClass('empty');
				var new_content = content.current.replace(/\n/g, '<br/>');
				$(this).html(new_content);
			},
			onEdit: function() {
				if(this.hasClass("empty")) {
					$("div.description.editable textarea").val("");
				} else {
					var content = $("div.description.editable textarea").val().replace(/<br>/g, "\n");
					$("div.description.editable textarea").val(content);
				}
				$(this).removeClass('highlight'); 
			},
			onCancel: function() { 
				$(this).addClass('highlight'); 
			}
		});
	});
	
	$("#add-tag-btn").ready(function() {
		$("#add-tag-btn").click(add_tag);
	});
	
	
	function add_tag() {
		var fields = $([]).add("#id").add("#tag_list");
		$.post('/api/tag_activity', fields.serialize(), function(data,text_status) {
			if(text_status == "success") {
				$("#tag_list").val("");
		
				for(n=0;n<data.tags.length;n++) {
					var tag = $('<li><a href="/activities/?by_tag=' + data.tags[n].replace(/\s/,'%20') + '">' + data.tags[n] + '</a><span class="delete-tag ui-icon ui-icon-close" title="Delete Tag"></span></li>').appendTo('#activity-tags');
				}
				
				$("span.delete-tag").click(function() {
					delete_tag(this);
				});
			}
			
			
			
		}, "json");
	}
	
	$("span.delete-tag").ready(function() {
		$("span.delete-tag").click(function() {
			delete_tag(this);
		});
	});
	
	function delete_tag(obj) {
		tag = $(obj).siblings().text();
		if(confirm("Are you sure you want to remove the '" + tag + "' tag?")) {
			$.post('/api/remove_tag', {id:$("#id").val(), tag:tag}, function(data,text_status) {
				if(text_status == 'success') {
					$(obj.parentNode).fadeOut(1000);
				}
			}, "json");
		}
	}
	
	$("form#add-tag-form").ready(function() {
		$("form#add-tag-form").submit(function() {
			add_tag();
			return false;
		});	
	});
	
	$("#add-comment-btn").ready(function() {
		$("#add-comment-btn").click(function() {
			$("#add-comment form").validate();
			if($("#add-comment form").valid()) {
				$("#add-comment form").submit();
			}
		});
	});
	
	$("span.delete-comment").ready(function() {
		$("span.delete-comment").click(function() {
			var fields = {
				id: $("#add-comment form input[name=id]").val(),
				remark_id: this.id.replace(/delete\-comment\-/,'')
			}
			$.post('/routes/delete_comment', fields, function(data,status) {
				if(status == 'success') {
					$("#remark-" + data.remark_id).fadeOut(1000, function() {
						$(this).remove();
						if($("#comments li").length == 0) {
							$("#comments").remove();
						}
					});
				}
			}, 'json');
		});
	});
	
	
	function activate_views(event) {
		var obj = event.currentTarget;
		var previous_view = $("#current_view").val();
		$(".show-filter.activities").loading({
			mask:true,
			align:"center",
			img: "/images/waiting.gif"
		});
		$.get('/api/get_activities', {view:obj.id, page:1}, function(data,status) {
			if(status == "success") {
				$(".show-filter.activities").loading();
				$(obj).removeClass('active');
				$(obj).click(function() {});
				$("#"+previous_view).addClass('active').click(activate_views);
				$("#activities h2").text($(obj).attr('title'));
				$("#current_view").val(obj.id);
				$("#current_page").val(1);
				$("#activities > ul").replaceWith('<ul>'+data+'</ul>');
				if($("#activities li.none").length > 0) {
					$("#activities > ul").replaceWith("<ul><li class=\"none\">You don't have any activities... You should really get out there and do something!</li></ul>");
					$('div.load-more').hide();
				} else if ($("#activities li.done").length > 0) {
					$('div.load-more').hide();
				} else {
					$('div.load-more').show();
				}
				
			}
		});
	}
	
	$(".activities span.view.active").ready(function() {
		$(".activities span.view.active").click(activate_views);
	});
	
	function lb_views(event) {
		var obj = event.currentTarget;
		var previous_view = $("#current_lb_view").val();
		$(".month-leader-board-widget .show-filter").loading({
			mask:true,
			align:"center",
			img: "/images/waiting.gif"
		});
		$.get('/api/leader_board', {view:obj.id.replace(/lb-/,"")}, function(data,status) {
			if(status == "success") {
				$(".month-leader-board-widget .show-filter").loading();
				$(obj).removeClass('active');
				$(obj).click(function() {});
				$("#"+previous_view).addClass('active').click(lb_views);
				$("#current_lb_view").val(obj.id);
				$(".month-leader-board-widget > ul").replaceWith('<ul>'+data+'</ul>');
			}
		});
	}
	
	$(".month-leader-board-widget span.view.active").ready(function() {
		$(".month-leader-board-widget span.view.active").click(lb_views);
	});
	
	$("div.load-more").ready(function() {
		$("div.load-more").click(function() {
			var previous_page = parseInt($("#current_page").val());
			$(this).loading({
				mask:true,
				align:"center",
				img: "/images/waiting.gif"
			});
			$.get('/api/get_activities', {view:$("#current_view").val(), page:previous_page+1}, function(data,status) {
				if(status == "success") {
					$('div.load-more').loading();
					$("#current_page").val(previous_page+1);
					$(data).appendTo('#activities > ul');
					if($('li.done').length > 0) {
						$('div.load-more').hide();
					}
				}
			});				
		});
	});
	
})(jQuery); // END Anonymous function
