Source: directives/mapa/mapa.service.js

(function () {
    'use strict';

    angular.module('s4c.components.mapa')
        .service('MapaService', MapaService);

    MapaService.$inject = [
        '$q',
        'localize',
        'API_ENDPOINT',
        '$mdDialog',
        'MainState'
    ];

    /**
     * @ngdoc directives
     * @name MapaService
     * @module s4c.directives.mapa.MapaService
     *
     * @description
     * `MapaService` Componente responsável pela comunicação entre o backend e frontend.
     */
    function MapaService($q, localize, API_ENDPOINT, $mdDialog, MainState) {

        var service = {
            incidentesFilters: {
                prioridades: [0],
                criticidades: [5],
                categorias: []
            },
            adicionarPonto: adicionarPonto,
            adicionarPontos: adicionarPontos,
            removerCamada: removerCamada,
            removerCamadaAcervo: removerCamadaAcervo,
            removerCamadaCategoria: removerCamadaCategoria,
            possuiLayer: possuiLayer,
            adicionarGeoJSON: adicionarGeoJSON,
            updateClick: updateClick,
            obterPontoCentral: obterPontoCentral,
            obterHtmlIcon: obterHtmlIcon,
            updateIconeIncidente: updateIconeIncidente,
            updateLayer: updateLayer,
            updateIncidentesRelacionados: updateIncidentesRelacionados,
            ativarCamadaPlanejamento: ativarCamadaPlanejamento,
            voarPara: voarPara,
            adicionarLayer: adicionarLayer,
            clickPoi: clickPoi,
            adicionarGeometria: adicionarGeometria,
            clearMarkerCluster: clearMarkerCluster,
            clearAllMarkerCluster: clearAllMarkerCluster,
            fitBounds: fitBounds,
            setView: setView,
            highlightFeature: highlightFeature,
            addMarker: addMarker,
            addLayer: addLayer,
            clearZoomEvents: clearZoomEvents,
            zoomOff: zoomOff,
            zoomOn: zoomOn,
            removerDesenho: removerDesenho,
            dataminingViewport: dataminingViewport,
            draw: draw,
            pegarZoom: pegarZoom,
            addMap: addMap,
            removeMap: removeMap,
            removerLinhas: removerLinhas,
            drawCameraLines: drawCameraLines,
            showCameras: showCameras,
            piscarAzul: piscarAzul,
            piscarVermelho: piscarVermelho,
            obterRotaAtiva: obterRotaAtiva,
            removerRotasUnificadasDoMapa: removerRotasUnificadasDoMapa,
            obterRotaUnificadaAtiva: obterRotaUnificadaAtiva,
            desenharRotaUnificadaKml: desenharRotaUnificadaKml,
            desenharTrajetoRotaUnificadaKml: desenharTrajetoRotaUnificadaKml,
            desenharRegioes: desenharRegioes,
            removerLayers: removerLayers,
            enquadrarPoisRelacionados: enquadrarPoisRelacionados,
            desenharCirculosPois: desenharCirculosPois,
            pingLayer: pingLayer,
            removerRouter: removerRouter,
            removerDesenhoPlanejamento: removerDesenhoPlanejamento,
            removerControleDesenho: removerControleDesenho,
            removerPontosPlanejamento: removerPontosPlanejamento,
            planejar: planejar,
            pegarGeometrias: pegarGeometrias,
            removerPoiClicado: removerPoiClicado,
            flyTo: flyTo,
            gridResized: gridResized,
            changeClass: changeClass,
            destacarSubItem: destacarSubItem,
            colocarIcon: colocarIcon,
            adicionarSubItem: adicionarSubItem,
            resetarDetalhamento: resetarDetalhamento,
            removerRouterRotaUnificada: removerRouterRotaUnificada,
            ativarCamada: ativarCamada,
            desativarCamada: desativarCamada,
            ativarKml: ativarKml,
            desenharPoligono: desenharPoligono,
            removerRotasDesenhadas: removerRotasDesenhadas,
            ativarBaseConhecimento: ativarBaseConhecimento,
            desativarBaseConhecimento: desativarBaseConhecimento,
            ativarCategoria: ativarCategoria,
            desativarCategoria: desativarCategoria,
            twitterFlyTo: twitterFlyTo,
            adicionarTweets: adicionarTweets,
            blueFlyTo: blueFlyTo,
            definirCorDaLinha: definirCorDaLinha,
            naoPiscar: naoPiscar,
            desenharPontoMovel: desenharPontoMovel,
            desenharERs: desenharERs,
            desenharPercursoER: desenharPercursoER,
            atualizarPosicaoPontoMovel: atualizarPosicaoPontoMovel,
            removerCirculosPois: removerCirculosPois,
            desenharRaioTwitter: desenharRaioTwitter,
            reloadBaseConhecimento: reloadBaseConhecimento,
            limparTweetsAtivos: limparTweetsAtivos,
            removerRaioTwitter: removerRaioTwitter,
            limparSubItem: limparSubItem,
            desenharPoligonoRotaUnficada: desenharPoligonoRotaUnficada,
            adicionarLinha: adicionarLinha,
            desenharRotaUnificada: desenharRotaUnificada,
            removerPontoRotaUnificada: removerPontoRotaUnificada,
            removerDesenhosZonaObservacao: removerDesenhosZonaObservacao,
            removerZonaObservacao: removerZonaObservacao,
            desenharFromJSON: desenharFromJSON,
            ativarShapeFile: ativarShapeFile,
            obterMapaAtivo: obterMapaAtivo,
            refreshMap: refreshMap

        };

        var mapList = [];


        /**
         * Adiciona o mapa na lista de mapas 
         * 
         * @method addMap
         * 
         * @param map {Object}
         * 
         */    
        function addMap(map) {
            mapList.push(map);
        }

        /**
         * Retorna o mapa ativo 
         * 
         * @method obterMapaAtivo
         * 
         * @returns map {Object}
         * 
         */            
        function obterMapaAtivo() {
            if (mapList != null && mapList.length >= 0) {
                return mapList[0];
            }
        }

       /**
         * Adiciona no mapa os dados do Shape File importado   
         * 
         * @method ativarShapeFile
         * 
         * @param obj
         * @param camada
         * @param cb
         * 
         */           
        function ativarShapeFile(obj, camada, cb) {
            angular.forEach(mapList, function (map) {
                map.ativarShapeFile(obj, camada, cb);
            });
        }

/**
         * Atualiza a centralização do mapa
         * 
         * @method refreshMap
         * 
         * 
         */           
        function refreshMap() {
            angular.forEach(mapList, function (map) {
                map.refreshMap();
            });
        }

        //Main map
        /**
         * Remove os pontos das rotas do mapa
         * 
         * @method removerPontoRotaUnificada
         * 
         * @param ponto {ponto}
         * 
         */               
        function removerPontoRotaUnificada(index) {
            angular.forEach(mapList, function (map) {
                map.removerPontoRotaUnificada(index);
            });
        }

        /**
         * Remove do mapa a camada de Zona de Observação   
         * 
         * @method removerZonaObservacao
         * 
         * 
         * 
         */  
        function removerZonaObservacao() {
            angular.forEach(mapList, function (map) {
                map.removerZonaObservacao();
            });
        }
        /**
         * Faz o desenho da geometria contido no GeoJson e inclui no mapa
         * 
         * @method desenharFromJSON
         * 
         * @param geojson {Json}
         * @param alarmeData {Object}
         * 
         */
        function desenharFromJSON(geojson, alarme) {
            angular.forEach(mapList, function (map) {
                map.desenharFromJSON(geojson, alarme);
            });
        }
        /**
         * Remove do mapa os desenhos de Zona de Observação   
         * 
         * @method removerDesenhosZonaObservacao
         * 
         * 
         * 
         */ 
        function removerDesenhosZonaObservacao() {
            angular.forEach(mapList, function (map) {
                map.removerDesenhosZonaObservacao();
            });
        }

        //Main map
        /**
         * Adiciona no mapa uma nova rota default
         * 
         * @method desenharRota
         * 
         * 
         */         
        function desenharRotaUnificada(pontos) {
            angular.forEach(mapList, function (map) {
                map.desenharRotaUnificada(pontos);
            });
        }

        //Main map
         /**
         * Configuração dos trechos das rotas que são desenhados no mapa
         * 
         * @method desenharPoligonoRotaUnficada
         * 
         * @param rota {Object}
         * 
         */       
        function desenharPoligonoRotaUnficada(data) {
            angular.forEach(mapList, function (map) {
                map.desenharPoligonoRotaUnficada(data);
            });
        }

        /**
         * Recebe dois arrays de latLng
         * calcula a distância entre eles e adiciona
         * uma linha entre eles no mapa, retornando uma
         * Promise que resolve com o polyline adicionado no mapa.
         * 
         * @method adicionarLinha
         * 
         * @param x {Object}
         * @param y {Object}
         * @param type {Object} 
         * 
         * @returns Promise que resolve com o polyline adicionado no mapa
         */         
        function adicionarLinha(x, y) {
            angular.forEach(mapList, function (map) {
                map.adicionarLinha(x, y).then(function (polyline) {
                    MainState.getManager('SubDetalhamentoManager').camerasMarcadas.addLayer(polyline);
                });
            });
        }

        /**
         * Limpa o detalhamento do subItem de um Item aberto no mapa
         * 
         * @method limparSubItem
         * 
         * 
         */         
        function limparSubItem() {
            angular.forEach(mapList, function (map) {
                map.limparSubItem();
            });
        }
        /**
         * Remove os tweets do mapa
         * 
         * @method limparTweetsAtivos
         * 
         */ 
        function limparTweetsAtivos() {
            angular.forEach(mapList, function (map) {
                map.limparTweetsAtivos();
            });
        }
        /**
         * Remove o raio ao redor da localização do Twitter
         * 
         * @method desenharRaioTwitter
         * 
         * 
         */ 
        function removerRaioTwitter() {
            angular.forEach(mapList, function (map) {
                map.removerRaioTwitter();
            });
        }
        /**
         * Atualiza a camada de Base de Conhecimento
         * 
         * @method reloadBaseConhecimento
         * 
         * 
         */ 
        function reloadBaseConhecimento() {
            angular.forEach(mapList, function (map) {
                map.reloadBaseConhecimento();
            });
        }

       /**
         * Remove o desenho de geometria circular ao redor do Poi
         * 
         * @method removerCirculosPois
         * 
         * @param arrayCircles {Object}
         * @param categoriaId {Object}
         * 
         */  
        function removerCirculosPois(arrayCircles, categoriaId) {
            angular.forEach(mapList, function (map) {
                map.removerCirculosPois(arrayCircles, categoriaId);
            });
        }

        /**
         * Desenha um raio ao redor da localização do Twitter
         * 
         * @method desenharRaioTwitter
         * 
         * 
         */  
        function desenharRaioTwitter(texto) {
            angular.forEach(mapList, function (map) {
                map.desenharRaioTwitter(texto);
            });
        }
        /**
         * Cria uma movimentação animada para mostrar no mapa a nova posição do Ponto Móvel
         * 
         * @method atualizarPosicaoPontoMovel
         * 
         * @param erInfo {Object}
         * 
         */     
        function atualizarPosicaoPontoMovel(erInfo) {
            angular.forEach(mapList, function (map) {
                map.atualizarPosicaoPontoMovel(erInfo);
            });
        }

        /**
         * Desenha a geometria do percursso feito pelo dispositivo de rastreamento
         * 
         * @method desenharPercursoER
         * 
         * @param listHistoricoPosicoesER {Object}
         * @param posicaoAtualER {Object}
         * @param pontoMovel {Object}
         * 
         */
        function desenharPercursoER(listHistoricoPosicoesER, posicaoAtualER, pontoMovel) {
            angular.forEach(mapList, function (map) {
                map.desenharPercursoER(listHistoricoPosicoesER, posicaoAtualER, pontoMovel);
            });
        }

        /**
         * Desenha a geometria dos dispositivos de rastreamento para adicionar no mapa
         * 
         * @method desenharERs
         * 
         * @param listERInfo {Object}
         * @param posicaoAtualER {Object}
         * @param pontoMovel {Object}
         * 
         */  
        function desenharERs(listERInfo, posicaoAtualER, pontoMovel) {
            angular.forEach(mapList, function (map) {
                map.desenharERs(listERInfo, posicaoAtualER, pontoMovel);
            });
        }
        /**
         * Desenha a geometria do Ponto Móvel para adicionar no mapa
         * 
         * @method desenharPontoMovel
         * 
         * @param pontoMovel {Object}
         * @param ponto {Object}
         * 
         */ 
        function desenharPontoMovel(pontoMovel, ponto) {
            angular.forEach(mapList, function (map) {
                map.desenharPontoMovel(pontoMovel, ponto);
            });
        }
        /**
         * Faz o mapa voar para uma coordenada específica e ficar piscando na cor azul
         * 
         * @method blueFlyTo
         * 
         * @param geo {Object}
         * @param camera {Object}
         * 
         */ 
        function blueFlyTo(coords) {
            angular.forEach(mapList, function (map) {
                map.blueFlyTo(coords);
            });
        }
        /**
         *  Faz o objeto nas coordenadas recebidas parar de piscar
         * 
         * @method naoPiscar
         * 
         * 
         */ 
        function naoPiscar() {
            angular.forEach(mapList, function (map) {
                map.naoPiscar();
            });
        }
        /**
         * Define a cor da linha dos desenhos das geometrias do mapa
         * 
         * @method definirCorDaLinha
         * 
         * @param cor {String}
         * 
         */  
        function definirCorDaLinha(cor) {
            angular.forEach(mapList, function (map) {
                map.definirCorDaLinha(cor);
            });
        }
        /**
         * Atualiza a camada de tweets
         * 
         * @method adicionarTweets
         * 
         * @param tweets {Object}
         * 
         */ 
        function adicionarTweets(tweets) {
            angular.forEach(mapList, function (map) {
                map.adicionarTweets(tweets);
            });
        }
        /**
         * Animação para exibição do tweet
         * 
         * @method twitterFlyTo
         * 
         * @param tweet {Object}
         * 
         */ 
        function twitterFlyTo(tweet) {
            angular.forEach(mapList, function (map) {
                map.twitterFlyTo(tweet);
            });
        }

        /**
         * Desativa a camada de Categoria do Mapa
         * 
         * @method desativarCategoria
         * 
         * @param categoria {Object}
         * 
         */
        function desativarCategoria(categoria) {
            angular.forEach(mapList, function (map) {
                map.desativarCategoria(categoria);
            });
        }
        /**
         * Ativa a camada de Categoria do Mapa
         * 
         * @method desativarCategoria
         * 
         * @param categoria {Object}
         * 
         */
        function ativarCategoria(categoria) {
            angular.forEach(mapList, function (map) {
                map.ativarCategoria(categoria);
            });
        }
         /**
         * Desativa a camada de Base de Conhecimento do Mapa
         * 
         * @method desativarBaseConhecimento
         * 
         * 
         */
        function desativarBaseConhecimento() {
            angular.forEach(mapList, function (map) {
                map.desativarBaseConhecimento();
            });
        }
        /**
         * Ativa a camada de Base de Conhecimento do Mapa
         * 
         * @method ativarBaseConhecimento
         * 
         * @param geojson {Object}
         * 
         */
        function ativarBaseConhecimento(geojson) {
            angular.forEach(mapList, function (map) {
                map.ativarBaseConhecimento(geojson);
            });
        }
        /**
         * Configuração dos trechos das rotas que são desenhados no mapa
         * 
         * @method desenharPoligono
         * 
         * @param rota {Object}
         * 
         */   
        function desenharPoligono(data) {
            angular.forEach(mapList, function (map) {
                map.desenharPoligono(data);
            });
        }
        /**
         * Remove os desenhos das rotas do mapa
         * 
         * @method removerRotasDesenhadas
         * 
         * 
         */  
        function removerRotasDesenhadas() {
            angular.forEach(mapList, function (map) {
                map.removerRotasDesenhadas();
            });
        }
        /**
         * Desativa uma camada de um planejamento
         * 
         * @method desativarCamada
         * 
         * @param obj {Object}
         * @param camada {Object}
         * 
         */ 
        function desativarCamada(obj, camada) {
            angular.forEach(mapList, function (map) {
                map.desativarCamada(obj, camada);
            });
        }
         /**
         * Adiciona no mapa os dados do kml importado   
         * 
         * @method ativarKml
         * 
         * @param url {String}
         * @param cb {Object}
         * 
         */ 
        function ativarKml(obj, cb) {
            angular.forEach(mapList, function (map) {
                map.ativarKml(obj, cb);
            });
        }
        /**
         * Ativa uma camada de um planejamento
         * 
         * @method ativarCamada
         * 
         * @param obj {Object}
         * @param cb {Object}
         * 
         */ 
        function ativarCamada(obj, cb) {
            angular.forEach(mapList, function (map) {
                map.ativarCamada(obj, cb);
            });
        }
        /**
         * Remove o mapa da lista de mapas
         * 
         * @method removeMap
         * 
         * @param map {Object}
         * 
         */ 
        function removeMap(map) {
            for (var index in mapList) {
                if (mapList[index] == map) {
                    mapList.splice(mapList.indexOf(map), 1);
                    return;
                }
            }
        }

        var icones = {
            'base_conhecimento': '/assets/images/BaseDeConhecimento/ic_base_conhecimento_mapa_24px.svg',
            'zona_observacao': '/data-s4c/ZonaDeObservacao/ic_zona_obervacao_48px.png',
            'incidente': '/data-s4c/Incidentes2/ic_maps_incidentes_geral_24px.png',
            'planejamento': '/assets/images/Planejamento/ic_maps_planejamento_48px.png',
            'viatura': '/assets/images/IconesMapa/s4c_ic_maps_police_car.png'
        };
        /**
         * Define a função do click do Poi
         * 
         * @method clickPoi
         * 
         * @param id {Integer}
         * 
         */ 
        function clickPoi(id) {

            var DetalhamentoManager = MainState.getManager('DetalhamentoManager');
            var SubDetalhamentoManager = MainState.getManager('SubDetalhamentoManager');

            return function (e) {
                if (DetalhamentoManager.ativo) {

                    DetalhamentoManager.resetarDetalhamento();
                    SubDetalhamentoManager.resetarSubDetalhamento();
                    DetalhamentoManager.abrirPoi(id, e.latlng);

                    angular.forEach(mapList, function (map) {
                        map.piscarAzul(e.latlng);
                    });

                } else {
                    // Não existe nenhum poi clicado no momento, abrindo detalhamento:
                    DetalhamentoManager.abrirPoi(id, e.latlng);

                    angular.forEach(mapList, function (map) {
                        map.piscarAzul(e.latlng);
                    });
                }
            }
        }
        /**
         * Retorna a ulr do Ícone
         * 
         * @method _obterIcone
         * 
         * @param feature {Object}
         * @param tipo {Object}
         * 
         * @returns Retorna o icone com a sua url definida
         */ 
        function _obterIcone(feature, tipo) {
            if (_.includes(['camera', 'terminal'], tipo)) {
                return feature.properties.urlIcone;
            }

            if (tipo === 'poi') {

                var urlIcone = feature.properties.urlIcone || (feature.properties.Categorium || {}).urlIcone;

                if (!urlIcone || urlIcone == '') {
                    return '/assets/images/generic_poi_icon.svg';
                }

                return urlIcone;
            }

            if (tipo === 'incidente') {
                if (feature.properties.status === 'FECHADO') {
                    feature.properties.urlIcone = feature.properties.urlIconeFechado ||
                        (feature.properties.TipoIncidente || {}).urlIconeFechado ||
                        (feature.properties.CategoriaIncidente || {}).urlIconeFechado;
                } else {
                    if (moment(feature.properties.inicio).isBefore(moment().startOf('day'))) {
                        feature.properties.urlIcone = feature.properties.urlIcone.replace('vermelho', 'purple');
                    }
                }
                return feature.properties.urlIcone;
            }

            if (tipo === 'viatura') {

                if (feature.properties.urlIcone) {
                    return feature.properties.urlIcone;
                }

                if (feature.properties.agencia === 'PMERJ') {
                    if (feature.properties.status === 0) {
                        // PMERJ INATIVO
                        return '/data-s4c/Camadas/Viaturas/ic_maps_carro_policia3_desativado_48px.png';
                    } else {
                        // PMERJ ATIVO
                        return '/data-s4c/Camadas/Viaturas/ic_maps_carro_policia3_48px.png';
                    }
                } else if (feature.properties.agencia === 'PCERJ') {
                    if (feature.properties.status === 0) {
                        // PCERJ INATIVO
                        return '/data-s4c/Camadas/Viaturas/ic_maps_carro_policia10_desativado_48px.png';
                    } else {
                        // PCERJ ATIVO
                        return '/data-s4c/Camadas/Viaturas/ic_maps_carro_policia10_48px.png';
                    }
                } else {
                    if (feature.properties.status === 0) {
                        // OUTRO INATIVO
                        return '/data-s4c/Camadas/Viaturas/ic_maps_carro_policia6_desativado_48px.png';
                    } else {
                        // OUTRO ATIVO
                        return '/data-s4c/Camadas/Viaturas/ic_maps_carro_policia6_48px.png';
                    }
                }
            }

            return icones[tipo];
        }
        /**
         * Retorna o html com a quantidade de comentários
         * 
         * @method _obterHtmlIconeComentarios
         * 
         * @param feature {Object}
         * @param tipo {Object}
         * @param totalComentarios {Object}
         * 
         * @returns Retorna o icone com a sua url definida
         */ 
        function _obterHtmlIconeComentarios(feature, tipo, totalComentarios) {

            if (!totalComentarios) {
                return '<div ' +
                    'class="marker-cluster-wrapper" ' +
                    'style="width: 24px; height: 24px; background-size: cover; background-image: url(' + _obterIcone(feature, tipo) + ')">' +
                    '</div>';
            }

            return '<div class="marker-cluster-wrapper" ' +
                'style="width: 24px; height: 24px; background-size: cover; background-image: url(' + _obterIcone(feature, tipo) + ')">' +
                '<b class="marker-cluster-counter comentarios-incidentes">' +
                totalComentarios + '</b></div>';
        }
        /**
         * Retorna o html do Ícone 
         * 
         * @method obterHtmlIcon
         * 
         * @param feature {Object}
         * @param tipo {Object}
         * 
         * @returns Retorna o html
         */ 
        function obterHtmlIcon(feature, tipo) {
            var html;

            if (feature.representacao) {
                return feature.representacao.html;
            }

            if (feature.properties.Comentarios && feature.properties.Comentarios.length > 0) {
                html = _obterHtmlIconeComentarios(feature, tipo, feature.properties.Comentarios.length);
            } else {

                var index = 0;
                var templatePoi = _.template('<img class="poi" width="24" height="24" src="${src}"/>')
                var templateIncidente = _.template('<img class="poi-incidente-tipo-${index}" src="${src}"/>');

                if (feature.properties.Incidentes && feature.properties.Incidentes.length > 5) {
                    feature.properties.Incidentes = feature.properties.Incidentes.slice(0, 5);
                    feature.properties.Incidentes[4].TipoIncidente.urlIconeRelacionado =
                        '/data-s4c/Embratel/s4c_ic_maps_etc_24px.png';
                }

                var icones = _.chain(feature.properties.Incidentes)
                    .filter({ status: 'ABERTO' })
                    .map(function (incidente) {
                        index++;

                        return templateIncidente({
                            index: index,
                            src: incidente.TipoIncidente.urlIconeRelacionado
                        });
                    })
                    .value();

                icones.unshift(templatePoi({ src: _obterIcone(feature, tipo) }));

                html = '<div class="marker-cluster-wrapper">' + icones.join('') + '</div>';
            }
            return html;
        }

        /**
         * Atualiza a camada com o Ícone correspondente
         * 
         * @method updateLayer
         * 
         * @param marker {Object}
         * @param feature {Object}
         * @param tipo {Object}
         * 
         */ 
        function updateLayer(marker, feature, tipo) {

            var html = obterHtmlIcon(feature, tipo);

            marker.setIcon(new L.DivIcon({
                html: html,
                iconSize: [24, 24]
            }));
        }

        /**
         * Atualiza a camada com o Ícone correspondente ao módulo de Incidente
         * 
         * @method updateIconeIncidente
         * 
         * @param marker {Object}
         * @param incidente {Object}
         * @param totalNotas {Object}
         * 
         */ 
        function updateIconeIncidente(marker, incidente, totalNotas) {
            if (marker != null) {
                marker.setIcon(new L.DivIcon({
                    html: _obterHtmlIconeComentarios({ properties: incidente }, 'incidente', totalNotas),
                    iconSize: [24, 24]
                }));
            }
        }
        /**
         * Atualiza a camada com o Ícone correspondente ao módulo de Incidente
         * 
         * @method updateIncidentesRelacionados
         * 
         * @param marker {Object}
         * @param poi {Object}
         * 
         */     
        function updateIncidentesRelacionados(marker, poi) {
            marker.setIcon(new L.DivIcon({
                html: obterHtmlIcon({
                    properties: poi
                }, 'poi'),
                iconSize: [24, 24]
            }));
        }
        /**
         * Remove a camada de acervo do mapa
         * 
         * @method removerCamadaAcervo
         * 
         * @param layer {Object}
         * @param acervoId {Object}
         * 
         */ 
        function removerCamadaAcervo(layer, acervoId) {
            angular.forEach(mapList, function (map) {
                map.removeLayer(layer.aggregate);
            });
        }

         /**
         * Remove a camada de categoria do mapa
         * 
         * @method removerCamadaAcervo
         * 
         * @param layer {Object}
         * @param categoriaId {Object}
         * 
         */ 
        function removerCamadaCategoria(layer, categoriaId) {
            angular.forEach(mapList, function (map) {
                if (layer.aggregate != null) {
                    map.removeLayer(layer.aggregate);
                } else if (layer.aggregate == null && layer != null && layer.length > 0 && layer[0].aggregate != null) {
                    map.removeLayer(layer[0].aggregate);
                }

            });
        }
        /**
         * Adiciona Pontos na Feature Collection 
         * 
         * @method adicionarPontos
         * 
         * @param featureCollection {Object}
         * @param zoom {Object}
         * 
         */  
        function adicionarPontos(featureCollection, zoom) {

            var defer = $q.defer();
            var resultList = [];
            adicionarPontosRecursivo(0, resultList, featureCollection, defer, zoom);
            return defer.promise;
        }
        /**
         * Adiciona Pontos na Feature Collection de todos os mapas 
         * 
         * @method adicionarPontosRecursivo
         * 
         * @param index {Object}
         * @param resultList {Object}
         * @param featureCollection {Object}
         * @param defer {Object}
         * @param zoom {Object}
         * 
         */  
        function adicionarPontosRecursivo(index, resultList, featureCollection, defer, zoom) {

            if (index == mapList.length) {
                defer.resolve(resultList);
                return;
            }

            mapList[index].adicionarPontos(featureCollection, zoom).then(function (camada) {
                resultList.push(camada);
                index += 1;
                adicionarPontosRecursivo(index, resultList, featureCollection, defer);
            });
        }

        //Main map ?
        /**
         * Adiciona Pontos na Feature Collection 
         * 
         * @method adicionarPonto
         * 
         * @param feature {Object}
         * @param tipo {Object}
         * @param layerGroup {Object}
         * 
         */         
        function adicionarPonto(feature, tipo, layerGroup) {

            var defer = $q.defer();
            var resultList = [];
            adicionarPontoRecursivo(0, resultList, feature, tipo, layerGroup, defer);
            return defer.promise;
        }
        /**
         * Adiciona Pontos na Feature Collection de todos os mapas 
         * 
         * @method adicionarPontosRecursivo
         * 
         * @param index {Object}
         * @param resultList {Object}
         * @param feature {Object}
         * @param tipo {Object}
         * @param layerGroup {Object}
         * @param defer {Object}
         * 
         * @return Promisse 
         */ 
        function adicionarPontoRecursivo(index, resultList, feature, tipo, layerGroup, defer) {

            if (index == mapList.length) {
                defer.resolve(resultList);
                return;
            }

            mapList[index].adicionarPonto(feature, tipo, layerGroup).then(function (camada) {
                resultList.push(camada);
                index += 1;
                adicionarPontoRecursivo(index, resultList, feature, tipo, layerGroup, defer);
            });
        }
         /**
         * Verifica se a camada está no mapa
         * 
         * @method possuiLayer
         * 
         * @param layer {Object}
         * 
         */   
        function possuiLayer(layer) {
            angular.forEach(mapList, function (map) {
                map.possuiLayer(layer);
            });
        }
        /**
         * Adiciona uma geometria no mapa
         * 
         * @method adicionarGeometria
         * 
         * @param feature {Object}
         * @param tipo {Object}
         * @param layerGroup {Object}
         * 
         */ 
        function adicionarGeometria(feature, tipo, layerGroup) {
            var defer = $q.defer();
            var resultList = [];
            adicionarGeometriaRecursivo(0, resultList, feature, tipo, layerGroup, defer);
            return defer.promise;
        }
        /**
         * Adiciona uma geometria no mapa recursivamente
         * 
         * @method adicionarGeometriaRecursivo
         * 
         * @param index {Object}
         * @param resultList {Object}
         * @param feature {Object}
         * @param tipo {Object}
         * @param layerGroup {Object}
         * @param defer {Object}
         *  
         */ 
        function adicionarGeometriaRecursivo(index, resultList, feature, tipo, layerGroup, defer) {

            if (index == mapList.length) {
                defer.resolve(resultList);
                return;
            }

            mapList[index].adicionarGeometria(feature, tipo, layerGroup).then(function (camada) {
                resultList.push(camada);
                index += 1;
                adicionarGeometriaRecursivo(index, resultList, feature, tipo, layerGroup, defer);
            });
        }
         /**
         * Inclui no mapa uma camada de geoJson 
         * 
         * @method adicionarGeoJSON
         * 
         * @param feature {Object}
         * @param options {Object}
         * 
         */ 
        function adicionarGeoJSON(feature, options) {
            angular.forEach(mapList, function (map) {
                map.adicionarGeoJSON(feature, options);
            });
        }
         /**
         * Ativa a camada de planejamento do mapa
         * 
         * @method ativarCamadaPlanejamento
         * 
         * @param geojson {Object}
         * 
         */      
        function ativarCamadaPlanejamento(geojson) {
            return obterMapaAtivo().ativarCamadaPlanejamento(geojson);
        }

         /**
         * Remove uma camada do mapa
         * 
         * @method removerCamada
         * 
         * @param layer {Object}
         * @param layerGroup {Object}
         * 
         */ 
        function removerCamada(layer, layerGroup) {
            var defer = $q.defer();
            var resultList = [];
            removerCamadaRecursivo(0, resultList, layer, layerGroup, defer);
            return defer.promise;
        }
        /**
         * Remove uma camada do mapa recurssivamente
         * 
         * @method removerCamada
         * 
         * @param layer {Object}
         * @param layerGroup {Object}
         * 
         */ 
        function removerCamadaRecursivo(index, resultList, layer, layerGroup, defer) {

            if (index == mapList.length) {
                defer.resolve(resultList);
                return;
            }

            mapList[index].removerCamada(layer, layerGroup).then(function (camada) {
                index += 1;
                removerCamadaRecursivo(index, resultList, layer, layerGroup, defer);
            });
        }

        //Main map
        /**
         * Obtem ponto central 
         * 
         * @method obterPontoCentral
         * 
         * 
         */  
        function obterPontoCentral() {
            for (var index in mapList) {
                return mapList[index].obterPontoCentral();
            }
        }

        /**
         * Adiciona um cluster para agrupar os Incidentes, Pois e Outros
         * 
         * @method adicionaCluster
         * 
         * 
         */              
        function adicionaCluster() {
            angular.forEach(mapList, function (map) {
                map.adicionaCluster();
            });
        }
         /**
         * Inicializa os Markers responsáveis pelo agrupamento de Poi, Incidente e outros. 
         * 
         * @method inicializaMarkerCluster
         * 
         */ 
        function inicializaMarkerCluster() {
            angular.forEach(mapList, function (map) {
                map.inicializaMarkerCluster();
            });
        }
        /**
         * Cria uma camada para agrupar os Pois
         * 
         * @method clearMarkerCluster
         * 
         * 
         */     
        function clearMarkerCluster() {
            angular.forEach(mapList, function (map) {
                map.clearMarkerCluster();
            });
        }
        /**
         * Cria uma camada para agrupar os Pois, Incidentes e Outros
         * 
         * @method clearAllMarkerCluster
         * 
         * 
         */ 
        function clearAllMarkerCluster() {
            angular.forEach(mapList, function (map) {
                map.clearAllMarkerCluster();
            });
        }
         /**
         * Atualiza as informações da camada
         * 
         * @method updateClick
         * 
         * @param tipo {Object}
         * @param camada {Object}
         * 
         */ 
        function updateClick(tipo, camada) {
            angular.forEach(mapList, function (map) {
                map.updateClick(tipo, camada);
            });
        }
        /**
         * Muda a centralização do mapa para as coordenadas passadas por parâmetro
         * 
         * @method voarPara
         * 
         * @param coordinates {Object}
         * 
         */  
        function voarPara(coordinates) {
            angular.forEach(mapList, function (map) {
                map.voarPara(coordinates);
            });
        }
        /**
         * Adiciona uma camada no mapa
         * 
         * @method adicionarLayer
         * 
         * @param layer {Object}
         * 
         */  
        function adicionarLayer(layer) {
            angular.forEach(mapList, function (map) {
                map.adicionarLayer(layer);
            });
        }

        /**
         * Ajusta o Mapa para caber os tweets
         * 
         * @method fitBounds
         * 
         * @param coordinates {Object}
         * @param tweets {Object}
         * 
         */ 
        function fitBounds(coordinates, tweets) {
            angular.forEach(mapList, function (map) {
                map.fitBounds(coordinates, tweets);
            });
        }
         /**
         * Define o centro do mapa e o nível de zoom
         * 
         * @method setView
         * 
         * @param ponto {Object}
         * @param zoom {Object}
         * @param noView {Object}
         * 
         */   
        function setView(newPos, zoom) {
            angular.forEach(mapList, function (map) {
                map.setView(newPos, zoom);
            });
        }

        /**
         * Inclui no mapa em uma coordenada específica um label e um valor 
         * 
         * @method highlightFeature
         * 
         * @param e {Object}
         * 
         */ 
        function highlightFeature(e) {
            angular.forEach(mapList, function (map) {
                map.highlightFeature(e);
            });
        }
        /**
         * Inclui um Marker no mapa 
         * 
         * @method addMarker
         * 
         * @param marker {Object}
         * 
         */   
        function addMarker(marker) {
            angular.forEach(mapList, function (map) {
                map.addMarker(marker);
            });
        }
          /**
         * Adiciona uma camada no mapa
         * 
         * @method addLayer
         * 
         * @param layer {Object}
         * 
         */  
        function addLayer(layer) {
            angular.forEach(mapList, function (map) {
                map.addLayer(layer);
            });
        }
          /**
         * Remove do mapa os eventos de zoom
         * 
         * @method clearZoomEvents
         * 
         * @param zoomEvents {Object}
         * 
         */  
        function clearZoomEvents(zoomEvents) {
            angular.forEach(mapList, function (map) {
                map.clearZoomEvents(zoomEvents);
            });
        }
        /**
         * Cria no mapa um listener de zoom
         * 
         * @method zoomOn
         * 
         * @param name {Object}
         * @param func {Object}
         * 
         */  
        function zoomOn(name, func) {
            angular.forEach(mapList, function (map) {
                map.zoomOn(name, func);
            });
        }
        /**
         * Remove do mapa o listener de zoom
         * 
         * @method zoomOff
         * 
         * @param name {Object}
         * @param func {Object}
         * 
         */ 
        function zoomOff(name, func) {
            angular.forEach(mapList, function (map) {
                map.zoomOff(name, func);
            });
        }
         /**
         * Remove os desenhos do mapa
         * 
         * @method removerDesenho
         * 
         */  
        function removerDesenho() {
            angular.forEach(mapList, function (map) {
                map.removerDesenho();
            });
        }
          /**
         * Controle da edição e criação de novas zonas de observação
         * 
         * @method dataminingViewport
         * 
         */ 
        function dataminingViewport() {
            angular.forEach(mapList, function (map) {
                map.dataminingViewport();
            });
        }

        //Main map
        /**
         * Faz um desenho no mapa, usando o parâmetro recebido
         * 
         * @method draw
         * 
         * @param areaType {Object}
         * 
         */ 
        function draw(areaType) {
            var defer = $q.defer();
            var resultList = [];
            drawRecursivo(0, resultList, areaType, defer);
            return defer.promise;
        }

        /**
         * Faz um desenho no mapa recurssivamente, usando o parâmetro recebido 
         * 
         * @method drawRecursivo
         * 
         * @param index {Object}
         * @param resultList {Object}
         * @param areaType {Object}
         * @param defer {Object}
         * 
         */ 
        function drawRecursivo(index, resultList, areaType, defer) {

            if (index == mapList.length) {
                defer.resolve(resultList);
                return;
            }

            mapList[index].draw(areaType).then(function (camada) {
                resultList.push(camada);
                index += 1;
                drawRecursivo(index, resultList, areaType, defer);
            });
        }


        //Main map
     /**
         * Obtem o zoom do mapa 
         * 
         * @method pegarZoom
         * 
         * @param cb {Object}
         * 
         * 
         */         
        function pegarZoom(func) {
            angular.forEach(mapList, function (map) {
                map.pegarZoom(func);
            });
        }

        /**
         * Remove do mapa os linhas que mostram as posições das Câmeras, Incidentes e Poi   
         * 
         * @method removerPoiClicado
         * 
         * 
         * 
         */            
        function removerLinhas() {
            angular.forEach(mapList, function (map) {
                map.removerLinhas();
            });
        }

       /**
         * Desenha linhas no mapa que mostram a localização das cameras 
         * 
         * @method drawCameraLines
         * 
         * @param ponto {Object}
         * @param cameraList {Array}
         * 
         * 
         */            
        function drawCameraLines(ponto, cameras) {
            angular.forEach(mapList, function (map) {
                map.drawCameraLines(ponto, cameras);
            });
        }

      /**
         * Mostra a lista de Câmeras próximas ao ponto clicado 
         * 
         * @method showCameras
         * 
         * @param ponto {Object}
         * @param cameraList {Array}
         * 
         * 
         */           
        function showCameras(ponto, cameras) {
            angular.forEach(mapList, function (map) {
                map.showCameras(ponto, cameras);
            });
        }

     /**
         *  Faz o objeto nas coordenadas recebidas piscar em vermelho
         * 
         * @method piscarVermelho
         * 
         * @param latLng {Object}
         * 
         */            
        function piscarVermelho(ponto) {
            angular.forEach(mapList, function (map) {
                map.piscarVermelho(ponto);
            });
        }

        /**
         *  Faz o objeto nas coordenadas recebidas piscar em azul
         * 
         * @method piscarAzul
         * 
         * @param latLng {Object}
         * 
         */          
        function piscarAzul(ponto) {
            angular.forEach(mapList, function (map) {
                map.piscarAzul(ponto);
            });
        }

        //Main map
        /**
         * Obtem a rota ativa
         * 
         * @method obterRotaAtiva
         * 
         */           
        function obterRotaAtiva() {
            angular.forEach(mapList, function (map) {
                map.obterRotaAtiva();
            });
        }

        //Main map
        /**
         * Remove a camada de rotas do mapa
         * 
         * @method removerRotasUnificadasDoMapa
         * 
         * 
         */        
        function removerRotasUnificadasDoMapa() {
            angular.forEach(mapList, function (map) {
                map.removerRotasUnificadasDoMapa();
            });
        }

        //Main map
      /**
         * Obtem a rota ativa
         * 
         * @method obterRotaUnificadaAtiva
         * 
         */          
        function obterRotaUnificadaAtiva() {

            var rotasAtivas = [];
            angular.forEach(mapList, function (map) {
                rotasAtivas.push(map.obterRotaUnificadaAtiva());
            });

            return rotasAtivas;
        }

        //Main map
        /**
         * Remove a camada de rotas do mapa
         * 
         * @method removerRotasUnificadasDoMapa
         * 
         * 
         */          
        function removerRotasUnificadasDoMapa() {
            angular.forEach(mapList, function (map) {
                map.removerRotasUnificadasDoMapa();
            });
        }

        //Main map
        /**
         * Adiciona no mapa uma nova rota apartir do Kml
         * 
         * @method desenharRotaUnificadaKml
         * 
         * @param pontos {Object}
         * 
         */        
        function desenharRotaUnificadaKml(pontos) {
            angular.forEach(mapList, function (map) {
                map.desenharRotaUnificadaKml(pontos);
            });
        }

        //Main map
      /**
         * Adiciona no mapa os trajetos da rota
         * 
         * @method desenharTrajetoRotaUnificadaKml
         * 
         * @param trajeto {Object}
         * 
         */         
        function desenharTrajetoRotaUnificadaKml(trajeto) {
            angular.forEach(mapList, function (map) {
                map.desenharRotaUnificadaKml(trajeto);
            });
        }

        /**
         * Faz o desenho das regiões da Área de Atuação para incluir no mapa
         * 
         * @method desenharRegioes
         * 
         * @param data {Object}
         * @param id {Integer}
         * @param abreJanela {Function}
         * 
         */
        function desenharRegioes(data, id, abrirJanela) {

            var defer = $q.defer();
            var resultList = [];
            adicionarRegioesRecursivo(0, resultList, data, id, abrirJanela, defer);
            return defer.promise;
        }

        /**
         * Faz o desenho das regiões da Área de Atuação para incluir no mapa de maneira recursiva
         * 
         * @method adicionarRegioesRecursivo
         * 
         * @param index {Integer}
         * @param resultList {Array}
         * @param data {Object}
         * @param id {Integer}
         * @param abrirJanela {Function}
         * @param defer {Object}
         * 
         */        
        function adicionarRegioesRecursivo(index, resultList, data, id, abrirJanela, defer) {

            if (index == mapList.length) {
                defer.resolve(resultList);
                return;
            }

            mapList[index].desenharRegioes(data, id, abrirJanela).then(function (camada) {
                resultList.push(camada);
                index += 1;
                adicionarRegioesRecursivo(index, resultList, data, id, abrirJanela, defer);
            });
        }

        /**
         * Remove as camadas recebidas por parâmetros do mapa
         * 
         * @method removerLayers
         * 
         * @param layers {Object}
         * 
         */          
        function removerLayers(layersToRemove) {
            angular.forEach(mapList, function (map) {
                map.removerLayers(layersToRemove);
            });
        }

        /**
         * Organiza os Pois relacionados para que fiquem enquadrados mapa
         * 
         * @method enquadrarPoisRelacionados
         * 
         * @param arrayCircles {Object}
         * 
         */             
        function enquadrarPoisRelacionados(circlesPoisRelacionados) {
            angular.forEach(mapList, function (map) {
                map.enquadrarPoisRelacionados(circlesPoisRelacionados);
            });
        }

        /**
         * Desenha uma geometria circular ao redor do Poi
         * 
         * @method desenharCirculosPois
         * 
         * @param featureCollection {Object}
         * @param radius {Object}
         * 
         */            
        function desenharCirculosPois(featureCollection, value) {

            var defer = $q.defer();
            var resultList = [];
            desenharCirculosPoisRecursivo(0, resultList, featureCollection, value, defer);
            return defer.promise;
        }

      /**
         * Desenha uma geometria circular ao redor do Poi de maneira recursiva
         * 
         * @method desenharCirculosPoisRecursivo
         * 
         * @param index {Object}
         * @param resultList {Object}
         * @param featureCollection {Object}
         * @param value {Object}
         * @param defer {Object}
         * 
         */          
        function desenharCirculosPoisRecursivo(index, resultList, featureCollection, value, defer) {

            if (index == mapList.length) {
                defer.resolve(resultList);
                return;
            }

            mapList[index].desenharCirculosPois(featureCollection, 40).then(function (camada) {
                resultList.push(camada);
                index += 1;
                desenharCirculosPoisRecursivo(index, resultList, featureCollection, value, defer);
            });
        }

        /**
         * Faz o ponto na coordenada recebida piscar 
         * 
         * @method pingLayer
         * 
         * @param cood {Object}
         * 
         */           
        function pingLayer(cood) {
            angular.forEach(mapList, function (map) {
                map.pingLayer.ping(cood);
            });
        }

       /**
         * Remove a camada de rotas do mapa
         * 
         * @method removerRouter
         * 
         * 
         */         
        function removerRouter() {
            angular.forEach(mapList, function (map) {
                map.removerRouter();
            });
        }

        //Main map
        /**
         * Remove o desenho da camada de planejamento do mapa
         * 
         * @method removerDesenhoPlanejamento
         * 
         * @param layer {Object}
         * 
         */         
        function removerDesenhoPlanejamento(layer) {
            angular.forEach(mapList, function (map) {
                map.removerDesenhoPlanejamento(layer);
            });
        }

        //Main map
    /**
         * Remove controles de desenho do módulo de planejamento
         * 
         * @method removerControleDesenho
         * 
         * 
         */         
        function removerControleDesenho() {

            var promises = [];
            for (var index in mapList) {
                promises.push(mapList[index].removerControleDesenho());
            }

            return promises;
        }

        /**
         * Remove controles de desenho do módulo de planejamento
         * 
         * @method removerControleDesenho
         * 
         * 
         */         
        function removerPontosPlanejamento() {
            angular.forEach(mapList, function (map) {
                map.removerPontosPlanejamento();
            });
        }

        //Main map
    /**
         * Recupera geometrias do Planejamento desenhadas no mapa
         * 
         * @method pegarGeometrias
         * 
         * 
         */          
        function pegarGeometrias() {

            //var geometrias = [];
            //for (var index in mapList) {
            //geometrias.push(mapList[index].pegarGeometrias());
            //}
            //return geometrias;
            return obterMapaAtivo().pegarGeometrias();
        }

        //Main map
        /**
         * Mostra o menu de adicionar geometria no mapa
         * 
         * @method planejar
         * 
         * @param saveCallBack {Function}
         * @param camada {Object}
         * 
         */  
        function planejar(saveCallBack, camada) {
            angular.forEach(mapList, function (map) {
                map.planejar(saveCallBack, camada);
            });
        }

        //Main map
        /**
         * Remove do mapa o Poi clicado e seus Sub Itens 
         * 
         * @method removerPoiClicado
         * 
         * 
         * 
         */          
        function removerPoiClicado() {
            angular.forEach(mapList, function (map) {
                map.removerPoiClicado();
            });
        }

        //Main map
        /**
         * Adiciona um marker no mapa
         * 
         * @method colocarIcon
         * 
         * @param callback {Function}
         * 
         */        
        function colocarIcon(callback) {
            angular.forEach(mapList, function (map) {
                map.colocarIcon(callback);
            });
        }

        //Main map

        /**
         * Reinicia o detalhamento
         * 
         * @method resetarDetalhamento
         * 
         * @param layers {Object}
         * 
         */  
        function resetarDetalhamento(layers) {
            angular.forEach(mapList, function (map) {
                map.resetarDetalhamento(layers).then(function () {
                    //subItens.clearLayers();
                    var detalhamento = MainState.getDirective('detalhamento');
                    if (detalhamento) {
                        detalhamento.removerPoisRelacionados(null);
                    }
                });
            });
        }

        //Main map
        /**
         * Remove a camada de rotas do mapa
         * 
         * @method removerRouter
         * 
         * 
         */         
        function removerRouterRotaUnificada() {
            angular.forEach(mapList, function (map) {
                map.removerRouterRotaUnificada();
            });
        }

        /**
         * Recebe duas coordenadas e adiciona
         * uma linha entre eles no mapa, retornando uma
         * Promise que resolve com o polyline adicionado no mapa.
         * 
         * @method adicionarSubItem
         * 
         * @param pos1 {Object}
         * @param pos2 {Object}
         * @param distancia {Object} 
         * 
         * @returns Promise que resolve com o polyline adicionado no mapa
         */   
        function adicionarSubItem(coords, coords2, distancia, subItens) {
            angular.forEach(mapList, function (map) {
                map.adicionarSubItem(coords, coords2, distancia).then(function (polyline) {
                    subItens.addLayer(polyline);
                    var lg = L.featureGroup(subItens.getLayers());
                    map.fitBounds(lg.getBounds());
                });
            });
        }

        /**
         * Método responsável por centralizar o mapa nas coordenadas recebidas por parâmetro
         * 
         * @method flyTo
         * 
         * @param input
         * 
         */  
        function flyTo(geojson) {
            return obterMapaAtivo().flyTo(geojson);
        }

        /**
         * Atualiza a centralização do mapa
         * 
         * @method gridResized
         * 
         * 
         */  
        function gridResized() {
            angular.forEach(mapList, function (map) {
                map.gridResized();
            });
        }

        /**
         * Muda o css das Câmeras para oculta-las 
         * 
         * @method changeClass
         * 
         * @param val {Object}
         * 
         * 
         */          
        function changeClass(change) {
            angular.forEach(mapList, function (map) {
                map.changeClass(change);
            });
        }

        /**
         * Recebe uma coordenada e faz o objeto ficar piscando em azul
         * 
         * @method destacarSubItem
         * 
         * @param pos1 {Object}
         * 
         */ 
        function destacarSubItem(coords) {
            angular.forEach(mapList, function (map) {
                map.destacarSubItem(coords);
            });
        }

        return service;
    }

})();