function Mapa(elementoId, lat, lng, usarClusterDefault) {
    this.elementoId = elementoId;
    this.map = null;
    this.lat = lat ? lat : -14;
    this.lng = lng ? lng : -54;
    this.numDeltas = 50;
    this.usarClusterDefault = usarClusterDefault;
    this.delayTransicao = 20; //milliseconds
    this.markerClusterer = null;
    this.lineSymbolplanejamento = {
        path: 'M 0,-0.5 0,0.5',
        strokeWeight: 4,
        strokeOpacity: 1,
        scale: 4
    };

    this.directionsDisplay = new google.maps.DirectionsRenderer();
    this.directionsService = new google.maps.DirectionsService();
    this.geocoder = null;
    this.infowindowPointer = new google.maps.InfoWindow();
    this.infowindowPointerInicial = new google.maps.InfoWindow();
    this.infowindowPointerFinal = new google.maps.InfoWindow();
    this.MarkerGeocodeSearch = null;
    this.MarkerGeocodePointer = null;
    this.MarkerGeocodePointerInicial = null;
    this.iconMarkerInicial = "https://chart.apis.google.com/chart?chst=d_map_pin_letter&chld=%E2%80%A2|0000ff";
    this.iconMarkerFinal = "https://chart.apis.google.com/chart?chst=d_map_pin_letter&chld=%E2%80%A2|ffd966";
    this.MarkerGeocodePointerFinal = null;

    this.buscarGeoCodeReversoInicial = false;
    this.buscarGeoCodeReversoFinal = false;
    this.autocomplete = null;
    this.buscarGeoCodeReverso = false;
    this.qtdMaxTransicao = 0;

    this.Markers = {};
    this.MarkersVeiculos = {};
    this.Polylines = {};

    this.PolylineSelecionada = null;
    this.CallbackConteudoInfoWindowSelecionada = null;

    this.infoWindowPolylineSelecionada = null;
    this.PolylineHighlight = null;

    this.ListPolylineHighlight = [];

    this.ListInfoWindows = [];

    this.infowindowMarker = new google.maps.InfoWindow();

    this.Poligonos = [];

    //this.Init();
}

Mapa.prototype.Init = function (usarGoogle, mapaStyle, hereMapId, hereMapCode) {
    var mSelf = this;
    this.geocoder = new google.maps.Geocoder();

    var el = document.getElementById(this.elementoId);

    if (el) {
        var centro = new google.maps.LatLng(this.lat, this.lng);
        var mapOptions = {
            zoom: 4,
            center: centro,
            keyboardShortcuts: false,
            minZoom: 4,
            gestureHandling: 'greedy',
            mapTypeControlOptions: {
                mapTypeIds: ['OSM', 'Here2',/* 'Here3', */google.maps.MapTypeId.ROADMAP, google.maps.MapTypeId.SATELLITE],
                style: google.maps.MapTypeControlStyle.HORIZONTAL_BAR
                // style: google.maps.MapTypeControlStyle.DROPDOWN_MENU,
            },
            fullscreenControl: false,
            styles: mapaStyle
        }

        this.map = new google.maps.Map(el, mapOptions);

        var osmMapTypeOptions = {
            getTileUrl: (coord, zoom) => `https://tile.openstreetmap.org/${zoom}/${coord.x}/${coord.y}.png`,
            tileSize: new google.maps.Size(256, 256),
            isPng: true,
            maxZoom: 19,
            minZoom: 0,
            name: "Open Street Map"
        };

        //var tokenMapbox = "pk.eyJ1IjoiY2Fyb2xpbmxvZyIsImEiOiJjanJjOXJ6bXkxYWVhNDRwOHduNWRwbHVjIn0.d-5QkAk1rPNfEGKyKSI3Nw";
        //var mapBoxMapTypeOptions = {
        //    getTileUrl: (coord, zoom) => `https://api.mapbox.com/styles/v1/mapbox/streets-v11/tiles/256/${zoom}/${coord.x}/${coord.y}?access_token=${tokenMapbox}`,
        //    tileSize: new google.maps.Size(256, 256),
        //    isPng: true,
        //    maxZoom: 20,
        //    minZoom: 0,
        //    name: "Mapbox"
        //};

        var hereMapsTypeOptions2 = {
            getTileUrl: (coord, zoom) => `https://2.base.maps.api.here.com/maptile/2.1/maptile/newest/pedestrian.day/${zoom}/${coord.x}/${coord.y}/256/png8?app_id=${hereMapId}&app_code=${hereMapCode}`,
            tileSize: new google.maps.Size(256, 256),
            isPng: true,
            maxZoom: 20,
            minZoom: 0,
            name: "Here"
        };

        var hereMapsTypeOptions3 = {
            getTileUrl: (coord, zoom) => `https://2.base.maps.api.here.com/maptile/2.1/maptile/newest/normal.day.transit/${zoom}/${coord.x}/${coord.y}/256/png8?app_id=${hereMapId}&app_code=${hereMapCode}`,
            tileSize: new google.maps.Size(256, 256),
            isPng: true,
            maxZoom: 20,
            minZoom: 0,
            name: "Here - Normal"
        };

        var osmMapType = new google.maps.ImageMapType(osmMapTypeOptions);
        var hereMapType2 = new google.maps.ImageMapType(hereMapsTypeOptions2);
        var hereMapType3 = new google.maps.ImageMapType(hereMapsTypeOptions3);
        //var mpaBoxMapType = new google.maps.ImageMapType(mapBoxMapTypeOptions);

        var mapLabel = this.map;
        google.maps.event.addListenerOnce(this.map, 'idle', () => resetLabel(mapLabel));

        function resetLabel(map) {
            map.mapTypes.satellite.name = 'Satélite Google Maps';
            map.mapTypes.roadmap.name = 'Google Maps';
            map.setOptions({
                'mapTypeControl': true
            });
        }

        this.map.mapTypes.set('Here2', hereMapType2);
        this.map.mapTypes.set('Here3', hereMapType3);

        this.map.mapTypes.set('OSM', osmMapType);
        //this.map.mapTypes.set('Mapbox', mpaBoxMapType);
        if (!usarGoogle)
            this.map.setMapTypeId('OSM');

        this.markerClusterer = new MarkerClusterer(
            this.map,
            [], {
            'minimumClusterSize': 10,
            'maxZoom': 10,
            'zoomOnClick': true
        }
        );

        this.PolylineHighlight = new google.maps.Polyline({
            strokeColor: "#000000",
            map: null,
            strokeWeight: 3,
            zIndex: 5,
            path: []
        });

        this.infoWindowPolylineSelecionada = new google.maps.InfoWindow();

        this.directionsDisplay.setMap(this.map);
        //this.directionsDisplay.setPanel(document.getElementById('directions-panel'));
        google.maps.event.addListener(this.map, 'click', function (event) {
            mSelf.OnMapClick(mSelf, event);
        });

        google.maps.event.addDomListener(document, "keydown", function (event) {
            mSelf.OnKeyDown(event, mSelf);
            return;
        });

        google.maps.event.addListener(this.map, 'zoom_changed', function () {
            mSelf.OnZoomChange(event, mSelf);
        });
    }
};

