// Circle Overlay Extension from: http://dawsdesign.com/drupal/google_maps_circle_overlay
// Point in Polygon Extension from: http://dawsdesign.com/drupal/google_maps_point_in_polygon

function loadPolygonExtensions() {
    loadCircleOverlayExtension();
    loadPointInPolygonExtension();
}

// This file adds a new circle overlay to GMaps2
// it is really a many-pointed polygon, but look smooth enough to be a circle.
var CircleOverlay = function(latLng, radius, strokeColor, strokeWidth, strokeOpacity, fillColor, fillOpacity) {
    this.latLng = latLng;
    this.radius = radius;
    this.strokeColor = strokeColor;
    this.strokeWidth = strokeWidth;
    this.strokeOpacity = strokeOpacity;
    this.fillColor = fillColor;
    this.fillOpacity = fillOpacity;
}

function loadCircleOverlayExtension() {
    // Implements google.maps.Overlay interface
    CircleOverlay.prototype = new google.maps.Overlay;

    CircleOverlay.prototype.initialize = function(map) {
        this.map = map;
    }

    CircleOverlay.prototype.clear = function() {
        if(this.polygon != null && this.map != null) {
            this.map.removeOverlay(this.polygon);
        }
    }

    // Calculate all the points and draw them
    CircleOverlay.prototype.redraw = function(force) {
        var d2r = Math.PI / 180;
        circleLatLngs = new Array();
        var circleLat = this.radius * 0.014483;  // Convert statute miles into degrees latitude
        var circleLng = circleLat / Math.cos(this.latLng.lat() * d2r);
        var numPoints = 40;

        // 2PI = 360 degrees, +1 so that the end points meet
        for (var i = 0; i < numPoints + 1; i++) {
            var theta = Math.PI * (i / (numPoints / 2));
            var vertexLat = this.latLng.lat() + (circleLat * Math.sin(theta));
            var vertexLng = this.latLng.lng() + (circleLng * Math.cos(theta));
            var vertextLatLng = new GLatLng(vertexLat, vertexLng);
            circleLatLngs.push(vertextLatLng);
        }

        this.clear();
        this.polygon = new GPolygon(circleLatLngs, this.strokeColor, this.strokeWidth, this.strokeOpacity, this.fillColor, this.fillOpacity);
        this.map.addOverlay(this.polygon);
    }

    CircleOverlay.prototype.remove = function() {
        this.clear();
    }

    CircleOverlay.prototype.containsLatLng = function(latLng) {
        // Polygon Point in poly
        if(this.polygon.containsLatLng) {
            return this.polygon.containsLatLng(latLng);
        }
    }

    CircleOverlay.prototype.setRadius = function(radius) {
        this.radius = radius;
    }

    CircleOverlay.prototype.setLatLng = function(latLng) {
        this.latLng = latLng;
    }
}

function loadPointInPolygonExtension() {
    // Create polygon method for collision detection
    GPolygon.prototype.containsLatLng = function(latLng) {
        // Do simple calculation so we don't do more CPU-intensive calcs for obvious misses
        var bounds = this.getBounds();

        if(!bounds.containsLatLng(latLng)) {
            return false;
        }

        var numPoints = this.getVertexCount();
        var inPoly = false;
        var i;
        var j = numPoints-1;

        for(var i=0; i < numPoints; i++) {
            var vertex1 = this.getVertex(i);
            var vertex2 = this.getVertex(j);

            if (vertex1.lng() < latLng.lng() && vertex2.lng() >= latLng.lng() || vertex2.lng() < latLng.lng() && vertex1.lng() >= latLng.lng())  {
                if (vertex1.lat() + (latLng.lng() - vertex1.lng()) / (vertex2.lng() - vertex1.lng()) * (vertex2.lat() - vertex1.lat()) < latLng.lat()) {
                    inPoly = !inPoly;
                }
            }

            j = i;
        }

        return inPoly;
    };
}
