function ModuloSetoresMapa(mapa, detalhes) {
    var mSelf = this;

    mSelf.Mapa = mapa;

    mSelf.Data = ko.observable("");

    mSelf.UrlIconPadrao = urlGlobal + "SetoresShape/SourceShape/CarregarImgVeiculoPorTipo";

    mSelf.InfoWindowSelecionado = null;

    mSelf.MarkersTempoReal = [];

    mSelf.Init = function () {
        mSelf.CarregarShapeSetores();
        $(".loading-div").hide();
    };

    mSelf.CarregarShapeSetores = function () {
        $.ajax({
            url: urlGlobal + "SetoresShape/SetoresShape/CarregarSetoresShape",
            contentType: 'application/json; charset=utf-8',
            dataType: "json",
            type: "GET",
            success: function (data) {
                if (data) {
                    mSelf.Data(data);
                    mSelf.PlotarSetores();
                }
            },
            complete: function () {
            }
        });
    };

    mSelf.SetoresPlotados = {};

    mSelf.PlotarSetores = function () {
        var count = 0;
        ko.utils.arrayForEach(mSelf.Data(), function (setor) {
            mSelf.SetoresPlotados[setor.Codigo] = new PlanejamentoSetor(setor, mSelf.Mapa.map, mSelf, count);
            count++;
        });
    };

    mSelf.RecarregarSetores = function () {
        for (var s in mSelf.SetoresPlotados) {
            mSelf.SetoresPlotados[s].SetMap(null);
            mSelf.SetoresPlotados[s].CentroOriginal = null;
            mSelf.SetoresPlotados[s].PoligonoGeral = null;
            google.maps.event.removeListener(mSelf.SetoresPlotados[s].listener);
        }
        mSelf.SetoresPlotados = {};
        mSelf.PlotarSetores();
    };

    mSelf.ViewModel = ko.observable({});

    mSelf.SetarEventoClickCluster = function (latLong, veiculos, cluster) {
        mSelf.ListaVeiculos = ko.observableArray([]);

        var grid = vm.GetModulo("GridSetoresShapeViewModel");

        ko.utils.arrayForEach(veiculos, function (item) {
            var codigo = item.id;

            var veiculo = ko.utils.arrayFirst(grid.Data().grid.Data(), function (valor) {
                return valor.CodigoVeiculo() == codigo;
            });

            if (veiculo != null)
                mSelf.ListaVeiculos.push({
                    Tipo: veiculo.TipoVeiculo(),
                    Descricao: veiculo.Descricao(),
                    Identificador: veiculo.Identificador(),
                    Velocidade: (veiculo.Velocidade() > 0),
                    Ignicao: veiculo.StatusIgnicao(),
                    Codigo: veiculo.CodigoVeiculo()
                });
        });

        var indexCluster = mSelf.Mapa.markerClusterer.clusters_.indexOf(cluster);

        //View Model com dados para infoWindow
        mSelf.ViewModel(ko.mapping.fromJS({
            ListaVeiculos: mSelf.ListaVeiculos(),
            IndexCluster: indexCluster
        }));

        var $elemento = $("<div>" + $("#template-iw-cluster").html() + "</div>");

        ko.applyBindings(mSelf.ViewModel, $elemento[0]);

        mSelf.OpenInfoWindowCluster(latLong, $elemento.html());
    };

    mSelf.OpenInfoWindowCluster = function (latLong, html, cluster) {
        if (mSelf.InfoWindow == null)
            mSelf.InfoWindow = new google.maps.InfoWindow();

        mSelf.InfoWindow.setContent(html);
        mSelf.InfoWindow.setPosition(latLong);
        mSelf.InfoWindow.open(mSelf.Mapa.map, cluster);
    };

    mSelf.InitGridSetoresShape = function () {

        var grid = vm.GetModulo("GridSetoresShapeViewModel");

        if (grid == null && grid.Data().grid.Data == null)
            return;

        ko.utils.arrayForEach(grid.Data().grid.Data(), function (item) {

            if (item.Latitude() != null && item.Longitude() != null) {

                var iconUrl = mSelf.alterarIconeMarker(item);

                mSelf.Mapa.AddMarker(item.CodigoVeiculo(), item.Latitude() / 1000000, item.Longitude() / 1000000, iconUrl, true, true);
                mSelf.Mapa.OnClickMarker(item.CodigoVeiculo(), mSelf, item);

                //mSelf.ItensPlotados++;

                iconUrl = null;
            }
        });

        mSelf.Mapa.RefreshCluster();
    };

    mSelf.alterarIconeMarker = function (veiculo) {

        var iconUrl = mSelf.UrlIconPadrao;

        iconUrl += "?codigoTipo=" + veiculo.TipoVeiculo();

        iconUrl += "&porcentagem=";

        iconUrl += "&temVelocidade=" + (veiculo.Velocidade() > 0);

        iconUrl += "&statusIgnicao=" + veiculo.StatusIgnicao();

        iconUrl += "&label=" + veiculo.Identificador();

        return iconUrl;
    };

    mSelf.OpenInfoWindow = function (marker, html) {
        if (mSelf.InfoWindow == null)
            mSelf.InfoWindow = new google.maps.InfoWindow();

        mSelf.InfoWindow.setContent(html);
        mSelf.InfoWindow.open(mSelf.Mapa.map, marker);

        google.maps.event.addListener(mSelf.InfoWindow, 'closeclick', function () {
            mSelf.InfoWindowSelecionado = null;
        });
    };

    mSelf.PlotarVeiculoDetalhes = function (veiculo) {
        var icon = urlGlobal + 'SetoresShape/SourceShape/CarregarImgVeiculoPorTipo?codigoTipo=' + veiculo.TipoVeiculo() +
            '&porcentagem=70&temVelocidade=' + (veiculo.Velocidade() > 0) + '&statusIgnicao=' + veiculo.StatusIgnicao() + '&label=' + veiculo.Identificador()

        mSelf.Mapa.AddMarker(veiculo.CodigoVeiculo(), veiculo.Latitude() / 1000000, veiculo.Longitude() / 1000000, icon, true, true);
        mSelf.Mapa.OnClickMarker(veiculo.CodigoVeiculo(), mSelf, veiculo);
    };

    mSelf.SetarEventoClickMarker = function (data) {
        //View Model com dados para infoWindow
        mSelf.ViewModel(ko.mapping.fromJS({
            Codigo: data.CodigoVeiculo,
            DataHora: data.DataHoraUltimoPeriodico,
            Descricao: data.Descricao,
            Identificador: data.Identificador,
            Placa: data.Placa,
            Velocidade: data.Velocidade() + "Km/h",
            TempoParado: data.TempoParado
        }));

        var $elemento = $("<div>" + $("#template-info-window-veiculo").html() + "</div>");

        ko.applyBindings(mSelf.ViewModel, $elemento[0]);

        mSelf.InfoWindowSelecionado = data;

        var grid = vm.GetModulo("GridSetoresShapeViewModel");
        if (grid) {
            var veiculo = ko.utils.arrayFirst(grid.Data().GridInlog.DataFiltrado(), function (item) {
                return item.CodigoVeiculo() == data.CodigoVeiculo();
            });
            var index = grid.Data().GridInlog.DataFiltrado().indexOf(veiculo);
            grid.Data().GridInlog.grid.scrollRowIntoView(index);
            grid.Data().GridInlog.SelecionarGrid(index);
            grid.Data().GridInlog.DataSelecionado(veiculo);
        }

        mSelf.OpenInfoWindow(mSelf.Mapa.Markers[data.CodigoVeiculo()], $elemento.html());
    };

    mSelf.AtualizarInfoWindow = function (data) {
        if (mSelf.InfoWindowSelecionado != null //&& mSelf.InfoWindow.isOpen()
            && mSelf.InfoWindowSelecionado.CodigoVeiculo() == data.CodigoVeiculo) {

            mSelf.ViewModel(ko.mapping.fromJS({
                Codigo: mSelf.InfoWindowSelecionado.CodigoVeiculo,
                DataHora: data.DisplayUltimoPeriodico ? data.DisplayUltimoPeriodico : mSelf.InfoWindowSelecionado.DataHoraUltimoPeriodico,
                Descricao: mSelf.InfoWindowSelecionado.Descricao,
                Identificador: mSelf.InfoWindowSelecionado.Identificador,
                Placa: mSelf.InfoWindowSelecionado.Placa,
                Velocidade: data.Velocidade ? (ko.isObservable(data.Velocidade) ? data.Velocidade() : data.Velocidade) + "Km/h" : mSelf.InfoWindowSelecionado.Velocidade() + "Km/h",
                TempoParado: data.TempoParado ? data.TempoParado : mSelf.InfoWindowSelecionado.TempoParado
            }));

            ko.applyBindings(mSelf.ViewModel, $("#infoOpen")[0]);
        }
    };

    mSelf.PlotarPosicaoTempoReal = function (posicao, cor) {
        var marker = new google.maps.Marker({
            position: new google.maps.LatLng(posicao.Lat / 1000000, posicao.Lon / 1000000),
            map: mSelf.Mapa.map,
            icon: {
                path: google.maps.SymbolPath.CIRCLE,
                fillColor: cor,
                strokeColor: cor,
                scale: 4,
                strokeWeight: 1,
                fillOpacity: 0.8
            },
        });

        mSelf.MarkersTempoReal.push(marker);

        google.maps.event.addListener(marker, 'click', function (event) {
            mSelf.EventoClickMarkerTempoReal(posicao, this);
        });
    };

    mSelf.EventoClickMarkerTempoReal = function (data, marker) {
        //View Model com dados para infoWindow
        mSelf.ViewModel(ko.mapping.fromJS({
            Codigo: data.CodigoVeiculo,
            DataHora: data.DataHoraDisplay,
            Velocidade: data.Velocidade + "Km/h",
        }));

        var $elemento = $("<div>" + $("#template-info-window-tempo-real").html() + "</div>");

        ko.applyBindings(mSelf.ViewModel, $elemento[0]);

        mSelf.OpenInfoWindow(marker, $elemento.html());
    };
}

function DesagruparCluster() {
    var index = $(event.target).attr('index');
    var mapa = vm.Perspectiva.SetoresMapa;
    var cluster = mapa.Mapa.markerClusterer.clusters_[index];
    var markerClusterer = cluster.getMarkerClusterer();

    // Trigger the clusterclick event.
    google.maps.event.trigger(markerClusterer, 'clusterclick', cluster);

    if (markerClusterer.isZoomOnClick()) {
        // Zoom into the cluster.
        mapa.Mapa.map.fitBounds(cluster.getBounds());
    }
    mapa.InfoWindow.setMap(null);
};