Mapa.prototype.OnKeyDown = function (event, mSelf) {
    if (mSelf.PolylineSelecionada != null) {
        mSelf.LimparInfoWindows();
        mSelf.NavegarPolyline(event);
    }
};

Mapa.prototype.AtivarGeoCodeReverso = function (ativo) {
    var mSelf = this;
    mSelf.buscarGeoCodeReverso = ativo;
};

Mapa.prototype.AtivarGeoCodeReversoInicial = function (ativo) {
    var mSelf = this;
    mSelf.buscarGeoCodeReversoInicial = ativo;
};

Mapa.prototype.AtivarGeoCodeReversoFinal = function (ativo) {
    var mSelf = this;
    mSelf.buscarGeoCodeReversoFinal = ativo;
};

Mapa.prototype.OnMapClick = function (mSelf, event) {
    //if (mSelf.buscarGeoCodeReverso) {

    //    mSelf.EfetuarBuscaGeoCodeReverso(event, mSelf.SetMarkerPointer, mSelf.MarkerGeocodePointer, mSelf.infowindowPointer);

    //} else if (mSelf.buscarGeoCodeReversoInicial) {

    //    mSelf.EfetuarBuscaGeoCodeReverso(event, mSelf.SetMarkerPointerInicial, mSelf.MarkerGeocodePointerInicial, mSelf.infowindowPointerInicial, mSelf.iconMarkerInicial);

    //} else if (mSelf.buscarGeoCodeReversoFinal) {

    //    mSelf.EfetuarBuscaGeoCodeReverso(event, mSelf.SetMarkerPointerFinal, mSelf.MarkerGeocodePointerFinal, mSelf.infowindowPointerFinal, mSelf.iconMarkerFinal);

    //}

    //if (mSelf.PolylineSelecionada) {
    //    mSelf.PolylineSelecionada = null;
    //    mSelf.PolylineHighlight.setPath([]);
    //    mSelf.PolylineHighlight.setMap(null);
    //    mSelf.infoWindowPolylineSelecionada.setMap(null);
    //    mSelf.infoWindowPolylineSelecionada.setContent("");
    //}

    //var ferramentaCamadas = vm.GetFerramenta("CamadasViewModel");
    //if (ferramentaCamadas) {
    //    ferramentaCamadas.Data().FecharModalDemandas();
    //}
};

Mapa.prototype.SetMarkerPointer = function (mSelf, marker) {
    mSelf.MarkerGeocodePointer = marker;
};
Mapa.prototype.SetMarkerPointerInicial = function (mSelf, marker) {
    mSelf.MarkerGeocodePointerInicial = marker;
};
Mapa.prototype.SetMarkerPointerFinal = function (mSelf, marker) {
    mSelf.MarkerGeocodePointerFinal = marker;
};

