if (Garmin == undefined) var Garmin = {};
/**
 * This code is based on the samples that are part of the Garmin Communicator API.
 * See http://developer.garmin.com/web-device/garmin-communicator-plugin/
 * 
 * The original code was released under the Apache license - see below for details.
 * I'm no lawyer so I'm not 100% sure what that means, but please feel free to reuse this code
 * as you wish under the terms of the original license.
 *
 * ------------------------------------------------------------------------
 * Licensed under the Apache License, Version 2.0 (the 'License')
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an 'AS IS' BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * ------------------------------------------------------------------------
 * 
 * @fileoverview WindowsLiveMapController Demonstrates Garmin.MapController adapted for Windows Live Maps
 * @author John Pollard yeltzland.at.hotmail.com
 * @version 1.0
 **/

/**
 * Accepts Garmin.Series objects and draws them on a Windows Live Map.
 * 
 * @class Garmin.WindowsLiveMapController
 * @constructor 
 * @param (String) mapString id of element to place map in
 **/
 
Garmin.WindowsLiveMapController = function(mapString){}; //just here for jsdoc
Garmin.WindowsLiveMapController = Class.create();
Garmin.WindowsLiveMapController.prototype = {

    initialize: function(mapString) {
        this.tracks = new Array();

        try {
            this.map = new VEMap(mapString);
            this.map.LoadMap();
        } catch (e) {
        	alert("WARNING: application will not function properly with missing WindowsLiveMapController script element.  Error: "+e);
        }
    },

    /** Set the center point and zoom level of the map.
     * @param (Number) Latitude of the center point
     * @param (Number) Longitude of the center point
     * @param (Number) Zoom level
     */
    centerAndScale: function(lat, lon, scale) {
    	scale = (scale == null ? 13 : scale);
    	var center = new VELatLong(parseFloat(lat), parseFloat(lon));
        this.map.SetCenterAndZoom(center, scale);
    },
    
    clearMap: function() {
        this.map.DeleteAllShapes();
    },
    
    /** Draw track on map.
     * @param (Garmin.Track) The track to draw
     * @param (VEColor) Color of the line, default: new VEColor(255, 0, 0, 1)
     */    
    drawTrack: function(series, color) {
        color = (color == null ? new VEColor(255, 0, 0, 1) : color);
        
        // create a smaller version of the whole track
        // create 300 points or so ...
	    // Problem is that Google Maps dies when you hit near 500 points, so we have to
	    // ensure that we create fewer than that for the track.
	    // I'm not certain of the limitations of Windows Live Maps, but it made sense to follow the same logic here
        var drawAt = Math.ceil(series.getSamplesLength()/300);
        var drawnPoints = new Array();

        try {
        	// create up to 300 points
			for(var h = 0; h < series.getSamplesLength() - 1; h += drawAt) {
				drawnPoints.push(this.createNearestValidLocationPoint(series, h, -1));
		    }
		    // create the end point
           	drawnPoints.push(this.createNearestValidLocationPoint(series, series.getSamplesLength()-1, -1));
        } catch( e ) {
            alert("WindowsLiveMapController.drawTrack: " + e.message);
        }	    
        
        if (drawnPoints.length > 0) {
			try {
			    // Center the map, and set the start and end points
	            this.map.SetMapView(drawnPoints);	   		    		         
		        this.addStartFinishMarkers(series);
		          
		        // Create a line from the drawn points 			
                var trackline = new VEShape(VEShapeType.Polyline, drawnPoints); 
                trackline.SetLineWidth(2);
                trackline.SetLineColor(color);
                trackline.HideIcon();
                                 
                this.map.AddShape(trackline);	            	            
	            	            
			} catch(e){ alert("WindowsLiveMapController.drawTrack, Error: " + e); } 
        }
    },

	/**Creates a VELatLong for the sample in the series closest to the index with a valid location (lat and lon).
	 * @param series - The series to search through.
	 * @param index - The index to start searching from.
	 * @param incDirection - The direction to travel for the search.
	 * @return A VELatLong of the nearest valid location sample found.
	 */
	createNearestValidLocationPoint: function(series, index, incDirection) {
    	var sample = series.findNearestValidLocationSample(index, -1);
    	if (sample != null) {
    		var sampleLat = sample.getMeasurement(Garmin.Sample.MEASUREMENT_KEYS.latitude).getValue();
    		var sampleLon = sample.getMeasurement(Garmin.Sample.MEASUREMENT_KEYS.longitude).getValue();
    		return new VELatLong(parseFloat(sampleLat), parseFloat(sampleLon));    		
    	} else {
			throw new Error("No valid location point in series.");
    	}
	},

    /** Draw waypoint on map.
     * @param (Garmin.Series) series containing a waypoint to add to the map
     */
    drawWaypoint: function(series) {
    	var sample = series.getSample(0);
        this.centerAndScale(sample.getLatitude(), sample.getLongitude(), 15);    	
        this.addMarker(sample.getLatitude(), sample.getLongitude());
    },
    
    /** Add an icon to a point.
     * @param {Number} latitude of marker
     * @param {Number} longitude of marker
     */
    addMarker: function(latitude, longitude) {
    	this.addMarkerWithIcon(latitude, longitude, Garmin.MapIcons.getRedIcon());
    },

    /** Adds a marker to the point with the icon specified
     * @param {Number} latitude of marker
     * @param {Number} longitude of marker
     * @param (string) URL of the icon to add at the point
     */
    addMarkerWithIcon: function(latitude, longitude, icon) {
        var marker = new VEShape(VEShapeType.Pushpin, new VELatLong(parseFloat(latitude), parseFloat(longitude))); 
        marker.SetCustomIcon(icon);
        this.map.AddShape(marker);
    },

    /** Add start and finish markers to a track
     * @param (Garmin.Series) The series to add markers to
     */
    addStartFinishMarkers: function(series) {
    	var firstSample = series.getFirstValidLocationSample();
    	var lastSample = series.getLastValidLocationSample();
        this.addMarkerWithIcon(firstSample.getLatitude(), firstSample.getLongitude(), Garmin.MapIcons.getGreenIcon());
        this.addMarkerWithIcon(lastSample.getLatitude(), lastSample.getLongitude(), Garmin.MapIcons.getRedIcon());
    },

    /** String representation of map.
     * @return (String)
     */
    toString: function() {
        return "Windows Live Based Map Controller, managing " + this.tracks.length + " track(s)";
    }
};

/** Icons used to mark waypoints and POIs on Google maps.  
 * 
 * @class Garmin.MapIcons
 * @constructor 
 */
Garmin.MapIcons = function(){}; //just here for jsdoc
Garmin.MapIcons = {
    getRedIcon: function() {
        return "http://trail.motionbased.com/trail/site/images/marker_red.png";
    },
    
    getGreenIcon: function() {
        return "http://trail.motionbased.com/trail/site/images/marker_green.png";
    },
}