/*
 * Copyright (C) 2009 WorkSmart Labs, Inc.
 */

/**
 * This file contains all the map functions.
 * TODO(vera): Make this into a real TrackMap class.
 *
 * @author Vera Kern <vera@worksmartlabs.com>
 */

function Map(container) {
    this.container_ = container;
    
    this.map_ = new GMap2(this.container_);
    this.map_.addControl(new GMapTypeControl());
    this.map_.addControl(new GSmallZoomControl());
    this.map_.addControl(new GScaleControl());
    this.map_.setCenter(new GLatLng(0,0), 2);
    
    // I have to create the markers here
    // because I need a map object first
    
    // Properties of the green (start) icon
    var startIcon = new GIcon(G_DEFAULT_ICON);
    startIcon.iconSize = new GSize(15, 15);
    startIcon.sprite = {image:"images/start_end_sprites.png", top:30}
    startIcon.shadow = "";
    startIcon.iconAnchor = new GPoint(8, 8);
    this.START_MARKER = { icon:startIcon };
        
    // Properties of the blue (break) icon
    var breakIcon = new GIcon(G_DEFAULT_ICON);
    breakIcon.iconSize = new GSize(15, 15);
    breakIcon.sprite = {image:"images/start_end_sprites.png", top:15}
    breakIcon.shadow = "";
    breakIcon.iconAnchor = new GPoint(8, 8);
    this.BREAK_MARKER = { icon:breakIcon };
    
    // Properties of the red (end) icon
    var endIcon = new GIcon(G_DEFAULT_ICON);
    endIcon.iconSize = new GSize(15, 15);
    endIcon.sprite = {image:"images/start_end_sprites.png", top:0}
    endIcon.shadow = "";
    endIcon.iconAnchor = new GPoint(8, 8);               
    this.END_MARKER = { icon:endIcon };
}

/*
* Displays the map
*/
Map.prototype.showMap = function() {
    this.container_.style.visibility = 'visible';
    displayNone(el('emtpyTrack_container'));
}

/*
* Hides the map
*/
Map.prototype.hideMap = function() {
    this.container_.style.visibility = 'hidden';
    displayBlock(el('emtpyTrack_container'));
}

/*
* Draws the track of the currentId
*/
Map.prototype.drawRun = function(intervalLatLngArray) {
    
    this.clearMap();

    // If there is only one point in the first Array this is a Location Hint
    // Set the maps center to this point with zoomlevel 12
    if (intervalLatLngArray.length < 2 && intervalLatLngArray[0].length == 1) {
        this.map_.setCenter(intervalLatLngArray[0][0], 12);
    } else {
        // If there is more data, calculate the zoomlevel and center...
        var bounds = new GLatLngBounds();
        for (var p = 0; p < intervalLatLngArray.length; p++) {
            for (var q = 0; q < intervalLatLngArray[p].length; q++) {
                bounds.extend(intervalLatLngArray[p][q]);
            }
        }
        // ...and set them
        var zoom = this.map_.getBoundsZoomLevel(bounds);
        var center = bounds.getCenter();
        this.map_.setCenter(center, zoom);
        
        // Draw a polyline for every part of the track and add the markers
        for (var k = 0; k < intervalLatLngArray.length; k++) {
            if (intervalLatLngArray[k].length == 0) { 
                continue; 
            } 
            // Do not draw a polyline for degenerate intervals of size 1. 
            if (intervalLatLngArray[k].length > 1) {
                var polyline = new GPolyline(intervalLatLngArray[k], "#435EE9", 7);
                this.map_.addOverlay(polyline);
            }
            var firstTrackPoint = intervalLatLngArray[k][0];
            if (k == 0) {
                this.map_.addOverlay(new GMarker (firstTrackPoint, this.START_MARKER));
            } else {
                this.map_.addOverlay(new GMarker (firstTrackPoint, this.BREAK_MARKER));
            }
            
            var lastTrackPoint = intervalLatLngArray[k][intervalLatLngArray[k].length-1];
            if (k == intervalLatLngArray.length-1) {
                this.map_.addOverlay(new GMarker (lastTrackPoint, this.END_MARKER));
            } else if (k != 0) {
                // Prevent a break marker from being displayed on top of the start 
                // marker in case of degenerate track of size 1.
                this.map_.addOverlay(new GMarker (lastTrackPoint, this.BREAK_MARKER));
            }
        }
    }
}

/**
 * This function draws a circle around the first point
 * of the user's last run. The radius is the user's 
 * total distance.
 *
 * @param float radius
 * @param float centerPointX
 * @param float centerPointY
 */
Map.prototype.drawTotalRunCircle = function (radius, centerX, centerY) {

    this.clearMap();
    var centerPoint = new GLatLng(centerX, centerY);
    this.map_.setCenter(centerPoint, 2);

    var bounds = new GLatLngBounds();
    // This array collects the coordinates for the circle.
    var circlePoints = Array();
    
    // This calculates the points for the circle.
    // Source: http://maps.forum.nu/gm_sensitive_circle2.html
    with (Math) {
        var d = radius / 3963.189;
        var lat1 = (PI / 180) * centerPoint.lat(); // radians
        var lng1 = (PI / 180) * centerPoint.lng(); // radians
        
        // Calculate the coordinates for the circle.
        for (var a = 0; a < 360; a+=2) {
            var tc = (PI / 180) * a;
            var y = asin(sin(lat1) * cos(d) + cos(lat1) * sin(d) * cos(tc));
            var dlng = atan2(sin(tc) * sin(d) * cos(lat1),cos(d) - sin(lat1) * sin(y));
            var x = ((lng1 - dlng + PI) % (2 * PI)) - PI ;
            var point = new GLatLng(parseFloat(y * (180 / PI)), parseFloat(x * (180 / PI)));
            circlePoints.push(point);
            if (a == 0 || a == 90 || a == 180 || a == 270) {
                bounds.extend(point);
            }
        }
    }
    
   // Create a GPolygon from the circlePoints and add it to the map
    var circle = new GPolyline(circlePoints, "#435EE9", 4);
    this.map_.setZoom(this.map_.getBoundsZoomLevel(bounds));
    this.map_.addOverlay(circle);
}

/*
* Removes all markers on the map
*/
Map.prototype.clearMap = function() {
    // Remove all overlays
    this.map_.clearOverlays(); 
}