Mapa.prototype.CalcularRota = function (callBack) {
    var mSelf = this;
    if (mSelf.MarkerGeocodePointerInicial != null && mSelf.MarkerGeocodePointerFinal != null) {
        var request = {
            origin: mSelf.MarkerGeocodePointerInicial.getPosition(),
            destination: mSelf.MarkerGeocodePointerFinal.getPosition(),
            travelMode: google.maps.TravelMode.DRIVING
        };

        mSelf.directionsService.route(request, function (response, status) {
            if (status == google.maps.DirectionsStatus.OK) {
                mSelf.directionsDisplay.setMap(mSelf.map);
                mSelf.directionsDisplay.setDirections(response);
                if (callBack)
                    callBack(true);
                mSelf.buscarGeoCodeReversoInicial = false;
                mSelf.buscarGeoCodeReversoFinal = false;
                mSelf.MarkerGeocodePointerInicial.setMap(null);
                mSelf.MarkerGeocodePointerFinal.setMap(null);
            }
        });
    }
}

Mapa.prototype.EfetuarBuscaGeoCodeReverso = function (event, funcaoOnSetMarker, markerPointer, infoWindow, icone) {
    var mSelf = this;
    mSelf.geocoder.geocode({
        'latLng': event.latLng
    }, function (results, status) {
        if (status == google.maps.GeocoderStatus.OK) {
            if (results[0]) {

                if (markerPointer) {

                    if (markerPointer.getMap() == null)
                        markerPointer.setMap(mSelf.map);

                    markerPointer.setPosition(event.latLng);
                } else {
                    if (icone) {
                        markerPointer = new google.maps.Marker({
                            position: event.latLng,
                            map: mSelf.map,
                            icon: icone
                        });
                    } else {
                        markerPointer = new google.maps.Marker({
                            position: event.latLng,
                            map: mSelf.map
                        });
                    }
                }

                funcaoOnSetMarker(mSelf, markerPointer);

                infoWindow.setContent(results[0].formatted_address);
                infoWindow.open(mSelf.map, markerPointer);

                mSelf.map.setCenter(event.latLng);

                if (mSelf.map.getZoom() < 11)
                    mSelf.map.setZoom(11);

            } else {
                alert('Nenhum resultado encontrado!');
            }
        } else {
            alert("Problema encontrado no serviço do google, contate o suporte!");
        }
    });
};

Mapa.prototype.VincularAutocomplete = function (elemento, change) {
    var mSelf = this;
    mSelf.autocomplete = new google.maps.places.Autocomplete(
        (elemento), {
        types: ['geocode']
    });

    google.maps.event.addListener(mSelf.autocomplete, 'place_changed', function (evt) {
        if (change)
            change();
    });
};

Mapa.prototype.GeocodeSearch = function (busca) {
    var mSelf = this;
    if (busca) {
        mSelf.geocoder.geocode({
            'address': busca
        }, function (results, status) {
            if (status == google.maps.GeocoderStatus.OK) {
                mSelf.map.setCenter(results[0].geometry.location);
                if (mSelf.MarkerGeocodeSearch) {
                    mSelf.MarkerGeocodeSearch.setMap(mSelf.map);
                    mSelf.MarkerGeocodeSearch.setPosition(results[0].geometry.location);
                } else {
                    mSelf.MarkerGeocodeSearch = new google.maps.Marker({
                        map: mSelf.map,
                        position: results[0].geometry.location
                    });
                }
                mSelf.map.setZoom(12);
            } else {
                alert('Nenhum resultado encontrado!');
            }
        });
    }
};

Mapa.prototype.RemoveMarkerGeocodeSearch = function () {
    var mSelf = this;
    if (mSelf.MarkerGeocodeSearch)
        mSelf.MarkerGeocodeSearch.setMap(null);
};

Mapa.prototype.Resize = function (newWidth, newHeight) {
    if (this.map) {
        google.maps.event.trigger(this.map, 'resize');
    }
};

Mapa.prototype.AddMarker = function (id, lat, lng, icone, addToMap, usarCluster) {
    var newMarker = new google.maps.Marker({
        position: new google.maps.LatLng(lat, lng),
        map: addToMap == null ? this.map : (addToMap ? this.map : null),
        icon: icone
    });

    if (this.Markers[id] != null) {
        this.Markers[id].setMap(null);
        this.Markers[id] = null;
    }

    this.Markers[id] = newMarker;

    if ((usarCluster != null && usarCluster) || this.usarClusterDefault) {
        if (this.markerClusterer.existsMarker(newMarker) == -1)
            this.markerClusterer.addMarker(newMarker, true);
    }
};

Mapa.prototype.AddMarkerVeiculo = function (id, lat, lng, icone, addToMap, usarCluster, setCenter) {
    if (this.MarkersVeiculos[id] != null) {
        this.MarkersVeiculos[id].setMap(null);
        this.MarkersVeiculos[id] = null;
    }

    var position = new google.maps.LatLng(lat, lng);

    var newMarker = new google.maps.Marker({
        position: position,
        map: addToMap == null ? this.map : (addToMap ? this.map : null),
        icon: icone
    });

    if (setCenter)
        this.map.setCenter(position);

    this.MarkersVeiculos[id] = newMarker;

    if ((usarCluster != null && usarCluster) || this.usarClusterDefault) {
        if (this.markerClusterer.existsMarker(newMarker) == -1)
            this.markerClusterer.addMarker(newMarker, true);
    }
};

