﻿var WorkoutMap = {
    map: {},
    workout_id: -1,
    points: [],

    manualCheckpoints: [],
    manualMarkers: [],
    autoCheckpoints: [],
    autoMarkers: [],
    statsMarkers: [],

    checkpointsCount: 0,
    marker_id: 0,

    workoutLocation: '',

    PAUSE_COLOR: '#00FF00',
    PAUSE_WIDTH: 4,
    PAUSE_OPACITY: 0.6,

    ACTIVE_COLOR: '#0000FF',
    ACTIVE_WIDTH: 4,
    ACTIVE_OPACITY: 0.6,

    BEST_SEGMENT_COLOR: '#FF0000',
    BEST_SEGMENT_WIDTH: 4,
    BEST_SEGMENT_OPACITY: 0.7,

    AUTO_CHECKPOINTS_COUNT: 8.5,

    startLoading: function() { },
    endLoading: function() { },

    baseIcon: {},
    markerIcon: {},


    unitSystem: 0,

    TERRAIN_MAP_TYPES: [6, 16],


    is3D: false,
    activate3D: function() {
        if (!WorkoutMap.is3D) {
            WorkoutMap.is3D = true;
            WorkoutMap.map.setMapType(G_SATELLITE_3D_MAP);
            $("#run3D").html("2D");
            WorkoutMap.map.getEarthInstance(WorkoutMap.initialize3D);
        }
        else {
            WorkoutMap.is3D = false;
            WorkoutMap.map.setMapType(G_HYBRID_MAP);
            $("#run3D").html("3D!");
        }
    },
    earth3D: null,
    initialize3D: function(googleEarth) {
        if (googleEarth != null) {
            WorkoutMap.earth3D = googleEarth;
        }
        if (WorkoutMap.earth3D) {
            if (!WorkoutMap.cameraAt) {
                var workoutType_id = $("#workoutType_id").val();
                var isTerrainType = false;
                for (var k = 0; k < WorkoutMap.TERRAIN_MAP_TYPES.length; ++k) {
                    if (workoutType_id == WorkoutMap.TERRAIN_MAP_TYPES[k]) { isTerrainType = true; break; }
                }

                var camLocation = null, camLookAt = null
                if (isTerrainType) {
                    // Find highest point
                    for (var k = 0; k < WorkoutMap.points.length; ++k) {
                        var p = WorkoutMap.points[k];
                        if ((!camLookAt || p.altitude > camLookAt.altitude) && p.altitude > 0) {
                            camLookAt = p;
                        }
                    }
                }
                // If the original map was not terrain-based, only use northmost point
                if (!camLookAt) {
                    for (var k = 0; k < WorkoutMap.points.length; ++k) {
                        var p = WorkoutMap.points[k];
                        if (!camLocation || p.point.lat() < camLocation.point.lat()) {
                            camLocation = p;
                        }
                        if (!camLookAt || p.point.lat() > camLookAt.point.lat()) {
                            camLookAt = p;
                        }
                    }
                }
                // Find the most distant point from the lookat point for the camera position.
                for (var k = 0; k < WorkoutMap.points.length; ++k) {
                    var p = WorkoutMap.points[k];
                    if (!camLocation || p.point.distanceFrom(camLookAt.point) >
                            camLocation.point.distanceFrom(camLookAt.point)) {
                        camLocation = p;
                    }
                }
                
                var maxDistance = camLookAt.point.distanceFrom(camLocation.point);
                var deltaLat = camLookAt.point.lat() - camLocation.point.lat();
                var deltaLng = camLookAt.point.lng() - camLocation.point.lng();
                var headingRad = Math.atan2(deltaLng, deltaLat);
                var heading = headingRad * 180 / 3.1416;

                WorkoutMap.cameraAt = WorkoutMap.earth3D.getView().copyAsLookAt(
                    WorkoutMap.earth3D.ALTITUDE_RELATIVE_TO_GROUND);
                WorkoutMap.cameraAt.set(
                    camLocation.point.lat() - Math.abs(deltaLat) * 0.5 * Math.cos(headingRad),
                    camLocation.point.lng() - Math.abs(deltaLng) * 0.5 * Math.sin(headingRad),
                    maxDistance / 3 + (isTerrainType ? (camLookAt.altitude - camLocation.altitude) * 1.5 : 50), // altitude
                    WorkoutMap.earth3D.ALTITUDE_RELATIVE_TO_GROUND,
                    heading, //heading
                    60, //tilt
                    0); // rotation               

            }
            setTimeout("WorkoutMap.earth3D.getView().setAbstractView(WorkoutMap.cameraAt)", 1500);
        }
    },
    startStopIcons: {
        Start: '/Images/Style/Map/signStart.png',
        End: '/Images/Style/Map/signStop.png'
    },

    statsIcons: {
        MaxSpeed: '/Images/Style/Map/signMaxSpeed.png',
        MaxAlt: '/Images/Style/Map/signMaxAlt.png'
    },

    mapControls: {
        centerData: null,
        zoomData: null,
        SetCenterZoom: function(center, zoom) {
            WorkoutMap.mapControls.centerData = center;
            WorkoutMap.mapControls.zoomData = zoom;
        },
        centerMap: function() {
            WorkoutMap.map.setCenter(WorkoutMap.mapControls.centerData);
            WorkoutMap.map.setZoom(WorkoutMap.mapControls.zoomData);
        }
    },



    setWorkoutLocation: function(locationObject) {

        var deepLookup = function(keyString, obj) {
            for (key in obj) {
                if (obj[key] && typeof obj[key] == 'object') {
                    var lookup = deepLookup(keyString, obj[key]);
                    if (lookup != "") {
                        return lookup;
                    }
                }
                else if (typeof obj[key] != 'object') {
                    if (key == keyString) {
                        return obj[key];
                    }
                }
            }
            return "";
        }
        WorkoutMap.workoutLocation = deepLookup('LocalityName', locationObject);
        if (WorkoutMap.workoutLocation != "") {
            WorkoutMap.workoutLocation += ", "
        }
        var country = deepLookup('CountryName', locationObject);
        country = country.replace("Poraneshna Jugoslovenska", "");
        WorkoutMap.workoutLocation += country;

    },

    autoMode: true,
    changeMode: function() {
        WorkoutMap.autoMode = !WorkoutMap.autoMode;
    },





    onCheckpointsChanged: function() { },


    init: function() {
        WorkoutMap.map = new GMap2(document.getElementById("map"));
        var isTerrainType = false;
        var workoutType_id = $("#workoutType_id").val();
        for (var k = 0; k < WorkoutMap.TERRAIN_MAP_TYPES.length; ++k) {
            if (workoutType_id == WorkoutMap.TERRAIN_MAP_TYPES[k]) { isTerrainType = true; break; }
        }
        if (isTerrainType) {
            WorkoutMap.map.setMapType(G_PHYSICAL_MAP);
        }
        else {
            WorkoutMap.map.setMapType(G_HYBRID_MAP);
        }
        GEvent.addListener(WorkoutMap.map, 'singlerightclick', WorkoutMap.removeCheckpoint);
        window.onunload = GUnload;
        WorkoutMap.createBaseIcons();
    },



    mapPeaks: {
        maxAlt: { point: null, altitude: -99999 },
        minAlt: { point: null, altitude: +99999 },
        maxSpeed: { point: null, speed: 0 },
        altAllZeros: true,
        oldPointIndex: 0,
        updateMaximums: function(pointIndex) {
            var point = WorkoutMap.points[pointIndex];
            var oldPoint = WorkoutMap.points[WorkoutMap.mapPeaks.oldPointIndex];
            if (point.altitude > this.maxAlt.altitude) {
                this.maxAlt.point = point.point;
                this.maxAlt.altitude = point.altitude;
            }
            if (point.altitude < this.minAlt.altitude) {
                this.minAlt.point = point.point;
                this.minAlt.altitude = point.altitude;
            }
            if (Math.round(point.altitude) != 0) {
                this.altAllZeros = false;
            }
            if (oldPoint == null) return;
            
            if ((point.distance - oldPoint.distance > 50) && (pointIndex - this.oldPointIndex > 4)) {
                var speed50m = 1000 *
                      (point.distance - oldPoint.distance)
                    / (point.timefromstart - oldPoint.timefromstart);

                if (speed50m > this.maxSpeed.speed) {
                    this.maxSpeed.point = point.point;
                    this.maxSpeed.speed = speed50m;
                }
                while (point.distance - WorkoutMap.points[this.oldPointIndex].distance > 50
                && (pointIndex - this.oldPointIndex > 4)) {
                    this.oldPointIndex += 1;
                }
            }

        },
        reset: function(pointIndex) {
            this.maxAlt.altitude = -99999;
            this.minAlt.altitude = +99999;
            this.maxSpeed.speed = 0;
            this.maxSpeed.point = null;
            this.maxAlt.point = null;
            this.altAllZeros = true;
            this.oldPointIndex = 0;
        }
    },

    loadedWorkout: function(workout, bestSegment) {
        WorkoutMap.mapPeaks.reset();
        try {
            WorkoutMap.map.clearOverlays();
        }
        catch (exc) { }
        WorkoutMap.manualCheckpoints = new Array();
        WorkoutMap.points = new Array();
        WorkoutMap.checkpointsCount = 0;
        var curPoint;
        var prevPoint;

        var currentCoordinate;
        var pausePoints;
        var activePoints;
        // temporary polyline used to compute bounds for map zoom level
        var allPoints = new Array();
        var lastActivePoint = -1;
        var lastPausePoint = -1;
        var partNumber = 0;
        var minLat = 9999, maxLat = -9999, minLng = 9999, maxLng = -9999;
        //iterate parts
        var partsCount = workout.length;
        var lastPartCoordinate = null; // used for pauses.

        var lastValidPart = null;
        for (var i = 0; i < partsCount; i++) {
            partNumber++;

            if (!(workout[i].IsPause)) {
                // workout part is not pause and is actual line.

                activePoints = new Array();
                var size = workout[i].Coordinates.length;
                /* Make pause line between two non-paused parts. */
                if (size > 0) { // non-empty part.
                    if (i > 0 && i < workout.length) { // is between-parts.
                        var firstPartCoordinate = workout[i].Coordinates[0];
                        if (lastPartCoordinate && lastValidPart != null && !(workout[lastValidPart].IsPause)) {
                            // only when previous part had coordinates
                            var pausePoints = [new GLatLng(lastPartCoordinate.Lat, lastPartCoordinate.Lng),
                                            new GLatLng(firstPartCoordinate.Lat, firstPartCoordinate.Lng)];
                            var pausePolyline = new GPolyline(pausePoints, WorkoutMap.PAUSE_COLOR, WorkoutMap.PAUSE_WIDTH, WorkoutMap.PAUSE_OPACITY);
                            WorkoutMap.map.addOverlay(pausePolyline);
                        }
                    }
                    lastPartCoordinate = workout[i].Coordinates[size - 1];
                }
                /* Make non-pause line */
                for (var j = 0; j < size; j++) { // part coordinates, non-pause
                    currentCoordinate = workout[i].Coordinates[j];
                    curPoint = new Object();
                    curPoint.point = new GLatLng(currentCoordinate.Lat, currentCoordinate.Lng);
                    curPoint.timestamp = currentCoordinate.TS;
                    curPoint.timefromstart = currentCoordinate.TFS;
                    curPoint.altitude = currentCoordinate.Alt;
                    if (i == 0 && j == 0) {
                        //create start marker
                        var marker = WorkoutMap.createStartEndMarker(curPoint.point, "Start<br>" + dateFormat(curPoint.timestamp, "HH:MM:ss"), WorkoutMap.startStopIcons.Start);
                        WorkoutMap.map.addOverlay(marker);

                        // Reverse geocoding.
                        var geoDeCoder = new GClientGeocoder();
                        geoDeCoder.getLocations(curPoint.point, function(placemarkObj) {
                            var geoLocation;
                            try {
                                geoLocation = placemarkObj.Placemark[0].AddressDetails;
                            }
                            catch (exc) { geoLocation = null; }
                            if (geoLocation) {
                                WorkoutMap.setWorkoutLocation(geoLocation);
                                try {
                                    $('#workoutLocationHolder').html(WorkoutMap.workoutLocation);
                                } finally { }
                            } else {
                                WorkoutMap.workoutLocation = 'N/A';
                            }
                        });
                    } else {
                        if (partNumber == partsCount && j == size - 1) {
                            //create end marker
                            var marker = WorkoutMap.createStartEndMarker(curPoint.point, "End<br>" + dateFormat(curPoint.timestamp, "HH:MM:ss"), WorkoutMap.startStopIcons.End);
                            WorkoutMap.map.addOverlay(marker);
                        }

                    }
                    curPoint.distance = currentCoordinate.DFS;
                    prevPoint = curPoint;

                    if (lastPausePoint != -1) {
                        pausePoints.push(curPoint.point);
                        var pausePolyline = new GPolyline(pausePoints, WorkoutMap.PAUSE_COLOR, WorkoutMap.PAUSE_WIDTH, WorkoutMap.PAUSE_OPACITY);
                        WorkoutMap.map.addOverlay(pausePolyline);
                        lastPausePoint = -1;
                    }

                    activePoints.push(curPoint.point);
                    allPoints.push(curPoint.point);

                    if (currentCoordinate.IsCP) {
                        WorkoutMap.manualCheckpoints.push(curPoint);
                        WorkoutMap.checkpointsCount++;
                    }
                    WorkoutMap.points.push(curPoint);
                    lastActivePoint = curPoint.point;
                    WorkoutMap.mapPeaks.updateMaximums(WorkoutMap.points.length - 1);
                    //find min, max latitude longitude
                    if (currentCoordinate.Lat > maxLat) {
                        maxLat = currentCoordinate.Lat;
                    }
                    if (currentCoordinate.Lng > maxLng) {
                        maxLng = currentCoordinate.Lng;
                    }
                    if (currentCoordinate.Lng < minLng) {
                        minLng = currentCoordinate.Lng;
                    }
                    if (currentCoordinate.Lat < minLat) {
                        minLat = currentCoordinate.Lat;
                    }
                }
                if (activePoints.length > 1) {
                    var activePolyline = new GPolyline(activePoints, WorkoutMap.ACTIVE_COLOR, WorkoutMap.ACTIVE_WIDTH, WorkoutMap.ACTIVE_OPACITY, { clickable: true });
                    GEvent.addListener(activePolyline, "click", WorkoutMap.polyLineClick);
                    WorkoutMap.map.addOverlay(activePolyline);
                    lastValidPart = i;
                }

            }
            else { // workout[i].IsPause

                if (workout[i].Coordinates.length > 1) { // Make pause line for a pause with min 2 coord.
                    var c1 = workout[i].Coordinates[0];
                    if (i > 0) { c1 = workout[i - 1].Coordinates[workout[i - 1].Coordinates.length - 1]; }
                    var c2 = workout[i].Coordinates[workout[i].Coordinates.length - 1];
                    if (i < workout.length - 1) {
                        c2 = workout[i + 1].Coordinates[0];
                    }
                    var pausePoints = [new GLatLng(c1.Lat, c1.Lng), new GLatLng(c2.Lat, c2.Lng)];
                    var pausePolyline = new GPolyline(pausePoints, WorkoutMap.PAUSE_COLOR, WorkoutMap.PAUSE_WIDTH, WorkoutMap.PAUSE_OPACITY);
                    WorkoutMap.map.addOverlay(pausePolyline);
                    lastValidPart = i;
                    if (i == 0) {
                        //create start marker
                        var marker = WorkoutMap.createStartEndMarker(pausePoints[0], "Start<br>" + dateFormat(c1.timestamp, "HH:MM:ss"), WorkoutMap.startStopIcons.Start);
                        WorkoutMap.map.addOverlay(marker);
                    }
                    if (i == partsCount) {
                        //create end marker
                        var marker = WorkoutMap.createStartEndMarker(pausePoints[1], "End<br>" + dateFormat(c2.timestamp, "HH:MM:ss"), WorkoutMap.startStopIcons.End);
                        WorkoutMap.map.addOverlay(marker);
                    }
                }
            }
            WorkoutMap.removeStatsMarkers();
            WorkoutMap.addStatsMarkers();
        }
        var bounds = new GLatLngBounds(new GLatLng(minLat, minLng), new GLatLng(maxLat, maxLng));
        WorkoutMap.map.setCenter(bounds.getCenter());
        WorkoutMap.map.setZoom(WorkoutMap.map.getBoundsZoomLevel(bounds));

        WorkoutMap.mapControls.SetCenterZoom(WorkoutMap.map.getCenter(), WorkoutMap.map.getZoom());
        bounds = null;
        WorkoutMap.autoMarkers = new Array();
        WorkoutMap.autoCheckpoints = new Array();
        if (bestSegment != 'success') {
            WorkoutMap.bestSegmentLoaded(bestSegment);
        }
        else {
            WorkoutMap.getBestSegment(WorkoutMap.workout_id);
        }
    },

    createStartEndMarker: function(point, title, typeImage) {
        WorkoutMap.baseIcon.image = typeImage;
        var marker = new GMarker(point, WorkoutMap.baseIcon);
        var html = '<div class="gmap-box"><b>' + title + '</b></div>';
        GEvent.addListener(marker, 'click', function() {
            marker.openInfoWindowHtml(html);
        });
        return marker;
    },

    createStatsMarker: function(point, title, typeImage) {
        var cp = WorkoutMap.findClosest(point);

        WorkoutMap.baseIcon.image = typeImage;
        var marker = new GMarker(point, WorkoutMap.baseIcon);
        var html = '<div class="gmap-box"><b>' + title + '</b></div>';
        GEvent.addListener(marker, 'click', function() {
            marker.openInfoWindowHtml(html);
        });
        WorkoutMap.statsMarkers.push(marker);
        WorkoutMap.map.addOverlay(marker);
    },

    createBaseIcons: function() {
        WorkoutMap.markerIcon = new GIcon();
        WorkoutMap.markerIcon.image = 'http://labs.google.com/ridefinder/images/mm_20_blue.png';
        WorkoutMap.markerIcon.shadow = 'http://labs.google.com/ridefinder/images/mm_20_shadow.png';
        WorkoutMap.markerIcon.iconSize = new GSize(12, 20);
        WorkoutMap.markerIcon.shadowSize = new GSize(22, 20);
        WorkoutMap.markerIcon.iconAnchor = new GPoint(6, 20);
        WorkoutMap.markerIcon.infoWindowAnchor = new GPoint(5, 1);

        WorkoutMap.baseIcon = new GIcon();
        //baseIcon.shadow = "http://www.google.com/mapfiles/shadow50.png";
        WorkoutMap.baseIcon.iconSize = new GSize(29, 34);
        WorkoutMap.baseIcon.image = WorkoutMap.startStopIcons.Start;

        WorkoutMap.baseIcon.shadowSize = new GSize(37, 34);
        WorkoutMap.baseIcon.iconAnchor = new GPoint(15, 34);
        WorkoutMap.baseIcon.infoWindowAnchor = new GPoint(15, 2);
    },
    bestSegmentLoaded: function(bestSegment) {
        if (bestSegment && bestSegment[0] && bestSegment[1]) {
            var best = new Array();
            var poly_points = new Array();
            for (var i in WorkoutMap.points) {
                var p = WorkoutMap.points[i];
                var ts = p.timestamp;
                if (ts >= bestSegment[0].Timestamp && ts <= bestSegment[1].Timestamp) {
                    poly_points.push(p.point);
                    best.push(p);
                } else if (ts > bestSegment[1].Timestamp) {
                    break;
                }
            }
            if (poly_points.length > 1) {
                var pl = new GPolyline(poly_points, WorkoutMap.BEST_SEGMENT_COLOR, WorkoutMap.BEST_SEGMENT_WIDTH, WorkoutMap.BEST_SEGMENT_OPACITY);
                WorkoutMap.map.addOverlay(pl);
                GEvent.addListener(pl, "click", WorkoutMap.polyLineClick);
            }
        }
        WorkoutMap.endLoading();
    },
    getBestSegment: function(workout_id) {
        $.getJSON("/Json/WorkoutBestSegment", { workoutId: workout_id }, WorkoutMap.bestSegmentLoaded);
    },

    polyLineClick: function(point) {
        if (!WorkoutMap.autoMode) {
            WorkoutMap.createCheckPoint(point);
            WorkoutMap.onCheckpointsChanged(WorkoutMap.manualCheckpoints, true);
        }
    },

    createCheckPoint: function(point) {
        var cp = WorkoutMap.findClosest(point);

        var mcp = WorkoutMap.manualCheckpoints;
        for (var k = 0; k < mcp.length; ++k) {
            if (mcp[k].point.x == cp.point.x && mcp[k].point.y == cp.point.y) {
                return null;
            }
        }


        WorkoutMap.manualCheckpoints[WorkoutMap.checkpointsCount] = new Object();
        WorkoutMap.manualCheckpoints[WorkoutMap.checkpointsCount].point = cp.point;
        WorkoutMap.manualCheckpoints[WorkoutMap.checkpointsCount].distance = cp.distance
        WorkoutMap.manualCheckpoints[WorkoutMap.checkpointsCount].timestamp = cp.timestamp;
        WorkoutMap.manualCheckpoints[WorkoutMap.checkpointsCount].timefromstart = cp.timefromstart;
        WorkoutMap.checkpointsCount++;
        WorkoutMap.manualCheckpoints.sort(WorkoutMap.sortCheckpoints);

        var marker = WorkoutMap.createMarker(cp.point, cp.distance, true);
        WorkoutMap.manualMarkers.push(marker);
        WorkoutMap.map.addOverlay(marker);
    },

    findClosest: function(point) {
        var min = 100000000;
        var cp = new Object();
        for (var i = 0; i < WorkoutMap.points.length; i++) {
            var p = WorkoutMap.points[i];
            var d = p.point.distanceFrom(point);
            if (d < min) {
                min = d;
                cp.point = p.point;
                cp.timestamp = p.timestamp;
                cp.distance = p.distance;
                cp.timefromstart = p.timefromstart;
            }
        }
        return cp;
    },

    sortCheckpoints: function(ob1, ob2) {
        return ob1.timestamp - ob2.timestamp;
    },

    createMarker: function(point, distance, removable) {
        var marker = new GMarker(point, WorkoutMap.markerIcon);
        if (removable) {
            marker.id = 'rm' + WorkoutMap.marker_id;
        } else {
            marker.id = 'nm' + WorkoutMap.marker_id;
        }
        WorkoutMap.marker_id++;
        var html = '<div class="gmap-box">Distance: <b>' + Convertor.toDistanceString(distance, WorkoutMap.unitSystem) + '</b></div>';
        GEvent.addListener(marker, 'click', function() {
            marker.openInfoWindowHtml(html);
        });
        return marker;
    },


    removeCheckpoint: function(point, el, overlay) {
        if (overlay != null && overlay.id) {
            var id = overlay.id.substring(0, 2);
            if (id == 'rm') {
                var toRemove = -1;
                var marker_point = overlay.getLatLng();
                for (var i = 0; i < WorkoutMap.manualCheckpoints.length; i++) {
                    var p = WorkoutMap.manualCheckpoints[i].point;
                    if (p == marker_point) {
                        toRemove = i;
                        break;
                    }
                }
                if (toRemove != -1) {
                    WorkoutMap.manualCheckpoints.splice(toRemove, 1);
                    WorkoutMap.checkpointsCount--;
                    WorkoutMap.onCheckpointsChanged(WorkoutMap.manualCheckpoints, true);
                    WorkoutMap.map.removeOverlay(overlay);
                }
            }
        }
    },

    loadAutocheckpoints: function() {
        WorkoutMap.autoMode = true;
        var KM_ML = Convertor.KM_TO_MILES[WorkoutMap.unitSystem];
        var factor = 1000 / KM_ML;
        if (WorkoutMap.autoCheckpoints.length == 0) {
            var d = WorkoutMap.points[WorkoutMap.points.length - 1].distance;
            var sectorDistance =
                Math.round(d / WorkoutMap.AUTO_CHECKPOINTS_COUNT / factor) * factor;
            if (sectorDistance < 1000 / KM_ML) { sectorDistance = 400; }
            if (d < 1000) { sectorDistance = 100 / KM_ML; }

            var curDistance = 0.0;
            var total = 0;
            var size = WorkoutMap.points.length;
            WorkoutMap.autoCheckpoints.push(WorkoutMap.points[0]);
            for (var i = 1; i < size; i++) {
                if (WorkoutMap.points[i].distance - curDistance >= sectorDistance) {
                    WorkoutMap.autoCheckpoints.push(WorkoutMap.points[i]);
                    curDistance = WorkoutMap.points[i].distance;
                    total++;
                }
                /*if (total == WorkoutMap.AUTO_CHECKPOINTS_COUNT - 1) {
                break;
                }*/
            }
            WorkoutMap.autoCheckpoints.push(WorkoutMap.points[size - 1]);
        }
        WorkoutMap.addAutoMarkers();
        WorkoutMap.onCheckpointsChanged(WorkoutMap.autoCheckpoints, false);
    },

    addAutoMarkers: function() {
        WorkoutMap.removeManualMarkers();
        if (WorkoutMap.autoMarkers.length == 0) {
            for (var i = 1; i < WorkoutMap.autoCheckpoints.length - 1; i++) {
                var marker = WorkoutMap.createMarker(WorkoutMap.autoCheckpoints[i].point, WorkoutMap.autoCheckpoints[i].distance, false);
                WorkoutMap.autoMarkers.push(marker);
                WorkoutMap.map.addOverlay(marker);
            }
        }
    },
    removeAutoMarkers: function() {
        for (var i = 0; i < WorkoutMap.autoMarkers.length; i++) {
            WorkoutMap.map.removeOverlay(WorkoutMap.autoMarkers[i]);
        }
        WorkoutMap.autoMarkers = new Array();
    },

    removeManualMarkers: function() {
        for (var i = 0; i < WorkoutMap.manualMarkers.length; i++) {
            WorkoutMap.map.removeOverlay(WorkoutMap.manualMarkers[i]);
        }
        WorkoutMap.manualMarkers = new Array();
    },


    loadAnyCheckpoints: function() {
        WorkoutMap.removeManualMarkers();
        WorkoutMap.removeAutoMarkers();
        if (WorkoutMap.autoMode) {
            WorkoutMap.addManualMarkers();
            WorkoutMap.onCheckpointsChanged(WorkoutMap.manualCheckpoints, !WorkoutMap.autoMode);
        }
    },

    loadManualcheckpoints: function() {
        WorkoutMap.autoMode = false;
        WorkoutMap.addManualMarkers();
        WorkoutMap.onCheckpointsChanged(WorkoutMap.manualCheckpoints, true);
    },
    addManualMarkers: function() {
        WorkoutMap.removeAutoMarkers();
        if (WorkoutMap.manualMarkers.length == 0) {
            for (var i = 1; i < WorkoutMap.manualCheckpoints.length - 1; i++) {
                var marker = WorkoutMap.createMarker(WorkoutMap.manualCheckpoints[i].point, WorkoutMap.manualCheckpoints[i].distance, true);
                WorkoutMap.manualMarkers.push(marker);
                WorkoutMap.map.addOverlay(marker);
            }
        }
    },

    removeAllMarkers: function() {
        WorkoutMap.removeManualMarkers();
        WorkoutMap.removeAutoMarkers();
    },

    addStatsMarkers: function() {
        var maxAlt = WorkoutMap.mapPeaks.maxAlt;
        if ((!WorkoutMap.mapPeaks.altAllZeros) && WorkoutMap.mapPeaks.maxAlt.point) {
            WorkoutMap.createStatsMarker(
                WorkoutMap.mapPeaks.maxAlt.point,
                "Maximum Altitude: " + Convertor.toAltitudeString(Math.round(WorkoutMap.mapPeaks.maxAlt.altitude), WorkoutMap.unitSystem),
                WorkoutMap.statsIcons.MaxAlt
            );
        }
        if (WorkoutMap.mapPeaks.maxSpeed.point) {
            WorkoutMap.createStatsMarker(
                WorkoutMap.mapPeaks.maxSpeed.point,
                "Maximum speed: " + Convertor.toSpeedString(Math.round(WorkoutMap.mapPeaks.maxSpeed.speed * 100.0) / 100.0, WorkoutMap.unitSystem),
                WorkoutMap.statsIcons.MaxSpeed
            );
        }
    },

    removeStatsMarkers: function() {
        for (var i = 0; i < WorkoutMap.statsMarkers.length; ++i) {
            WorkoutMap.map.removeOverlay(WorkoutMap.statsMarkers[i]);
        }
        WorkoutMap.statsMarkers = [];
    },

    subPathHighlight: {
        oldPolyLine: null,
        draw: function(firstPoint, lastPoint) {
            if (WorkoutMap.subPathHighlight.oldPolyLine != null) { // remove old marker
                WorkoutMap.map.removeOverlay(WorkoutMap.subPathHighlight.oldPolyLine);
            }
            var markedSegment = [];
            for (var i = firstPoint; i <= lastPoint; ++i) {
                if (WorkoutMap.points[i] != null) {
                    markedSegment.push(WorkoutMap.points[i].point);
                }
            }
            var polyline = new GPolyline(markedSegment, "#33ffff", 7, 0.7);
            WorkoutMap.map.addOverlay(polyline);
            WorkoutMap.subPathHighlight.oldPolyLine = polyline;
        }
    },
    makeImageLink: function() {
        pathString = "http://maps.google.com/staticmap?path=rgba:0x0000ff99,weight:5";
        var count = WorkoutMap.points.length;
        var step = Math.round(count / 40);
        if (step < 1) { step = 1; }
        var minLat = 200, minLng = 200, maxLat = -200, maxLng = -200;
        for (var i = 0; i < count; i += step) {
            var Lat = WorkoutMap.points[i].point.lat();
            var Lng = WorkoutMap.points[i].point.lng();
            pathString += "|" + Lat + "," + Lng;
        }
        pathString += "&size=480x480&maptype=hybrid&sensor=false&key="
        + Config.google_ajax_api_key;
        return pathString;
    }

}



var WorkoutMapInit = function(runLoader) {
    WorkoutMap.startLoading = function() {
        $('#map').hide();
        Loader.startLoading();
    };
    WorkoutMap.endLoading = function() {
        Loader.endLoading();
        $('#map').show();
    };
}