﻿
///
/// Google map used on the DoSearch page
///

var _exploreMap = null;

var AdminMap = Class.create();


AdminMap.prototype = {
    ///<summary>
    /// Development administration map allowing the exact location of a development to be plotted manually.
    /// A single marker point will be plotted on the map and moved by clicking on the map and the lat lng cords stored.
    /// </summary>

    // ID of the map element
    mapElementID: null,

    // latitude
    developmentLat: null,

    developmentLng: null,

    latElementID: null,

    lngElementID: null,

    // internal reference to the map
    map: null,

    // map bounds
    bounds: null,

    // collection of geo-coder failure result codes (currently not implemented)
    geoCoderReasons: [],

    // geo-coder object
    geoCoder: null,

    // geo-coder retry delay
    delay: 100,

    // development street address (i.e. 10 Some Road)
    _streetAddress: null,

    // development city name
    _city: null,

    // development postcode
    _postcode: null,

    // default center lat (Edinburgh-ish)
    centerLat: 55.9584,

    // default center lng (Edinburgh-ish)
    centerLng: -3.19702,

    // default zoom level
    zoom: 13,

    // enable map dragging 
    enableDrag: true,

    // enable map info window
    enableInfoWindow: true,

    // enable double click zooming
    enableDoubleClickZoom: true,

    // enable scroll wheel zooming
    enableScrollWheelZoom: true,

    // google maps not compatible with browser message
    notCompatibleMessage: "Sorry, the Google Maps API is not compatible with this browser",

    // ref to current marker point
    currentMarker: null,

    initialize: function(elMap, elLat, elLng) {
        ///<summary>Object initialiser</summary>
        ///<param name="elMap" optional="false">The ID of the map element</param>
        ///<param name="elLat" optional="false">The ID of the form field element to initially read the store the map point Lat cords</param>
        ///<param name="elLat" optional="false">The ID of the form field element to initially read the store the map point Long cords</param>

        if (elMap == null)
            throw "Map element not specified";

        if (elLat == null)
            throw "Latitude form element not specified";

        if (elLng == null)
            throw "Longitude form element not specified";

        this.mapElementID = elMap;
        this.latElementID = elLat;
        this.lngElementID = elLng;

        _exploreMap = this;

        this.geoCoder = new GClientGeocoder();

        this._loadGeoCoderReasons();

        this.load();
    },

    _loadGeoCoderReasons: function() {
        ///<summary>Load the GeoCoder message array</summary>
        this.geoCoderReasons[G_GEO_SUCCESS] = "Success";
        this.geoCoderReasons[G_GEO_MISSING_ADDRESS] = "Missing Address: The address was either missing or had no value.";
        this.geoCoderReasons[G_GEO_UNKNOWN_ADDRESS] = "Unknown Address:  No corresponding geographic location could be found for the specified address.";
        this.geoCoderReasons[G_GEO_UNAVAILABLE_ADDRESS] = "Unavailable Address:  The geocode for the given address cannot be returned due to legal or contractual reasons.";
        this.geoCoderReasons[G_GEO_BAD_KEY] = "Bad Key: The API key is either invalid or does not match the domain for which it was given";
        this.geoCoderReasons[G_GEO_TOO_MANY_QUERIES] = "Too Many Queries: The daily geocoding quota for this site has been exceeded.";
        this.geoCoderReasons[G_GEO_SERVER_ERROR] = "Server error: The geocoding request could not be successfully processed.";
        this.geoCoderReasons[403] = "Error 403: Probably an incorrect error caused by a bug in the handling of invalid JSON.";
    },

    load: function(defaultLat, defaultLng, defaultZoom) {
        ///<summary>Load the google map and plot the development point if known</summary>                
        ///<param name="defaultLat" optional="true">Default lat</param>
        ///<param name="defaultLng" optional="true">Default lng</param>
        ///<param name="defaultZoom" optional="true">Default zoom level</param>

        if (!this.mapElementID)
            throw "Map element ID not specified";

        if (GBrowserIsCompatible()) {

            this.bounds = new GLatLngBounds();

            // init map
            this.map = new GMap2(document.getElementById(this.mapElementID));

            // pan\zoom control
            this.map.addControl(new GLargeMapControl());

            if (!this.enableDrag)
                this.map.disableDragging();

            if (!this.enableInfoWindow)
                this.map.disableInfoWindow()

            if (!this.enableDoubleClickZoom)
                this.map.enableDoubleClickZoom()

            if (this.enableScrollWheelZoom)
                this.map.enableScrollWheelZoom();

            if (!defaultLat)
                defaultLat = this.centerLat;

            if (!defaultLng)
                defaultLng = this.centerLng;

            if (!defaultZoom)
                defaultZoom = this.zoom;

            this.map.setCenter(new GLatLng(defaultLat, defaultLng), defaultZoom);

            // plot development point
            var lat = document.getElementById(this.latElementID).value;
            var lng = document.getElementById(this.lngElementID).value;

            this.createPoint(lat, lng);

            // add map click event to locate the development
            GEvent.addListener(this.map, "click", function(o, point) {

                if (point) {
                    // remove any markers
                    _exploreMap.clearMap();

                    // add a new marker at the clicked point
                    _exploreMap.createPoint(point.lat(), point.lng())

                    // store the lat lng cords in page form fields
                    document.getElementById(_exploreMap.latElementID).value = point.lat();
                    document.getElementById(_exploreMap.lngElementID).value = point.lng();
                }
            });

            // add reset location button click handler
            Event.observe($('btnResetPosition'), 'click', _exploreMap.remapLocation);

            // center and zoom
            _exploreMap.map.setZoom(_exploreMap.zoom);
            _exploreMap.map.setCenter(this.bounds.getCenter());

        } else {
            // alert(notCompatibleMessage);
        }
    },

    remapLocation: function() {
        ///<summary>remap location based on know address</summary>

        // disable the button
        $('btnResetPosition').disabled = true;

        var houseAddress = document.getElementById('ctl00_mainContentPlaceHolder_tbxAddress1').value;
        var postcode = document.getElementById('ctl00_mainContentPlaceHolder_tbxPostcode').value;

        var address = '';

        if (houseAddress.length > 0) {
            address += houseAddress + ', ';
        }
        if (postcode.length > 0) {
            address += postcode + ', UK';
        } else {
            alert("The postcode for this property must be known for it to be ploted on the map");
        }

        _exploreMap.geoCoder.getLocations(address, function(response) {

            if (!response || response.Status.code != 200) {
                // no address match, retry using postcode only
                _exploreMap._goecodeByPostcode(postcode, address);
            } else {

                place = response.Placemark[0];

                var accuracy = response.Placemark[0].AddressDetails.Accuracy;

                // extract the lat and long cords
                var lat = place.Point.coordinates[1];
                var lng = place.Point.coordinates[0];

                // update the Lat Long hidden fields
                document.getElementById(_exploreMap.latElementID).value = lat;
                document.getElementById(_exploreMap.lngElementID).value = lng;

                // rwn : temp alert new locaiton
                alert("Location updated to: " + lat + ", " + lng);

                // move the map pointer
                _exploreMap.clearMap();
                _exploreMap.createPoint(lat, lng)

                if (accuracy != 9) {
                    alert("Development location may not be accurate, please verify and re-position by clicking on the map.");
                }

            }

            // re-enable the button
            $('btnResetPosition').disabled = false;

        });
    },

    // called if full address is not matched, use postcode only and inform user
    _goecodeByPostcode: function(postcode, address) {

        _exploreMap.geoCoder.getLocations(postcode, function(response) {

            if (!response || response.Status.code != 200) {
                alert("Sorry, we were unable to geocode the postcode '" + postcode + "', please position the marker manually.");
            } else {

                place = response.Placemark[0];

                var accuracy = response.Placemark[0].AddressDetails.Accuracy;

                // extract the lat and long cords
                var lat = place.Point.coordinates[1];
                var lng = place.Point.coordinates[0];

                // update the Lat Long hidden fields
                document.getElementById(_exploreMap.latElementID).value = lat;
                document.getElementById(_exploreMap.lngElementID).value = lng;

                // move the map pointer
                _exploreMap.clearMap();
                _exploreMap.createPoint(lat, lng)

                if (accuracy != 9) {
                    alert("Development location may not be accurate (based on postcode only), please verify and re-position by clicking on the map.");
                }
            }

            // re-enable the button
            $('btnResetPosition').disabled = false;
        });

    },

    createPoint: function(lat, lng) {
        ///<summary>Create map point</summary>
        ///<param name="lat"></param>
        ///<param name="lng"></param>

        point = new GLatLng(lat, lng);

        _exploreMap.currentMarker = new GMarker(point);
        this.map.addOverlay(_exploreMap.currentMarker);
        this.bounds.extend(_exploreMap.currentMarker.getPoint());

        // center and zoom
        _exploreMap.map.setCenter(_exploreMap.currentMarker.getPoint());
    },

    clearMap: function() {
        ///<summary>Clear map overlays</summary>

        if (this.currentMarker)
            this.currentMarker.remove();
    }
};