Mapa.prototype.RefreshCluster = function () {
    this.markerClusterer.repaint();
};

Mapa.prototype.MarkerExists = function (id) {
    return this.Markers[id] != null;
};

Mapa.prototype.MarkerVeiculoExists = function (id) {
    return this.MarkersVeiculos[id] != null;
};

Mapa.prototype.EsconderMarker = function (id, remove) {
    if (this.Markers[id] != null) {
        this.markerClusterer.removeMarker(this.Markers[id]);
        this.Markers[id].setMap(null);

        if (remove)
            this.Markers[id] = null;
    }
};

Mapa.prototype.EsconderMarkerVeiculo = function (id) {
    if (this.MarkersVeiculos[id] != null) {
        this.markerClusterer.removeMarker(this.MarkersVeiculos[id]);
        this.MarkersVeiculos[id].setMap(null);
    }
};

Mapa.prototype.ShowMarker = function (id) {
    if (this.Markers[id] != null) {
        this.markerClusterer.addMarker(this.Markers[id]);
        this.Markers[id].setMap(this.map);
    }
};

Mapa.prototype.ShowMarkerVeiculo = function (id) {
    if (this.MarkersVeiculos[id] != null) {
        this.markerClusterer.addMarker(this.MarkersVeiculos[id]);
        this.MarkersVeiculos[id].setMap(this.map);
    }
};

Mapa.prototype.ClearMarkers = function () {
    this.markerClusterer.clearMarkers();
};

Mapa.prototype.EsconderTodosMarkers = function () {
    for (var i in this.Markers) {
        this.markerClusterer.removeMarker(this.Markers[i]);
        this.Markers[i].setMap(null);
    }
};

Mapa.prototype.VoltarMarkersEscondidos = function () {
    for (var i in this.Markers) {
        if (this.Markers[i]) {
            this.markerClusterer.removeMarker(this.Markers[i]);
            this.Markers[i].setMap(this.map);
        }
    }

    this.RefreshCluster();
};

Mapa.prototype.EsconderMarkersExceto = function (id) {
    for (var i in this.Markers) {
        if (id != i) {
            this.markerClusterer.removeMarker(this.Markers[i]);
            this.Markers[i].setMap(null);
        }
    }

    if (this.Markers[id] != null) {
        this.map.setCenter(this.Markers[id].getPosition());
    }

    this.map.setZoom(11);

    this.RefreshCluster();
};

Mapa.prototype.ShowTodosMarkers = function () {
    for (var i in this.Markers) {
        this.markerClusterer.addMarker(this.Markers[i]);
        this.Markers[i].setMap(this.map);
    }
};

Mapa.prototype.AlterarPosicaoMarker = function (id, lat, lng, comTransicao) {
    if (this.Markers[id] != null && lat != null && lng != null) {
        if (comTransicao || this.VerificarConfiguracaoDeslize()) {
            this.TransitionMarker(lat, lng, this.Markers[id]);
        } else {
            this.Markers[id].setPosition(new google.maps.LatLng(lat, lng));
        }
    }
};

Mapa.prototype.TransitionMarker = function (lat, lng, marker) {
    //var posicao = [marker.getPosition().lat(), marker.getPosition().lng()];
    //var referencia = { position: [marker.getPosition().lat(), marker.getPosition().lng()], i: 0, deltaLat: (lat - marker.getPosition().lat()) / this.numDeltas, deltaLng: (lng - marker.getPosition().lng()) / this.numDeltas
    //};
    MoveMarkerSinoticoVeiculos(marker, {
        position: [marker.getPosition().lat(), marker.getPosition().lng()],
        i: 0,
        deltaLat: (lat - marker.getPosition().lat()) / this.numDeltas,
        deltaLng: (lng - marker.getPosition().lng()) / this.numDeltas
    }, this.delayTransicao, this.numDeltas);
};

function MoveMarkerSinoticoVeiculos(marker, referencia, delayTransicao, numDeltas) {
    referencia.position[0] += referencia.deltaLat;
    referencia.position[1] += referencia.deltaLng;
    //var latlng = new google.maps.LatLng(referencia.position[0], referencia.position[1]);
    marker.setPosition(new google.maps.LatLng(referencia.position[0], referencia.position[1]));
    if (referencia.i <= numDeltas) {
        referencia.i++;
        setTimeout(function () {
            MoveMarkerSinoticoVeiculos(marker, referencia, delayTransicao, numDeltas);
        }, delayTransicao);
    }
};

Mapa.prototype.Centralizar = function () {

};

