if (Garmin == undefined) var Garmin = {};
/** Copyright © 2007 Poly9 Group.
 * @author Denis Laprise
 * @version 1.0
 */
 
/**
 * Accepts Garmin.Series objects and draws them on a Google Map.
 * 
 * @class Garmin.MapController
 * @constructor 
 * @param (String) mapString id of element to place map in
 */
Garmin.MapController = function(mapString){}; //just here for jsdoc
Garmin.MapController = Class.create();
Garmin.MapController.prototype = {

    initialize: function(mapString) {
        this.mapElement = $(mapString);
        this.usePositionMarker = true;
        
        this.polylines = new Array();
        this.markers = new Array();
        this.tracks = new Array();
        this.markerIndex = 0;

        this.timeToCheck = false;
        try {
	        this.map = new FE.Map( $(mapString) );
            this.map.load();
        } catch (e) {
        	alert("WARNING: application will not function properly with missing FreeEarth scripts.  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);
        this.map.panTo(new FE.LatLng(lat, lon), 2);
        this.map.zoomTo((21-scale) * 80000, 2);
        this.map.focus();
    },
    
    /** Draw track on map.
     * @param (Garmin.Track) The track to draw
     * @param (String) Color in RGB Hex format, default: "#ff0000"
     */    
    drawTrack: function(series, color) {
        color = (color == null ? "#ff0000" : color);
        color = 'red';
        // create a smaller version of the whole track
        // create 300 points or so ...
        var drawAt = Math.ceil(series.getSamplesLength()/300);
        var drawnPoints = new Array();

        try {
        	// create up to 300 points
			for(var h = 0; h < series.getSamplesLength(); 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("FreeEarthControl.drawTrack: " + e.message);
        }	    
        if (drawnPoints.length > 0) {
	        //draw the new smaller version
	        var polyline = new FE.Polyline(drawnPoints, color, 2, .8)
			try {
				this.centerAndScale(drawnPoints[0].lat, drawnPoints[0].lng);			
	        	this.map.addOverlay( polyline );
		        this.addStartFinishMarkers(series);
		        this.bounds = this.findAZoomLevel(drawnPoints);
		        this.setOnBounds( this.bounds );
			} catch(e){ alert("FreeEarthControl.drawTrack, IE error on map.addOverlay("+polyline+") err: "+e); }
        }
    },

	/**Creates a GLatLng 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 GLatLng 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 FE.LatLng(sampleLat, 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());
    },

    /** Calculates minimum bounding box for an set of points.
     * @param (Array) The array of points to find a zoom level for
     */
    findAZoomLevel: function(points) {
        var bounds = new FE.LatLngBounds(points[0], points[0]);
        
        for(var i=1; i<points.length-1; i+=3) {
            bounds.extend(points[i]);
        }
        
        return bounds;
    },
    
	/** Check the new dimensions of the map, and determine the bounds of the tracks
	 * Then set the map to zoom to that bound level
   	 * @private
	 */
    sizeAndSetOnBounds: function() {
        //this.map.checkResize();
        this.setOnBounds( this.bounds );
    },

    /** Set the bounding box on the map.
     * @param (GLatLngBounds) bounding box for the
     */
    setOnBounds: function(bounds) {
        this.map.setTargetLatLng( this.bounds.getCenter());
        //this.map.setCenter( this.bounds.getCenter(), this.map.getBoundsZoomLevel(this.bounds) );
    },
    
    /** 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 (GIcon) icon to add at the point
     */
    addMarkerWithIcon: function(latitude, longitude, icon) {
        var gMarker = new FE.Pushpin(new FE.LatLng(latitude, longitude), icon);
        this.markers.push(gMarker);
        this.map.addOverlay(gMarker);
    },

    /** 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 "FreeEarth 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() {
        var icon = new FE.Icon("http://trail.motionbased.com/trail/site/images/marker_red.png");
        return Garmin.MapIcons._applyShadowAndStuff(icon);
    },
    
    getGreenIcon: function() {
        var icon = new FE.Icon("http://trail.motionbased.com/trail/site/images/marker_green.png");
        return Garmin.MapIcons._applyShadowAndStuff(icon);
    },
    
    getBaseIcon: function() {
    	var baseIcon = new FE.Icon("http://www.google.com/mapfiles/shadow50.png");
        return baseIcon;
    },
    
    _applyShadowAndStuff: function(icon) {
        return icon;
    }
}
