function VeiculoDetalhesGridModuloViewModel(data) {
    const mSelf = this;
    mSelf.Data = new VeiculoDetalhesGridAlarmesViewModel(data.Data);
    mSelf.ModuloId = data.ModuloId;
    mSelf.Template = data.Template;
    mSelf.UrlIconPadrao = data.UrlIconPadrao;
    mSelf.PendentesIndex = ko.observable(0);
    mSelf.ValidosIndex = ko.observable(-1);
    mSelf.InvalidosIndex = ko.observable(-1);
    mSelf.StatusAlarmeFiltro = ko.observable("P"); /* Status inicial */
    mSelf.ConnectionID = ko.observable(vmEventos.TempoReal.GetId());
    mSelf.ExibeAlarmes = data.ExibeAlarmes;
    mSelf.TratarAlarmeVM = new TratarAlarmeViewModel();
    mSelf.NovoFiltro = mSelf.ExibeAlarmes() ?
        new FerramentaNovoFiltroDetalhesViewModel(data.Data.NovoFiltro.ItensFiltro, mSelf) : null;

    mSelf.MultiTratamento = ko.observable(false);
    mSelf.MultiTratamentoChecked = ko.observable(false);
    mSelf.IconeOn = data.IconeOn;
    mSelf.IconeOff = data.IconeOff;
    mSelf.Titulo = data.Titulo;
    mSelf.AlarmeContextoHistorico = new AlarmeContextoHistorico();
    mSelf.UrlIconPadrao = urlGlobal + "RastreamentoGeral/SourceGenerico/MarkerSVG";

    mSelf.Init = () => {
        if (!mSelf.ExibeAlarmes()) {
            $("footer").css("display", "none");
        } else gridBuilder();

        mSelf.Data.Init();
        mSelf.TratarAlarmeVM.Init();

        if (vm.Perspectiva.TemQuePlotarVeiculo()) {
            mSelf.plotarVeiculo();
        }

        mSelf.AplicaCssResizable();
    };

    mSelf.AtualizarTamanhoMapa = () => {
        const alturaGrid = $(".grid-footer").height();
        $("#mapa").css("bottom", alturaGrid);
        $("#menu").css("bottom", alturaGrid);

        vm.currentMap.resizeMap();
    }

    mSelf.AplicaCssResizable = () => {
        $(".table-head").toggle(() => {
            $(".grid-footer").css({ "top": "auto", "height": "auto" });
            $("#tab-alarmes").hide();
            $("#menu, #mapa").css({ "bottom": "47px" });
            $("#barra-alarmes").css({ "bottom": "47px" });
            vm.currentMap.resizeMap();
        }, () => {
            $("#tab-alarmes").show();
            /* Ajusta o menu de acordo com a altura da grid */
            const h = $(".grid-footer").outerHeight();
            $("#menu, #mapa").css({ "bottom": +h + "px" });
            $("#barra-alarmes").css({ "bottom": h });
            vm.currentMap.resizeMap();
        });

        $("#barra-alarmes").css({ "top": "164px" });
        vm.Perspectiva.PopUp = new VeiculosPopUp([]);
        vm.currentMap.resizeMap();
    };

    mSelf.plotarVeiculo = async () => {
        if (mSelf.Data == null || data.Data.Veiculos == null) {
            return;
        }

        const veiculo = data.Data.Veiculos;
        if (veiculo) {
            if (veiculo.Latitude() != null && veiculo.Longitude() != null) {
                if (!ko.isObservable(veiculo.InfoOperacao)) {
                    veiculo.InfoOperacao = ko.observable(veiculo.InfoOperacao);
                }

                const iconUrl = mSelf.getIconeMarker(veiculo);
                const iconSize = await vm.getIconSize(iconUrl);
                const icon = new InlogMaps.MarkerIcon(iconUrl, iconSize);
                const object = ko.mapping.toJS(veiculo);
                const options = new InlogMaps.MarkerOptions([veiculo.Latitude() / 1000000, veiculo.Longitude() / 1000000],
                    true, false, icon, false, object);

                vm.currentMap.drawMarker('veiculos', options, () => mSelf.SetarEventoClickMarker());
                vm.currentMap.setZoom(19);
                vm.currentMap.setCenterMarker('veiculos');
            }
        }
    };

    mSelf.SetarEventoClickMarker = () => {
        const veiculo = mSelf.Data.Veiculo;
        const html = mSelf.getHtmlInfoWindowVeiculo(veiculo);
        const options = new InlogMaps.PopupOptions();

        options.content = html;
        options.marker = 'veiculos';
        options.conditionMarker = (item) => item.CodigoVeiculo === veiculo.CodigoVeiculo();
        options.notCalledByMap = false;
        options.object = veiculo.CodigoVeiculo();

        vm.currentMap.drawPopup('veiculos', options);
    };

    mSelf.getHtmlInfoWindowVeiculo = (data) => {
        const html = $('#info-window-veiculo-tpl').html();
        let htmlResult = html.replace('{Identificador}', data.Identificador());
        htmlResult = htmlResult.replace('{Descricao}', data.Descricao());
        htmlResult = htmlResult.replace('{Placa}', data.Placa());
        htmlResult = htmlResult.replace('{DataHoraDisplay}', data.DataHoraUltimoPeriodico());
        htmlResult = htmlResult.replace('{Velocidade}', data.Velocidade());
        return htmlResult;
    };

    mSelf.divAlarmeScroll = (id, fila, evt) => {
        const containerTopPosition = evt.target.scrollTop;
        const containerHeight = evt.target.clientHeight;
        const contentHeight = evt.target.firstElementChild.clientHeight;

        if (Math.round(containerTopPosition) == contentHeight - containerHeight) {
            mSelf.setStatusAlarmeFiltro(id);

            const filtroAlarmeVM = {
                CodigoVeiculo: mSelf.NovoFiltro.ItemFiltro().CodigoVeiculo(),
                StatusAlarmeFiltro: mSelf.NovoFiltro.ItemFiltro().StatusAlarmeFiltro(),
                Data: mSelf.NovoFiltro.ItemFiltro().Data,
                OrdenacaoData: mSelf.NovoFiltro.ItemFiltro().OrdenacaoData,
                TiposAlarmesSelecionados: mSelf.NovoFiltro.ItemFiltro().TiposAlarmesSelecionados,
                CodigoOperacao: mSelf.NovoFiltro.ItemFiltro().CodigoOperacao(),
                ConnectionID: mSelf.ConnectionID
            };

            $.ajax({
                url: "VeiculoGenericoDetalhes/PaginarListaAlarmes?pageIndex=" + mSelf.getPaginacaoIndex(id),
                data: filtroAlarmeVM,
                contentType: 'application/json; charset=utf-8',
                dataType: "json",
                type: "GET",
                beforeSend: () => $("footer:visible .loading-inlog-modulo").fadeIn(),
                success: (data) => {
                    if (data && data.length > 0) {
                        ko.utils.arrayForEach(data, (i) => {
                            const kojs = ko.mapping.fromJS(i);
                            mSelf.SetarAlarmesPaginadosMultiTratamento(kojs);

                            if (mSelf.StatusAlarmeFiltro() == "P") {
                                mSelf.Data.Pendentes.push(kojs);
                            } else if (mSelf.StatusAlarmeFiltro() == "F") {
                                mSelf.Data.Validos.push(kojs);
                            }
                            else mSelf.Data.Invalidos.push(kojs);
                        });
                    }
                }
            }).done(() => {
                $("footer:visible .loading-inlog-modulo").fadeOut();
                gridBuilder();
            });
        }
    };

    mSelf.CarregamentoAlarmesPorStatus = (id) => {
        mSelf.setStatusAlarmeFiltro(id);

        const filtroAlarmeVM = {
            CodigoVeiculo: mSelf.NovoFiltro.ItemFiltro().CodigoVeiculo(),
            StatusAlarmeFiltro: mSelf.NovoFiltro.ItemFiltro().StatusAlarmeFiltro(),
            Data: mSelf.NovoFiltro.ItemFiltro().Data,
            OrdenacaoData: mSelf.NovoFiltro.ItemFiltro().OrdenacaoData,
            TiposAlarmesSelecionados: mSelf.NovoFiltro.ItemFiltro().TiposAlarmesSelecionados,
            CodigoOperacao: mSelf.NovoFiltro.ItemFiltro().CodigoOperacao(),
            ConnectionID: mSelf.ConnectionID
        };

        $.ajax({
            url: "VeiculoGenericoDetalhes/PaginarListaAlarmes?pageIndex=" + mSelf.GetDefaultPageIndex(),
            data: filtroAlarmeVM,
            contentType: 'application/json; charset=utf-8',
            dataType: "json",
            type: "GET",
            beforeSend: () => $("footer:visible .loading-inlog-modulo").fadeIn(),
            success: (data) => {
                if (data && data.length > 0) {
                    ko.utils.arrayForEach(data, (i) => {
                        const kojs = ko.mapping.fromJS(i);
                        mSelf.SetarAlarmesPaginadosMultiTratamento(kojs);

                        if (mSelf.StatusAlarmeFiltro() == "P") {
                            mSelf.Data.Pendentes.push(kojs);
                        } else if (mSelf.StatusAlarmeFiltro() == "F") {
                            mSelf.Data.Validos.push(kojs);
                        }
                        else mSelf.Data.Invalidos.push(kojs);
                    });
                }
            }
        }).done(() => {
            if (mSelf.StatusAlarmeFiltro() == "F") {
                mSelf.Data.HabilitarContadorAlarmesValidos(true);
            } else if (mSelf.StatusAlarmeFiltro() == "I") {
                mSelf.Data.HabilitarContadorAlarmesInvalidos(true);
            }

            $("footer:visible .loading-inlog-modulo").fadeOut();
            gridBuilder();
        });
    };

    mSelf.GetDefaultPageIndex = () => 0;

    mSelf.SetarAlarmesPaginadosMultiTratamento = (alarme) => {
        if (mSelf.MultiTratamentoChecked()) {
            const tipoAlarmeSelecionado = mSelf.TratarAlarmeVM.GetTipoAlarmeSelecionadoMultiTratamento();

            if (tipoAlarmeSelecionado) {
                if (alarme.IdentificadorTipo() === tipoAlarmeSelecionado) {
                    alarme.AlarmeSelecionado(true);
                    alarme.IsMultiTratamento(true);
                }
                else {
                    alarme.AlarmeSelecionado(false);
                    alarme.IsMultiTratamento(false);
                }
            }
        }
    };

    mSelf.getPaginacaoIndex = (id) => {
        if (id == 1) {
            mSelf.PendentesIndex(mSelf.PendentesIndex() + 1);
            return mSelf.PendentesIndex();
        } else if (id == 2) {
            mSelf.ValidosIndex(mSelf.ValidosIndex() + 1);
            return mSelf.ValidosIndex();
        } else {
            mSelf.InvalidosIndex(mSelf.InvalidosIndex() + 1);
            return mSelf.InvalidosIndex();
        }
    };

    mSelf.setStatusAlarmeFiltro = (id) => {
        if (id == 1) {
            mSelf.StatusAlarmeFiltro("P"); /* Pendentes */
        } else if (id == 2) {
            mSelf.StatusAlarmeFiltro("F"); /* Validos */
        }
        else mSelf.StatusAlarmeFiltro("I"); /* Invalidos */
    };

    mSelf.ReconfigurarHtml = (data, evt) => alinhaGrid(evt.target);

    mSelf.abaSelecionada = (id, fila, evt) => {
        mSelf.setStatusAlarmeFiltro(id);
        mSelf.AnularTratamentoAlarmes();

        if (mSelf.StatusAlarmeFiltro() == "P" && mSelf.Data.Pendentes().length > 0) {
            return;
        } else if (mSelf.StatusAlarmeFiltro() == "F" && mSelf.Data.HabilitarContadorAlarmesValidos()
            && mSelf.Data.Validos().length > 0) {
            return;
        } else if (mSelf.StatusAlarmeFiltro() == "I" && mSelf.Data.HabilitarContadorAlarmesInvalidos()
            && mSelf.Data.Invalidos().length > 0) {
            return;
        }

        if (id == 1) {
            mSelf.PendentesIndex(0);
        } else if (id == 2) {
            mSelf.ValidosIndex(0);
        }
        else mSelf.InvalidosIndex(0);

        mSelf.CarregamentoAlarmesPorStatus(id, fila, evt);
    };

    mSelf.GetStatusAlarmes = () => mSelf.StatusAlarmeFiltro();

    mSelf.AnularTratamentoAlarmes = () => {
        mSelf.MultiTratamentoChecked(false);
        mSelf.MultiTratamento(false);
        mSelf.Data.HabilitarBotao(true);

        const alarmesTratamento = mSelf.TratarAlarmeVM.RetornaListaAlarmes();
        if (alarmesTratamento) {
            ko.utils.arrayForEach(alarmesTratamento, (alarme) => {
                alarme.AlarmeSelecionado(false);
                alarme.IsMultiTratamento(true);
            });
        }
    };

    mSelf.SetarMultiTratamentoAlarmes = (data, evt) => {
        const alarmesTratamento = mSelf.TratarAlarmeVM.RetornaListaAlarmes();

        if (alarmesTratamento) {
            ko.utils.arrayForEach(alarmesTratamento, (alarme) => {
                if (evt.target.checked && alarme.IsMultiTratamento()) {
                    alarme.AlarmeSelecionado(true);
                } else if (evt.target.checked) {
                    alarme.AlarmeSelecionado(false);
                    alarme.IsMultiTratamento(false);
                } else {
                    alarme.AlarmeSelecionado(false);
                    alarme.IsMultiTratamento(true);
                }
            });
        }

        if (!evt.target.checked) {
            mSelf.MultiTratamento(false);
            mSelf.MultiTratamentoChecked(false);
            mSelf.Data.HabilitarBotao(true);
        }
        else mSelf.Data.HabilitarBotao(false);

        return true;
    };

    mSelf.MultiTratamentoClick = () => mSelf.TratarAlarmeVM.MultiTratamentoAlarmes();
    mSelf.TratarAlarmeIndividual = (data, evt) => mSelf.TratarAlarmeVM.TratarAlarmeIndividual(data, evt);
    mSelf.FinalizarAlarmes = () => mSelf.TratarAlarmeVM.FinalizarAlarmes();
    mSelf.CloseModal = () => mSelf.TratarAlarmeVM.Fechar();
    mSelf.CancelarModal = () => mSelf.TratarAlarmeVM.Cancelar();

    mSelf.CarregarContexto = (data) => {
        /* remove a class da selecao da linha anterior */
        $("tr[class=row-fluid-error]").removeClass();

        const codigoAlarme = data.Codigo();
        /* verificar se o contexto está vazio */
        if (typeof (codigoAlarme) === "undefined" || codigoAlarme == null) {
            return;
        }

        /* Insere o css para a linha selecionada */
        $("#alarme_" + codigoAlarme)
            .addClass("row-fluid-error")
            .siblings()
            .removeClass("row-fluid-error");

        const paramsContextoAlarme = {
            codigoAlarme: codigoAlarme
        };

        $.ajax({
            url: urlGlobal + "RastreamentoGeral/VeiculoGenericoDetalhes/CarregarContextoAlarme",
            data: paramsContextoAlarme,
            beforeSend: () => $(".loading-inlog").fadeIn("fast"),
            success: mSelf.OnProcessaData
        }).done(() => $(".loading-inlog").fadeOut());
    };

    mSelf.OnProcessaData = (data) => {
        if (data && data.length > 0) {
            const jsonVM = $.parseJSON(data);
            mSelf.AlarmeContextoHistorico.LimparContextoAlarmeMapa();
            mSelf.AlarmeContextoHistorico.ProcessarDados(jsonVM);
        }
    };

    mSelf.getIconeMarker = (veiculo) => {
        let iconUrl = mSelf.UrlIconPadrao;
        const cor = "ff0000";

        iconUrl += "?colorHex=" + cor;
        iconUrl += "&codigoTipo=" + veiculo.TipoVeiculo();
        iconUrl += "&hasSinalizador=" + false;
        iconUrl += "&hasInconformidade=" + false;
        return iconUrl;
    };
}