Mapa.prototype.AddPolyline = function (id, latLngArray, addToMap, cor, usarSymbol, fitBounds, permitirNavegacao) {
    var pts = [];
    var latLng = null;
    var bounds = new google.maps.LatLngBounds();
    var mSelf = this;

    for (var j = 0; j < latLngArray.length; j++) {
        if (latLngArray[j].Latitude() < -90 || latLngArray[j].Latitude() > 90)
            latLng = new google.maps.LatLng(latLngArray[j].Latitude() / 1000000, latLngArray[j].Longitude() / 1000000);
        else
            latLng = new google.maps.LatLng(latLngArray[j].Latitude(), latLngArray[j].Longitude());

        latLng.InfoWindow = this.MontarInfoWindow(latLngArray[j].InfoWindow);

        pts.push(latLng);


        if (fitBounds)
            bounds.extend(latLng);
    }

    if (fitBounds) {
        this.map.fitBounds(bounds);
    }

    var icons = null;

    if (usarSymbol) {
        icons = [{
            icon: this.lineSymbolplanejamento,
            offset: '100%',
            repeat: '10px'
        }]
    }

    var newPolyline = new google.maps.Polyline({
        strokeColor: cor,
        path: pts,
        map: addToMap == null ? this.map : (addToMap ? this.map : null),
        icons: icons
    });

    if (permitirNavegacao) {
        google.maps.event.addListener(newPolyline, 'click', function (event) {
            mSelf.Selecao(event, mSelf, this, null);
        });
    }

    if (this.Polylines[id] != null) {
        this.Polylines[id].setMap(null);
        this.Polylines[id] = null;
    }

    this.Polylines[id] = newPolyline;
};

Mapa.prototype.verificarIdx = function (p, point, minor = true) {
    var path = p.getPath();
    var d = 0;
    var minD = Number.MAX_VALUE;
    var ret = -1;
    for (var i = 0; i < path.length - 1; i++) {
        var pt1 = path.getAt(i);
        var pt2 = path.getAt(i + 1);

        d = this.distanceToLine(pt1, pt2, point)

        if (minor) {
            if (d < minD) {
                minD = d;
                ret = i;
            }
        } else {
            if (d <= minD) {
                minD = d;
                ret = i;
            }
        }

    }
    return ret;
};

Mapa.prototype.buildObjectLatLng = function (copy) {
    var result = new google.maps.LatLng(copy.lat(), copy.lng());
    result.Codigo = copy.Codigo ? copy.Codigo : "CI_" + copy.lat() + ":" + copy.lng();
    result.Sequencia = copy.Sequencia;
    result.Tipo = copy.Tipo;
    result.Trecho = copy.Trecho;
    result.PossuiGeocode = copy.PossuiGeocode;
    result.TransversalInicio = copy.TransversalInicio;
    result.TransversalFim = copy.TransversalFim;
    result.Rua = copy.Rua;
    result.PacmanAtivo = copy.PacmanAtivo;
    result.Distancia = copy.Distancia;
    result.DentroSetor = copy.DentroSetor;
    result.CodigoTrecho = copy.CodigoTrecho;
    return result;
};

Mapa.prototype.distanceToLine = function (pt1, pt2, pt) {

    var deltaX = pt2.lng() - pt1.lng();
    var deltaY = pt2.lat() - pt1.lat();

    var incIntersect = (pt.lng() - pt1.lng()) * deltaX;
    incIntersect += (pt.lat() - pt1.lat()) * deltaY;

    var deltaSum = (deltaX * deltaX) + (deltaY * deltaY);
    if (deltaSum > 0)
        incIntersect /= deltaSum;
    else
        incIntersect = -1;

    if (incIntersect < 0) // A interseção ocorre fora do segmento de reta, "antes" do pt1.
        return this.kmTo(pt, pt1);
    else if (incIntersect > 1) // A interseção ocorre fora do segmento de reta, "depois" do pt2.
        return this.kmTo(pt, pt2);

    //Cálculo do ponto de interseção.
    var intersect = new google.maps.LatLng(pt1.lat() + incIntersect * deltaY, pt1.lng() + incIntersect * deltaX)
    return this.kmTo(pt, intersect);

};

Mapa.prototype.kmTo = function (pt1, pt2) {
    var e = Math,
        ra = e.PI / 180;
    var b = pt1.lat() * ra,
        c = pt2.lat() * ra,
        d = b - c;
    var g = pt1.lng() * ra - pt2.lng() * ra;
    var f = 2 * e.asin(e.sqrt(e.pow(e.sin(d / 2), 2) + e.cos(b) * e.cos(c) * e.pow(e.sin(g / 2), 2)));
    return f * 6378.137 * 1000;
};

