﻿function GoogleMap() {

}

/**************
* Marker Info 
**************/
GoogleMap.MarkerInfo = function(title, text, markerObject, latitude, longitude) {
    this.title = title;
    this.text = text;
    this.markerObject = markerObject;
    this.latitude = latitude;
    this.longitude = longitude;
}

GoogleMap.MarkerInfo.prototype.title = "";
GoogleMap.MarkerInfo.prototype.text = "";
GoogleMap.MarkerInfo.prototype.latitude = 0;
GoogleMap.MarkerInfo.prototype.longitude = 0;
GoogleMap.MarkerInfo.prototype.markerObject = null;

/******
* Map 
******/

/*****
 * Constructor.
 *
 * container - The html container that will hold the map
 * centerLatitude - latitude coordinate that will be the initial center of the viewport
 * centerLongitude - longitude coordinate that will be the initial center of the viewport
 * defaultZoom - The initial zoom level of the map
 * mapLoaded - A callback function that is called when the map is fully loaded and initialized
 *             It is passed a single parameter that is a reference to this new GoogleMap.Map object
 * autoZoom - Set to true to automatically set the map to the best zoom level as markers are added
 *****/
GoogleMap.Map = function(container, centerLatitude, centerLongitude, defaultZoom, mapLoaded, autoZoom) {
    this.container = container;
    this.centerLatitude = centerLatitude;
    this.centerLongitude = centerLongitude;
    this.defaultZoom = defaultZoom;
    this.mapLoaded = mapLoaded;
    this.autoZoom = autoZoom;

    google.load("maps", "2");
    var obj = this;
    google.setOnLoadCallback(function() { obj._initialize(); });
}

//Public member functions
/****
* If a marker exists at the given location will return a MarkerInfoObject.  Otherwise, null.
*
* latitude - The latitude coordinate to check
* longitude - The longitude coordinate to check
****/
GoogleMap.Map.prototype.HasMarkerAtLocation = function(latitude, longitude) {
    if (!this.initialized)
        return;
        
    for (var i = 0; i < this.markerList.length; i++) {
        var marker = this.markerList[i];

        if (marker.latitude == latitude && marker.longitude == longitude) {
            return marker;
        }
    }

    return null;
}

/*****
 * Remove a marker from the map
 *
 * markerInfoObject - A GoogleMap.MarkerInfo object contained in the marker list
 *****/
GoogleMap.Map.prototype.RemoveMarker = function(markerInfoObject) {
    if (!this.initialized)
        return;
        
    var newMarkerList = new Array();
    this.mapObject.removeOverlay(markerInfoObject.markerObject);

    //rebuild markerlist without this element
    for (var i = 0; i < this.markerList.length; i++) {
        var item = this.markerList[i];

        if (item != markerInfoObject) {
            newMarkerList.push(item);
        }
    }

    this.markerList = newMarkerList;
}

/*****
 * Adds a marker to the map
 *
 * title - The title to be used for the marker
 * text - The text to be used for the marker
 * latitude - The latitude coordinate to place the marker
 * longitude - The longitude coordinate to place the marker
 * address - If this is not null it will display the address with 
 *           the title and provide a link for directions
 *****/
GoogleMap.Map.prototype.AddMarker = function(title, text, latitude, longitude, address, letter) {
    if (!this.initialized)
        return;

    var directions = "";

    //Create a new marker bounds object if it doesnt exist yet
    if (this.markerBounds == null)
        this.markerBounds = new google.maps.LatLngBounds();

    //create a LatLng object that will be passed to the marker constructor
    var point = new google.maps.LatLng(latitude, longitude);
    //create the google maps marker
    var marker = new google.maps.Marker(point);

    //lettered icon
    if (letter != null && letter.charCodeAt(0) >= "A".charCodeAt(0) &&
        letter.charCodeAt(0) <= "Z".charCodeAt(0)) {
        var baseIcon = new google.maps.Icon(G_DEFAULT_ICON);
        baseIcon.shadow = "http://www.google.com/mapfiles/shadow50.png";
        baseIcon.iconSize = new google.maps.Size(20, 34);
        baseIcon.shadowSize = new google.maps.Size(37, 34);
        baseIcon.iconAnchor = new google.maps.Point(9, 34);
        baseIcon.infoWindowAnchor = new GPoint(9, 2);

        var icon = new google.maps.Icon(baseIcon);
        icon.image = "http://www.google.com/mapfiles/marker" + letter + ".png";

        marker = new google.maps.Marker(point, { icon: icon });
    }

    //a temp copy of this object that can be accessed from an anonymous function
    var mapObj = this;

    /** Construct marker text **/
    //Check if a marker already exists at this location
    var existingMarker = this.HasMarkerAtLocation(latitude, longitude);

    //Set up info window title/header
    var header = "<div style='font-weight:bold'>" + title + "</div>";

    //if an address is set, add directions to the google maps marker
    if (address != null) {
        var directions = "<a style='font-size:10px' target='__blank' href='http://maps.google.com/maps?f=d&hl=en&geocode=&daddr=" + address + "&ie=UTF8'>(Driving Directions)</a>";
        header += "<div style='font-size:10px;color:#999999'>" + address + "</div>";
        header += directions + "<br />";
    }

    header += "<br />";

    var markerText = "";

    if (existingMarker == null) {
        markerText = text + "<br />";
    }
    else {
        markerText = existingMarker.text + text + "<br />";
        this.RemoveMarker(existingMarker);
    }

    /** Add the marker to the map **/
    google.maps.Event.addListener(marker, "click",
        function() {
            mapObj.SetCenter(latitude, longitude);
            marker.openInfoWindowHtml(header + markerText + "<br />", { "maxWidth": 300 });
        }
    );

    this.mapObject.addOverlay(marker);

    //if the option is set, automatically zoom to the best level
    if (this.autoZoom) {
        this.markerBounds.extend(point);
        //this.mapObject.setZoom(this.mapObject.getBoundsZoomLevel(this.markerBounds));
        var center = this.markerBounds.getCenter();
        this.SetCenter(center.lat(), center.lng());
    }

    var markerObject = new GoogleMap.MarkerInfo(title, markerText, marker, latitude, longitude);
    this.markerList.push(markerObject);
}

