Source: directives/camadas/camadas.service.js

'use strict';

(function () {

    angular.module('s4c.components.camadas')
        .service('CamadasService', CamadasService);

    CamadasService.$inject = [
        'Menu',
        'Base',
        'CommService',
        '$q',
        'MainState',
        'IncidenteFilter',
        'DetalhamentoManager',
        '$filter',
        '$http',
        'MapaManager',
        'ZonasDeObservacaoFilter',
        'ZonaDeObservacaoManager',
        'MsiFilter',
        '$rootScope',
        'Preset',
        '$mdDialog',
        'RepresentacaoService',
        'Viatura',
        'Camera',
        '$timeout',
        'LegendaService',
        'MapaService'
    ];

    /**
     * @ngdoc directives
     * @name CamadasService
     * @module s4c.directives.camadas.CamadasService
     *
     * @description
     * `CamadasService` gerencia a comunicação entre a diretiva que controla as
     * camadas do sistema e a API do backend.
     */
    function CamadasService(Menu, Base, CommService, $q, MainState, IncidenteFilter,
        DetalhamentoManager, $filter, $http, MapaManager, ZonasDeObservacaoFilter, ZonaDeObservacaoManager,
        MsiFilter, $rootScope, Preset, $mdDialog, RepresentacaoService, Viatura, Camera, $timeout, LegendaService, MapaService) {

        var service = {
            categoriasAtivas: [],
            grupos: [],
            indicadores: [],
            menusPorAcervo: [],
            toggleMenu: toggleMenu,
            isIndeterminate: isIndeterminate,
            isDisabled: isDisabled,
            isChecked: isChecked,
            reloadCamadas: reloadCamadas,
            reloadIncidentes: reloadIncidentes,
            reloadPlanejamentos: reloadPlanejamentos,
            reloadBasesConhecimento: reloadBasesConhecimento,
            reloadZonasObservacao: reloadZonasObservacao,
            exibirZonasDeObservacao: exibirZonasDeObservacao,
            filtrarZonasDeObservacao: filtrarZonasDeObservacao,
            exibirBasesConhecimento: exibirBasesConhecimento,
            exibirPlanejamentos: exibirPlanejamentos,
            ativarSubMenuIncidente: ativarSubMenuIncidente,
            desativarSubMenuIncidente: desativarSubMenuIncidente,
            ativarMenuCategoria: ativarMenuCategoria,
            ativarMenuDoIncidente: ativarMenuDoIncidente,
            ativarMenuDaAreaAtuacao: ativarMenuDaAreaAtuacao,
            ativarMenuDoPontoMovel: ativarMenuDoPontoMovel,
            ativarMenuPoi: ativarMenuPoi,
            limparCamadas: limparCamadas,
            atualizarIconeIncidente: atualizarIconeIncidente,
            ativarMenuDaCamera: ativarMenuDaCamera,
            ativarMenuCategoriaCamera: ativarMenuCategoriaCamera,
            ativarSubCategorias: ativarSubCategorias,
            ativarSubMenuStatusIncidente: ativarSubMenuStatusIncidente,
            desativarSubMenuStatusIncidente: desativarSubMenuStatusIncidente,
            ativarSubMenuStatusMsi: ativarSubMenuStatusMsi,
            desativarSubMenuStatusMsi: desativarSubMenuStatusMsi,
            ativarMenuViatura: ativarMenuViatura,
            reloadCameras: reloadCameras,
            ativarThemeMenu: ativarThemeMenu,
            vincularAoPreset: vincularAoPreset,
            initCategorias: initCategorias,
            ativarMenuCamada: ativarMenuCamada,
            departamentosAtivosZO: departamentosAtivosZO,
            getInstance: getInstance,
            atualizarCamadaIncidente: atualizarCamadaIncidente,
            ativarMenuZonasDeObservacao: ativarMenuZonasDeObservacao,
            _filtros: {},
            _adicionarPontos: _adicionarPontos,
            isLoaded: false,
            ativarMenuIncidente: ativarMenuIncidente,
            reloadNodes: reloadNodes,
            clearReloadNodes: clearReloadNodes,
            carregarPoisRelacionados: carregarPoisRelacionados,
            removerPoisRelacionados: removerPoisRelacionados,
            representacoes_das_Categorias_Ativas: [],
            representacoes_das_Categorias: [],
            markCategories: markCategories,
            markMenuCamadas: markMenuCamadas,
            nodesAlreadyReloaded: nodesAlreadyReloaded,
            clearLayers: clearLayers
        };

        var appElement = document.querySelector('[ng-app=s4CApp]');
        var appScope = angular.element(appElement).scope();
        var moduloIncientesFiltro = IncidenteFilter.getInstance('filtro-incidentes');
        var moduloZonaObservacaoFilter = ZonasDeObservacaoFilter.getInstance('zonas-de-observacao-filter');

        LegendaService.pegarCategoriaDasLegendas()
            .then(function (data) {
                service.representacoes_das_Categorias = data;
            });

        var listenerViatura = {
            1: function (parametros) {
                var organizacoes = parametros.organizacoes;
                var promises = [];

                _.each(organizacoes, function (organizacao) {

                    var menuViaturas = _obterMenu({
                        urlSubMenus: 'menuCamada/viatura',
                        headers: {
                            version: 1
                        }
                    });

                    var menuAgencia = _.find(_obterSubMenus(menuViaturas), {
                        texto: organizacao.agencia
                    });

                    if (!menuAgencia) {
                        promises.push(_reloadMenu(menuViaturas))
                    } else {
                        promises.push($q.when());
                    }

                    _.chain(organizacao.viaturas)
                        .keys()
                        .each(function (key) {
                            var viaturaAtualizada = organizacao.viaturas[key];

                            $q.all(promises).then(function () {

                                menuViaturas = _obterMenu({
                                    urlSubMenus: 'menuCamada/viatura',
                                    headers: {
                                        version: 1
                                    }
                                });

                                menuAgencia = _.find(_obterSubMenus(menuViaturas), {
                                    texto: organizacao.agencia
                                });

                                _tratarMenuOrganizacao(menuViaturas, menuAgencia, organizacao, viaturaAtualizada, key);
                            });
                        })
                        .value();
                });
            },
            2: function (parametros) {
                var organizacoes = parametros.organizacoes;

                _.each(organizacoes, function (organizacao) {

                    var menuOrganizacao = _obterMenuOrganizacaoViatura(organizacao.chave_estrangeira);

                    if (menuOrganizacao) {
                        _.chain(organizacao.viaturas)
                            .keys()
                            .each(function (key) {
                                var viaturaAtualizada = organizacao.viaturas[key];

                                if (menuOrganizacao) {
                                    _atualizarViaturas(menuOrganizacao, viaturaAtualizada);
                                }
                            })
                            .value();
                    }
                });
            }
        };

      /**
        * Faz a seleção das categorias
        *
        * @method markCategories
		*        
        * @param categories {Array} Lista com as categorias
		*               
        */ 
        function markCategories(categories) {

            _.each(service.grupos, function (grupo) {
                _.each(grupo.subMenus, function (acervo) {

                    if (acervo.subMenus) {
                        _.each(acervo.subMenus, function (categoria) {
                            if (containsCategory(categoria, categories)) {
                                categoria.ativo = true;
                                toggleMenu(categoria);
                            }
                        });
                    }
                });
            });
        }

      /**
        * Faz a seleção dos itens do MenuCamada
        *
        * @method markMenuCamadas
		*        
        * @param menuCamadas {Array} Lista com os itens do MenuCamada
		*               
        */ 
        function markMenuCamadas(menuCamadas) {

            _.each(menuCamadas, function (menu) {
                _.each(service.grupos, function (grupo) {
                    _.each(grupo.subMenus, function (acervo) {

                        if (!acervo.acervoId && acervo.id == menu.id) {
                            acervo.ativo = true;
                            _.each(acervo.subMenus, function (categoria) {
                                categoria.ativo = true;
                                toggleMenu(categoria);
                            }
                            );
                        }
                    });
                });
            });
        }

     /**
        * Verifica se a categoria passada como parâmetro está presente na lista de categorias
        *
        * @method containsCategory
		*        
        * @param categoria {Object} Categoria
        * @param categories {Array} Lista com as categorias
		*               
        */ 
        function containsCategory(categoria, categories) {
            for (var index in categories) {
                if (categories[index].categoriaId == categoria.id) {
                    return true;
                }
            }
        }

        /*
         * A Exibição automática das camadas
         * foram comentadas para não serem exibidas em outros terminais
        */
        CommService.on('newDocuments', function (document) {
            var menus = {
                'planejamento': function (data) {
                    exibirPlanejamentos();
                },
                'base_conhecimento': function (data) {
                    exibirBasesConhecimento();
                },
                'zona_observacao': function (data) {
                    exibirZonasDeObservacao();
                },
                'rota': function (data) {
                }
            };

            var menu = menus[document.tipo](document.data);

            if (menu && menu.ativo) {
                MapaService.adicionarPonto(document, document.tipo).then(function (camadas) {

                    _.each(camadas, function (camada) {
                        if (!menu._camada) {
                            menu._camada = camada;
                        } else {
                            menu._camada.camadas.push(camada.camadas);
                            menu._camada.aggregate.addLayer(camada.camadas.layer);
                        }
                    })
                });
            }
        });

        CommService.on('novaZona', function (zona) {
            reloadZonasObservacao();
            moduloZonaObservacaoFilter.trigger('filterChangedZona', zona);
        });

        CommService.on('removeZona', function (zona) {
            reloadZonasObservacao();
            ZonaDeObservacaoManager.fechar();
            moduloZonaObservacaoFilter.trigger('removedZonaObs', zona);
        });

        CommService.on('cameras', function (data) {
            reloadCameras(data.CategoriaCameraId);
        });

     /**
        * Obtem incidentes
        *
        * @method _obterIncidente
		*        
        * @param camadas {Object} Camadas
        * @param chave_estrangeira {String} Chave estrangeira
		*               
        */ 
        function _obterIncidente(camadas, chave_estrangeira) {
            return _.find(camadas, function (camada) {
                if (camada.feature != null && camada.feature.properties != null) {
                    return camada.feature.properties.chave_estrangeira === chave_estrangeira;
                }
                if (camada.feature == null && camada.properties != null) {
                    return camada.properties.chave_estrangeira === chave_estrangeira;
                }
            });
        }

      /**
        * Atualiza a camada de incidentes
        *
        * @method atualizarCamadaIncidente
		*        
        * @param incidente {Object} Incidente
        * 
		*               
        */ 
        function atualizarCamadaIncidente(incidente) {

            var menuStatusIncidente = _obterMenuStatusIncidente(incidente);

            if (menuStatusIncidente && menuStatusIncidente.ativo) {
                var incidenteExistente = false;

                if (incidente.geojson != null) {
                    var coordinates = incidente.geojson.coordinates;
                    var feature = turf.point(coordinates, incidente);
                }

                // Procurar incidente dentro das camadas existentes
                if (menuStatusIncidente._camada && menuStatusIncidente._camada.camadas) {
                    incidenteExistente = _obterIncidente(menuStatusIncidente._camada.camadas, incidente.chave_estrangeira);
                }

                // MapaService espera um geojson (com properties)
                if (!incidenteExistente) {
                    MapaService.adicionarPonto(feature, 'incidente').then(function (camadas) {

                        _.each(camadas, function (camada) {
                            if (!menuStatusIncidente._camada) {
                                menuStatusIncidente._camada = camada;
                            } else {

                                var latLng = camada.camadas.layer.getLatLng();
                                MapaService.pingLayer([
                                    latLng.lng,
                                    latLng.lat
                                ]);
                            }
                        });

                    });
                } else {
                    if (!incidenteExistente) {
                        return;
                    }
                    // Trocando propriedades do incidente
                    _.each(Object.keys(incidente), function (key) {
                        if (incidenteExistente.feature != null) {
                            incidenteExistente.feature.properties[key] = incidente[key];
                        } else {
                            incidenteExistente.properties[key] = incidente[key];
                        }
                    });

                    if (incidenteExistente.layer) {
                        MapaService.removerCamada(incidenteExistente.layer);
                    }

                }
            }

            if (DetalhamentoManager.ativo) {
                if (DetalhamentoManager.data.id === incidente.id) {
                    var geojson = incidente.geojson;
                    DetalhamentoManager.fechar(true);
                    DetalhamentoManager.abrirIncidente(incidente.id, {
                        lat: geojson.coordinates[1],
                        lng: geojson.coordinates[0]
                    });
                }
            }
        }

        CommService.on('incidenteNewNota', function (comentario) {
            var incidente = comentario.Incidente;
            var menuStatusIncidente = _obterMenuStatusIncidente(incidente);

            if (menuStatusIncidente.ativo) {
                var camada = _.find(menuStatusIncidente._camada.camadas, function (camada) {
                    return camada.feature.properties.id == incidente.id
                });

                if (camada) {
                    MapaService.updateIconeIncidente(camada.layer, incidente, incidente.Comentarios.length);
                }
            }
        });

        service.getInstance('camadas-service')
            .on('reloadPoi', function (poi) {
                var menu = _obterMenu(function (menu) {
                    return menu.url == 'pois/categoria/' + poi.CategoriumId + '/geojson' ||
                        menu.categoriaId == poi.CategoriumId;
                });

                _reloadPoiRepresentacao(poi, menu);

            });

        CommService.on('poi:incidente-relacionado', function (poi) {
            var menuCategoria = _obterMenu({ categoriaId: poi.CategoriumId });
            var camada = _.find(menuCategoria._camada.camadas, function (camada) {
                return camada.feature.properties.id == poi.id;
            });

            camada.feature.properties = poi;
            MapaService.updateIncidentesRelacionados(camada.layer, poi);
        });

        CommService.on('camadas', function (data) {
            var menu = _obterMenu(function (menu) {
                return menu.url == 'pois/categoria/' + data.categoriaId + '/geojson' ||
                    menu.categoriaId == data.categoriaId;
            });

            if (menu != null && menu.ativo && data.poisUpdate != null && data.poisUpdate == "importacao") {
                _updateMenuCategoria(menu, data.pois);
            } else if (menu != null && menu.ativo && data.poisUpdate != null && data.poisUpdate == "update") {
                addOrUpdatePoiAtualizado(_.first(data.pois), menu);
            }
        });


        function getInstance(id) {
            if (!service._filtros[id]) {
                service._filtros[id] = new Service()
            }

            return service._filtros[id];
        }

        function Service() {
            var self = this;

            angular.extend(self, {
                on: on,
                trigger: trigger,
                events: {
                    'reloadMenuCamada': [],
                    'reloadPoi': []
                }
            });

            function on(eventName, callback) {
                self.events[eventName].push(callback);
            }

            function trigger(eventName, args) {
                _.each(self.events[eventName], function (callback) {
                    callback(args);
                });
            }

        }

      /**
        * Atualiza a representação do poi
        *
        * @method _reloadPoiRepresentacao
		*        
        * @param poi {Object} Poi
        * @param menu {Object} Item do Menu
		*               
        */ 
        function _reloadPoiRepresentacao(poi, menu) {
            if (menu != null && menu._camada != null) {
                _.each(menu._camada, function (_camada) {
                    _.each(_camada.camadas, function (camada) {
                        if (camada.feature != null && camada.feature.properties != null && camada.feature.properties.id == poi.id) {

                            var point;
                            if (!menu.representacao) {

                                camada.feature.properties.urlIcone = poi.urlIcone;
                                point = {
                                    type: 'Feature',
                                    properties: poi,
                                    geometry: poi.geojson
                                };

                                camada.layer.options.icon.options.html = MapaService.obterHtmlIcon(point, 'poi');

                            } else {

                                camada.feature.properties.extras = poi.extras;
                                if (camada.feature.geometry.type == 'Point' && menu.representacao.pointLayout) {

                                    RepresentacaoService.buildFeatureHtml(menu.representacao.pointLayout, camada.feature).then(function (feature) {

                                        camada.feature = feature;
                                        lastPoi = poi;
                                        var point = {
                                            type: 'Feature',
                                            properties: poi,
                                            geometry: poi.geojson,
                                            representacao: feature.representacao
                                        };

                                        var html_ = MapaService.obterHtmlIcon(point, 'poi');
                                        camada.layer.options.icon.options.html = html_;
                                        if (camada.layer._icon) {
                                            camada.layer._icon.innerHTML = html_;
                                        }

                                    });
                                } else {

                                    RepresentacaoService.buildGeometryStyle(menu.representacao.geometryStyle, camada.feature);
                                }
                            }
                        }
                    });
                });


                var latlng = {
                    lat: poi.latitude,
                    lng: poi.longitude
                };
                _atualizarPonto(menu, poi, [
                    latlng.lng,
                    latlng.lat
                ], 'poi', function () {
                    if (DetalhamentoManager.ativo && DetalhamentoManager.samePoi(poi.id)) {

                        var mapZoom;
                        MapaService.pegarZoom(function (zoom) {
                            mapZoom = zoom;
                        });

                        $timeout(function () {
                            MapaService.setView([
                                latlng.lat,
                                latlng.lng
                            ], mapZoom);
                        }, 200);

                        DetalhamentoManager.abrirPoi(poi.id, latlng);
                    }
                });


            }
        }

        var lastPoi;
      /**
        * Atualiza ou adiciona pois ao mapa
        *
        * @method addOrUpdatePoiAtualizado
		*        
        * @param poi {Object} Poi
        * @param menu {Object} Item do Menu
		*               
        */         
        function addOrUpdatePoiAtualizado(poi, menu) {

            var latlng = {
                lat: poi.latitude,
                lng: poi.longitude
            };

            var poiAlterado = DetalhamentoManager.alreadyAdded(poi);
            if (poiAlterado) {
                if (!poiAlterado.alerta || poiAlterado.alerta != poi.alerta) {
                    var point = {
                        type: 'Feature',
                        properties: poiAlterado,
                        geometry: poi.geojson
                    };

                    if (poi.alerta == 'OK') {
                        MapaManager.piscarAzul(latlng);
                    } else if (poi.alerta == 'NOK') {
                        MapaManager.piscarVermelho(latlng);
                    }
                    poiAlterado.alerta = poi.alerta;
                    poiAlterado.urlIcone = poi.urlIcone;
                }

            } else {

                if (poi.alerta == 'OK') {
                    MapaManager.piscarAzul(latlng);
                } else if (poi.alerta == 'NOK') {
                    MapaManager.piscarVermelho(latlng);
                }

                DetalhamentoManager.addPoiAlertado(poi);
            }

            _reloadPoiRepresentacao(poi, menu);
        }

      /**
        * Obtem a estrutura de menus da camada de viaturas
        *
        * @method _obterMenuOrganizacaoViatura
		*        
        * @param chave_estrangeira {String} chave estrangeira
        *
		*               
        */  
        function _obterMenuOrganizacaoViatura(chave_estrangeira) {
            var menuViaturas = _obterMenu({
                urlSubMenus: 'menuCamada/viatura',
                headers: {
                    version: 2
                }
            });
            var menusViatura = _obterMenu(function (menu) {
                return _.startsWith(menu.urlSubMenus, 'menuCamada/organizacao')
            }, true);

            var menuOrganizacao;

            _.each(menusViatura, function (menuViatura) {
                if (!menuOrganizacao) {
                    menuOrganizacao = _.find(_obterSubMenus(menuViatura), {
                        chave_estrangeira: chave_estrangeira
                    });
                }
            });

            if (!menuOrganizacao && menuViaturas) {
                menuOrganizacao = _.find(_obterSubMenus(menuViaturas), {
                    chave_estrangeira: chave_estrangeira
                });
            }

            return menuOrganizacao;
        }

      /**
        * Converte o poi para uma estrutura que o mapa possa usar
        *
        * @method _obterFeature
		*        
        * @param poi {Object} POI
        *
		*               
        */  
        function _obterFeature(poi) {

            var feature;

            if (poi.tipo === 'POLYGON') {

                var obj = poi;
                for (var key in poi.geometry.properties) {
                    if (!obj.hasOwnProperty(key)) {
                        obj[key] = poi.geometry.properties[key];
                    }
                }

                feature = {
                    type: 'Feature',
                    geometry: poi.geometry.geometry,
                    properties: obj
                };

            } else {
                feature = {
                    type: 'Feature',
                    geometry: turf.point([poi.geojson.coordinates[0], poi.geojson.coordinates[1]]).geometry,
                    properties: poi
                };

                if (!poi.urlIcone && poi.Categorium && poi.Categorium.urlIcone) {
                    poi.urlIcone = poi.Categorium.urlIcone;
                }
            }

            return feature;
        }

      /**
        * Atualiza os itens do Menu, para verificar se existem novos pois
        *
        * @method _updateMenuCategoria
		*        
        * @param menu {Object} Menu
        * @param pois {Array} Pois
        *
		*               
        */  
        function _updateMenuCategoria(menu, pois) {

            var featureCollection = turf.featurecollection(_.map(pois, _obterFeature));
            featureCollection.properties = {
                cluster: _.first(pois).Categorium.cluster,
                urlClusterIcone: _.first(pois).Categorium.urlIcone,
                tipo: 'poi'
            };
            if (menu != null && menu._camada != null && menu._camada.aggregate != null) {
                MapaService.removerCamada(menu._camada.aggregate);
                _ativarCamada(featureCollection, menu);
            }
        }

        CommService.on('viaturas', function (data) {
            listenerViatura[data.versao](data.parametros);
        });

      /**
        * Faz o tratamento para os itens do Menu de viaturas
        *
        * @method _tratarMenuOrganizacao
		*        
        * @param menuViaturas {Object} Menu de viaturas
        * @param menuAgencia {Object} Menu de agências
        * @param organizacao {Object} Organização
        * @param viaturaAtualizada {Object} Viatura
        *
		*               
        */ 
        function _tratarMenuOrganizacao(menuViaturas, menuAgencia, organizacao, viaturaAtualizada) {
            var menuStatus;
            var menuOrganizacao;

            if (viaturaAtualizada.status == 1) {
                menuStatus = _.find(menuAgencia.subMenus, function (item) {
                    return item.texto.indexOf('Ativo') != -1;
                });
            } else {
                menuStatus = _.find(menuAgencia.subMenus, function (item) {
                    return item.texto.indexOf('Inativo') != -1;
                });
            }

            menuOrganizacao = _.find(_obterSubMenus(menuStatus), { texto: organizacao.nome });

            if (!menuOrganizacao) {
                _reloadMenu(menuViaturas).then(function () {
                    menuOrganizacao = _.find(_obterSubMenus(menuStatus), { texto: organizacao.nome })
                    _atualizarViaturas(menuOrganizacao, viaturaAtualizada)
                })
            } else {
                _atualizarViaturas(menuOrganizacao, viaturaAtualizada);
            }
        }

      /**
        * Atualiza o ponto de interesse
        *
        * @method _atualizarPonto
		*        
        * @param menu {Object} Menu do Poi
        * @param ponto {Object} Poi
        * @param coordenadas {Object} Localização
        * @param tipoPonto {Object} Tipo de Poi
        * @param endMoveCallback {Function} Função a ser chamada ao fim da execução do método
        *
		*               
        */ 
        function _atualizarPonto(menu, ponto, coordenadas, tipoPonto, endMoveCallback) {
            if (!menu.ativo) {
                return;
            }

            if (tipoPonto == 'viatura') {
                menu._camada = Viatura.getLayer(menu.chave_estrangeira);
            }

            var pontosAntigos = menu._camada[0].camadas,
                pontoAntigo = _.find(pontosAntigos, function (item) {
                    return item.feature.properties.chave_estrangeira == ponto.chave_estrangeira
                }),
                feature = turf.point(coordenadas, ponto);

            if (pontoAntigo) {

                //Se POI for ponto
                if (coordenadas[0] && coordenadas[1]) {

                    pontoAntigo.layer.moveTo({
                        lat: coordenadas[1],
                        lng: coordenadas[0]
                    }, 1500);

                    pontoAntigo.feature = feature;

                    MapaService.updateClick(tipoPonto, pontoAntigo);

                    pontoAntigo.layer.once('end', function (e) {

                        atualizarCamadaMapa(e.target, feature).then(function (obj) {

                        }, function (err) {
                            console.log("Erro ao atualizar a camada.");
                        });

                        if (endMoveCallback) {
                            endMoveCallback();
                        }
                    });

                    return;
                }

                //Se POI for geometria
                var layerToRemove = getLayerToRemove(pontoAntigo.feature.properties.id, menu);
                menu._camada[0].camadas.splice(menu._camada[0].camadas.indexOf(pontoAntigo), 1);

                MapaService.removerCamada(layerToRemove != null ? layerToRemove.layer : null);

                MapaService.adicionarGeometria(pontoAntigo.feature, tipoPonto, menu._camada[0].aggregate).then(function (camadas) {
                    _.each(camadas, function (camada) {
                        if (!menu._camada) {
                            menu._camada = camada;
                        } else {
                            menu._camada[0].camadas.push(camada.camadas);
                            menu._camada[0].aggregate.addLayer(camada.aggregate);
                        }
                    });

                });

                if (endMoveCallback) {
                    endMoveCallback();
                }

            } else {

                //Se for geometria usar a feature do ponto Antigo.
                if (!coordenadas[0] || !coordenadas[1]) {
                    feature = pontoAntigo.feature;
                }

                MapaService.adicionarPonto(feature, tipoPonto, menu._camada.aggregate).then(function (camadas) {

                    _.each(camadas, function (camada) {
                        if (!menu._camada) {
                            menu._camada = camada;
                        } else {
                            menu._camada[0].camadas.push(camada.camadas);
                            menu._camada[0].aggregate.addLayer(camada.camadas.layer);
                        }
                    });

                });
            }

        }

      /**
        * Atualiza a camada do mapa
        *
        * @method atualizarCamadaMapa
		*        
        * @param layer {Object} Menu
        * @param feature {Object} Poi
        *
		*               
        */ 
        function atualizarCamadaMapa(layer, feature) {
            var deferred = $q.defer();

            var menu = _obterMenu(function (menu) {
                return menu.url == 'pois/categoria/' + feature.properties.CategoriumId + '/geojson' ||
                    menu.categoriaId == feature.properties.CategoriumId;
            });

            if (!menu.ativo) {
                deferred.resolve(false);
                return deferred.promise;
            }

            if (feature.properties.Categorium != null && feature.properties.Categorium.cluster != null && feature.properties.Categorium.cluster.id == 3) {
                MapaService.removerCamada(layer).then(function () {
                    MapaService.addLayer(layer);
                    deferred.resolve(true);
                });

            }
            else {
                MapaService.removerCamada(layer, layer.layerGroup).then(function () {
                    MapaService.adicionarLayer(layer);
                    deferred.resolve(true);
                });
            }

            return deferred.promise;
        }

      /**
        * Obtem a camada a ser removida
        *
        * @method getLayerToRemove
		*        
        * @param id {Integer} Identificador
        * @param menu {Menu} Menu
        *
		*               
        */ 
        function getLayerToRemove(id, menu) {

            for (var index in menu._camada.camadas) {
                if (menu._camada.camadas[index].feature.properties.id == id) {
                    return menu._camada.camadas[index];
                }
            }

            return null;
        }

      /**
        * Atualiza as viaturas do menu de viaturas
        *
        * @method _atualizarViaturas
		*        
        * @param menuOrganizacao {Object} Menu
        * @param viaturaAtualizada {Object} Viatura
        *
		*               
        */ 
        function _atualizarViaturas(menuOrganizacao, viaturaAtualizada) {

            _atualizarPonto(menuOrganizacao, viaturaAtualizada, [
                viaturaAtualizada.posicao.longitude,
                viaturaAtualizada.posicao.latitude
            ], 'viatura', function () {
                if (DetalhamentoManager.ativo &&
                    DetalhamentoManager.data &&
                    DetalhamentoManager
                        .data
                        .chave_estrangeira == viaturaAtualizada.chave_estrangeira) {

                    DetalhamentoManager.data.informacoes = viaturaAtualizada.informacoes;
                    DetalhamentoManager.data.nome = viaturaAtualizada.nome;
                    DetalhamentoManager.titulo = viaturaAtualizada.nome;

                    var latlng = {
                        lat: viaturaAtualizada.posicao.latitude,
                        lng: viaturaAtualizada.posicao.longitude
                    };

                    MapaService.piscarAzul(latlng);
                }
            });
        }

      /**
        * Verifica status dos menus pais.
        *
        * @method _checkParentStatus
		*        
        * @param menu {Object} Menu
        * 
		*               
        */ 
        function _checkParentStatus(menu) {
            var parentMenu = menu.parentNode;

            if (parentMenu != null && parentMenu.hasOwnProperty('subMenus') && parentMenu.subMenus.length > 0) {
                var disabledMenus = parentMenu.subMenus.filter(function (menu) {
                    return !menu.ativo;
                });

                if (disabledMenus != null && parentMenu != null && disabledMenus.length === parentMenu.subMenus.length) {
                    parentMenu.ativo = false;
                    _removerLegendaDeGrupo(parentMenu);
                } else if (disabledMenus != null && parentMenu != null && disabledMenus.length === 0) {
                    parentMenu.ativo = true;
                }
            }
        }

      /**
        * Ativa o menu
        *
        * @method ativarMenu
		*        
        * @param menu {Object} Menu
        * 
		*               
        */ 
        function ativarMenu(menu) {
            vincularAoPreset();
            if (menu.subMenus && menu.subMenus.length > 0) {
                _.each(menu.subMenus, function (subMenu) {
                    if (!subMenu.disabled) {
                        subMenu.ativo = menu.ativo;
                        ativarMenu(subMenu);
                    }
                });
            }
        }

      /**
        * Desativa o menu
        *
        * @method desativarMenu
		*        
        * @param menu {Object} Menu
        * 
		*               
        */ 
        function desativarMenu(menu) {
            if (menu.subMenus && menu.subMenus.length > 0) {
                _.each(menu.subMenus, function (subMenu) {
                    if (subMenu.ativo) {
                        subMenu.ativo = false;
                        if (subMenu.subMenus && subMenu.subMenus.length > 0) {
                            desativarMenu(subMenu);
                        }
                    }
                });
            }
        }

        var chavesViaturas = [];
        var chavesCameras = [];
   
      /**
        * Ação chamada no click do item de menu
        *
        * @method toggleMenu
		*        
        * @param menu {Object} Menu
        * 
		*               
        */ 
        function toggleMenu(menu) {

            if (menu.menuViatura) {
                chavesViaturas = [];
            }

            if ((menu.urlSubMenus && menu.urlSubMenus.indexOf('camera') !== -1) || menu.camera) {
                chavesCameras = [];
            }

            function toggleMenuRecursive(menu) {
                if (menu.subMenus && menu.subMenus.length > 0) {
                    _.each(menu.subMenus, function (subMenu) {
                        if (!subMenu.disabled) {
                            subMenu.ativo = menu.ativo;
                            toggleMenuRecursive(subMenu);
                        }
                    });
                } else {
                    menu.categoriaFim = true;
                    if (menu.menuViatura) {
                        chavesViaturas.push({ organizacao: menu.chave_estrangeira, node: menu });
                    }

                    if (menu.camera) {
                        chavesCameras.push({ categoria: menu.categoriaCameraId, node: menu });
                    }
                }

                if (menu.url || menu.categoriaId) {
                    toggleNode(menu);
                }

                if (menu.menuSensor) {
                    var _node = menu;
                    _.each(service.menusPorAcervo[menu.acervoTipoId], function (menu) {
                        menu.ativo = _node.ativo;
                        toggleMenuRecursive(menu);
                    });
                }
            }

            if (menu.acervoId != null && menu.ativo) {
                return _toggleMenuPoiAcervo(menu);

            } else if (menu.GrupoId != null && menu.ativo) {

                return _toggleMenuPoiGrupo(menu);

            } else if (!menu.ativo && (menu.GrupoId != null || menu.categoriaId != null)) {
                desativarMenu(menu);
                _desabilitarCategoriaPai(menu);
                if (menu.categoriaId != null) {
                    _removerLegenda(menu.categoriaId);
                    _removerCamadasAcervoCategoria(menu, menu.categoriaId);
                } else {
                    _removerCamadasAcervoCategoria(menu);
                }
                MapaService.naoPiscar();
                vincularAoPreset();
                return;
            } else if (menu.ativo && menu.tipo == 'ZO' && moduloZonaObservacaoFilter && !!MainState.getDirective('zonasDeObservacao')) {
                return _toggleMenuZonaObservacao(menu);

            } else if (!!MainState.getDirective('areaAtuacao') && menu.area) {
                _toggleMenuAreaAtuacao(menu);

            } else if (!!MainState.getDirective('pontoMovel') && menu.pontoMovel) {
                _toggleMenuPontoMovel(menu);

            } else {
                toggleMenuRecursive(menu);
            }

            if (menu.ativo && (menu.menuViatura || (menu.urlSubMenus && menu.urlSubMenus.indexOf('viatura') !== -1))) {

                loadViaturas(menu);

            } else if ((menu.ativo && menu.urlSubMenus && menu.urlSubMenus.indexOf('camera') !== -1) || (menu.camera && menu.ativo)) {

                loadCameras(menu);

            } else {

                toggleParentNode(menu);
                _checkParentStatus(menu);
            }
            vincularAoPreset();
        }

      /**
        * Carrega as câmeras
        *
        * @method loadCameras
		*        
        * @param menu {Object} Menu
        * 
		*               
        */ 
        function loadCameras(menu) {

            Base.obter('categoria_camera')
                .then(function (categorias) {

                    categorias = _.map(categorias, function (categoria) {
                        return categoria.id;
                    });
                    Camera.obterCamerasPorCategoria(categorias).then(function (cameras) {

                        _.each(cameras, function (featureCollection) {

                            if (featureCollection.features.length > 0) {
                                if (!featureCollection.properties.urlClusterIcone) {
                                    featureCollection.properties.urlClusterIcone = featureCollection.features[0].properties.urlIcone;
                                }
                                _ativarCamada(featureCollection, menu);

                            }
                        });
                    });
                });
        }

      /**
        * Carrega as viaturas
        *
        * @method loadViaturas
		*        
        * @param menu {Object} Menu
        * 
		*               
        */ 
        function loadViaturas(menu) {

            var organizacoes = chavesViaturas.reduce(function (filtered, chave) {

                filtered.push(chave.organizacao);
                return filtered;
            }, []);

            if (menu) { menu.disabled = true; }
            Viatura.obterViaturas(organizacoes).then(function (viaturas) {

                if (menu) { menu.disabled = false; }
                _.each(viaturas, function (featureCollection) {

                    if (featureCollection.features.length > 0) {
                        var node = _.find(chavesViaturas, function (chave) {
                            return chave.organizacao == featureCollection.features[0].properties.organizacao;
                        });

                        if (node) {
                            if (node.node) {
                                node = node.node;
                            }
                        } else {
                            node = menu;
                        }

                        Viatura.addLayer(featureCollection, node);

                    }
                });
            });
        }

      /**
        * Remove os pois do mapa pelo código do acervo
        *
        * @method _removerCamadasAcervoGrupo
		*        
        * @param menu {Object} Menu
        * @param acervoId {Integer} Identificador
        * 
		*               
        */ 
        function _removerCamadasAcervoGrupo(menu, acervoId) {
            if (menu._camada != null && acervoId != null) {
                MapaService.removerCamadaAcervo(menu._camada, acervoId);
            } else if (menu._camada != null && acervoId == null) {
                MapaService.removerCamada(menu._camada.aggregate);
            }
            if (menu.subMenus && menu.subMenus.length > 0) {
                _.each(menu.subMenus, function (subMenu) {
                    if (subMenu._camada != null) {
                        if (subMenu._camada != null && acervoId != null) {
                            MapaService.removerCamadaAcervo(subMenu._camada, acervoId);
                        } else if (subMenu._camada != null && acervoId == null) {
                            MapaService.removerCamada(subMenu._camada.aggregate);
                        }
                        if (subMenu.subMenus && subMenu.subMenus.length > 0) {
                            _.each(subMenu.subMenus, function (subMenu_) {
                                _removerCamadasAcervoGrupo(subMenu_, acervoId);
                            });
                        }
                    } else {
                        _removerCamadasAcervoGrupo(subMenu, acervoId);
                    }
                });
            }
            vincularAoPreset();
        }

      /**
        * Remove os pois do mapa pelo código da categoria
        *
        * @method _removerCamadasAcervoCategoria
		*        
        * @param menu {Object} Menu
        * @param categoriaId {Integer} Identificador
        * 
		*               
        */ 
        function _removerCamadasAcervoCategoria(menu, categoriaId) {
            if (menu._camada != null) {
                MapaService.removerCamadaCategoria(menu._camada, categoriaId);
            }
            if (menu.subMenus && menu.subMenus.length > 0) {
                _.each(menu.subMenus, function (subMenu) {
                    if (subMenu._camada != null) {
                        MapaService.removerCamadaCategoria(subMenu._camada, subMenu.categoriaId);
                        if (subMenu.categoriaId != null) {
                            _removerLegenda(subMenu.categoriaId);
                        }
                        if (subMenu.subMenus && subMenu.subMenus.length > 0) {
                            _.each(subMenu.subMenus, function (subMenu_) {
                                _removerCamadasAcervoCategoria(subMenu_, categoriaId);
                            });
                        }
                    } else {
                        _removerCamadasAcervoCategoria(subMenu, categoriaId);
                    }
                });
            }
        }

      /**
        * Ativa o menu de pois e coloca no mapa
        *
        * @method _ativarCamada
		*        
        * @param featureCollection {Object} Lista de Pois no formato de feature
        * @param node {Object} Item do menu
        * 
		*               
        */
        function _ativarCamada(featureCollection, node) {
            vincularAoPreset();
            if (node._camada) {

                for (var index in node._camada) {
                    if(node._camada[index])
                        MapaService.removerCamada(node._camada[index].aggregate);
                }
                return _adicionarPontos(featureCollection, node, true);
            } else {
                return _adicionarPontos(featureCollection, node);
            }
        }

        var canAddNewPoints = true;
        
      /**
        * Adiciona os incidentes no mapa
        *
        * @method _adicionarPontos
		*        
        * @param featureCollection {Object} Lista de Pois no formato de feature
        * @param node {Object} Item do menu
        * @param zoom {Object} Zoom
        * 
		*               
        */        
        function _adicionarPontos(featureCollection, node, zoom) {
            return MapaService.adicionarPontos(featureCollection, zoom).then(function (camadas) {

                if(!camadas){
                    return;
                }

                node.disabled = false;
                node._camada = camadas;

                if (!featureCollection || !featureCollection.properties) {
                    return;
                }

                if (featureCollection.properties.tipo == 'incidente') {
                    _.each(featureCollection.features, function (feature) {

                        var menuStatusIncidente = _obterMenuStatusIncidente(feature.properties || feature);
                        var camada;
                        if (menuStatusIncidente._camada) {
                            camada = _.find(menuStatusIncidente._camada.camadas, function (camada) {
                                if (camada != undefined && camada != null) {
                                    return camada.feature.properties.chave_estrangeira ==
                                        feature.properties ? feature.properties.chave_estrangeira : feature.chave_estrangeira;
                                }
                            });
                        }

                        if (camada != null) {
                            MapaService.updateIconeIncidente(camada.layer, feature.properties ||
                                feature, feature.properties ? feature.properties.qtdComentarios : undefined)
                        }
                    });
                }

                canAddNewPoints = true;
                return camadas;
            });
        }

      /**
        * Aciona o pai do item de menu
        *
        * @method toggleParentNode
		*        
        * @param node {Object} Item do menu
        * 
		*               
        */  
        function toggleParentNode(node) {
            if (node.parentNode) {
                node.parentNode.ativo = _.every(node.parentNode.subMenus, 'ativo');
                toggleParentNode(node.parentNode);
            } else {
                node.selecionarTodos = _.every(node.subMenus, 'ativo');
            }
        }

        //Função para recarregar as informações selecionadas nas camadas após a seleção de uma área de atuação.
      /**
        * Função para recarregar as informações selecionadas nas camadas após a seleção de uma área de atuação.
        *
        * @method reloadNodes
		*        
        * 
		*               
        */         
        function reloadNodes() {

            MapaService.clearAllMarkerCluster();
            for (index in nodesToBeReloaded) {
                nodesToBeReloaded[index].ativo = false;
                toggleNode(nodesToBeReloaded[index], 'naoRemove');
            }

            var hasViaturas = false;
            var hasCameras = false;
            for (index in nodesToBeReloaded) {
                nodesToBeReloaded[index].ativo = true;

                if (!nodesToBeReloaded[index].menuViatura && (!nodesToBeReloaded[index].url || nodesToBeReloaded[index].url.indexOf('camera') == -1)) {
                    if (!nodesToBeReloaded[index].acervoId) {
                        toggleNode(nodesToBeReloaded[index], 'remove');
                    } else {
                        _toggleMenuPoiAcervo(nodesToBeReloaded[index]);
                    }
                } else if (nodesToBeReloaded[index].menuViatura) {
                    hasViaturas = true;
                } else {
                    hasCameras = true;
                }
            }

            if (hasViaturas) {
                loadViaturas();
            }

            if (hasCameras) {
                loadCameras();
            }

            clearZoomEvents();
        }

      /**
        * Limpa a lista de itens de menus que devem ser recarregados
        *
        * @method clearReloadNodes
		*        
        * 
        */   
        function clearReloadNodes() {
            nodesToBeReloaded = [];
        }

      /**
        * Adiciona itens de menu a lista de itens que serão recarregados
        *
        * @method addToNodesToBeReloaded
		*        
        * @param node {Object} Item do menu
        * 
		*               
        */  
        function addToNodesToBeReloaded(node) {

            var hasNode = false;
            for (var index in nodesToBeReloaded) {
                if (nodesToBeReloaded[index].id == node.id
                    && nodesToBeReloaded[index].acervoId == node.acervoId
                    && (node.parentNode.acervoId == nodesToBeReloaded[index].parentNode.acervoId || node.parentNode.acervoId == nodesToBeReloaded[index].acervoId)
                    && node.texto == nodesToBeReloaded[index].texto) {

                    hasNode = true;
                }
            }

            if (!hasNode) {
                nodesToBeReloaded.push(node);
            }
        }

        var nodesToBeReloaded = [];
        
       /**
        * Função chamada no click do item de menu
        *
        * @method toggleNode
		*        
        * @param node {Object} Item do menu
        * @param options {Object} Options
		*               
        */  
        function toggleNode(node, options) {

            if (node && node.ativo) {
                if (moduloIncientesFiltro && node.categoriaIncidenteId) {
                    moduloIncientesFiltro.ativarCategoria(node.categoriaIncidenteId, 'camadas');
                    moduloIncientesFiltro.toggleStatus(node.parentNode.texto, true);
                }

                addToNodesToBeReloaded(node);

                if (node.categoriaId && node.categoriaFim) {
                    return _toggleNodePoi(node);

                } else {

                    if (moduloIncientesFiltro && node.url == "incidente") {
                        return _toggleNodeMsi(node);

                    } else if (moduloZonaObservacaoFilter && !!MainState.getDirective('zonasDeObservacao') && node.url != null && node.zo) {
                        return _toggleNodeZonaObservacao(node);

                    } else if (!!MainState.getDirective('areaAtuacao') && node.area) {
                        return _toggleNodeAreaAtuacao(node);

                    } else if (!!MainState.getDirective('pontoMovel') && node.pontoMovel) {
                        return _toggleNodePontoMovel(node);
                    }
                    else {
                        urlFilter = node.url;
                    }

                    if (node.url != null && !node.menuViatura && node.url.indexOf('camera') == -1) {

                        node.disabled = true;
                        return Menu
                            .obterGeoJSON(urlFilter)
                            .then(function (featureCollection) {
                                node.disabled = false;
                                return _ativarCamada(featureCollection, node);
                            });

                    }
                }
            } else {
                if (node) {

                    //Só remove da lista se o usuário deselecionar o checkbox do node correspondente.
                    if (!options || options != 'naoRemove') {
                        nodesToBeReloaded = _.filter(nodesToBeReloaded, function (n) {
                            return node.text != n.texto && node.url != n.url;
                        });
                    }

                    if (moduloIncientesFiltro && node.categoriaIncidenteId &&
                        !(options && options.origem == 'filtro')) {

                        if (_.every(node.parentNode.subMenus, { ativo: false })) {
                            moduloIncientesFiltro.toggleStatus(node.parentNode.texto, false);
                        }
                    }

                    if (!!MainState.getDirective('areaAtuacao') && node.area) {
                        return _removerCamadaAreaAtuacao(node);
                    }

                    if (!!MainState.getDirective('pontoMovel') && node.pontoMovel) {
                        return _removerCamadaPontoMovel(node);
                    }

                    if (node.menuViatura) {
                        if (options != 'naoRemove') {
                            return _removerCamadaViatura(node);
                        } else {
                            //Se tiver sido chamado pela filtragem de área de atuação, remove todas as viaturas.
                            return _removerCamadaViatura(node, 'removeAll');
                        }
                    }

                    if (node._camada) {

                        if (node.url == "incidente") {
                            var msiDirective = MainState.getDirective('filtro-msi');
                            msiDirective.removerCamadas();

                            for (var index in node._camada) {
                                MapaService.removerCamada(node._camada[index].aggregate);
                            }
                        }
                        else {
                            for (var index in node._camada) {
                                MapaService.removerCamada(node._camada[index].aggregate);
                            }
                        }
                        MapaService.naoPiscar();
                        MapaManager.removerLinhas();

                        if (node.categoriaIncidenteId) {
                            node._camada = null;
                        }
                        vincularAoPreset();

                    } else if (node.subMenus) {
                        _removerCamadasAcervoGrupo(node, node.acervoId);
                    }

                }
            }
        }

       /**
        * Verifica se os itens de menu já foram recarregados
        *
        * @method nodesAlreadyReloaded
		*        
		*               
        */  
        function nodesAlreadyReloaded(){
            return nodesToBeReloaded.length > 0;
        }

       /**
        * Carrega os pois de um Grupo
        *
        * @method _toggleMenuPoiGrupo
        * @param menu {Object} Menu       
		*               
        */ 
        function _toggleMenuPoiGrupo(menu) {

            if (nodesToBeReloaded.indexOf(menu) <= -1) {

                for (var index in menu.subMenus) {
                    nodesToBeReloaded.push(menu.subMenus[index]);
                }
            }

            ativarMenu(menu);
            return Base
                .obter('pois/grupo/simple/' + menu.GrupoId)
                .then(function (poiDTO) {
                    _incluirLegenda(poiDTO);

                    ativarCamada(generateFeatureCollectionList(poiDTO), menu);
                });
        }

       /**
        * Carrega os pois de um Acervo
        *
        * @method _toggleMenuPoiAcervo
        * @param menu {Object} Menu       
		*               
        */
        function _toggleMenuPoiAcervo(menu) {

            if (nodesToBeReloaded.indexOf(menu) <= -1) {
                nodesToBeReloaded.push(menu);
            }

            ativarMenu(menu);
            return Base
                .obter('pois/acervo/simple/' + menu.acervoId)
                .then(function (poiDTO) {
                    _incluirLegenda(poiDTO);

                    ativarCamada(generateFeatureCollectionList(poiDTO), menu);
                });
        }

        circlesPoisRelacionados = [];
       /**
        * Carrega os pois relacionados a uma categoria
        *
        * @method carregarPoisRelacionados
        * @param id {Integer} Identificador do Poi
        * @param categoriaId {Integer} Identificador da categoria               
		*               
        */        
        function carregarPoisRelacionados(id, categoriaId) {

            return Base
                .obter('pois/rel/simple/' + id)
                .then(function (poiDTO) {

                    var featureCollectionList = generateFeatureCollectionList(poiDTO);
                    removerPoisRelacionados(categoriaId);

                    for (var i = 0; i < featureCollectionList.length; i++) {

                        var featureCollection = featureCollectionList[i];

                        if (featureCollection != null && featureCollection.properties != null) {

                            if (featureCollection.categoriaId != categoriaId) {
                                continue;
                            }

                            if (featureCollection.properties.acervo && featureCollection.properties.acervo.AcervoTipo) {
                                featureCollection.properties.tipo = $filter('lowercase')(featureCollection.properties.acervo.AcervoTipo.nome);
                            }

                            var menu;
                            if (featureCollection.features && featureCollection.features.length > 0) {
                                menu = _obterMenu(function (meuMenu) {
                                    return meuMenu.categoriaId == featureCollection.features[0].properties.CategoriumId ||
                                        meuMenu.url === 'pois/categoria/' + featureCollection.features[0].properties.CategoriumId + '/geojson';
                                });
                            }

                            MapaService.desenharCirculosPois(featureCollection, 40).then(function (arrayCircles) {
                                circlesPoisRelacionados = circlesPoisRelacionados.concat(arrayCircles);
                            });
                        }
                    }

                    $timeout(function () {
                        MapaService.enquadrarPoisRelacionados(circlesPoisRelacionados);
                    }, 600);
                });
        }

       /**
        * Remove os pois relacionados a uma categoria
        *
        * @method removerPoisRelacionados
		*
        * @param categoriaId {Integer} Identificador da categoria               
		*               
        */   
        function removerPoisRelacionados(categoriaId) {

            MapaManager.removerCirculosPois(circlesPoisRelacionados, categoriaId);
            if (categoriaId == null) {
                circlesPoisRelacionados = [];
            }
        }

       /**
        * Obtem a representação do Poi
        *
        * @method getRepresentacao
		*
        * @param representacoes {Array} Representações               
		* @param poi {Object} Poi               
        */  
        function getRepresentacao(representacoes, poi) {

            return representacoes[poi.CategoriumId].json;
        }

       /**
        * Gera uma FeatureColletion com o Poi
        *
        * @method generateFeatureCollectionList
		*
        * @param poiDTO {Object} Dados do Poi               
		*                
        */ 
        function generateFeatureCollectionList(poiDTO) {
            var featureCollectionList = [];
            var featureMap = {};
            var listPois = poiDTO.pois;
            var representacoes = poiDTO.representacoes;

            for (var i = 0; i < listPois.length; i++) {

                var poi = listPois[i];
                poi.Categorium = findObjectById(poiDTO.categorias, poi.CategoriumId);
                poi.acervo = findObjectById(poiDTO.acervos, poi.AcervoId);
                var featureCollection;
                var features = [];

                if (featureMap[poi.CategoriumId] == null || featureMap[poi.CategoriumId] == undefined) {

                    var rep = getRepresentacao(representacoes, poi);
                    featureCollection = {
                        features: [], type: "FeatureCollection", categoriaId: poi.CategoriumId,
                        representacao: rep != null && rep != undefined ? rep : null
                    };
                    featureMap[poi.CategoriumId] = featureCollection;

                } else {
                    featureCollection = featureMap[poi.CategoriumId];
                }

                var feature = {
                    geometry: poi.geometry,
                    type: "Feature",
                    properties: poi
                };
                featureCollection.features.push(feature);
                var urlClusterIcone = "";
                var cluster = null;

                if (poi.Categorium != null) {
                    if (poi.Categorium.urlClusterIcone != null) {
                        urlClusterIcone = poi.Categorium.urlClusterIcone;
                    }
                    if (poi.Categorium.cluster != null) {
                        cluster = poi.Categorium.cluster;
                    }
                }
                else {
                    cluster = 1; //"AGRUPAR_JUNTO"
                }

                var properties = { cluster: cluster, tipo: "poi", urlClusterIcone: urlClusterIcone, acervo: poi.acervo };
                featureCollection.properties = properties;

                featureCollectionList = updatePoiCollections(featureCollectionList, featureCollection);
            }

            return featureCollectionList;
        }

       /**
        * Obtem um objeto pelo Id
        *
        * @method generateFeatureCollectionList
		*
        * @param listData {Array} Lista com os objetos
        * @param id {Integer} Identificador do Objeto                       
		*                
        */ 
        function findObjectById(listData, id) {

            for (var i = 0; i < listData.length; i++) {
                var data = listData[i];
                if (data.id == id) {
                    return data;
                }
            }

            return null;
        }

       /**
        * Atualiza a lista de pois com o id da categoria
        *
        * @method updatePoiCollections
		*
        * @param collections {Array} 
        * @param featureCollection {Array}                        
		*                
        */ 
        function updatePoiCollections(collections, featureCollection) {

            var index = -1;

            for (var i = 0; i < collections.length; i++) {
                if (collections[i].categoriaId == featureCollection.categoriaId) {
                    index = i;
                    break;
                }
            }

            if (index > -1) {
                collections[index] = featureCollection;
            }
            else {
                collections.push(featureCollection);
            }

            return collections;
        }

       /**
        * Ativa a camada
        *
        * @method ativarCamada
		*
        * @param featureCollection {Array} 
        * @param menu {Objeto}                        
		*                
        */ 
        function ativarCamada(featureCollectionList, menu) {

            _.each(featureCollectionList, function (featureCollection) {

                if (featureCollection != null && featureCollection.properties != null) {

                    if (featureCollection.properties.acervo && featureCollection.properties.acervo.AcervoTipo) {
                        featureCollection.properties.tipo = $filter('lowercase')(featureCollection.properties.acervo.AcervoTipo.nome);
                    }

                    if (featureCollection.features && featureCollection.features.length > 0) {
                        menu = _obterMenu(function (meuMenu) {
                            return meuMenu.categoriaId == featureCollection.features[0].properties.CategoriumId ||
                                meuMenu.url === 'pois/categoria/' + featureCollection.features[0].properties.CategoriumId + '/geojson';
                        });
                    }

                    if (featureCollection.representacao) {
                        buildRepresentation(featureCollection, menu);
                        return;
                    }

                    _ativarCamada(featureCollection, menu);
                }
            });

            if (menu.ativo && menu.parentNode != null) {
                toggleParentNode(menu);
            }
            return;
        }

       /**
        * Verifica se o extra possui indicador para mudar a representação do POI no mapa
        *
        * @method containsExtra
		*
        * @param extra {Json} 
		*                
        */
        function containsExtra(extra) {

            for (var index in service.indicadores) {
                if (service.indicadores[index].label == extra.label) {
                    return true;
                }
            }

            return false;
        }

        var zoomEvents = [];
        
       /**
        * Obtem os pois referente ao item de menu (que possui uma categoria associada)
        *
        * @method _toggleNodePoi
		*
        * @param node {Object} 
		*                
        */        
        function _toggleNodePoi(node) {
            return Base
                .obter('pois/categoria/simple/' + node.categoriaId + '/geojson')
                .then(function (poiDTO) {

                    _incluirLegenda(poiDTO);

                    var featureCollectionList = generateFeatureCollectionList(poiDTO);
                    var featureCollection = {};

                    if (featureCollectionList.length > 0) {
                        featureCollection = featureCollectionList[0];
                        if (featureCollection.properties.acervo && featureCollection.properties.acervo.AcervoTipo) {
                            featureCollection.properties.tipo = $filter('lowercase')(featureCollection.properties.acervo.AcervoTipo.nome);
                        }

                        for (var index in featureCollection.features) {
                            if (featureCollection.features[index].properties.extras) {
                                for (var index2 in featureCollection.features[index].properties.extras.informacoes) {
                                    if (!containsExtra(featureCollection.features[index].properties.extras.informacoes[index2])) {
                                        if (featureCollection.features[index].properties.extras.informacoes[index2].tipo == "INDICADOR") {
                                            node.isToShowColorMapSelector = true;
                                            service.indicadores.push(featureCollection.features[index].properties.extras.informacoes[index2]);
                                        }
                                    }
                                }
                            }
                        }

                        if (featureCollection.representacao) {
                            buildRepresentation(featureCollection, node);
                        }
                    }

                    return _ativarCamada(featureCollection, node);
                });
        }

       /**
        * Limpa os markclusters do mapa
        *
        * @method clearLayers
		*
        *  
		*                
        */       
        function clearLayers(){
            MapaService.clearMarkerCluster();
        }

       /**
        * Obtem a representação do Poi
        *
        * @method buildRepresentation
		*
		* @param featureCollection {Object} FeatureCollection 
        * @param node {Object} Item de Menu
		*                
        */ 
        function buildRepresentation(featureCollection, node) {

            node.representacao = featureCollection.representacao;
            RepresentacaoService.obterLayout(featureCollection, MapaService.obterMapaAtivo());

            //Função a ser executada no evento de zoom.
            var func = function (e) {

                if (!node || node.ativo) {

                    MapaService.clearMarkerCluster();

                    //Pega as coordenadas do ultimo poi recebido por websocket e atualiza o featureCollection
                    if (lastPoi) {
                        for (var index in featureCollection.features) {
                            if (featureCollection.features[index].properties.id == lastPoi.id) {
                                featureCollection.features[index].geometry = lastPoi.geometry;
                                featureCollection.features[index].properties.geometry = lastPoi.geometry;
                            }
                        }
                    }

                    if (canAddNewPoints == false) {

                        $timeout(function () {
                            canAddNewPoints = false;
                            RepresentacaoService.obterLayoutByZoom(featureCollection, e.target);
                            _ativarCamada(featureCollection, node);

                        }, 50);

                    } else {
                        canAddNewPoints = false;
                        RepresentacaoService.obterLayoutByZoom(featureCollection, e.target);
                        _ativarCamada(featureCollection, node);
                    }
                }
            }

            //Remove o evento antigo de zoom e coloca um novo. Evita de ter varios listeners
            //associados à mesma camada de poi e que estava dando problema de camadas replicadas.
            var eventToRemove = containsEvent(((node && node.categoriaId) || featureCollection.features[0].properties.CategoriumId));
            if (!eventToRemove) {

                zoomEvents.push({ categoriaId: ((node && node.categoriaId) || featureCollection.features[0].properties.CategoriumId), evento: func });
                MapaService.zoomOn('zoomend', func);

            } else {

                MapaService.zoomOff('zoomend', eventToRemove.evento);
                MapaService.zoomOn('zoomend', func);
                eventToRemove.evento = func;
            }
        }

       /**
        * Limpa os eventos de zoom do mapa
        *
        * @method clearZoomEvents
		*
		*                
        */ 
        function clearZoomEvents() {
            MapaService.clearZoomEvents(zoomEvents);
        }

       /**
        * Verifica se a categoria possui evento de zoom
        *
        * @method containsEvent
		*
		* @param categoriaId {Integer} Identificador da categoria 
		*                
        */ 
        function containsEvent(categoriaId) {

            if (zoomEvents.length == 0) {
                return false;
            }

            for (var index = 0; index < zoomEvents.length; index++) {
                if (zoomEvents[index].categoriaId == categoriaId) {
                    return zoomEvents[index];
                }
            }

            return false;
        }

       /**
        * Retorna uma lista com os departamentos das zonas de observação que estão ativos no mapa
        *
        * @method departamentosAtivosZO
		*
		*  
		*                
        */ 
        function departamentosAtivosZO() {
            var menu = _obterMenu({ urlSubMenus: 'menuCamada/zona_observacao' });

            var departamentosAtivos = [];
            if (menu != null && menu.ativo) {
                _.each(menu.subMenus, function (submenus) {
                    if (submenus.ativo) {
                        departamentosAtivos.push(submenus.DepartamentoId);
                    }
                });
            }
            return departamentosAtivos;
        }

       /**
        * Remove as zonas de observação do mapa
        *
        * @method _removerZonasDeObservacao
		*
		*
		*                
        */ 
        function _removerZonasDeObservacao() {
            var menu = _obterMenu({ urlSubMenus: 'menuCamada/zona_observacao' });

            if (menu != null && menu.ativo) {
                menu.subMenus.map(function (camadaZo) {
                    if (camadaZo._camada) {
                        for (var index in camadaZo._camada) {
                            camadaZo._camada[index].camadas.map(function (camada) {
                                MapaService.removerCamada(camada.layer);
                            });
                        }
                    }
                });
            }
        }

       /**
        * Obtem as zonas de observação para adicionar no mapa
        *
        * @method _toggleMenuZonaObservacao
		*
		* @param menu {Object} Item do Menu 
		*                
        */ 
        function _toggleMenuZonaObservacao(menu) {
            _removerZonasDeObservacao();
            ativarMenu(menu);
            var zonasDeObservacaoDirective = MainState.getDirective('zonasDeObservacao');

            if (!zonasDeObservacaoDirective) {
                return;
            }

            return Base
                .obter('zona_observacao/geojson' + '?' + 'filtro=' + JSON.stringify(zonasDeObservacaoDirective.setQuery()))
                .then(function (data) {
                    var zonas = [];
                    _.each(menu.subMenus, function (subMenu) {
                        _.each(data, function (dto) {
                            if (subMenu.DepartamentoId == dto.DepartamentoId) {
                                _.each(dto.zonaObservacao.features, function (feature) {
                                    feature.properties.active = false;
                                    zonas.push(feature.properties);
                                });
                                _ativarCamada(dto.zonaObservacao, subMenu);
                            }
                        });
                    });

                    zonasDeObservacaoDirective.refreshZonas(zonas);

                    return;
                });
        }

       /**
        * Adiciona as zonas de observação no mapa
        *
        * @method _toggleNodeZonaObservacao
		*
		* @param node {Object} Item do Menu 
		*                
        */ 
        function _toggleNodeZonaObservacao(node) {
            var urlFilter;
            var zonasDeObservacaoDirective = MainState.getDirective('zonasDeObservacao');

            urlFilter = node.url + '?' + 'filtro=' + JSON.stringify(zonasDeObservacaoDirective.setQuery());

            return Menu
                .obterGeoJSON(urlFilter)
                .then(function (featureCollection) {

                    var zonas = [];

                    _.each(featureCollection.features, function (feature) {
                        feature.properties.active = false;
                        zonas.push(feature.properties);
                    });

                    zonasDeObservacaoDirective.refreshZonas(zonas);

                    _ativarCamada(featureCollection, node);
                });
        }

       /**
        * Ativa o menu da Área de Atuação  e obtem as Áreas de Atuação para adicionar no Mapa
        *
        * @method ativarMenuDaAreaAtuacao
		*
		* @param node {Object} Item do Menu 
		*                
        */ 
        function ativarMenuDaAreaAtuacao(idArea, idRegiao) {
            var menuAreaAtuacao = _obterMenu({ urlSubMenus: 'menuCamada/area_atuacao' });
            var subMenu = {};
            _.each(menuAreaAtuacao.subMenus, function (item) {
                if (item.id == idArea) {
                    subMenu = item;
                    subMenu.idRegiao = idRegiao;
                }
            });
            _ativarMenu(subMenu);
        }

       /**
        * Adiciona as Áreas de Atuação no Mapa
        *
        * @method _toggleMenuAreaAtuacao
		*
		* @param menu {Object} Menu 
		*                
        */ 
        function _toggleMenuAreaAtuacao(menu) {
            var areaAtuacaoDirective = MainState.getDirective('areaAtuacao');
            var regiao = { idArea: menu.id, id: menu.idRegiao, remover: true }
            areaAtuacaoDirective.carregarLayerAreaAtuacao(regiao, menu);
        }

       /**
        * Carrega as Áreas de Atuação no Mapa
        *
        * @method _toggleNodeAreaAtuacao
		*
		* @param menu {Object} Menu 
		*                
        */ 
        function _toggleNodeAreaAtuacao(node) {
            var areaAtuacaoDirective = MainState.getDirective('areaAtuacao');
            var regiao = { idArea: node.id, id: node.idRegiao }
            areaAtuacaoDirective.carregarLayerAreaAtuacao(regiao, node);
        }

       /**
        * remove as Áreas de Atuação no Mapa
        *
        * @method _removerCamadaAreaAtuacao
		*
		* @param menu {Object} Menu 
		*                
        */ 
        function _removerCamadaAreaAtuacao(node) {
            var areaAtuacaoDirective = MainState.getDirective('areaAtuacao');
            areaAtuacaoDirective.removerLayers(node.id);
            vincularAoPreset();
        }

        //Ponto Móvel
       /**
        * Carrega os pontos móveis pelo tipo do menu
        *
        * @method _toggleMenuPontoMovel
		*
		* @param menu {Object} Menu 
		*                
        */        
        function _toggleMenuPontoMovel(menu) {
            var pontoMovelDirective = MainState.getDirective('pontoMovel');
            if (menu.ativo) {
                pontoMovelDirective.buscarPontosMoveisPorTipo(menu.id);
            }
            else {
                pontoMovelDirective.removerLayers(menu.id);
            }
        }

       /**
        * Carrega os pontos móveis pelo tipo do item do menu
        *
        * @method _toggleNodePontoMovel
		*
		* @param node {Object} Item do Menu 
		*                
        */    
        function _toggleNodePontoMovel(node) {
            var pontoMovelDirective = MainState.getDirective('pontoMovel');
            pontoMovelDirective.buscarPontosMoveisPorTipo(node.id);

            node.disabled = false;
        }

       /**
        * Remova a camada de viatura do Mapa
        *
        * @method _removerCamadaViatura
		*
		* @param node {Object} Item do Menu
		* @param mode {Object} Item do Menu  
		*                
        */ 
        function _removerCamadaViatura(node, mode) {
            Viatura.removerLayers(node.chave_estrangeira, mode);
            chavesViaturas = [];
            vincularAoPreset();
        }

       /**
        * Remova a camada de ponto móvel do Mapa
        *
        * @method _removerCamadaPontoMovel
		*
		* @param mode {Object} Item do Menu  
		*                
        */ 
        function _removerCamadaPontoMovel(node) {
            var pontoMovelDirective = MainState.getDirective('pontoMovel');
            pontoMovelDirective.removerLayers(node.id);
            vincularAoPreset();
        }

       /**
        * Ativa a camada de ponto móvel pelo tipo
        *
        * @method ativarMenuDoPontoMovel
		*
		* @param idTipoPontoMovel {Integer} Identificador do Ponto Móvel  
		*                
        */
        function ativarMenuDoPontoMovel(idTipoPontoMovel) {
            var menuPontoMovel = _obterMenu({ urlSubMenus: 'menuCamada/ponto_movel' });
            var subMenu = {};
            _.each(menuPontoMovel.subMenus, function (item) {
                if (item.id == idTipoPontoMovel) {
                    subMenu = item;
                }
            });
            _ativarMenu(subMenu);
        }


       /**
        * Ativa a camada de Incidentes pelo item de menu
        *
        * @method ativarMenuDoPontoMovel
		*
		* @param node {Integer} Identificador do Menu
	    * @param incidentes {Integer} Lista de Incidentes 		 
		*                
        */
        function toggleNodeMsi(node, incidentes) {
            if (moduloIncientesFiltro && node.categoriaIncidenteId) {
                moduloIncientesFiltro.ativarCategoria(node.categoriaIncidenteId, 'camadas');
                moduloIncientesFiltro.toggleStatus(node.parentNode.texto, true);
            }

            return _toggleNodeMsi(node);
        }

       /**
        * Desabilita a categoria Pai
        *
        * @method _desabilitarCategoriaPai
		*
		* @param node {Integer} Identificador do Menu
	    * 	 
		*                
        */
        function _desabilitarCategoriaPai(node) {
            if (node.parentNode != null && node.parentNode.subMenus != null) {
                var desabilitarCategoriaPai = true;
                var subMenusAtivos = 0;
                _.each(node.parentNode.subMenus, function (subMenu_) {
                    if (subMenu_.ativo == true) {
                        desabilitarCategoriaPai = false;
                        subMenusAtivos = subMenusAtivos + 1;
                    }
                });
                if (desabilitarCategoriaPai || subMenusAtivos < node.parentNode.subMenus.length) {
                    node.parentNode.ativo = false;
                }
                if (node.parentNode.parentNode != null && node.parentNode.parentNode.subMenus != null) {
                    _desabilitarCategoriaPai(node.parentNode);
                }
            }
        }

      /**
        * Verifica se a quantidade de subMenus é igual a de menus ativos  
        *
        * @method isIndeterminate
		*        
		* @param node {Object} Menu clicado              
        */ 
        function isIndeterminate(node) {
            var numeroMenusAtivos = _.filter(node.subMenus, 'ativo').length;
            return !!(node && (node.subMenus && numeroMenusAtivos !== node.subMenus.length
                && numeroMenusAtivos != 0) || _.some(node.subMenus, function (subMenu) {
                    return isIndeterminate(subMenu);
                }))
        }


      /**
        * Verifica se o menu está marcado  
        *
        * @method isChecked
		*        
		* @param node {Object} Menu clicado              
        */ 
        function isChecked(node) {
            return node.ativo;
        }

      /**
        * Verifica se o menu está desabilitado  
        *
        * @method isDisabled
		*        
		* @param node {Object} Menu clicado              
        */ 
        function isDisabled(node) {
            return node.disabled || _.some(node.subMenus, function (subMenu) {
                return subMenu.disabled;
            });
        }

      /**
        * Recarrega as camadas do mapa 
        *
        * @method reloadCamadas
		*        
		*              
        */ 
        function reloadCamadas() {
            _.chain(service.grupos)
                .map('subMenus')
                .flatten()
                .each(toggleMenu)
                .value();
        }

      /**
        * Recarega a camada do menu acionado  
        *
        * @method _reloadMenu
		*        
		* @param menu {Object} Menu Clicado              
        */ 
        function _reloadMenu(menu) {
            var deferred = $q.defer();
            var subMenus = menu.subMenus;

            Base.obter(menu.urlSubMenus, null, menu.headers).then(function (subMenusAtualizados) {
                menu.subMenus = subMenusAtualizados;

                subMenusAtualizados = _obterSubMenus(menu);

                _.each(subMenusAtualizados, function (subMenuAtualizado) {
                    var subMenu = _.find(subMenus, { url: subMenuAtualizado.url });

                    if (subMenu) {
                        if (subMenu.ativo) {
                            subMenuAtualizado.ativo = true;
                            subMenuAtualizado._camada = subMenu._camada;
                        }
                    }
                })

                deferred.resolve();
            });

            return deferred.promise;
        }

      /**
        * Remove as camadas do mapa  
        *
        * @method limparCamadas
		*        
		*              
        */ 
        function limparCamadas() {
            _.each(service.grupos, function (grupo) {
                _.each(grupo.subMenus, function (acervo) {

                    acervo.ativo = false;
                    if (acervo.subMenus) {
                        _.each(acervo.subMenus, function (categoria) {
                            categoria.ativo = false;
                            _.each(categoria._camadas, function (camada) {
                                MapaService.removerCamada(camada);
                            });
                        });
                    }

                    _.each(acervo._camadas, function (camada) {
                        MapaService.removerCamada(camada);
                    });
                });
            });
        }

      /**
        * Obtem os submenus
        *
        * @method _obterSubMenus
		*        
		* @param menu {Object} Menu              
        */ 
        function _obterSubMenus(menu) {
            if (menu != null && menu.subMenus != null) {
                return _.chain(menu.subMenus)
                    .map(function (subMenu) {
                        return _nodeToArray(subMenu, 'subMenus')
                    })
                    .flatten()
                    .value();
            }
        }

      /**
        * Converte os itens de menu para um array
        *
        * @method _nodeToArray
		*        
		* @param menu {Object} Menu
		* @param property {Object} Propriedades do item do menu
		*               
        */
        function _nodeToArray(node, property) {

            var array = [];

            function parse(node) {
                _.each(node[property], function (item) {
                    parse(item)
                });

                array.push(node);
            }

            parse(node);

            return array;
        }

      /**
        * Obtem o menu
        *
        * @method _obterMenu
		*        
		* @param filtro {Object} Filtro
		* @param multiple {Object} 
		*               
        */
        function _obterMenu(filtro, multiple) {
            var menus = _obterSubMenus({ subMenus: service.grupos });

            if (multiple) {
                return _.filter(menus, filtro);
            }

            return _.find(menus, filtro);
        }


      /**
        * Obtem o submenu
        *
        * @method _obterSubMenu
		*        
		* @param menu {Object} 
		* @param filtro {Object} 
		*               
        */
        function _obterSubMenu(menu, filtro) {
            return _.find(_obterSubMenus(menu), filtro);
        }

      /**
        * Ativa o menu
        *
        * @method _ativarMenu
		*        
		* @param menu {Object} 
		*  
		*               
        */
        function _ativarMenu(menu) {
            if (menu) {
                menu.ativo = true;
                toggleMenu(menu);
            }
        }

      /**
        * Ativa o menu de Pois
        *
        * @method ativarThemeMenu
		*        
		* @param poi {Object} 
		*  
		*               
        */
        function ativarThemeMenu(poi) {
            var menu = _obterMenu(function (menu) {
                meuMenu = menu;
                return menu.categoriaId == poi.CategoriumId || menu.url === 'pois/categoria/' + poi.CategoriumId + '/geojson';
            });
            menu.ativo = true;
        }

     /**
        * Exibe o menu
        *
        * @method _exibirMenu
		*        
		* @param filtro {Object} 
		*  
		*               
        */
        function _exibirMenu(filtro) {
            var menu = _obterMenu(filtro);

            if (menu) {
                _ativarMenu(menu);
            }
        }

     /**
        * Carrega o menu de status de incidentes 
        *
        * @method _obterMenuStatusMsi
		*        
		* @param incidente {Object} 
		*  
		*               
        */
        function _obterMenuStatusMsi(incidente) {
            var menuIncidente = _obterMenu({ urlSubMenus: 'menuCamada/incidente' });
            var menuStatusIncidente = _obterSubMenu(menuIncidente, { texto: incidente.status });
            var menuCategoriaIncidente = _obterSubMenu(menuStatusIncidente, { categoriaIncidenteId: incidente.CategoriaIncidenteId });
            menuCategoriaIncidente.msi = true;

            return menuCategoriaIncidente;
        }

     /**
        * Obtem o menu de status de incidentes
        *
        * @method _obterMenuStatusIncidente
		*        
		* @param incidente {Object} 
		*  
		*               
        */
        function _obterMenuStatusIncidente(incidente) {
            var menuIncidente = _obterMenu({ url: 'incidente' });
            return menuIncidente;
        }

     /**
        * Ativa o subMenu de Incidetes
        *
        * @method ativarSubMenuIncidente
		*        
		* @param categoriaIncidenteId {Integer} Identificador da Categoria de Incidente
		*  
		*               
        */
        function ativarSubMenuIncidente(categoriaIncidenteId) {
            var menuIncidente = _obterMenu({
                urlSubMenus: 'menuCamada/incidente'
            });

            var subMenu = _obterSubMenu(menuIncidente, {
                categoriaIncidenteId: categoriaIncidenteId
            });

            _ativarMenu(subMenu);
        }

     /**
        * Ativa o Menu de Incidentes
        *
        * @method ativarSubMenuIncidente
		*        
		*               
        */
        function ativarMenuIncidente() {
            var menuIncidente = _obterMenu({
                url: 'incidente'
            });

            if (!menuIncidente) {
                return false;
            }

            menuIncidente.ativo = true;
            toggleMenu(menuIncidente);

            return true;
        }

     /**
        * Carrega a camada de incidentes 
        *
        * @method _toggleNodeMsi
		*        
		* @param node {Object} 
		*  
		*               
        */
        function _toggleNodeMsi(node) {
            var msiDirective = MainState.getDirective('filtro-msi') || MainState.getDirective('none');
            msiDirective.carregarLayerIncidentes(node);
            node.disabled = false;
            vincularAoPreset();
        }

    	/**
        * Desativa o subMenu de Incidentes 
        *
        * @method desativarSubMenuIncidente
		*        
		* @param categoriaIncidenteId {Integer} Identificador do Incidente 
		*  
		*               
        */
        function desativarSubMenuIncidente(categoriaIncidenteId) {
            var menuIncidente = _obterMenu({ urlSubMenus: 'menuCamada/incidente' });
            var subSubMenu = _.find(menuIncidente.subMenus, {
                categoriaIncidenteId: categoriaIncidenteId
            });

            if (subSubMenu) {
                subSubMenu.ativo = false;
                toggleNode(subSubMenu);
            }
        }

    	/**
        * Ativa o subMenu de Incidentes 
        *
        * @method ativarSubMenuStatusMsi
		*        
		* @param categoriaIncidenteId {Integer} Identificador da Categoria do Incidente
		* @param status {String} Status do Incidente  
		* @param incidentes {Array} Incidentes
		*  
		*               
        */
        function ativarSubMenuStatusMsi(categoriaIncidenteId, status, incidentes) {
            var menu = _obterMenuStatusMsi({
                CategoriaIncidenteId: categoriaIncidenteId,
                status: status
            });

            if (menu) {
                menu.ativo = true;
                function toggleMenuRecursiveMsi(menu, incidentes) {
                    if (menu.subMenus && menu.subMenus.length > 0) {
                        _.each(menu.subMenus, function (subMenu) {
                            if (!subMenu.disabled) {
                                subMenu.ativo = menu.ativo;
                                toggleMenuRecursiveMsi(subMenu, incidentes);
                            }
                        });
                    }

                    if (menu.url || menu.categoriaId) {
                        toggleNodeMsi(menu, incidentes);
                    }

                    if (menu.menuSensor) {
                        var _node = menu;
                        _.each(service.menusPorAcervo[menu.acervoTipoId], function (menu) {
                            menu.ativo = _node.ativo;
                            toggleMenuRecursiveMsi(menu, incidentes);
                        });
                    }
                }

                toggleMenuRecursiveMsi(menu, incidentes);
            }
        }

      /**
        * Desativa o subMenu de Status de Incidentes 
        *
        * @method desativarSubMenuStatusMsi
		*        
		* @param categoriaIncidenteId {Integer} Identificador da Categoria do Incidente
		* @param status {String} Status do Incidente  
		* @param options {Object} 
		*  
		*               
        */
        function desativarSubMenuStatusMsi(categoriaIncidenteId, status, options) {
            var menu = _obterMenuStatusIncidente({
                CategoriaIncidenteId: categoriaIncidenteId,
                status: status
            });

            if (menu) {
                menu.ativo = false;
                toggleNode(menu, options);
            }

            var menusAtivos = false;
            if (menu != null && menu.parentNode != null && menu.parentNode.subMenus != null) {
                _.each(menu.parentNode.subMenus, function (subMenu) {
                    if (subMenu.ativo) {
                        menusAtivos = true;
                        return;
                    }
                });
            }
            if (menu != null && menu.parentNode != null && !menusAtivos) {
                toggleNode(menu.parentNode);
            }
        }

      /**
        * Ativa o subMenu de Status de Incidentes 
        *
        * @method ativarSubMenuStatusIncidente
		*        
		* @param categoriaIncidenteId {Integer} Identificador da Categoria do Incidente
		* @param status {String} Status do Incidente  
		* 
		*  
		*               
        */
        function ativarSubMenuStatusIncidente(categoriaIncidenteId, status) {
            var menu = _obterMenuStatusIncidente({
                CategoriaIncidenteId: categoriaIncidenteId,
                status: status
            });

            if (menu) {
                _ativarMenu(menu);
            }
        }

      /**
        * Desativa o subMenu de Status de Incidentes 
        *
        * @method desativarSubMenuStatusIncidente
		*        
		* @param categoriaIncidenteId {Integer} Identificador da Categoria do Incidente
		* @param status {String} Status do Incidente  
		* @param options {Object}
		*  
		*               
        */
        function desativarSubMenuStatusIncidente(categoriaIncidenteId, status, options) {
            var menu = _obterMenuStatusIncidente({
                CategoriaIncidenteId: categoriaIncidenteId,
                status: status
            });

            if (menu) {
                menu.ativo = false;
                toggleNode(menu, options);
            }

            var menusAtivos = false;
            if (menu != null && menu.parentNode != null && menu.parentNode.subMenus != null) {
                _.each(menu.parentNode.subMenus, function (subMenu) {
                    if (subMenu.ativo) {
                        menusAtivos = true;
                        return;
                    }
                });
            }
            if (menu != null && menu.parentNode != null && !menusAtivos) {
                toggleNode(menu.parentNode);
            }
        }

      /**
        * Recarrega a camada de Planejamentos 
        *
        * @method reloadPlanejamentos
		*        
		* @param ativar {Boolean} 
		*  
		*               
        */
        function reloadPlanejamentos(ativar) {
            exibirPlanejamentos();
        }

      /**
        * Recarrega a camada de Incidentes 
        *
        * @method reloadIncidentes
		*        
		* @param ativar {Boolean} 
		*  
		*               
        */
        function reloadIncidentes(ativar) {
            var menu = _obterMenu({ urlSubMenus: 'menuCamada/incidente' });

            if (!menu) {
                return;
            }

            if (ativar) {
                _ativarMenu(menu);
            } else {
                _.each(menu.subMenus, function (subMenu) {
                    toggleNode(subMenu)
                })
            }
        }

      /**
        * Recarrega a camada de Câmeras 
        *
        * @method reloadCameras
		*        
		* @param categoriaCameraId {Integer} 
		*  
		*               
        */
        function reloadCameras(categoriaCameraId) {
            var menuCameras = _obterMenu({ urlSubMenus: 'menuCamada/camera' });
            var subMenu = _obterSubMenu(menuCameras,
                { url: 'cameras/categoria/' + categoriaCameraId + '/geojson' });

            console.log(subMenu);

            if (subMenu != null && !subMenu.ativo) {
                // Do nothing.
                console.log('não está ativo.');
            } else if (subMenu != null) {
                toggleMenu(subMenu);
            }
        }

      /**
        * Recarrega a camada de Base de Conhecimentos 
        *
        * @method reloadBasesConhecimento
		*        
		* @param ativar {Boolean} 
		*  
		*               
        */
        function reloadBasesConhecimento(ativar) {
            var menu = _obterMenu({ url: 'base_conhecimento/geojson' });

            if (ativar) {
                _ativarMenu(menu);
            } else {
                toggleMenu(menu);
            }
        }

      /**
        * Recarrega a camada de Zona de Observação
        *
        * @method reloadZonasObservacao
		*        
		* @param ativar {Boolean} 
		*  
		*               
        */
        function reloadZonasObservacao(ativar) {
            var menu = _obterMenu({ urlSubMenus: 'menuCamada/zona_observacao' });

            if (ativar) {
                _ativarMenu(menu);
            } else {
                toggleMenu(menu);
            }
        }

      /**
        * Filtra a camada de Zona de Observação
        *
        * @method reloadZonasObservacao
		*        
		* @param zonas {Object} 
		*  
		*               
        */
        function filtrarZonasDeObservacao(zonas) {
            var menu = _obterMenu({ urlSubMenus: 'menuCamada/zona_observacao' });
            var zonasId = zonas.map(function (zona) {
                return zona.id;
            });

            if (menu != null && menu.ativo) {
                menu.subMenus.map(function (camadaZo) {
                    if (camadaZo._camada) {
                        try {
                            camadaZo._camada.camadas.map(function (camada) {
                                mapa.removeLayer(camada.layer);
                                if (zonasId.indexOf(camada.feature.properties.id) > -1) {
                                    MapaService.removerCamada(camada.layer);
                                }
                            });
                        } catch (err) {
                            _.each(zonas, function (zona) {
                                if (zona.poigeojson != null) {

                                    var coordinates = zona.poigeojson.coordinates;
                                    var feature = turf.point(coordinates, zona);


                                    MapaService.adicionarPonto(feature, 'zona_observacao').then(function (camadas) {

                                        _.each(camadas, function (camada) {
                                            MapaService.removeLayer(camada.camadas.layer);
                                            if (zonasId.indexOf(feature.properties.id) > -1) {
                                                MapaService.addLayer(camada.camadas.layer);
                                            }
                                            camadaZo._camada = camada;
                                        });

                                    });
                                }

                            });
                        }
                    } else {
                        _.each(zonas, function (zona) {
                            if (zona.poigeojson != null) {

                                var coordinates = zona.poigeojson.coordinates;
                                var feature = turf.point(coordinates, zona);


                                MapaService.adicionarPonto(feature, 'zona_observacao').then(function (camadas) {

                                    _.each(camadas, function (camada) {
                                        MapaService.removerCamada(camada.camadas.layer);
                                        if (zonasId.indexOf(feature.properties.id) > -1) {
                                            MapaService.addLayer(camada.camadas.layer);
                                        }
                                        camadaZo._camada = camada;
                                    });

                                });
                            }

                        });
                    }
                });
            }
        }

      /**
        * Ativa a o menu de Zona de Observação
        *
        * @method ativarMenuZonasDeObservacao
		*        
		* 
		*  
		*               
        */
        function ativarMenuZonasDeObservacao() {
            var menuURL = { urlSubMenus: 'menuCamada/zona_observacao' },
                menu = _obterMenu(menuURL);

            _exibirMenu(menuURL);
        }

      /**
        * Exibe as Zonas de Observação
        *
        * @method exibirZonasDeObservacao
		*        
		*               
        */
        function exibirZonasDeObservacao() {

            var menuURL = { urlSubMenus: 'menuCamada/zona_observacao' };
            var menu = _obterMenu(menuURL);

            if (!menu) {
                setTimeout(function () {
                    exibirZonasDeObservacao();
                }, 100);
                return;
            }

            menu.subMenus.map(function (camadaZo) {
                try {
                    if (camadaZo._camada) {

                        for (var index in camadaZo._camada) {
                            camadaZo._camada[index].camadas.map(function (camada) {
                                MapaService.removerCamada(camada.layer);
                            });
                        }
                    }
                }
                catch (err) {
                    MapaService.removerCamada(camadaZo._camada.camadas.layer);
                }
            });

            _exibirMenu(menuURL);

            _toggleMenuZonaObservacao(menu);

        }

      /**
        * Exibe as Bases de Conhecimentos
        *
        * @method exibirBasesConhecimento
		*        
		*               
        */
        function exibirBasesConhecimento() {
            _exibirMenu({ url: 'base_conhecimento/geojson' });
        }

      /**
        * Exibe os Planejamentos
        *
        * @method exibirBasesConhecimento
		*        
		*               
        */
        function exibirPlanejamentos() {
            _exibirMenu({ urlSubMenus: 'menuCamada/planejamento' });
        }

      /**
        * Ativa o menu de Categoria
        *
        * @method ativarMenuCategoria
		*  @param categoriaId {Integer} Identificador da categoria       
		*               
        */
        function ativarMenuCategoria(categoriaId) {
            var meuMenu;
            _exibirMenu(function (menu) {
                meuMenu = menu;
                return menu.categoriaId == categoriaId || menu.url === 'pois/categoria/' + categoriaId + '/geojson';
            });

            return meuMenu;
        }

      /**
        * Ativa as SubCategorias
        *
        * @method ativarSubCategorias
		*  @param categoriaId {Integer} Identificador da categoria       
		*               
        */
        function ativarSubCategorias(categoriaId) {
            $http.get('/categorias/subcategorias/' + categoriaId)
                .then(function (result) {
                    _.each(result.data, function (sub) {
                        _exibirMenu(function (menu) {
                            return menu.categoriaId == sub.id || menu.url === 'pois/categoria/' + sub.id + '/geojson';
                        });
                        ativarSubCategorias(sub.id);
                    })
                }, function (err) {
                    console.log(err);
                })
        }

      /**
        * Ativa o menu de Incidente
        *
        * @method ativarMenuDoIncidente
		*  @param incidente {Object}        
		*               
        */
        function ativarMenuDoIncidente(incidente) {
            ativarSubMenuIncidente(incidente.CategoriaIncidenteId);
        }

      /**
        * Altera o Ícone de Incidente
        *
        * @method atualizarIconeIncidente
		*  @param incidente {Object}        
		*               
        */
        function atualizarIconeIncidente(incidente) {
            var menuStatusIncidente = _obterMenuStatusIncidente(incidente);
            var camada = _.find(menuStatusIncidente._camada.camadas, function (camada) {
                return camada.feature.properties.id == incidente.chave_estrangeira
            });

            if (incidente.Comentarios && incidente.Comentarios.length) {
                MapaService.updateIconeIncidente(camada.layer, incidente.Comentarios.length)
            }
        }

      /**
        * Ativa o menu da Camera
        *
        * @method ativarMenuDaCamera
		*  @param camera {Object}        
		*               
        */
        function ativarMenuDaCamera(camera) {
            var menuCameras = _obterMenu({ urlSubMenus: 'menuCamada/camera' });
            var subMenu = _obterSubMenu(menuCameras,
                { url: 'cameras/categoria/' + camera.CategoriaCameraId + '/geojson' });
            _ativarMenu(subMenu);
        }

      /**
        * Ativa o menu da Camera
        *
        * @method ativarMenuCategoriaCamera
		*  @param categoriaCameraId {Integer} Identificador        
		*               
        */
        function ativarMenuCategoriaCamera(categoriaCameraId) {
            var menuCameras = _obterMenu({ urlSubMenus: 'menuCamada/camera' });
            var subMenu = _obterSubMenu(menuCameras,
                { url: 'cameras/categoria/' + categoriaCameraId + '/geojson' });
            _ativarMenu(subMenu);
        }

      /**
        * Ativa o menu do Poi
        *
        * @method ativarMenuPoi
		*  @param poi {Object}         
		*               
        */
        function ativarMenuPoi(poi) {
            if (poi.CategoriumId != null) {
                return ativarMenuCategoria(poi.CategoriumId);
            } else if (poi.cat != null && poi.cat.CategoriumId != null) {
                return ativarMenuCategoria(poi.cat.CategoriumId);
            } else {
                var latlng = {};
                latlng.lat = poi.latitude;
                latlng.lng = poi.longitude;
                DetalhamentoManager.abrirPoi(poi.id, latlng);
            }
        }

      /**
        * Ativa o menu da viatura
        *
        * @method ativarMenuViatura
		*  @param viatura {Object}         
		*               
        */
        function ativarMenuViatura(viatura) {
            var menuOrganizacao = _obterMenuOrganizacaoViatura(viatura.organizacao);

            if (menuOrganizacao) {
                _ativarMenu(menuOrganizacao);
            }
            vincularAoPreset();
        }

      /**
        * Vincula as categorias ao preset
        *
        * @method vincularAoPreset
		*          
		*               
        */
        function vincularAoPreset() {
            var categorias = [];
            var categoriaIncidentes = [];
            var categoriaCameras = [];
            var menuCamadas = [];
            var atualPreset = Preset.config.preset;
            function acervoSubMenu(acervo) {

                if (!acervo.acervoId && acervo.ativo == true) {
                    menuCamadas.push({ id: acervo.id });
                    return;
                }

                if (acervo.subMenus && acervo.subMenus.length > 0) {
                    _.each(acervo.subMenus, function (categoria) {
                        if (categoria.subMenus != null && categoria.subMenus.length > 0) {
                            acervoSubMenu(categoria);
                        } else if (categoria.ativo && categoria.id != null) {
                            categorias.push(categoria.id);
                        }
                        else if (categoria.ativo && categoria.categoriaIncidenteId != null) {
                            categoriaIncidentes.push({
                                categoriaId: categoria.categoriaIncidenteId,
                                status: categoria.parentNode.texto
                            });
                        }
                        else if (categoria.ativo && categoria.categoriaCameraId != null) {
                            categoriaCameras.push(categoria.categoriaCameraId);
                        }
                    });
                } else if (acervo.ativo && acervo.id != null) {
                    categorias.push(acervo.id);
                }
            }

            _.each(service.grupos, function (grupo) {
                _.each(grupo.subMenus, function (acervo) {
                    acervoSubMenu(acervo);
                });
            });

            $http.post("/categoria_preset", {
                presetId: atualPreset.id,
                categoriaIds: categorias,
                categoriaCameraIds: categoriaCameras,
                categoriaIncidenteIds: categoriaIncidentes
            }).then(function () {
            });

            $http.post("/menucamada_preset/" + atualPreset.id, menuCamadas).
                then(function () {
                });

        }
        
      /**
        * Sets the parent on the node
        *
        * @method _indexNode
		*  
		* @param parent {Object}         
		* @param menu {Object}
		*               
        */
        function _indexNode(parent, menu) {
            /* Sets the parent on the node */
            menu.parentNode = parent;

            /* Recursive check for subMenus */
            return _indexMenu(menu);
        }

       
      /**
        * Verifica se o menu tem subMenus
        *
        * @method _indexMenu
		*  
		* @param menu {Object}
		*               
        */
        function _indexMenu(menu) {
            /* Menu should have subMenus to index */
            if (!menu.hasOwnProperty('subMenus')) {
                return;
            }

            var linkParent = _.partial(_indexNode, menu);

            return _.map(menu.subMenus, linkParent);
        }

      /**
        * Obtem a lista de Menus
        *
        * @method _getMenuList
		*  
		* @param menus {Object}
		*               
        */
        function _getMenuList(menus) {
            return _.chain(menus)
                .map(function (menu) {
                    return _.nodeToArray(menu, 'subMenus');
                })
                .flatten()
                .reject('menuSensor')
                .value();

            return list;
        }


      /**
        * Inicializa as categorias
        *
        * @method initCategorias
		*  
		* 
        */
        function initCategorias() {
            var grupos = service.grupos;

            var _grupos = [];
            _.each(grupos, function (grupo) {
                if (grupo.subMenus != null && grupo.subMenus.length > 0) {
                    _grupos.push(grupo);
                }
            });

            grupos = _grupos;
            _.each(grupos, function (menu) {
                _desmarcarMenus(menu);
            });
            _.each(grupos, function (menu) {
                _marcarMenus(menu);
            });

        }


      /**
        * Ativa o menu camada
        *
        * @method ativarMenuCamada
		*  
		* @param menuCamada {Object}
		*               
        */
        function ativarMenuCamada(menuCamada) {
            var grupos = service.grupos;

            var _grupos = [];
            _.each(grupos, function (grupo) {
                if (grupo.subMenus != null && grupo.subMenus.length > 0) {
                    _grupos.push(grupo);
                }
            });

            grupos = _grupos;
            _.each(grupos, function (menu) {
                _toggleMenuCamada(menu, menuCamada);
            });

        }

      /**
        * Desmarca os Menus
        *
        * @method _desmarcarMenus
		*  
		* @param submenu {Object}
		*               
        */
        function _desmarcarMenus(submenu) {
            if (submenu.subMenus != null) {
                _.each(submenu.subMenus, function (submenus) {
                    submenus.ativo = false;
                    if (submenus.subMenus != null) {
                        _desmarcarMenus(submenus);
                    }
                    toggleMenu(submenus);
                });

                if (submenu != null) {
                    submenu.subMenus.map(function (camadaZo) {
                        if (camadaZo._camada) {
                            MapaService.removerCamada(camadaZo._camada.aggregate);
                        }
                    });
                }
            }
        }

      /**
        * Marca os Menus
        *
        * @method _marcarMenus
		*  
		* @param submenu {Object}
		*               
        */
        function _marcarMenus(submenu) {
            if (submenu.subMenus != null) {
                _.each(submenu.subMenus, function (submenus) {
                    if (submenus.presetIds != null) {
                        _.each(submenus.presetIds, function (preset) {
                            if (preset == Preset.config.preset.id || (preset.presetId != null && preset.status != null && preset.presetId == Preset.config.preset.id && preset.status == submenus.parentNode.texto)) {
                                submenus.ativo = true;
                                toggleMenu(submenus);
                            }
                        });
                    }

                    if (submenus.subMenus != null) {
                        _marcarMenus(submenus);
                    }
                });
            }
        }

      /**
        * Carrega a camada do item de menu clicado
        *
        * @method _toggleMenuCamada
		*  
		* @param submenu {Object}
		* @param menuCamada {Object}
		*               
        */
        function _toggleMenuCamada(submenu, menuCamada) {
            if (submenu.subMenus != null) {
                _.each(submenu.subMenus, function (submenus) {
                    if (submenus.id != null && menuCamada != null && submenus.id == menuCamada.id) {
                        submenus.ativo = true;
                        toggleMenu(submenus);
                    }
                    if (submenus.subMenus != null) {
                        _toggleMenuCamada(submenus);
                    }
                });
            }
        }

      /**
        * Inclui a legenda no Poi
        *
        * @method _incluirLegenda
		*  
		* @param poiDTO {Object}
		*               
        */
        function _incluirLegenda(poiDTO) {
            if (poiDTO.representacoes) {
                for (var index in poiDTO.representacoes) {
                    var representacaoRepetida = _.find(service.representacoes_das_Categorias_Ativas, function (representacao_) { return representacao_.id === poiDTO.representacoes[index].id; });
                    if (representacaoRepetida == null) {
                        var representacao = poiDTO.representacoes[index];
                        representacao.categoriaIds = [];
                        representacao.categoriaIds.push(index);
                        representacao.categorias = [];
                        representacao.categorias.push(_obtemRepresentacao(index));
                        service.representacoes_das_Categorias_Ativas.push(representacao);
                    } else if (!_containsCategoriaId(representacaoRepetida.categoriaIds, index)) {
                        representacaoRepetida.categoriaIds.push(index);
                        representacaoRepetida.categorias.push(_obtemRepresentacao(index));
                        _.remove(service.representacoes_das_Categorias_Ativas, function (rep) { return rep.id == poiDTO.representacoes[index].id; });
                        service.representacoes_das_Categorias_Ativas.push(representacaoRepetida);
                    }
                }
            }
        }

      /**
        * Obtem a representação
        *
        * @method _obtemRepresentacao
		*  
		* @param categoriaId {Object}
		*               
        */
        function _obtemRepresentacao(categoriaId) {
            for (var index in service.representacoes_das_Categorias) {
                if (service.representacoes_das_Categorias[index].id == categoriaId) {
                    return service.representacoes_das_Categorias[index];
                }
            }
        }

      /**
        * Remove a legenda
        *
        * @method _removerLegenda
		*  
		* @param categoriaId {Object}
		*               
        */
        function _removerLegenda(categoriaId) {
            var representacaoLegenda = _.find(service.representacoes_das_Categorias_Ativas, function (rep) {
                return _containsCategoriaId(rep.categoriaIds, categoriaId);
                //return rep.categoriaId == categoriaId;
            });
            if (representacaoLegenda != null) {
                _.remove(service.representacoes_das_Categorias_Ativas, function (rep) {
                    return _containsCategoriaId(rep.categoriaIds, categoriaId);
                    //return rep.categoriaId == categoriaId
                });
            }
        }

      /**
        * Verifica se na lista tem o id da categoria
        *
        * @method _containsCategoriaId
		*  
		* @param array {Array}
		* @param categoriaId {Integer}
		*               
        */
        function _containsCategoriaId(array, categoriaId) {
            var retorno = false;
            for (var index in array) {
                if (array[index] == categoriaId) {
                    retorno = true;
                }
            }
            return retorno;
        }

      /**
        * Remove a legenda do grupo
        *
        * @method _removerLegendaDeGrupo
		*  
		* @param menu {Object}
		*               
        */
        function _removerLegendaDeGrupo(menu) {
            if (menu.subMenus && menu.subMenus.length > 0) {
                _.each(menu.subMenus, function (subMenu) {
                    if (subMenu.categoriaId != null) {
                        _removerLegenda(subMenu.categoriaId);
                    }
                    if (subMenu.subMenus && subMenu.subMenus.length > 0) {
                        return _removerLegendaDeGrupo(subMenu);
                    }

                });
            }
        }

        return service;

    }

})();