Mapa.prototype.Selecao = function (event, mSelf, polyline, latLng, callBack) {

    if (polyline) {
        mSelf.PolylineSelecionada = polyline;
        if (callBack) {
            mSelf.CallbackConteudoInfoWindowSelecionada = callBack;
        }
        var index = null;
        if (event) {
            index = mSelf.verificarIdx(polyline, event.latLng);
        } else {
            index = mSelf.verificarIdx(polyline, latLng);
        }

        mSelf.PolylineSelecionada.indexInicial = index;
        mSelf.PolylineSelecionada.indexFinal = index + 1;
    }
    var path = mSelf.PolylineSelecionada.getPath().getArray().slice(mSelf.PolylineSelecionada.indexInicial, mSelf.PolylineSelecionada.indexFinal + 1);
    mSelf.PolylineHighlight.setPath(path);
    mSelf.PolylineHighlight.setMap(mSelf.map);
    mSelf.PontoSelecao = null;

    //var pathAux = null;

    //if (path[0] && path[1]) {
    //    var dt1 = Date.parse('1-1-2000' + ' ' + path[0].dataHora.split(' ')[1])
    //    var dt2 = Date.parse('1-1-2000' + ' ' + path[1].dataHora.split(' ')[1])
    //    if (dt1 > dt2)
    //        pathAux = path[0];
    //    else
    //        pathAux = path[1];
    //}

    //if (pathAux) {
    //    mSelf.infoWindowPolylineSelecionada.setPosition(pathAux);

    //    if (mSelf.CallbackConteudoInfoWindowSelecionada)
    //        mSelf.infoWindowPolylineSelecionada.setContent(mSelf.CallbackConteudoInfoWindowSelecionada(mSelf.PolylineSelecionada.indexInicial, mSelf.PolylineSelecionada.indexFinal));
    //    else
    //        mSelf.infoWindowPolylineSelecionada.setContent(pathAux.InfoWindow);
    //    mSelf.infoWindowPolylineSelecionada.open(mSelf.map);
    //}
};

Mapa.prototype.SelecaoPlanejamento = function (mSelf, direcao) {

    var path = mSelf.PolylineSelecionada.getPath().getArray().slice(mSelf.PolylineSelecionada.indexFinal - 1, mSelf.PolylineSelecionada.indexInicial);
    mSelf.PolylineHighlight.setPath(path);
    mSelf.PolylineHighlight.setMap(mSelf.map);

    if (direcao === "frente") var pathAux = path[path.length - 1];
    if (direcao === "tras") var pathAux = path[0];

    if (pathAux) {
        mSelf.infoWindowPolylineSelecionada.setPosition(pathAux);

        if (mSelf.CallbackConteudoInfoWindowSelecionada)
            mSelf.infoWindowPolylineSelecionada.setContent(mSelf.CallbackConteudoInfoWindowSelecionada(mSelf.PolylineSelecionada.indexInicial, mSelf.PolylineSelecionada.indexFinal));
        else
            mSelf.infoWindowPolylineSelecionada.setContent(pathAux.InfoWindow);
        mSelf.infoWindowPolylineSelecionada.open(mSelf.map);
    }
};

Mapa.prototype.SelecaoMultipla = function (polyline, latLng, criarInfoWindow, indexPonto, addClick) {

    if (polyline) {
        if (this.PolylineSelecionada == null)
            this.PolylineSelecionada = polyline;

        var index = this.verificarIdx(polyline, latLng);

        this.PolylineSelecionada.indexInicial = index;
        this.PolylineSelecionada.indexFinal = index + 1;
    }
    var path = this.PolylineSelecionada.getPath().getArray().slice(this.PolylineSelecionada.indexInicial, this.PolylineSelecionada.indexFinal + 1);

    var PolylineHighlight = new google.maps.Polyline({
        strokeColor: "#000000",
        map: null,
        strokeWeight: 3,
        zIndex: 5,
        path: path
    });

    PolylineHighlight.Id = indexPonto;

    PolylineHighlight.setMap(this.map);

    this.ListPolylineHighlight.push(PolylineHighlight);

    if (criarInfoWindow) {
        var infoWindow = new google.maps.InfoWindow();

        infoWindow.setPosition(path[0]);
        infoWindow.setContent(path[0].InfoWindow);
        infoWindow.open(this.map);
        infoWindow.Id = indexPonto;

        this.ListInfoWindows.push(infoWindow);
    }
};

Mapa.prototype.MontarInfoWindow = function (infoWindow) {
    var elemento = $("#tpl-infoWindow").html();

    elemento = elemento.replace("{DataHora}", infoWindow.DataHora());
    elemento = elemento.replace("{Velocidade}", infoWindow.Velocidade());
    elemento = elemento.replace("{Distancia}", infoWindow.Distancia());
    elemento = elemento.replace("{Tempo}", infoWindow.Duracao());

    return elemento;
}

Mapa.prototype.NavegarPolyline = function (e) {
    var mSelf = this;
    var key = e.which ? e.which : e.keyCode;
    switch (key) {
        // navegar para frente
        case 38: // seta para cima
        case 39: // seta para direita
            mSelf.navegarFrente(event.shiftKey);
            break;
        // navegar para trás
        case 37: // seta para esquerda
        case 40: // seta para baixo
            mSelf.navegarTras(event.shiftKey);
            break;
    }
};