/*****
 * Add a marker to the map at the location retrieved by geocoding an address.
 * The function returns true if a marker was added successfully, and false if the
 * address could not be geocoded and the marker was not added.
 *
 * title - The title to be used for the info window
 * text - Additional text to be displayed below the title
 * address - The address at which to place the marker
 *****/
GoogleMap.Map.prototype.AddMarkerWithAddress = function(title, text, address, letter) {
    if (!this.initialized)
        return false;
        
    var thisObj = this;
    var status = true;
    var geocoder = new google.maps.ClientGeocoder();

    geocoder.getLatLng(address,
        function(point) {
            if (point) {
                thisObj.AddMarker(title, text, point.lat(), point.lng(), address, letter);
            }
            else {
                status = false;
            }
        }
    );

    return status;
}

GoogleMap.Map.prototype.ZoomLocation = function(latitude, longitude) {
    if (!this.initialized)
        return;

    var bounds = new google.maps.LatLngBounds();

    bounds.extend(new google.maps.LatLng(latitude, longitude));
    var zoom = this.mapObject.getBoundsZoomLevel(bounds);

    if (zoom > 2)
        zoom -= 2;
        
    this.mapObject.setZoom(zoom);
    var center = bounds.getCenter();
    this.SetCenter(center.lat(), center.lng());
}

/*****
 * Removes all markers from the map
 *****/
GoogleMap.Map.prototype.ClearAllMarkers = function() {
    if (!this.initialized)
        return;

    this.mapObject.clearOverlays();
    this.markerList = null;
    this.markerList = new Array();

    this.markerBounds = null;
}

/*****
 * Moves the center of the users viewport to the given location
 *
 * latitude - The latitude coordinate that will become the center of the map
 * longitude - The longitude coordinate that will become the center of the map
 *****/
GoogleMap.Map.prototype.SetCenter = function(latitude, longitude) {
    if (!this.initialized)
        return;

    this.mapObject.panTo(new google.maps.LatLng(latitude, longitude));
}

//Private member functions
GoogleMap.Map.prototype._initialize = function() {
    this.mapObject = new google.maps.Map2(this.container);
    this.mapObject.setCenter(new google.maps.LatLng(this.centerLatitude, this.centerLongitude),
        this.defaultZoom);
    this.initialized = true;
    this.mapObject.addControl(new google.maps.LargeMapControl());

    if (this.mapLoaded != null) {
        this.mapLoaded(this);
    }
}

//Member variables
//Stores the google map object
GoogleMap.Map.prototype.mapObject = null; 
//A list of GoogleMap.MarkerInfo objects
GoogleMap.Map.prototype.markerList = new Array();
//A check to make sure google maps has been loaded before anything can be done
//Functions should check this and return before doing anything if this is false
GoogleMap.Map.prototype.initialized = false;
//Container that will hold the google map
GoogleMap.Map.prototype.container = null;
//initial center of the viewport
GoogleMap.Map.prototype.centerLatitude = 0;
//initial center of the viewport
GoogleMap.Map.prototype.centerLongitude = 0;
//initial zoom level
GoogleMap.Map.prototype.defaultZoom = 1;
//callback function that is called when the map is loaded and initialized
GoogleMap.Map.prototype.mapLoaded = null;
//object used to calculate the best zoom level based on markers
GoogleMap.Map.prototype.markerBounds = null;
//A flag that enables or disables finding the best zoom level as markers are added
GoogleMap.Map.prototype.autoZoom = false;

