function FerramentaCamadasViewModel(data) {
    const mSelf = this;
    mSelf.Data = ko.observable(new FerramentaCamadasViewModelData(data.Data));
    mSelf.FerramentaId = data.FerramentaId;
    mSelf.Template = data.Template;
    mSelf.Nome = data.Nome;
    mSelf.Titulo = data.Titulo;
    mSelf.Icone = data.Icone;

    mSelf.Init = () => {
        mSelf.Data().Init();
    }
};

function FerramentaCamadasViewModelData(data) {
    const mSelf = this;

    mSelf.ListaMacroSetores = ko.observableArray([]);
    mSelf.ListaRegioes = ko.observableArray([]);
    mSelf.ListaSetores = ko.observableArray([]);
    mSelf.ListaBairros = ko.observableArray([]);

    mSelf.MacroSetoresSelecionados = [];
    mSelf.SetoresSelecionados = [];
    mSelf.RegioesSelecionados = [];
    mSelf.BairrosSelecionados = [];

    mSelf.TodosMacroSetor = ko.observable(false);
    mSelf.TodosRegiao = ko.observable(false);
    mSelf.TodosSetor = ko.observable(false);
    mSelf.TodosBairro = ko.observable(false);

    mSelf.ConfiguracoesForma = {};

    mSelf.HoraHistorico = ko.observable('');
    mSelf.PesquisaMacroSetor = ko.observable('');
    mSelf.PesquisaRegiao = ko.observable('');
    mSelf.PesquisaSetor = ko.observable('');
    mSelf.PesquisaBairros = ko.observable('');
    mSelf.PesquisaVeiculo = ko.observable('');
    mSelf.ViewModel = ko.observable({});
    mSelf.ViewModelDemandas = ko.observable({});

    mSelf.Init = () => {
        mSelf.CarregarConfiguracoesForma();

        vm.currentMap.addEventMap(InlogMaps.MapEventType.ZoomChanged, () => {
            vm.currentMap.toggleOverlay(vm.currentMap.getZoom() >= 14, 'macro');
            vm.currentMap.toggleOverlay(vm.currentMap.getZoom() >= 14, 'setor');
            vm.currentMap.toggleOverlay(vm.currentMap.getZoom() >= 14, 'regiao');
            vm.currentMap.toggleOverlay(vm.currentMap.getZoom() >= 14, 'bairro');
        });
    }

    mSelf.CarregarConfiguracoesForma = () => {
        mSelf.ConfiguracoesForma['macro'] = {
            Cor: '#e65c5c',
            zIndex: 1,
            FormaProximoNivel: 'regiao',
            FormaNivelAnterior: ''
        };

        mSelf.ConfiguracoesForma['regiao'] = {
            Cor: '#7b58a4',
            zIndex: 2,
            FormaProximoNivel: 'setor',
            FormaNivelAnterior: 'macro'
        };

        mSelf.ConfiguracoesForma['setor'] = {
            Cor: '#8abf22',
            zIndex: 3,
            FormaProximoNivel: 'bairro',
            FormaNivelAnterior: 'regiao'
        };

        mSelf.ConfiguracoesForma['bairro'] = {
            Cor: '#428bca',
            zIndex: 4,
            FormaProximoNivel: '',
            FormaNivelAnterior: 'setor'
        };
    };

    mSelf.CarregarCamada = (url, listaSelecionados, lista) => {
        if (lista().length == 0) {
            $.ajax({
                url: urlGlobal + url,
                contentType: 'application/json; charset=utf-8',
                dataType: 'json',
                type: 'GET',
                success: (ret) => {
                    ret.forEach((item) => {
                        item.Visivel = ko.observable(true);

                        if (listaSelecionados.indexOf(item.CodigoGrupo) >= 0) {
                            item.Selecionado = ko.observable(true);
                        } else item.Selecionado = ko.observable(false);

                        lista.push(item);
                    });
                }
            });
        }
    }

    mSelf.CarregarMacroSetores = () =>
        mSelf.CarregarCamada('DemandaTarefa/Demanda/CarregarMacroSetores',
            mSelf.MacroSetoresSelecionados, mSelf.ListaMacroSetores);

    mSelf.CarregarRegioes = () =>
        mSelf.CarregarCamada('DemandaTarefa/Demanda/CarregarRegioesCamada',
            mSelf.RegioesSelecionados, mSelf.ListaRegioes);

    mSelf.CarregarSetores = () =>
        mSelf.CarregarCamada('DemandaTarefa/Demanda/CarregarSetoresCamada',
            mSelf.SetoresSelecionados, mSelf.ListaSetores);

    mSelf.CarregarBairros = () =>
        mSelf.CarregarCamada('DemandaTarefa/Demanda/CarregarBairrosCamada',
            mSelf.BairrosSelecionados, mSelf.ListaBairros);

    mSelf.CheckCamada = (data, evt, tipo, todos, selecionados, lista) => {
        todos(false);

        if (evt.target.checked == true) {
            selecionados.push(data.CodigoGrupo);
            mSelf.CarregarForma(data.CodigoGrupo, tipo, data.Descricao);
        } else {
            selecionados.splice(selecionados.indexOf(data.CodigoGrupo), 1);
            mSelf.RemoverFormaMapa(data.CodigoGrupo, tipo);
            vm.currentMap.removeOverlays(tipo, (item) =>
                item.CodigoGrupo === parseInt(data.CodigoGrupo))
        }

        if (lista().length == selecionados.length) {
            todos(true);
        }
    }

    mSelf.MacroSetorCheck = (data, evt) =>
        mSelf.CheckCamada(data, evt, 'macro', mSelf.TodosMacroSetor, mSelf.MacroSetoresSelecionados, mSelf.ListaMacroSetores);

    mSelf.RegiaoCheck = (data, evt) =>
        mSelf.CheckCamada(data, evt, 'regiao', mSelf.TodosRegiao, mSelf.RegioesSelecionados, mSelf.ListaRegioes);

    mSelf.SetorCheck = (data, evt) =>
        mSelf.CheckCamada(data, evt, 'setor', mSelf.TodosSetor, mSelf.SetoresSelecionados, mSelf.ListaSetores);

    mSelf.BairroCheck = (data, evt) =>
        mSelf.CheckCamada(data, evt, 'bairro', mSelf.TodosBairro, mSelf.BairrosSelecionados, mSelf.ListaBairros);

    mSelf.ClickTodos = (data, evt) => {
        switch (evt.target.value) {
            case 'macro': mSelf.ClickTodasCamadas(mSelf.ListaMacroSetores, mSelf.MacroSetoresSelecionados, evt.target); break;
            case 'regiao': mSelf.ClickTodasCamadas(mSelf.ListaRegioes, mSelf.RegioesSelecionados, evt.target); break;
            case 'setor': mSelf.ClickTodasCamadas(mSelf.ListaSetores, mSelf.SetoresSelecionados, evt.target); break;
            case 'bairro': mSelf.ClickTodasCamadas(mSelf.ListaBairros, mSelf.BairrosSelecionados, evt.target); break;
        }
        return true;
    };

    mSelf.ClickTodasCamadas = (lista, listaSelecionados, target) => {
        const checado = target.checked;
        const tipoForma = target.value;

        lista().forEach((item) => {
            if (item.Visivel()) {
                item.Selecionado(checado);

                if (!checado) {
                    let index = listaSelecionados.indexOf(item.CodigoGrupo);
                    if (index >= 0)
                        listaSelecionados.splice(index, 1);

                    mSelf.RemoverFormaMapa(item.CodigoGrupo, tipoForma);
                } else listaSelecionados.push(item.CodigoGrupo);
            }
        });

        if (checado)
            mSelf.PlotarTodasFormasMapa(tipoForma, listaSelecionados);
    }

    mSelf.CarregarForma = (codigoGrupo, tipoForma, descricao) => {
        mSelf.ValidaVisualizacaoOverlay(codigoGrupo, tipoForma);

        const condition = (item) => item.CodigoGrupo === parseInt(codigoGrupo);
        const cor = mSelf.ConfiguracoesForma[tipoForma].Cor;

        if (!vm.currentMap.polygonExists(tipoForma, condition)) {
            $.ajax({
                url: urlGlobal + 'DemandaTarefa/Demanda/CarregarFormaPorEntidade',
                contentType: 'application/json; charset=utf-8',
                dataType: 'json',
                type: 'GET',
                data: { 'codigoGrupo': codigoGrupo },
                success: (data) => {
                    if (data) {
                        const zIndex = mSelf.ConfiguracoesForma[tipoForma].zIndex;

                        if (data && data.length > 0)
                            mSelf.PlotarForma(data, tipoForma, cor, zIndex, false);
                    }
                }
            });
        } else {
            vm.currentMap.togglePolygons(true, tipoForma, condition);
            vm.currentMap.fitBoundsPolygons(tipoForma);

            mSelf.DesenhaOverlay({
                CodigoGrupo: codigoGrupo,
                DescricaoForma: descricao,
                TipoForma: tipoForma
            }, cor);
        }
    };

    mSelf.PlotarForma = (formas, tipoForma, cor) => {
        /* Plota no mapa as novas formas */
        let formasPlotadas = 0;

        /* Percorre o array dos codigos dos grupos para plotar as formas separadamente */
        formas.map(x => x.CodigoGrupo)
            .filter((value, index, self) => self.indexOf(value) === index)
            .forEach((codigo) => {
                const condition = (item) => item.CodigoGrupo === parseInt(codigo);
                if (vm.currentMap.polygonExists(tipoForma, condition)) {
                    vm.currentMap.togglePolygons(true, tipoForma, condition);

                    mSelf.DesenhaOverlay({
                        CodigoGrupo: codigo,
                        TipoForma: tipoForma,
                        DescricaoForma: formas.find(x => x.CodigoGrupo === codigo).Descricao
                    }, cor);
                } else {
                    const formasGrupo = formas.filter((forma) => forma.CodigoGrupo == codigo);

                    if (formasGrupo) {
                        formasGrupo.forEach((forma) => {
                            let pts = [];

                            for (var j = 0; j < forma.Coordenadas.length; j++) {
                                pts.push([forma.Coordenadas[j].Latitude / 1000000, forma.Coordenadas[j].Longitude / 1000000]);
                            }

                            const options = new InlogMaps.PolygonOptions(pts, 2, true, cor);
                            options.fillOpacity = 0.4;
                            options.fillColor = cor;
                            options.object = {
                                CodigoGrupo: codigo,
                                TipoForma: tipoForma,
                                DescricaoForma: forma.Descricao
                            }

                            vm.currentMap.drawPolygon(tipoForma, options, mSelf.ClickForma);
                            mSelf.DesenhaOverlay(options.object, cor);

                            formasPlotadas++;
                        });

                        mSelf.ValidaVisualizacaoOverlay(codigo, tipoForma);
                    };
                }
            });

        $('.loading-div').fadeOut('fast');

        if (formasPlotadas > 0) {
            vm.currentMap.fitBoundsPolygons(tipoForma);
        }
    };

    mSelf.DesenhaOverlay = (forma, cor, iconeVoltar) => {
        forma.CodigoGrupo = parseInt(forma.CodigoGrupo);

        const divElement = mSelf.CreateOverlayDiv(forma.DescricaoForma.toUpperCase(), 'white', cor, iconeVoltar, forma.CodigoGrupo);
        const overlayOptions = new InlogMaps.OverlayOptions(divElement, true, null, forma, forma.TipoForma,
            (item) => item.CodigoGrupo === parseInt(forma.CodigoGrupo));

        vm.currentMap.drawOverlay(forma.TipoForma, overlayOptions);

        if (iconeVoltar) {
            setTimeout(() =>
                document.getElementById(`overlay-codigo-${forma.CodigoGrupo}`)
                    .addEventListener('click', () => mSelf.ClickOverlayForma(forma))
                , 500);
        }
    }

    mSelf.CreateOverlayDiv = (descricao, fonte, fundo, iconeVoltar, codigo) => {
        let div = document.createElement('div');
        div.setAttribute("id", `overlay-codigo-${codigo}`);
        div.style.color = fonte;
        div.style.fontSize = "13px";
        div.style.backgroundColor = fundo;
        div.style.position = 'absolute';
        div.style.minWidth = "90px";
        div.style.zIndex = 999;

        let p_forma = document.createElement('p');
        let span = document.createElement('span');

        if (iconeVoltar) {
            let icone = document.createElement('i');
            icone.setAttribute("class", "icon-left-arrow");

            p_forma.appendChild(icone);
            span.textContent = descricao;

            p_forma.appendChild(span);
            p_forma.style.marginRight = "3px";
            div.appendChild(p_forma);
        } else {
            p_forma.style.margin = "5px";
            div.appendChild(p_forma);
            div.childNodes[0].textContent = descricao;
        }

        return div;
    }

    mSelf.ClickOverlayForma = (overlay) => {
        /* Oculta todas as formas plotadas no mapa */
        vm.currentMap.closeAllPopups();

        const configs = mSelf.ConfiguracoesForma[overlay.TipoForma];
        vm.currentMap.togglePolygons(false, configs.FormaProximoNivel);
        vm.currentMap.removeOverlays(configs.FormaProximoNivel);

        const condition = (item) => item.CodigoGrupo === parseInt(overlay.CodigoGrupo);
        vm.currentMap.removeOverlays(overlay.TipoForma, condition);
        mSelf.DesenhaOverlay(overlay, configs.Cor);

        /* Plota no mapa apenas a forma referente ao overlay clicado */
        vm.currentMap.togglePolygons(true, overlay.TipoForma, condition);
        $(`#${overlay.TipoForma}` + overlay.CodigoGrupo).attr('checked', true);

        /* Remove a seleção das formas filhas */
        let niveis = ['macro', 'regiao', 'setor', 'bairro'];

        niveis.forEach(tipo => {
            let lista = mSelf.GetListaSelecionado(tipo);

            if (tipo != overlay.TipoForma) {
                lista.forEach(codigo => $(`#${tipo}` + codigo).attr('checked', false));
                lista = [];
            } else {
                lista = [];
                lista.push(overlay.CodigoGrupo);
            }
        });
    };

    mSelf.GetListaSelecionado = (tipo) => {
        switch (tipo) {
            case 'macro': return mSelf.MacroSetoresSelecionados;
            case 'regiao': return mSelf.RegioesSelecionados;
            case 'setor': return mSelf.SetoresSelecionados;
            case 'bairro': return mSelf.BairrosSelecionados;
        }
    }

    mSelf.AlterarCoresFormas = (tipo) => {
        const options = new InlogMaps.PolygonAlterOptions();
        options.color = mSelf.ConfiguracoesForma[tipo].Cor;
        vm.currentMap.alterPolygonOptions(tipo, options);
    }

    mSelf.AlterarCoresFormaSelecionada = (forma) => {
        mSelf.AlterarCoresFormas('macro');
        mSelf.AlterarCoresFormas('setor');
        mSelf.AlterarCoresFormas('regiao');
        mSelf.AlterarCoresFormas('bairro');

        const options = new InlogMaps.PolygonAlterOptions();
        options.color = '#000000';

        vm.currentMap.alterPolygonOptions(forma.TipoForma, options, (item) => item.CodigoGrupo === forma.CodigoGrupo);
    }

    mSelf.CarregarInfoWindowDemanda = (evt, forma) => {
        $.ajax({
            url: urlGlobal + 'DemandaTarefa/Demanda/CarregarDemandasPorEntidade',
            contentType: 'application/json; charset=utf-8',
            dataType: 'json',
            type: 'GET',
            data: { 'codigoGrupo': forma.CodigoGrupo, 'tipoForma': forma.TipoForma },
            success: (data) => {
                if (data) {
                    vm.currentMap.closeAllPopups();

                    let viewModel = ko.mapping.fromJS({
                        Descricao: forma.DescricaoForma,
                        TiposDemandas: data.TiposDemandas,
                        PrioridadeAlta: data.PrioridadeAlta,
                        PrioridadeMedia: data.PrioridadeMedia,
                        PrioridadeBaixa: data.PrioridadeBaixa,
                        TipoForma: forma.TipoForma,
                        CodigoGrupo: forma.CodigoGrupo,
                        VisualizarDetalhes: forma.TipoForma == 'bairro' ? false : true
                    });

                    viewModel.CarregarProximoNivelFormas = (forma) =>
                        mSelf.NavegarProximoNivel(forma.CodigoGrupo(), forma.TipoForma(), forma.Descricao());

                    let $elemento = $('<div>' + $('#template-info-window-demandas').html() + '</div>');
                    ko.applyBindings(viewModel, $elemento[0]);

                    const options = new InlogMaps.PopupOptions(evt.latlng, $elemento[0]);
                    vm.currentMap.drawPopup(forma.CodigoGrupo, options);
                }
            }
        });
    };

    mSelf.CarregarInfoWindowTarefa = (evt, forma) => {
        $.ajax({
            url: urlGlobal + 'DemandaTarefa/Tarefa/CarregarTarefasPorEntidade',
            contentType: 'application/json; charset=utf-8',
            dataType: 'json',
            type: 'GET',
            data: { 'codigoGrupo': forma.CodigoGrupo, 'tipoForma': forma.TipoForma },
            success: (data) => {
                if (data) {
                    vm.currentMap.closeAllPopups();

                    let viewModel = ko.mapping.fromJS({
                        Descricao: forma.DescricaoForma,
                        QuantidadeAndamento: data.QuantidadeAndamento,
                        QuantidadeAgendadas: data.QuantidadeAgendadas,
                        TipoForma: forma.TipoForma,
                        CodigoGrupo: forma.CodigoGrupo,
                        VisualizarDetalhes: forma.TipoForma == 'bairro' ? false : true
                    });

                    viewModel.CarregarProximoNivelFormas = (forma) =>
                        mSelf.NavegarProximoNivel(forma.CodigoGrupo(), forma.TipoForma(), forma.Descricao());

                    let $elemento = $('<div>' + $('#template-info-window-tarefas').html() + '</div>');
                    ko.applyBindings(viewModel, $elemento[0]);

                    const options = new InlogMaps.PopupOptions(evt.latlng, $elemento[0]);
                    vm.currentMap.drawPopup(forma.CodigoGrupo, options);
                }
            }
        });
    };

    mSelf.ClickForma = (evt, forma) => {
        mSelf.AlterarCoresFormaSelecionada(forma);

        if (vm.Perspectiva.Titulo == 'Demanda') {
            mSelf.CarregarInfoWindowDemanda(evt, forma);
        } else {
            mSelf.CarregarInfoWindowTarefa(evt, forma);
        }
    };

    mSelf.PlotarTodasFormasMapa = (tipoForma, lista) => {
        lista.filter(item => vm.currentMap.polygonExists(tipoForma,
            (poly) => poly.CodigoGrupo === parseInt(item)))
            .forEach(item => {
                const condition = (poly) => poly.CodigoGrupo === parseInt(item);
                vm.currentMap.togglePolygons(true, tipoForma, condition);

                mSelf.ValidaVisualizacaoOverlay(item, tipoForma);
            });

        const codigosGrupo = lista.filter(item => !vm.currentMap
            .polygonExists(tipoForma, (poly) => poly.CodigoGrupo === parseInt(item)));

        if (codigosGrupo.length > 0) {
            $('.loading-div').fadeIn('fast');
            $.ajax({
                url: urlGlobal + 'DemandaTarefa/Demanda/CarregarListaFormasPorEntidade',
                contentType: 'application/json; charset=utf-8',
                dataType: 'json',
                type: 'POST',
                data: JSON.stringify({ 'listaCodigos': codigosGrupo }),
                success: (data) => {
                    if (data) {
                        const forma = mSelf.ConfiguracoesForma[tipoForma];
                        mSelf.PlotarForma(data, tipoForma, forma.Cor, forma.zIndex, true);
                    } else {
                        vm.ShowMensagemAlerta('Não foram encontradas formas para a entidade');
                        $('.loading-div').fadeOut('fast');
                    }
                }
            });
        }

        vm.currentMap.fitBoundsPolygons(tipoForma);
    };

    mSelf.NavegarProximoNivel = (codigoGrupo, tipoForma, descricao) => {
        if (tipoForma != 'bairro') {
            $('.loading-div').fadeIn('fast');
            vm.currentMap.closePopup(codigoGrupo);

            $.ajax({
                url: urlGlobal + 'DemandaTarefa/Demanda/CarregarFormasPorNivel',
                contentType: 'application/json; charset=utf-8',
                dataType: 'json',
                type: 'GET',
                data: { 'codigoGrupo': codigoGrupo, 'tipoForma': tipoForma },
                success: (data) => {
                    if (data && data.length > 0) {

                        /* Apagar do mapa as formas já plotadas*/
                        vm.currentMap.togglePolygons(false, tipoForma);
                        vm.currentMap.closePopup(codigoGrupo);

                        const formaAtual = mSelf.ConfiguracoesForma[tipoForma];
                        const cor = mSelf.ConfiguracoesForma[formaAtual.FormaProximoNivel].Cor;
                        const zIndex = mSelf.ConfiguracoesForma[formaAtual.FormaProximoNivel].zIndex;

                        /* Apagar do mapa os overlays já plotadas - mantém no mapa o overlay da forma selecionada*/
                        vm.currentMap.removeOverlays(tipoForma);
                        mSelf.PlotarForma(data, formaAtual.FormaProximoNivel, cor, zIndex, true);

                        mSelf.DesenhaOverlay({
                            CodigoGrupo: codigoGrupo,
                            DescricaoForma: descricao,
                            TipoForma: tipoForma
                        }, formaAtual.Cor, true);

                        const codigosFormas = data.map(x => x.CodigoGrupo);

                        /* Marca na ferramenta de camadas as formas selecionadas */
                        switch (formaAtual.FormaProximoNivel) {
                            case 'macro':
                                mSelf.MacroSetoresSelecionados = codigosFormas;
                                mSelf.MarcarCamadasSelecionadas(codigosFormas, mSelf.ListaMacroSetores(), mSelf.MacroSetoresSelecionados)
                                break;
                            case 'regiao':
                                mSelf.CarregarRegioes();
                                mSelf.MarcarCamadasSelecionadas(codigosFormas, mSelf.ListaRegioes(), mSelf.RegioesSelecionados)
                                break;
                            case 'setor':
                                mSelf.CarregarSetores();
                                mSelf.MarcarCamadasSelecionadas(codigosFormas, mSelf.ListaSetores(), mSelf.SetoresSelecionados)
                                break;
                            case 'bairro':
                                mSelf.CarregarBairros();
                                mSelf.MarcarCamadasSelecionadas(codigosFormas, mSelf.ListaBairros(), mSelf.BairrosSelecionados)
                                break;
                        }

                        /* Desmarca na ferramenta de camadas as formas apagadas do mapa */
                        codigosFormas.filter(x => x != codigoGrupo)
                            .forEach(codigo => $(`#${tipoForma}` + codigo)
                                .attr('checked', false));
                    } else {
                        $('.loading-div').fadeOut();
                    }

                    $('#template-info-window-demandas').hide();
                }
            });
        }
    };

    mSelf.MarcarCamadasSelecionadas = (codigos, lista, selecionados) => {
        codigos.forEach(codigo => {
            const forma = ko.utils.arrayFirst(lista, (item) => item.CodigoGrupo == codigo);

            if (forma) {
                forma.Selecionado(true);
            }

            if (selecionados.indexOf(codigo) < 0) {
                selecionados.push(codigo);
            }
        });
    }

    mSelf.RemoverFormaMapa = (codigoGrupo, tipo) => {
        const condition = (item) => item.CodigoGrupo === parseInt(codigoGrupo);
        vm.currentMap.togglePolygons(false, tipo, condition);
        vm.currentMap.removeOverlays(tipo, condition)

        vm.currentMap.closePopup(codigoGrupo);
    };

    mSelf.AutoCompletGenerico = (lista, data, evt, campo) => {
        ko.utils.arrayForEach(lista, (valor) => {
            if (valor.Descricao.toUpperCase().indexOf(campo.toUpperCase()) > -1) {
                valor.Visivel(true);
                return;
            }
            valor.Visivel(false);
        });
    };

    mSelf.FecharModalDemandas = () => {
        vm.currentMap.closeAllPopups();
    };

    mSelf.LimparTodas = (lista, tipo) => {
        vm.currentMap.togglePolygons(false, tipo);
        vm.currentMap.removeOverlays(tipo);

        ko.utils.arrayForEach(lista(), (item) => {
            item.Selecionado(false);
            vm.currentMap.closePopup(parseInt(item.CodigoGrupo));
        });
    }

    mSelf.LimparTodosMacroSetores = () => {
        mSelf.TodosMacroSetor(false);
        mSelf.MacroSetoresSelecionados = [];
        mSelf.LimparTodas(mSelf.ListaMacroSetores, 'macro');
    }

    mSelf.LimparTodosSetores = () => {
        mSelf.TodosSetor(false);
        mSelf.SetoresSelecionados = [];
        mSelf.LimparTodas(mSelf.ListaSetores, 'setor');
    }

    mSelf.LimparTodasRegioes = () => {
        mSelf.TodosRegiao(false);
        mSelf.RegioesSelecionados = [];
        mSelf.LimparTodas(mSelf.ListaRegioes, 'regiao');
    }

    mSelf.LimparTodosBairros = () => {
        mSelf.TodosBairro(false);
        mSelf.BairrosSelecionados = [];
        mSelf.LimparTodas(mSelf.ListaBairros, 'bairro');
    }

    mSelf.LimparTodasCamadas = () => {
        mSelf.LimparTodosMacroSetores();
        mSelf.LimparTodasRegioes();
        mSelf.LimparTodosSetores();
        mSelf.LimparTodosBairros();
    }

    mSelf.ValidaVisualizacaoOverlay = (codigoGrupo, tipo) =>
        vm.currentMap.toggleOverlay(vm.currentMap.getZoom() >= 14, tipo,
            (overlay) => overlay.CodigoGrupo === parseInt(codigoGrupo));
}