Mapa.prototype.navegarFrente = function (multiselecao) {
    var mSelf = this;
    if (mSelf.PolylineSelecionada.indexInicial <= mSelf.PolylineSelecionada.getPath().getArray().length - 1) {
        if (mSelf.PontoSelecao == null)
            mSelf.PontoSelecao = mSelf.PolylineSelecionada.indexFinal + 1;

        var direcao;
        mSelf.PontoSelecao++;

        if (multiselecao) {
            mSelf.multiFrente = true;
            if (mSelf.multiTras) {
                if (mSelf.PolylineSelecionada.indexFinal == 0)
                    return;

                mSelf.PolylineSelecionada.indexFinal++;
                if (mSelf.PolylineSelecionada.indexInicial == mSelf.PolylineSelecionada.indexFinal)
                    mSelf.multiTras = false;
                mSelf.PontoSelecao = mSelf.PolylineSelecionada.indexFinal;
                direcao = "tras";
            } else {
                if (mSelf.PolylineSelecionada.indexInicial == mSelf.PolylineSelecionada.getPath().getArray().length - 1)
                    return;

                mSelf.PolylineSelecionada.indexInicial++;
                mSelf.PontoSelecao = mSelf.PolylineSelecionada.indexInicial;
                direcao = "frente";
            }
        } else {
            mSelf.PolylineSelecionada.indexInicial = mSelf.PontoSelecao;
            mSelf.PolylineSelecionada.indexFinal = mSelf.PontoSelecao - 1;
            mSelf.multiFrente = false;
            mSelf.multiTras = false;
            direcao = "frente";
        }
        mSelf.SelecaoPlanejamento(mSelf, direcao);
    }
};

Mapa.prototype.navegarTras = function (multiselecao) {
    var mSelf = this;
    if (mSelf.PolylineSelecionada.indexFinal > 1) {
        if (mSelf.PontoSelecao == null)
            mSelf.PontoSelecao = mSelf.PolylineSelecionada.indexInicial;

        var direcao;
        mSelf.PontoSelecao--;

        if (multiselecao) {
            mSelf.multiTras = true;
            if (mSelf.multiFrente) {
                if (mSelf.PolylineSelecionada.indexInicial == mSelf.PolylineSelecionada.getPath().getArray().length - 1)
                    return;

                mSelf.PolylineSelecionada.indexInicial--;
                if (mSelf.PolylineSelecionada.indexInicial == mSelf.PolylineSelecionada.indexFinal)
                    mSelf.multiFrente = false;
                direcao = "frente";
                mSelf.PontoSelecao = mSelf.PolylineSelecionada.indexInicial;
            } else {
                if (mSelf.PolylineSelecionada.indexFinal == 0)
                    return;

                mSelf.PolylineSelecionada.indexFinal--;
                mSelf.PontoSelecao = mSelf.PolylineSelecionada.indexFinal;
                direcao = "tras";
            }
        } else {
            mSelf.PolylineSelecionada.indexInicial = mSelf.PontoSelecao + 1;
            mSelf.PolylineSelecionada.indexFinal = mSelf.PontoSelecao;
            mSelf.multiTras = false;
            mSelf.multiFrente = false;
            direcao = "tras";
        }
        mSelf.SelecaoPlanejamento(mSelf, direcao);
    }
};


Mapa.prototype.EsconderPolyline = function (id) {
    for (var i in this.Polylines) {
        if (id != i) {
            this.Polylines[i].setMap(null);
        }
    }
};

Mapa.prototype.AlterarConfiguracoesMarkers = function (isZoom, qtdMarkers, zoomMarkers, qtdDeslize) {

    this.markerClusterer.zoomOnClick_ = isZoom;

    this.markerClusterer.minClusterSize_ = qtdMarkers;

    this.markerClusterer.maxZoom_ = zoomMarkers;

    //Seta a quantidade definida pelo usuário para que haja transição entre os markers.
    this.qtdMaxTransicao = qtdDeslize;
};

Mapa.prototype.VerificarConfiguracaoDeslize = function () {

    if (this.markerClusterer && this.markerClusterer.getMarkers().length > 0)
        return this.markerClusterer.getMarkers().length <= this.qtdMaxTransicao;

    return false;
};

Mapa.prototype.EsconderPolylinePorId = function (id) {
    if (this.Polylines[id] != null) {
        this.Polylines[id].setMap(null);
    }
};

Mapa.prototype.MudarIcone = function (id, icone) {

    if (this.Markers && this.Markers[id]) {

        if (icone != this.Markers[id].getIcon()) {

            this.Markers[id].setIcon(icone);

            return true;
        }
    }

    return false;
};

Mapa.prototype.GetQuantidadeMarkers = function () {

    if (this.markerClusterer)
        return this.markerClusterer.getMarkers().length;

    return 0;
};

Mapa.prototype.LimparComponentes = function () {

    if (this.PolylineSelecionada) {
        this.PolylineSelecionada = null;
    }

    this.infoWindowPolylineSelecionada.setMap(null);
    this.infoWindowPolylineSelecionada.setContent("");

    if (this.PolylineHighlight) {
        this.PolylineHighlight.setMap(null);
        this.PolylineHighlight.setPath([]);
    }

    for (var x in this.ListPolylineHighlight) {
        this.ListPolylineHighlight[x].setMap(null);
    }
    this.ListPolylineHighlight = [];

    this.LimparInfoWindows();
};

Mapa.prototype.LimparInfoWindows = function () {
    for (var i in this.ListInfoWindows) {
        this.ListInfoWindows[i].setMap(null);
    }
    this.ListInfoWindows = [];
}