function VeiculoDetalhesGridAlarmesViewModel(data) {
    const mSelf = this;
    mSelf.Veiculo = data.Veiculos;
    mSelf.Pendentes = data.Pendentes;
    mSelf.Validos = data.Validos;
    mSelf.Invalidos = data.Invalidos;
    mSelf.HabilitarBotao = ko.observable(true);
    mSelf.HabilitarContadorAlarmesValidos = ko.observable(false);
    mSelf.HabilitarContadorAlarmesInvalidos = ko.observable(false);

    mSelf.Init = () => {
        if (vm.Perspectiva.SetarVeiculo) {
            vm.Perspectiva.SetarVeiculo(mSelf.Veiculo);
        }
    };

    mSelf.SetarAlarmes = (data, evt) => {
        if (evt.target.checked) {
            data.AlarmeSelecionado(true);
            mSelf.SetarAlarmesMultiTratamento(data.IdentificadorTipo());
        } else {
            data.AlarmeSelecionado(false);
            mSelf.TravarMultiTratamento(data);
        }
    };

    mSelf.SetarAlarmesMultiTratamento = (identificador) => {
        const moduloGridViewDetalhes = vm.GetModulo("GridVeiculoDetalhesViewModel");
        if (moduloGridViewDetalhes) {
            const statusArlarme = moduloGridViewDetalhes.GetStatusAlarmes();
            let alarmes = null;

            if (statusArlarme === "P") {
                alarmes = mSelf.Pendentes();
            } else if (statusArlarme === "F") {
                alarmes = mSelf.Validos();
            }
            else alarmes = mSelf.Invalidos();

            ko.utils.arrayForEach(alarmes, (alarme) => {
                if (alarme.IdentificadorTipo() === identificador) {
                    alarme.IsMultiTratamento(true);
                }
                else alarme.IsMultiTratamento(false);
            });

            moduloGridViewDetalhes.MultiTratamento(true);
            mSelf.HabilitarBotao(false);
        }
    };

    mSelf.TravarMultiTratamento = () => {
        const moduloGridViewDetalhes = vm.GetModulo("GridVeiculoDetalhesViewModel");
        if (moduloGridViewDetalhes) {
            const statusArlarme = moduloGridViewDetalhes.GetStatusAlarmes();
            let desabilitarMultiTratamento = true;
            let alarmes = null;

            if (statusArlarme === "P") {
                alarmes = mSelf.Pendentes();
            } else if (statusArlarme === "F") {
                alarmes = mSelf.Validos();
            }
            else alarmes = mSelf.Invalidos();

            ko.utils.arrayForEach(alarmes, (alarme) => {
                if (alarme.AlarmeSelecionado()) {
                    desabilitarMultiTratamento = false;
                }
            });

            if (desabilitarMultiTratamento) {
                ko.utils.arrayForEach(alarmes, (alarme) => alarme.IsMultiTratamento(true));
                moduloGridViewDetalhes.MultiTratamentoChecked(false);
                moduloGridViewDetalhes.MultiTratamento(false);
                mSelf.HabilitarBotao(true);
            }
        }
    };
}

