function AgendamentoTarefasViewModel() {
    const mSelf = this;
    mSelf.ListaRegioes = new ko.observableArray();
    mSelf.FiltroBairro = new ko.observable();

    /* Variáveis alteradas dependendo da região selecionada */
    mSelf.ListaBairros = new ko.observableArray();
    mSelf.ListaFiltradaBairros = new ko.observableArray();
    mSelf.QuantidadeTarefasAgendadas = new ko.observable(0);
    mSelf.RegiaoSelecionada = new ko.observable();
    mSelf.TodosBairrosExpandidos = new ko.observable(false);

    mSelf.EdicaoTarefa = new ko.observable(null);

    mSelf.MensagemErro = ko.observable('');
    mSelf.MensagemSucesso = ko.observable('');

    mSelf.HabilitaBuscaBairros = new ko.observable(true);
    mSelf.TarefaSelecaoAnterior = ko.observable();
    mSelf.TarefaEmEdicao = ko.observable();

    /* Variáveis de controle do Mapa */

    mSelf.Forma = new ko.observable();
    mSelf.ApontamentoSelecionado = new ko.observable();
    mSelf.IconeNaoSelecionado = new ko.observable(urlGlobal + 'DemandaTarefa/SourceDT/MarkerApontamento');
    mSelf.IconeSelecionado = new ko.observable(urlGlobal + 'DemandaTarefa/SourceDT/MarkerApontamentoSelecionado');

    /* Funções */

    mSelf.Init = () => mSelf.CarregarRegioes();

    mSelf.FiltrarBairros = (data, evt, value) => {
        if (!value) {
            value = evt.target.value;
        }

        if (mSelf.RegiaoSelecionada() > 0) {
            if (value != '') {
                mSelf.ListaFiltradaBairros(ko.utils.arrayFilter(mSelf.ListaBairros(),
                    (b) => b.Descricao().toUpperCase().indexOf(value.toUpperCase()) > -1));

                mSelf.AplicarAcaoClickBairros();
            } else {
                mSelf.ListaFiltradaBairros(mSelf.ListaBairros());
                mSelf.AplicarAcaoClickBairros();
            }
        }
    };

    mSelf.RegiaoSelecionada.subscribe((regiao) => {
        mSelf.TodosBairrosExpandidos(false);
        if (regiao > 0) {
            mSelf.CarregarBairros();
        } else {
            mSelf.ListaFiltradaBairros([]);
        }
    });

    mSelf.CarregarRegioes = () => {
        $.ajax({
            url: urlGlobal + "DemandaTarefa/Tarefa/CarregarRegioes",
            contentType: 'application/json; charset=utf-8',
            dataType: "json",
            type: "GET",
            success: (data) => {
                if (data) {
                    const kojs = ko.mapping.fromJS(data);
                    mSelf.ListaRegioes(kojs());
                }
            }
        });
    };

    mSelf.CarregarBairros = () => {
        $(".barra-alarme-modal").hide();
        mSelf.ListaBairros([]);
        mSelf.ListaFiltradaBairros([]);
        mSelf.HabilitaBuscaBairros(false);
        $("#loadBairros").addClass("loading-interno-tarefas");

        $.ajax({
            url: urlGlobal + "DemandaTarefa/Tarefa/CarregarBairros",
            contentType: 'application/json; charset=utf-8',
            dataType: "json",
            type: "GET",
            data: { 'codigoRegiao': mSelf.RegiaoSelecionada() },
            success: (data) => {
                if (data) {
                    $("#loadBairros").removeClass("loading-interno-tarefas");
                    mSelf.HabilitaBuscaBairros(true);

                    const kojs = ko.mapping.fromJS(data);
                    const regiao = ko.utils.arrayFirst(mSelf.ListaRegioes(),
                        (r) => r.CodigoGrupo() == mSelf.RegiaoSelecionada());

                    ko.utils.arrayForEach(kojs.Bairros(), (bairro) =>
                        mSelf.ListaBairros.push(new BairroViewModel(bairro, mSelf.RegiaoSelecionada(), regiao.CodigoMacroSetor())));

                    mSelf.ListaFiltradaBairros(mSelf.ListaBairros());
                    mSelf.AplicarAcaoClickBairros();
                    mSelf.QuantidadeTarefasAgendadas(kojs.QuantidadeTarefasAgendadas());
                }
            }
        });
    };

    mSelf.AplicarAcaoClickBairros = () => {
        $(".bairro_title").unbind("click");

        $(".bairro_title").click((e) => {
            if (!$("span", e.currentTarget).hasClass("icon-circle-up")) {

                const codigoBairro = $("span", e.currentTarget).attr("id");
                const bairro = ko.utils.arrayFirst(mSelf.ListaFiltradaBairros(),
                    (bairro) => bairro.Codigo() == codigoBairro);

                if (bairro) {
                    bairro.BuscarDetalhesBairro();
                }
            }
        });

        AplicarEfeitosTarefas();
    };

    mSelf.CarregarDetalhesTodosBairros = () => {
        if (mSelf.TodosBairrosExpandidos()) {
            $(".bairro_title span.btn_bairro").parents(".agtarefa_listabairros").children(".bairro_content").slideDown();
            $(".bairro_title span.btn_bairro").removeClass("icon-circle-down").addClass("icon-circle-up");

            ko.utils.arrayForEach(mSelf.ListaFiltradaBairros(), (bairro) => bairro.BuscarDetalhesBairro());
        } else {
            $(".bairro_title span.btn_bairro").parents(".agtarefa_listabairros").children(".bairro_content").slideUp();
            $(".bairro_title span.btn_bairro").removeClass("icon-circle-up").addClass("icon-circle-down");
        }
    };

    mSelf.EditarTarefa = (tarefa) => {
        mSelf.EdicaoTarefa(new EdicaoTarefa(tarefa));
        mSelf.EdicaoTarefa().CarregarDadosEdicaoTarefa();
    };

    mSelf.CarregarApontamentosTarefa = (tarefa) => {
        mSelf.LimparItensMapa();

        $(".loading-div").show();

        $.ajax({
            url: urlGlobal + "DemandaTarefa/Tarefa/CarregarApontamentosPorTarefa",
            contentType: 'application/json; charset=utf-8',
            dataType: "json",
            type: "GET",
            data: { 'codigoTarefa': tarefa.Codigo(), 'codigoSetor': tarefa.CodigoBairro() },
            success: (data) => mSelf.DetalhesTarefa(data)
        });
    };

    mSelf.DetalhesTarefa = async (data) => {
        if (data) {
            const kojs = ko.mapping.fromJS(data);

            //plota a forma do bairro
            const pts = [];
            const coordenadas = kojs.Forma.Coordenadas();

            for (var j = 0; j < coordenadas.length; j++) {
                let latLng = null;
                if (coordenadas[j].Latitude() < -90 || coordenadas[j].Latitude() > 90) {
                    latLng = [coordenadas[j].Latitude() / 1000000, coordenadas[j].Longitude() / 1000000];
                } else latLng = [coordenadas[j].Latitude(), coordenadas[j].Longitude()];

                pts.push(latLng);
            }

            //plota os apontamentos da tarefa
            await Promise.all(kojs.Apontamentos().map(async (item) => {
                const iconSize = await vm.getIconSize(mSelf.IconeNaoSelecionado());
                const icon = new InlogMaps.MarkerIcon(mSelf.IconeNaoSelecionado(), iconSize);

                const options = new InlogMaps.MarkerOptions([item.Latitude() / 1000000, item.Longitude() / 1000000], true);
                options.icon = icon;
                options.object = item.Codigo();

                vm.currentMap.drawMarker('apontamentos', options, mSelf.OnClickApontamentos);
            }));

            const options = new InlogMaps.PolygonOptions(pts, 2, true, '#428bca');
            options.fillOpacity = 0.4;
            options.fillColor = '#428bca';
            options.fitBounds = true;
            options.object = {
                tipo: 1,
                forma: kojs.Forma.Codigo()
            }

            vm.currentMap.drawPolygon('bairro-tarefa', options, mSelf.OnClickForma);
            vm.currentMap.removeEventMap(InlogMaps.MapEventType.Click);
            vm.currentMap.addEventMap(InlogMaps.MapEventType.Click, () => mSelf.LimparApontamentoSelecionado());
        }
        $(".loading-div").hide();
    }

    mSelf.OnClickForma = (event, object) => {
        const options = new InlogMaps.PolygonAlterOptions();
        options.color = '#000000';

        vm.currentMap.alterPolygonOptions('bairro-tarefa', options, (item) => item === object);
    }

    mSelf.OnClickApontamentos = (event, codigoApontamento) => {
        if (mSelf.ApontamentoSelecionado()) {
            mSelf.AlterarIconeMarker(mSelf.ApontamentoSelecionado(), mSelf.IconeNaoSelecionado());
        }

        mSelf.ApontamentoSelecionado(codigoApontamento);
        mSelf.AlterarIconeMarker(codigoApontamento, mSelf.IconeSelecionado());

        vm.Perspectiva.DetalheTarefa.CarregarTarefa(codigoApontamento);
    }

    mSelf.LimparItensMapa = () => {
        vm.currentMap.removeMarkers('apontamentos');
        vm.currentMap.removePolygons('bairro-tarefa');
        mSelf.LimparApontamentoSelecionado();
    }

    mSelf.LimparApontamentoSelecionado = () => {
        if (mSelf.ApontamentoSelecionado()) {
            mSelf.AlterarIconeMarker(mSelf.ApontamentoSelecionado(), mSelf.IconeNaoSelecionado());
        }

        mSelf.ApontamentoSelecionado(null);
    }

    mSelf.AlterarIconeMarker = (codigo, urlIcon) => {
        const icon = new InlogMaps.MarkerIcon();
        icon.url = urlIcon;

        const options = new InlogMaps.MarkerAlterOptions();
        options.icon = icon;

        vm.currentMap.alterMarkerOptions('apontamentos', options, (item) => item === codigo);
    }

    mSelf.InsereMarkerApontamentoEvento = (apontamento) => {
        const icon = new InlogMaps.MarkerIcon();
        icon.url = mSelf.IconeNaoSelecionado();

        const options = new InlogMaps.MarkerOptions([apontamento.Latitude() / 1000000, apontamento.Longitude() / 1000000], true);
        options.icon = icon;
        options.object = apontamento.CodigoApontamento();

        vm.currentMap.drawMarker('apontamentos', options, mSelf.OnClickApontamentos);
    }

    mSelf.Init();
};