Mapa.prototype.AbrirInfoWindowMarker = function (id, html, focarZoom) {

    this.infowindowMarker.setMap(null);

    if (this.Markers && this.Markers[id]) {

        this.infowindowMarker.setContent(html);

        this.infowindowMarker.open(this.map, this.Markers[id]);

        if (focarZoom) {
            this.map.panTo(this.Markers[id].position);
            this.map.setZoom(19);
        }
    }
};

Mapa.prototype.OnClickMarker = function (id, handler, data) {

    if (this.Markers && this.Markers[id])
        google.maps.event.addListener(this.Markers[id], 'click', function (event) {
            handler.SetarEventoClickMarker(data);
        });
};

Mapa.prototype.OnClickMarkerVeiculos = function (id, handler, data) {

    if (this.MarkersVeiculos && this.MarkersVeiculos[id]) {
        var marker = this.MarkersVeiculos[id];
        google.maps.event.addListener(this.MarkersVeiculos[id], 'click', function (event) {
            handler.SetarEventoClickMarkerVeiculo(data, marker);
        });
    }
};

Mapa.prototype.LimparBuscaSearchPontos = function () {
    var mSelf = this;
    if (mSelf.MarkerGeocodePointer) {
        mSelf.MarkerGeocodePointer.setMap(null);
        mSelf.MarkerGeocodePointer = null;
    }

    if (mSelf.MarkerGeocodePointerInicial) {
        mSelf.MarkerGeocodePointerInicial.setMap(null);
        mSelf.MarkerGeocodePointerInicial = null;
    }

    if (mSelf.MarkerGeocodePointerFinal) {
        mSelf.MarkerGeocodePointerFinal.setMap(null);
        mSelf.MarkerGeocodePointerFinal = null;
    }

    if (mSelf.infowindowPointerInicial) {
        mSelf.infowindowPointerInicial.setMap(null);
    }

    if (mSelf.infowindowPointerFinal) {
        mSelf.infowindowPointerFinal.setMap(null);
    }


    if (mSelf.MarkerGeocodeSearch) {
        mSelf.MarkerGeocodeSearch.setMap(null);
    }

    mSelf.directionsDisplay.setMap(null);

};

Mapa.prototype.AtualizarConteudoInfoWindowMarker = function (id, html) {

    if (this.Markers && this.Markers[id]) {

        if (this.infowindowMarker.getMap() != null) {

            if (this.Markers[id].position == this.infowindowMarker.getAnchor().position) {

                if (html != this.infowindowMarker.getContent()) {

                    this.infowindowMarker.setContent(html);

                    return true;
                }
            }
        }
    }

    return false;
};

Mapa.prototype.DeslocarMapaPosicaoMarker = function (id) {

    if (this.Markers && this.Markers[id])
        this.map.panTo(this.Markers[id].position);
};

Mapa.prototype.MarkersVisiveis = function () {
    var lista = 0;
    for (var i in this.Markers)
        if (this.Markers[i].getMap() != null)
            lista++;

    return lista;
};

Mapa.prototype.BuscaReferenciaCidade = function (cidade) {
    var mSelf = this;

    this.geocoder.geocode({
        'address': cidade
    }, function (results, status) {
        if (status == google.maps.GeocoderStatus.OK) {
            mSelf.map.setCenter(results[0].geometry.location);
            mSelf.map.setZoom(12);
        } else {
            alert('Nenhum resultado encontrado!');
        }
    });
};

//adiciona uma polilinha sem navegação e sem infowindow
Mapa.prototype.AddPolylineSimple = function (id, latLngArray) {
    var pts = [];
    var latLng = null;
    var bounds = new google.maps.LatLngBounds();
    var mSelf = this;

    for (var j = 0; j < latLngArray.length; j++) {
        if (latLngArray[j].Latitude() < -90 || latLngArray[j].Latitude() > 90)
            latLng = new google.maps.LatLng(latLngArray[j].Latitude() / 1000000, latLngArray[j].Longitude() / 1000000);
        else
            latLng = new google.maps.LatLng(latLngArray[j].Latitude(), latLngArray[j].Longitude());

        pts.push(latLng);

        bounds.extend(latLng);
    }

    this.map.fitBounds(bounds);

    var newPolyline = new google.maps.Polyline({
        //strokeColor: cor,
        path: pts,
        map: this.map
    });

    if (this.Polylines[id] != null) {
        this.Polylines[id].setMap(null);
        this.Polylines[id] = null;
    }

    this.Polylines[id] = newPolyline;
};

Mapa.prototype.OnZoomChange = function (mSelf, event) {
    //var ferramentaCamadas = vm.GetFerramenta("CamadasViewModel");
    //if (ferramentaCamadas) {
    //    ferramentaCamadas.Data().PlotarOverlays(event.map.getZoom() >= 14);
    //}
};

Mapa.prototype.AlteraCorBordasPoligonos = function (formaSelecionada) {

    var poligonos = this.Poligonos;

    poligonos.forEach(function (poligono) {
        poligono.setOptions({
            strokeColor: poligono.fillColor
        });
    });

    formaSelecionada.setOptions({
        strokeColor: '#000000'
    });
};