ko.bindingHandlers.jqColorPicker = {
    init: (element, valueAccessor) => Spectrum(element, valueAccessor())
};

var jQueryWidget = (element, valueAccessor, name, constructor) => {
    const $element = $(element);
    const $widget = $element.data(name) || constructor($element, ko.utils.unwrapObservable(valueAccessor()));
    $element.data(name, $widget);
};

ko.bindingHandlers.dialog = {
    init: (element, valueAccessor) => jQueryWidget(element, valueAccessor, 'dialog',
        ($element, options) => $element.dialog(options))
};

function Spectrum(element, value) {
    $(element).spectrum({
        color: value,
        showInput: true,
        className: "full-spectrum",
        showInitial: true,
        showPalette: true,
        showSelectionPalette: true,
        maxPaletteSize: 10,
        preferredFormat: "hex",
        move: () => { },
        show: () => { },
        beforeShow: () => { },
        hide: () => { },
        change: () => { },
        palette: [
            ["rgb(0, 0, 0)", "rgb(67, 67, 67)", "rgb(102, 102, 102)",
                "rgb(204, 204, 204)", "rgb(217, 217, 217)", "rgb(255, 255, 255)"],
            ["rgb(152, 0, 0)", "rgb(255, 0, 0)", "rgb(255, 153, 0)", "rgb(255, 255, 0)", "rgb(0, 255, 0)",
                "rgb(0, 255, 255)", "rgb(74, 134, 232)", "rgb(0, 0, 255)", "rgb(153, 0, 255)", "rgb(255, 0, 255)"],
            ["rgb(230, 184, 175)", "rgb(244, 204, 204)", "rgb(252, 229, 205)", "rgb(255, 242, 204)", "rgb(217, 234, 211)",
                "rgb(208, 224, 227)", "rgb(201, 218, 248)", "rgb(207, 226, 243)", "rgb(217, 210, 233)", "rgb(234, 209, 220)",
                "rgb(221, 126, 107)", "rgb(234, 153, 153)", "rgb(249, 203, 156)", "rgb(255, 229, 153)", "rgb(182, 215, 168)",
                "rgb(162, 196, 201)", "rgb(164, 194, 244)", "rgb(159, 197, 232)", "rgb(180, 167, 214)", "rgb(213, 166, 189)",
                "rgb(204, 65, 37)", "rgb(224, 102, 102)", "rgb(246, 178, 107)", "rgb(255, 217, 102)", "rgb(147, 196, 125)",
                "rgb(118, 165, 175)", "rgb(109, 158, 235)", "rgb(111, 168, 220)", "rgb(142, 124, 195)", "rgb(194, 123, 160)",
                "rgb(166, 28, 0)", "rgb(204, 0, 0)", "rgb(230, 145, 56)", "rgb(241, 194, 50)", "rgb(106, 168, 79)",
                "rgb(69, 129, 142)", "rgb(60, 120, 216)", "rgb(61, 133, 198)", "rgb(103, 78, 167)", "rgb(166, 77, 121)",
                "rgb(91, 15, 0)", "rgb(102, 0, 0)", "rgb(120, 63, 4)", "rgb(127, 96, 0)", "rgb(39, 78, 19)",
                "rgb(12, 52, 61)", "rgb(28, 69, 135)", "rgb(7, 55, 99)", "rgb(32, 18, 77)", "rgb(76, 17, 48)"]
        ]
    });
}