
/**
 * the PeopleNearMe class generates and manages a google
 * Map object and uses geolocation (if approved) to watch
 * the visitors position (also movement) and identify
 * potentially near users.
 **/
function PeopleNearMe()
{
    this.map            = null;
    this.infowindow     = null;
    this.coords         = {};
    this.updateInterval = null;
    this.myPosMarker    = null;
    this.dealMarker     = null;
    this.userMarkers    = [];
    this.autoComplete   = null;
    this.spiderAround   = null;
    this.delivMarker 	= null;

    this.markerIcons = {
    	currentPosition: "/static/images/google_maps_icon/me-marker.png",
		unloggedUser: "/static/images/google_maps_icon/inactive-marker.png",
		loggedUser: "/static/images/google_maps_icon/watch-blu.png",
		pulledOver: "/static/images/google_maps_icon/yellow-marker.png",
		alertUser: "/static/images/google_maps_icon/green_marker.gif",
		//alertUser: "/static/images/google_maps_icon/RedDot.gif",
		//delivLocation: "/static/images/google_maps_icon/red-map-marker.gif"
		//delivLocation: "/static/images/google_maps_icon/RedDot.gif"
		
//        currentPosition: "https://continualevents.com/static/images/google_maps_icon/me-marker.png",
//        unloggedUser: "https://continualevents.com/static/images/google_maps_icon/inactive-marker.png",
//        loggedUser: "https://continualevents.com/static/images/google_maps_icon/watch-blu.png",
//        pulledOver: "https://continualevents.com/static/images/google_maps_icon/yellow-marker.png",
//        alertUser: "https://continualevents.com/static/images/google_maps_icon/RedDot.gif"
    }

    /**
     * register a watchPosition interval. This function can be
     * used in pages where a Google Map is available. It will
     * get the visitor's current position by geolocation and
     * watch it move + update the marker when movement is
     * registered.
     *
     * @return PeopleNearMe
     **/
    this.initialize = function()
    {
        var self = this;

        // get current position, then create map and center.
        this.watchMyPosition(function(obj)
        {
            coordinates = obj.getCoordinates();
            current_pos = new google.maps.LatLng(coordinates.latitude, coordinates.longitude);

            // map will be centered on the Deals Coordinates
            deal_coords = {latitude: $("input[name=location_lat]").val(), longitude: $("input[name=location_lng]").val()};
            deal_pos    = new google.maps.LatLng(deal_coords.latitude, deal_coords.longitude);
            
//            deliv_coords = {latitude: $("input[name=location_lat2]").val(), longitude: $("input[name=location_lng2]").val()};
//			deliv_pos    = new google.maps.LatLng(deliv_coords.latitude, deliv_coords.longitude);

            if (obj.map != null) {
                obj.updateMyMarker(coordinates, false);
                return false;
            }

            // first time map creation.
            obj.map = new google.maps.Map(document.getElementsByClassName('map-canvas')[0], {
                center: deal_pos,
                zoom: 9,
                scrollwheel: false,
                mapTypeId: google.maps.MapTypeId.ROADMAP
            });
            
//        	var posLatLngHome = new google.maps.LatLng('41.884821','-87.628118');
//			var posLatLngDest = new google.maps.LatLng('41.884821','-87.628118');
//
//			var line = new google.maps.Polyline({path: [posLatLngHome, posLatLngDest], map: map});

            obj.initSpider();

            icon = obj.markerIcons.currentPosition;
            html = $("#my-marker").html();
            obj.myPosMarker = obj.createMarker(current_pos, html, icon, "My Position");

            icon = obj.markerIcons.alertUser;
            html = $("#deal-marker").html();
            obj.dealMarker = obj.createMarker(deal_pos, html, icon, "Pickup Location");
            
//            icon = obj.markerIcons.delivLocation;
//			html = $("#deliv-marker").html();
//			obj.delivMarker = obj.createMarker(deliv_pos, html, icon, "Delivery Location");
			
			// Calculate and display the distance in miles
			var distance = google.maps.geometry.spherical.computeDistanceBetween(deal_pos, deliv_pos);
			var distanceInMiles = distance * 0.000621371; // Conversion factor to miles

			document.getElementById("distance").innerHTML = "" + distanceInMiles.toFixed(2) + " miles";

            // when the map is displayed, we can save the user position
//            obj.updateCoordinatesRequest(coordinates);

            // map is displayed, we can also get user's positions
            obj.addMarkersFromDirectory();

            // update all 30 seconds.
//            obj.registerCoordinatesUpdate();
        });

        return this;
    }

    this.initSpider = function()
    {
        this.spiderAround = new OverlappingMarkerSpiderfier(this.getMap(), {markersWontMove: true, markersWontHide: true, keepSpiderfied: true});

        if (this.infowindow == null)
            this.infowindow = new google.maps.InfoWindow();

        var map  = this.getMap();
        var self = this;
        this.spiderAround.addListener("click", function(marker, event)
        {
            self.infowindow.setContent(marker.content);
            self.infowindow.open(self.getMap(), marker);
        });

        var shadow = new google.maps.MarkerImage(
            'https://www.google.com/intl/en_ALL/mapfiles/shadow50.png',
            new google.maps.Size(37, 34),  // size   - for sprite clipping
            new google.maps.Point(0, 0),   // origin - ditto
            new google.maps.Point(10, 34)  // anchor - where to meet map location
        );
        this.spiderAround.addListener('spiderfy', function(markers) {
            for(var i = 0; i < markers.length; i ++) {
                markers[i].setShadow(null);
            }
            self.infowindow.close();
        });
        this.spiderAround.addListener('unspiderfy', function(markers) {
            for(var i = 0; i < markers.length; i ++) {
                markers[i].setShadow(shadow);
            }
        });
    }

    /**
     * getter method for map property.
     *
     * @return google.maps.Map
     **/
    this.getMap = function()
    {
        return this.map;
    }

    /**
     * getter method for coords property.
     * Represent the current visitor's coordinates.
     *
     * @return Object {latitude: decimal, longitude: decimal}
     **/
    this.getCoordinates = function()
    {
        return this.coords;
    }

    /**
     * update a user_id's current marker position to the last
     * one fetched from database. The coords parameter must be
     * a object containing 'latitude' and 'longitude' fields.
     *
     * @param   integer     user_id
     * @param   object      coords  MUST contain 'latitude' and 'longitude'
     * @param   boolean     is_logged_in
     * @return google.maps.Marker
     **/
    this.updateUserMarker = function(user_id, coords, is_logged_in)
    {
        if (user_id == parseInt($("#current_user_id").text()))
            return false;

        icon        = this.markerIcons.unloggedUser;
        current_pos = new google.maps.LatLng(coords.latitude, coords.longitude);
        marker      = null;

        for (i = 0; i < this.userMarkers.length; i++) {
            var obj = this.userMarkers[i];

            if (parseInt(obj.uid) != user_id)
                continue;

            marker = obj.marker;

            // if the marker is at the same position we don't need to update.
            if (marker.getPosition().lat() == coords.latitude
                && marker.getPosition().lng() == coords.longitude)
                return marker;

            // marker needs an update, then finish.
            marker.setPosition(current_pos);
            marker.setIcon(icon);
            return marker;
        }

        return marker;
    }

    /**
     * This method is used to execute the navigator.geolocation
     * API call to watchPosition(). Also it defines 2 callback
     * functions that will be called respectively on success
     * geolocation and on error.
     * The callback parameter must be a function that will
     * be executed after the geolocation process.
     *
     * @param callback  callable
     * @return PeopleNearMe
     **/
    this.watchMyPosition = function(callback)
    {
        var obj = this;
        function successWatch(position)
        {
            console.log("success");
            geolocation = new google.maps.LatLng(position.coords.latitude, position.coords.longitude);
            obj.coords  = position.coords;
            callback(obj);
        }

        function errorWatch()
        {
            console.log("error");
            fallback = $("#fallback-coordinates").text().split(",");
            obj.coords = {latitude: fallback[0], longitude: fallback[1]};
            callback(obj);
        }

        watchOpts = {
            enableHighAccuracy:true,
            timeout:60000,
            maximumAge:0
        };
        var watchId = navigator.geolocation.watchPosition(successWatch, errorWatch, watchOpts);
        return this;
    }

    /**
     * This method iterates through .user-coords elements
     * and creates markers for the given user on the map.
     *
     * @return PeopleNearMe
     **/
    this.addMarkersFromDirectory = function()
    {
        var self = this;

        // also we need to iterate through listed users for generating
        // the markers on the map corresponding to each user.
        $(".user-coords").each(function()
        {
            var current_user = parseInt($("#current_user_id").text());
            coords  = $(this).attr("data-coordinates");
            uid     = $(this).attr("data-uid");
            logged  = parseInt($(this).attr("data-logstate"));

            if (uid == current_user)
                return true;

            info_html = $(this).find(".infowindow-content").html();

            if (coords == "Unknown")
                // no coords for user.
                return true;

            // create marker for the user.
            coords = coords.split(",");
            gpos   = new google.maps.LatLng(coords[0], coords[1]);
            icon   = self.markerIcons.unloggedUser;

            // create marker and store.
            marker = self.createMarker(gpos, info_html, icon, "User Position");
            self.userMarkers.push({"uid": uid, "marker": marker});
        });

        this.liveMarkersTick();
        return this;
    }

    /**
     * This method executes an AJAX request that fetches users
     * and their respective coordinates from the database.
     * This method is used in liveMarkersTick() to be executed
     * every 5 seconds.
     *
     * @return PeopleNearMe
     **/
    this.fetchLiveMarkers = function()
    {
        var self = this;

        $.ajax({
            url: "/directory/ajaxGetUsersCoordinates",
            success: function(d)
            {
                var d = eval(d);
                for (i in d) {
                    user_row   = d[i];
                    user_id    = user_row.id;
                    new_coords = user_row.coords;
                    is_logged  = user_row.logged === 1;
                    html       = user_row.html;

                    geoloc     = new_coords.split(",");
                    new_coords = {latitude: geoloc[0], longitude: geoloc[1]};

                    // find marker and update (or create) as needed.
                    marker = self.updateUserMarker(user_id, new_coords, is_logged, html);
                }
            },
            complete: function()
            {
                setTimeout(function() { self.fetchLiveMarkers(); }, 10000);
            }
        });

        return this;
    }

    /**
     * Allows to automatically check for new user positions
     * or logged_in states in real-time on the map.
     * @return void
     **/
    this.liveMarkersTick = function()
    {
        var self = this;
        self.fetchLiveMarkers();
    }

    /**
     * create a marker on the google map. Provided
     * argument MUST be a google.maps.LatLng object.
     *
     * @param coord     google.maps.LatLng
     * @param text      string
     * @param icon      string
     * @return PeopleNearMe
     **/
    this.createMarker = function(coord, text, icon, title)
    {
        var self   = this;
        var marker = new google.maps.Marker({
            flat: true,
            map: this.getMap(),
            position: coord,
            icon: icon,
            content: text,
            title: title,
            optimized: false,
            visible: true
        });
        self.spiderAround.addMarker(marker);
        return marker;
    }

    /**
     * This method UPDATES a google map marker to the given
     * new coordinates. Also it will pan the map so that the
     * movement can be seen.
     *
     * @param coords                Object {latitude: decimal, longitude: decimal}
     * @param update_last_coord     boolean     wether to update the user coord in DB, or not
     * @return PeopleNearMe
     **/
    this.updateMyMarker = function(coords, pan_to_it)
    {
        current_pos = new google.maps.LatLng(coords.latitude, coords.longitude);

        if (pan_to_it)
            this.map.panTo(current_pos);

        this.myPosMarker.setPosition(current_pos);

        return this;
    }
}
