function GridFormasViewModel(data) {

    var mSelf = this;

    mSelf.Template = data.Template;
    mSelf.ViewModelKnockout = data.ViewModelKnockout;
    mSelf.ModuloId = data.ModuloId;
    mSelf.Data = ko.observable(new GridFormas(data.Data, mSelf));
    mSelf.Titulo = data.Titulo;

    mSelf.Init = function () {

        $(document).keydown(function (e) {
            switch (e.which) {
                case 13:
                    //ENTER
                    //aplica a ação selecionada
                    return;
                case 37:
                    //SETA ESQUERDA
                    //Seleciona item anterior
                    mSelf.Data().ClickBotaoAnterior();
                    return;
                case 38:
                    //SETA CIMA
                    //Seleciona item anterior
                    mSelf.Data().ClickBotaoAnterior();
                    return;
                case 39:
                    //SETA DIREITA
                    //Seleciona item próximo
                    mSelf.Data().ClickBotaoProximo();
                    return;
                case 40:
                    //SETA BAIXO
                    //Seleciona item próximo
                    mSelf.Data().ClickBotaoProximo();
            }
        });

        mSelf.Data().Init();
    };
}

function GridFormas(data, moduloGrid) {

    var mSelf = this;

    mSelf.ModuloGridFormas = moduloGrid;

    mSelf.grid;

    mSelf.Formas = ko.observableArray(data());

    mSelf.LinhaSelecionada = ko.observable(-1);

    mSelf.ElementoHtmlSelecionado = ko.observable();

    mSelf.FormaIndefinida = ko.observable(false);

    mSelf.PilhaFormas = new ControleFormaAcaoViewModel();

    mSelf.Init = function () {

        mSelf.CarregarGrid();
        mSelf.AplicaCssResizable();

        if (vm.Perspectiva.EdicaoDetalheOperacao()) {
            mSelf.FormaAlterada(true);
            mSelf.ToggleHide();
            $('#alvo_next').click();
        }

    };

    mSelf.AplicaCssResizable = function () {
        $(".table-head").toggle(
            function () {
                mSelf.ToggleHide();
            }, function () {
                mSelf.ToggleShow();
            }
        );

        $('.grid-footer').resizable({
            alsoResize: ".slick-viewport, .wrap-grid, #myGrid",
            animate: false,
            minHeight: 171,
            handles: "n",
            stop: function (event, ui) {
                mSelf.grid.resizeCanvas();
                mSelf.ControleMapa.Resize();
            },
            start: function (event, ui) {
                $("#mapa").css("height", "auto");

                $("#mapa").css("margin-bottom", "0px");

                mSelf.ControleMapa.Resize();
            }
        });
    };

    mSelf.ToggleHide = function () {
        $(".grid-footer").css({ "top": "auto", "height": "auto" });
        $(".wrap-grid").hide();

        $("#menu, #mapa").css({ "bottom": "20px" });
        $("#mapa").css("height", $("#menu").css("height"));

        mSelf.ControleMapa.Resize();
        mSelf.grid.resizeCanvas();

        resize();
    };

    mSelf.ToggleShow = function () {
        $(".wrap-grid").show();
        //Ajusta o menu de acordo com a altura da grid
        var h = $(".grid-footer").outerHeight();

        $("#menu, #mapa").css({ "bottom": +h + "px" });
        $("#mapa").css("height", $("#menu").css("height"));

        mSelf.ControleMapa.Resize();
        mSelf.grid.resizeCanvas();

        resize();
    };

    mSelf.ClickBotaoProximo = function () {
        if (!$(document.activeElement).is("input")) {
            if (mSelf.FormaAlterada()) {
                mSelf.SalvarForma(mSelf.grid.getDataItem(mSelf.LinhaSelecionada()), "proxima", { row: mSelf.LinhaSelecionada() + 1 });
            } else {
                vm.Perspectiva.ControleMapa.EsconderMarker("markerAlvo");

                if (mSelf.FormaSelecionada() !== undefined && mSelf.FormaSelecionada().Tipo() == 4) //Forma indefinida
                    mSelf.SalvarPontoReferencia(null, "proxima", null);
                else
                    mSelf.SelecionaProximaLinha();

                mSelf.AlvoReferenciaSelecionadaClick(false);
            }
        }
    };

    mSelf.ClickBotaoAnterior = function () {
        if (!$(document.activeElement).is("input")) {
            if (mSelf.FormaAlterada()) {
                mSelf.SalvarForma(mSelf.grid.getDataItem(mSelf.LinhaSelecionada()), "anterior", { row: mSelf.LinhaSelecionada() - 1 });
            } else {
                vm.Perspectiva.ControleMapa.EsconderMarker("markerAlvo");

                if (mSelf.FormaSelecionada() !== undefined && mSelf.FormaSelecionada().Tipo() == 4)//forma indefinida
                    mSelf.SalvarPontoReferencia(null, "anterior", null);
                else
                    mSelf.SelecionaLinhaAnterior();

                mSelf.AlvoReferenciaSelecionadaClick(false);
            }
        }
    };

    mSelf.CarregarGrid = function () {

        $(function () {
            // Função para alterar o formato do valor das células
            function formatter(row, cell, value, columnDef, dataContext) {

                if (columnDef.field == "Identificador") {
                    var html = "<input type='hidden' class='ordem-html-" + row + "'/>" + value();
                    return html;
                }

                if (columnDef.field == "Tipo") {
                    switch (value()) {
                        case 1: return "Polígono";
                        case 2: return "Polilinha";
                        case 3: return "Círculo";
                        case 4: return "Indefinido";
                        default:
                            return;
                    }
                }

                if (columnDef.field == "Acao") {
                    if (dataContext.StatusForma() == 1)//Forma com status edicao
                        return '<button type="button" class="btn-acao">Excluir</button>&nbsp;<button type="button" class="btn-acao">Ativar</button>';
                }


                if (columnDef.field == "PontoReferencia" && dataContext.ReferenciaLatitude() != 0 && dataContext.ReferenciaLongitude() != 0)
                    return (dataContext.ReferenciaLatitude() / 1000000) + "," + (dataContext.ReferenciaLongitude() / 1000000);

                if (columnDef.field == "StatusForma") {
                    switch (dataContext.StatusForma()) {
                        case 0:
                            return "Ativa";
                        case 1:
                            return "Em edição";
                        case 2:
                            return "Finalizada";
                    };
                }

                if (ko.isObservable(value))
                    return value();
                else
                    return value;
            }

            // Configura as opções da grid
            var options = {
                enableCellNavigation: false,
                enableColumnReorder: true,
                forceFitColumns: true,
                syncColumnCellResize: true,
                multiColumnSort: true,
                headerRowHeight: 25,
                rowHeight: 25,
                //forceSyncScrolling: true,
                enableAsyncPostRender: true
            }

            var columns = [];

            //console.log("PermiteEditarFormas" + vm.Perspectiva.PermiteEditarFormas());
            //console.log("Query string" + vm.Perspectiva.QueryString("forma"));

            if (vm.Perspectiva.PermiteEditarFormas() && !vm.Perspectiva.EdicaoDetalheOperacao()) {
                // Array com os valores das células do cabeçalho
                columns = [
                    { id: "Identificador", name: "Identificador", field: "Identificador", formatter: formatter, sortable: true, width: 50 },
                    { id: "Descricao", name: "Descrição", field: "Descricao", formatter: formatter, sortable: true, width: 150 },
                    { id: "ReferenciaLatitude", name: "Ponto de Referência", field: "PontoReferencia", formatter: formatter, sortable: true, width: 100 },
                    //{ id: "alvo_ativo", name: "Alvo ativo", field: "alvo_ativo", formatter:formatter, sortable: true, width: 70 },
                    { id: "Tipo", name: "Forma", field: "Tipo", formatter: formatter, sortable: true },
                    { id: "DescricaoEntidade", name: "Tipo de Entidade", field: "DescricaoEntidade", formatter: formatter, sortable: true, cssClass: 'plataforma-cell', width: 100 },
                    { id: "StatusForma", name: "Status", field: "StatusForma", formatter: formatter, sortable: true, width: 50 },
                    { id: "Acao", name: "Ações", field: "Acao", formatter: formatter, sortable: true, width: 40 }
                ];
            } else {
                // Array com os valores das células do cabeçalho
                columns = [
                    { id: "Identificador", name: "Identificador", field: "Identificador", formatter: formatter, sortable: true, width: 50 },
                    { id: "Descricao", name: "Descrição", field: "Descricao", formatter: formatter, sortable: true, width: 150 },
                    { id: "ReferenciaLatitude", name: "Ponto de Referência", field: "PontoReferencia", formatter: formatter, sortable: true, width: 100 },
                    //{ id: "alvo_ativo", name: "Alvo ativo", field: "alvo_ativo", formatter:formatter, sortable: true, width: 70 },
                    { id: "Tipo", name: "Forma", field: "Tipo", formatter: formatter, sortable: true },
                    { id: "DescricaoEntidade", name: "Tipo de Entidade", field: "DescricaoEntidade", formatter: formatter, sortable: true, cssClass: 'plataforma-cell', width: 100 },
                    { id: "StatusForma", name: "Status", field: "StatusForma", formatter: formatter, sortable: true, width: 50 }
                ];
            }



            // Função que mostra os valores das células na grid
            $(function () {

                mSelf.grid = new Slick.Grid("#myGrid", mSelf.Formas(), columns, options);

                columnpicker = new Slick.Controls.ColumnPicker(columns, mSelf.grid, options);

                mSelf.grid.onSort.subscribe(function (e, args) {
                    var cols = args.sortCols;

                    mSelf.Formas().sort(function (dataRow1, dataRow2) {
                        for (var i = 0, l = cols.length; i < l; i++) {
                            var result;

                            var field = cols[i].sortCol.id;
                            var sign = cols[i].sortAsc ? 1 : -1;

                            var value1 = dataRow1[field], value2 = dataRow2[field];

                            result = (value1() == value2() ? 0 : (value1() > value2() ? 1 : -1)) * sign;

                            if (result != 0) {
                                return result;
                            }
                        }

                        return 0;
                    });

                    mSelf.grid.invalidate();
                    mSelf.grid.render();
                });

                mSelf.grid.onClick.subscribe(function (e, args) {

                    var coluna = args.grid.getColumns()[args.cell];

                    if (coluna.field == "Acao") {//Excluir Forma

                        if (e.target.textContent == "Excluir") {
                            abrirDialogModal({
                                resizable: false,
                                height: 190,
                                modal: true,
                                buttons: {
                                    "Sim": function () {
                                        $(this).dialog("close");
                                        mSelf.ExcluirForma(args.grid.getDataItem(args.row));
                                    },
                                    "Não": function () {
                                        $(this).dialog("close");
                                    }
                                }
                            }, "Excluir Forma", "Confirma a Exclusão da Forma ?");
                        }
                        else if (e.target.textContent == "Ativar") {
                            var forma = args.grid.getDataItem(args.row);
                            if (forma.Tipo() != 4) {
                                abrirDialogModal({
                                    resizable: false,
                                    height: 190,
                                    modal: true,
                                    buttons: {
                                        "Sim": function () {
                                            $(this).dialog("close");
                                            mSelf.AtivarForma(args.grid.getDataItem(args.row));
                                        },
                                        "Não": function () {
                                            $(this).dialog("close");
                                        }
                                    }
                                }, "Ativar Forma", "Confirma a Ativação da Forma ?");
                            } else {
                                abrirDialogModal(null, "Ativar Forma", "Não é permitido ativar uma forma indefinida.");
                            }
                        }
                    }
                    else {
                        //plota forma no mapa
                        if (mSelf.FormaSelecionada() !== undefined && mSelf.FormaSelecionada().Tipo() == 4) //Forma indefinida
                            mSelf.SalvarPontoReferencia(null, null, args);
                        else
                            mSelf.ConfiguracoesClick(args);
                    }

                    //mSelf.ElementoHtmlSelecionado(e.target.parentNode);
                    $(".slick-row").removeClass("ui-state-active");
                    $(".ordem-html-" + args.row).parent().parent().addClass("ui-state-active");

                });

                $('#alvo_next').click(function (e) {
                    mSelf.ClickBotaoProximo();
                });

                $('#alvo_prev').click(function (e) {
                    mSelf.ClickBotaoAnterior();
                });

                $('#alvo_active').click(function (e) {
                    mSelf.AlvoPlotarForma(e);
                    mSelf.AlvoReferenciaSelecionadaClick(true);
                });

                $('#picker').click(function (e) {
                    mSelf.AlvoAlterarCorForma();
                });

                $('#btn_undo').click(function (e) {
                    mSelf.DesfazerForma(e);
                });

                $('#btn_alvo').click(function (e) {
                    mSelf.AlvoMarker();
                    mSelf.AlvoReferenciaSelecionadaClick(true);
                });

                $('#alvo_menu').click(function (e) {
                    AcaoClickAlvo();
                });

            });
            mSelf.ControleMapa.Resize();
        });
    };

    mSelf.AcaoClickAlvo = function () {
        var L = ($('#alvo').outerWidth() - $('#alvo_options').outerWidth()) / 2;
        $('#alvo_options').css('left', L);
    };

    mSelf.ConfiguracoesClick = function (args) {

        vm.Perspectiva.ControleMapa.EsconderMarker("markerAlvo");

        if (mSelf.FormaAlterada()) {
            mSelf.SalvarForma(mSelf.FormaSelecionada(), null, args);
        } else {
            mSelf.LinhaSelecionada(args.row);
            mSelf.PlotarForma(args.grid.getDataItem(args.row));
        }

        mSelf.AlvoReferenciaSelecionadaClick(false);

        //habilita os botões do alvo
        if (!vm.Perspectiva.VisualizaBotoesAlvo()) {
            vm.Perspectiva.VisualizaBotoesAlvo(true);
            AcaoClickAlvo();
        }

        // desbloqueia quando a forma esta indefinida
        var forma = args.grid.getDataItem(args.row);
        if (forma && forma.Tipo()) {
            if (forma.Tipo() == 4) $("#btn_undo").hide();
            else $("#btn_undo").show();
        }
        // se a forma for finalizada nao pode alterar a mesma
        if (forma.StatusForma() == 2) {
            vm.Perspectiva.VisualizaBotoesAlvo(false);
            AcaoClickAlvo();
        }

        mSelf.AcaoClickAlvo();
    };

    mSelf.AlvoMarker = function () {
        vm.Perspectiva.ControleMapa.EsconderMarker("markerAlvo");
        vm.Perspectiva.ControleMapa.AddMarker("markerAlvo", vm.Perspectiva.ControleMapa.map.getCenter().lat(), vm.Perspectiva.ControleMapa.map.getCenter().lng(), null, true, false);
    };

    mSelf.AlvoAlterarCorForma = function () {
        var rgb = $("#btn_color path").css("fill");
        mSelf.forma.fillColor = mSelf.rgb2hex(rgb);
        mSelf.FormaSelecionada().Cor(mSelf.rgb2hex(rgb));
        mSelf.forma.setMap(null);
        mSelf.forma.setMap(mSelf.ControleMapa.map);

        mSelf.CapturarAcao();
    };

    mSelf.rgb2hex = function (rgb) {
        rgb = rgb.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/);
        function hex(x) {
            return ("0" + parseInt(x).toString(16)).slice(-2);
        }
        return "#" + hex(rgb[1]) + hex(rgb[2]) + hex(rgb[3]);
    }

    mSelf.HexToRgb = function (hex) {

        if (hex) {

            if (hex.length > 0 && hex[0] == "#")
                hex = hex.substr(1);

            if (hex.length == 3) {

                var temp = hex; hex = '';

                temp = /^([a-f0-9])([a-f0-9])([a-f0-9])$/i.exec(temp).slice(1);

                for (var i = 0; i < 3; i++) {

                    hex += temp[i] + temp[i];
                }
            }

            var triplets = /^([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})$/i.exec(hex).slice(1);

            var rgb = {
                r: parseInt(triplets[0], 16),
                g: parseInt(triplets[1], 16),
                b: parseInt(triplets[2], 16)
            };

            if (rgb.r === 0 && rgb.g === 0 && rgb.b === 0)
                return "rgb(255, 255, 255)";
            else
                return "rgb(" + rgb.r + ", " + rgb.g + ", " + rgb.b + ")";
        }

        return "rgb(255, 255, 255)";
    };

    mSelf.AlvoPlotarForma = function (event) {

        var tpAlvo = $("#alvo_active svg").attr("id");

        if (tpAlvo) {

            if (tpAlvo == "svgAlvo") {

                mSelf.AlvoMarker();

            } else {

                if (mSelf.forma == null || mSelf.forma == undefined) {

                    var ferramenta = vm.GetFerramenta("FerramentaConfiguracoes");

                    if (ferramenta) {
                        var descricaoCidade = ferramenta.Data().DescricaoCidade();

                        if (descricaoCidade != undefined)
                            vm.Perspectiva.ControleMapa.BuscaReferenciaCidade(descricaoCidade);
                    }
                }

                if (mSelf.ControleMapa.map.getZoom() > 17)
                    mSelf.ControleMapa.map.setZoom(17);

                switch (tpAlvo) {
                    case 'svgCirculo': {
                        mSelf.AlteraFormaSelecionadaCirculo();
                        break;
                    }
                    case 'svgPoligono': {
                        mSelf.AlteraFormaSelecionadaPoligono();
                        break;
                    } case 'svgPolilinha': {
                        mSelf.CriarPolilinha();
                        break;
                    }
                }

                if (tpAlvo != 'svgPolilinha')
                    mSelf.PlotarForma(mSelf.FormaSelecionada(), true);

                mSelf.CapturarAcao();

            }
        }

    };

    mSelf.AlteraFormaSelecionadaPoligono = function () {

        var pos1 = mSelf.CalculaPixelsToLatLng(+75, -75);
        var pos2 = mSelf.CalculaPixelsToLatLng(-75, -75);
        var pos3 = mSelf.CalculaPixelsToLatLng(-75, +75);
        var pos4 = mSelf.CalculaPixelsToLatLng(+75, +75);

        var FormaOV = function (codigo, latitude, longitude) {
            this.Codigo = ko.observable(codigo);
            this.CodigoForma = ko.observable(0);
            this.Latitude = ko.observable(latitude);
            this.Longitude = ko.observable(longitude);
        };

        if (mSelf.FormaSelecionada().Coordenadas() == null)
            mSelf.FormaSelecionada().Coordenadas = ko.observableArray([]);
        else
            mSelf.FormaSelecionada().Coordenadas.removeAll();

        mSelf.FormaSelecionada().Coordenadas.push(new FormaOV(mSelf.FormaSelecionada().Codigo(), pos1.lat(), pos1.lng()));
        mSelf.FormaSelecionada().Coordenadas.push(new FormaOV(mSelf.FormaSelecionada().Codigo(), pos2.lat(), pos2.lng()));
        mSelf.FormaSelecionada().Coordenadas.push(new FormaOV(mSelf.FormaSelecionada().Codigo(), pos3.lat(), pos3.lng()));
        mSelf.FormaSelecionada().Coordenadas.push(new FormaOV(mSelf.FormaSelecionada().Codigo(), pos4.lat(), pos4.lng()));

        mSelf.FormaSelecionada().Tipo(1);

        google.maps.event.clearListeners(mSelf.ControleMapa.map, 'click');
    };

    mSelf.AlteraFormaSelecionadaCirculo = function () {
        var pos1 = mSelf.CalculaPixelsToLatLng(0, 0);
        var pos2 = mSelf.CalculaPixelsToLatLng(0, 75);

        var dist = new DistanciaGPS();

        var distancia = dist.LeiCosenos(dist.LatLng(pos1.lat(), pos1.lng()), dist.LatLng(pos2.lat(), pos2.lng()));

        mSelf.FormaSelecionada().Tipo(3);

        mSelf.FormaSelecionada().CentroLatitude(pos1.lat());
        mSelf.FormaSelecionada().CentroLongitude(pos1.lng());

        mSelf.FormaSelecionada().Raio(distancia);

        google.maps.event.clearListeners(mSelf.ControleMapa.map, 'click');
    };

    mSelf.SelecionaProximaLinha = function () {
        if (mSelf.FormaAlterada()) {
            mSelf.SalvarForma(mSelf.FormaSelecionada(), "proxima", null);
        } else {

            if (mSelf.LinhaSelecionada() <= mSelf.Formas().length - 1) {

                mSelf.LinhaSelecionada(mSelf.LinhaSelecionada() + 1);
                mSelf.PlotarForma(mSelf.grid.getDataItem(mSelf.LinhaSelecionada()));

                mSelf.grid.scrollRowIntoView(mSelf.LinhaSelecionada());

                $(".slick-row").removeClass("ui-state-active");
                $(".ordem-html-" + mSelf.LinhaSelecionada()).parent().parent().addClass("ui-state-active");

                var forma = mSelf.grid.getDataItem(mSelf.LinhaSelecionada());
                // desbloqueia quando a forma esta indefinida
                if (forma && forma.Tipo()) {
                    if (forma.Tipo() == 4) $("#btn_undo").hide();
                    else $("#btn_undo").show();

                    if (forma.StatusForma() == 2) {
                        vm.Perspectiva.VisualizaBotoesAlvo(false);
                        AcaoClickAlvo();
                    }
                }
                mSelf.AcaoClickAlvo();
            }
        }
    }

    mSelf.SelecionaLinhaAnterior = function () {
        if (mSelf.FormaAlterada()) {
            mSelf.SalvarForma(mSelf.FormaSelecionada(), "anterior", null);
        } else {
            if (mSelf.LinhaSelecionada() > 0) {

                mSelf.LinhaSelecionada(mSelf.LinhaSelecionada() - 1);
                mSelf.PlotarForma(mSelf.grid.getDataItem(mSelf.LinhaSelecionada()));

                mSelf.grid.scrollRowIntoView(mSelf.LinhaSelecionada());

                $(".slick-row").removeClass("ui-state-active");
                $(".ordem-html-" + mSelf.LinhaSelecionada()).parent().parent().addClass("ui-state-active");

                var forma = mSelf.grid.getDataItem(mSelf.LinhaSelecionada());
                // desbloqueia quando a forma esta indefinida
                if (forma && forma.Tipo()) {
                    if (forma.Tipo() == 4) $("#btn_undo").hide();
                    else $("#btn_undo").show();

                    if (forma.StatusForma() == 2) {
                        vm.Perspectiva.VisualizaBotoesAlvo(false);
                        AcaoClickAlvo();
                    }
                }
                mSelf.AcaoClickAlvo();
            }
        }
    }

    mSelf.forma = null;

    mSelf.infoWindow = null;

    mSelf.pontoReferencia = ko.observable();

    mSelf.labelMap = null;

    mSelf.ControleMapa = vm.Perspectiva.ControleMapa;

    mSelf.LimparForma = function () {

        if (mSelf.forma != undefined) {

            mSelf.forma.setMap(null);

            //mSelf.labelMap.setMap(null);
        }
    }

    mSelf.FormaSelecionada = ko.observable();

    mSelf.AlvoReferenciaSelecionadaClick = ko.observable(false);

    mSelf.PlotarForma = function (forma, acaoAlvo) {

        if (acaoAlvo == undefined)
            acaoAlvo = false;
        
        //removendo ultima forma do mapa
        if (forma && (mSelf.FormaSelecionada() == undefined || mSelf.FormaSelecionada().Codigo() != forma.Codigo() || acaoAlvo)) {

            mSelf.LimparForma();

            mSelf.LimparPilhaFormas();

            var nivelZoom = mSelf.ControleMapa.map.getZoom();

            var formaJS = ko.toJS(forma);

            mSelf.FormaSelecionada(ko.mapping.fromJS(formaJS));

            switch (mSelf.FormaSelecionada().Tipo()) {
                case 1: // poligono
                    mSelf.AddPoligono(mSelf.FormaSelecionada(), acaoAlvo);
                    break;
                case 2: //2 - Polilinha
                    mSelf.AddPolyline(mSelf.FormaSelecionada());
                    break;
                case 3: // circulo
                    mSelf.AddCirculo(mSelf.FormaSelecionada(), acaoAlvo);
                    break;
                default:
                    break;

            }

            if (mSelf.FormaSelecionada().Tipo() != 4) {

                mSelf.forma.setMap(mSelf.ControleMapa.map);
                if (acaoAlvo)
                    mSelf.ControleMapa.map.setZoom(nivelZoom);
                else
                    mSelf.ControleMapa.map.setZoom(17);

            } else {
                mSelf.LimparForma();

                if (mSelf.FormaSelecionada().ReferenciaLatitude() && mSelf.FormaSelecionada().ReferenciaLongitude()) {

                    mSelf.bounds = new google.maps.LatLngBounds();
                    var ptAux = new google.maps.LatLng(
                        mSelf.FormaSelecionada().ReferenciaLatitude() / 1000000,
                        mSelf.FormaSelecionada().ReferenciaLongitude() / 1000000,
                        false);
                    mSelf.bounds.extend(ptAux);

                    vm.Perspectiva.ControleMapa.map.fitBounds(mSelf.bounds);
                    mSelf.ControleMapa.map.setZoom(17);
                    mSelf.AlvoMarker();

                } else {
                    mSelf.ControleMapa.map.setZoom(4);

                    vm.Perspectiva.ControleMapa.EsconderMarker("markerAlvo");

                    //recupera a cidade gravada no local storage
                    var cidade = localStorage.getItem("cidade");
                    if (cidade) {
                        vm.Perspectiva.ControleMapa.BuscaReferenciaCidade(cidade);
                    }
                }
            }

            mSelf.EditarForma(mSelf.FormaSelecionada());

            //habilita os botões do alvo
            if (!vm.Perspectiva.VisualizaBotoesAlvo()) {
                vm.Perspectiva.VisualizaBotoesAlvo(true);
                AcaoClickAlvo();
            }            
        }        
    };

    mSelf.LimparPilhaFormas = function () {

        mSelf.PilhaFormas.LimparPilha();
    };

    mSelf.CapturarAcao = function () {

        if (mSelf.forma) {

            if (mSelf.forma.tipo === 1 || mSelf.forma.tipo === 2) { //Polígono ou Polilinha

                var pts = [];

                for (var i in mSelf.forma.getPath().getArray()) {

                    var ptAux = new google.maps.LatLng(
                                mSelf.forma.getPath().getArray()[i].lat(),
                                mSelf.forma.getPath().getArray()[i].lng(),
                                false);

                    pts.push(ptAux);
                }

                if (mSelf.forma.tipo === 1) //Polígono
                    mSelf.PilhaFormas.Push({ Centro: null, Raio: null, Paths: pts, Cor: mSelf.forma.fillColor });
                else //Polilinha
                    mSelf.PilhaFormas.Push({ Centro: null, Raio: null, Paths: pts, Cor: null });
            }
            else if (mSelf.forma.tipo === 3) //Círculo
                mSelf.PilhaFormas.Push({ Centro: mSelf.forma.getCenter(), Raio: mSelf.forma.getRadius(), Paths: null, Cor: mSelf.forma.fillColor });
        }
    };

    mSelf.DesfazerForma = function (event) {

        mSelf.PilhaFormas.Pop();

        var forma = mSelf.PilhaFormas.GetFormaPilha();

        if (forma) {

            mSelf.LimparForma();

            google.maps.event.clearInstanceListeners(mSelf.forma);

            if (mSelf.forma.tipo === 1 || mSelf.forma.tipo === 2) { //Polígono ou Polilinha

                mSelf.forma.setPath(forma.Paths);

                if (mSelf.forma.tipo === 1) { //Polígono => Setar a cor da forma e do componente para seleção de cores

                    mSelf.forma.fillColor = forma.Cor;

                    $("#btn_color path").css("fill", mSelf.HexToRgb(forma.Cor));
                }

                google.maps.event.addListener(mSelf.forma.getPath(), 'set_at', mSelf.CapturarAcao);

                google.maps.event.addListener(mSelf.forma.getPath(), 'insert_at', mSelf.CapturarAcao);

                if (mSelf.forma.tipo === 2) //Polilinha
                    google.maps.event.addListener(mSelf.forma.getPath(), "remove_at", mSelf.CapturarAcao);
            }
            else if (mSelf.forma.tipo === 3) { //Círculo => Setar a cor da forma e do componente para seleção de cores

                mSelf.forma.setCenter(forma.Centro);

                mSelf.forma.setRadius(forma.Raio);

                mSelf.forma.fillColor = forma.Cor;

                $("#btn_color path").css("fill", mSelf.HexToRgb(forma.Cor));

                google.maps.event.addListener(mSelf.forma, 'center_changed', mSelf.CapturarAcao);

                google.maps.event.addListener(mSelf.forma, 'radius_changed', mSelf.CapturarAcao);
            }

            mSelf.forma.setMap(mSelf.ControleMapa.map);
        }
    };

    mSelf.AddCirculo = function (forma, acaoAlvo) {
        mSelf.bounds = new google.maps.LatLngBounds();

        var centro = new google.maps.LatLng(
                        !acaoAlvo ? forma.CentroLatitude() / 1000000 : forma.CentroLatitude(),
                        !acaoAlvo ? forma.CentroLongitude() / 1000000 : forma.CentroLongitude(),
                        false);

        mSelf.bounds.extend(centro);

        mSelf.pontoReferencia(centro);

        objetoForma = {
            clickable: true,
            fillOpacity: 0.4,
            fillColor: forma.Cor(),
            strokeOpacity: 1.0,
            strokeWeight: 2.0,
            zIndex: 1,
            center: centro,
            radius: forma.Raio(),
            tipo: 3,
        };

        mSelf.ControleMapa.map.fitBounds(mSelf.bounds);

        mSelf.forma = new google.maps.Circle(objetoForma);

        //mSelf.labelMap = new USGSOverlay(mSelf.bounds, mSelf.ControleMapa.map, forma.Descricao());

        google.maps.event.clearInstanceListeners(mSelf.forma);

        google.maps.event.addListener(mSelf.forma, 'center_changed', mSelf.CapturarAcao);

        google.maps.event.addListener(mSelf.forma, 'radius_changed', mSelf.CapturarAcao);

        mSelf.PilhaFormas.Push({ Centro: mSelf.forma.getCenter(), Raio: mSelf.forma.getRadius(), Paths: null, Cor: mSelf.forma.fillColor });

        $("#btn_color path").css("fill", mSelf.HexToRgb(null));
    };

    mSelf.AddPoligono = function (forma, acaoAlvo) {
        mSelf.bounds = new google.maps.LatLngBounds();
        var pts = [];
        var coordenadas = forma.Coordenadas();
        if (coordenadas) {
            for (var j = 0; j < coordenadas.length; j++) {
                var ptAux = new google.maps.LatLng(
                    !acaoAlvo ? coordenadas[j].Latitude() / 1000000 : coordenadas[j].Latitude(),
                    !acaoAlvo ? coordenadas[j].Longitude() / 1000000 : coordenadas[j].Longitude(),
                    false);
                mSelf.bounds.extend(ptAux);
                pts.push(ptAux);

                if (j == 0) {
                    mSelf.infoWindow = checkValue(mSelf.infoWindow, new google.maps.InfoWindow());
                    mSelf.infoWindow.setPosition(ptAux);

                    mSelf.pontoReferencia(ptAux);
                }
            }
        }

        objetoForma = {
            fillOpacity: 0.4,
            fillColor: checkValue(forma.Cor(), "#000000"),
            strokeOpacity: 1.0,
            strokeWeight: 1.0,
            zIndex: 1,
            paths: pts,
            tipo: 1
        };

        mSelf.ControleMapa.map.fitBounds(mSelf.bounds);

        mSelf.forma = new google.maps.Polygon(objetoForma);

        //mSelf.labelMap = new USGSOverlay(mSelf.bounds, mSelf.ControleMapa.map, forma.Descricao());

        google.maps.event.clearInstanceListeners(mSelf.forma);

        google.maps.event.addListener(mSelf.forma.getPath(), 'set_at', mSelf.CapturarAcao);

        google.maps.event.addListener(mSelf.forma.getPath(), 'insert_at', mSelf.CapturarAcao);

        mSelf.PilhaFormas.Push({ Centro: null, Raio: null, Paths: pts, Cor: mSelf.forma.fillColor });

        $("#btn_color path").css("fill", mSelf.HexToRgb(null));
    };

    mSelf.AddPolyline = function (forma) {
        var mSelf = this;
        var pts = [];
        var latLng = null;
        mSelf.bounds = new google.maps.LatLngBounds();

        for (var j = 0; j < forma.Coordenadas().length; j++) {
            if (forma.Coordenadas()[j].Latitude() < -90 || forma.Coordenadas()[j].Latitude() > 90)
                latLng = new google.maps.LatLng(forma.Coordenadas()[j].Latitude() / 1000000, forma.Coordenadas()[j].Longitude() / 1000000);
            else
                latLng = new google.maps.LatLng(forma.Coordenadas()[j].Latitude(), forma.Coordenadas()[j].Longitude());

            pts.push(latLng);

            mSelf.bounds.extend(latLng);
        }

        mSelf.ControleMapa.map.fitBounds(mSelf.bounds);

        mSelf.forma = new google.maps.Polyline({
            //strokeColor: cor,
            path: pts,
            map: mSelf.ControleMapa.map,
            tipo: 2
        });

        //mSelf.labelMap = new USGSOverlay(mSelf.bounds, mSelf.ControleMapa.map, forma.Descricao());

        google.maps.event.clearInstanceListeners(mSelf.forma);

        google.maps.event.addListener(mSelf.forma.getPath(), "insert_at", mSelf.CapturarAcao);

        google.maps.event.addListener(mSelf.forma.getPath(), "set_at", mSelf.CapturarAcao);

        google.maps.event.addListener(mSelf.forma.getPath(), "remove_at", mSelf.CapturarAcao);

        mSelf.PilhaFormas.Push({ Centro: null, Raio: null, Paths: pts, Cor: null });

        $("#btn_color path").css("fill", mSelf.HexToRgb(null));
    };

    mSelf.AtulizarLinhaGridVeiculo = function (index) {

        mSelf.grid.invalidateRow(index);
        mSelf.grid.render();

    };

    mSelf.AtulizarGridListaFormas = function (listaFormas) {

        var lista = ko.mapping.fromJS(listaFormas);

        mSelf.Formas.removeAll();

        if (lista() != null) {

            ko.utils.arrayForEach(lista(), function (item) {
                mSelf.Formas.push(item);
            });

            mSelf.ModuloGridFormas.Titulo("Formas(" + lista().length + ")");

        } else {

            vm.ShowMensagemAlerta("Não foram encontradas formas para esse filtro");

        }

        mSelf.grid.invalidate();
        mSelf.grid.render();
    }

    mSelf.EditarForma = function (forma) {

        //altera as informações do alvo
        vm.Perspectiva.DescricaoFormaSelecionada(forma.Descricao());
        vm.Perspectiva.ReferenciaFormaSelecionada("");

        if (forma.ReferenciaLatitude() != null && forma.ReferenciaLatitude() != 0 && forma.ReferenciaLongitude() != null && forma.ReferenciaLongitude() != 0)
            vm.Perspectiva.ReferenciaFormaSelecionada((forma.ReferenciaLatitude() / 1000000) + "/" + (forma.ReferenciaLongitude() / 1000000));
        else {
            var centroMapa = vm.Perspectiva.ControleMapa.map.getCenter();
            vm.Perspectiva.ReferenciaFormaSelecionada(centroMapa.lat() + "/" + centroMapa.lng());
        }

        //valida se o usuário possui permissão para editar forma
        if (vm.Perspectiva.PermiteEditarFormas()) {
            if (mSelf.forma && mSelf.FormaSelecionada().StatusForma() != 2) {
                mSelf.forma.setEditable(true);

                //evento para permitir arrastar forma
                //mSelf.forma.setDraggable(true);
            } else {
                mSelf.FormaIndefinida(true);
            }
        }
    };

    mSelf.PermiteNavegarFormas = ko.observable(false);

    mSelf.FormaAlterada = function () {
        var formaAlterada = false;

        if (mSelf.forma) {
            if (mSelf.PilhaFormas._pilhaFormas().length > 1)
                formaAlterada = true;
        }

        return formaAlterada;
    };

    mSelf.SalvarForma = function (forma, linha, args) {
        abrirDialogModal({
            resizable: false,
            width: 400,
            height: 300,
            modal: true,
            close: function () {
                $(".slick-row").removeClass("ui-state-active");
                $(".ordem-html-" + mSelf.LinhaSelecionada()).parent().parent().addClass("ui-state-active");
            },
            buttons: {
                "Sim": function () {
                    $(this).dialog("close");
                    mSelf.SalvarAlteracoesForma(linha);
                },
                "Não": function () {
                    if (args)
                        mSelf.LinhaSelecionada(args.row);

                    $(this).dialog("close");

                    mSelf.PilhaFormas.LimparPilha();

                    mSelf.PlotarForma(mSelf.grid.getDataItem(mSelf.LinhaSelecionada()));
                }
            }
        }, "Salvar Forma", "A forma selecionada foi alterada, deseja salvar as alterações?");
    };

    mSelf.SalvarPontoReferencia = function (forma, linha, args) {

        if (!mSelf.AlvoReferenciaSelecionadaClick()) {
            if (linha)
                mSelf.SelecionarLinha(linha);
            if (args)
                mSelf.ConfiguracoesClick(args);
            return;
        }

        var novaRefLatitude = Math.floor(mSelf.ControleMapa.Markers.markerAlvo.position.lat() / .000001);
        var novaRefLongitude = Math.floor(mSelf.ControleMapa.Markers.markerAlvo.position.lng() / .000001);
        var variacaoLat = novaRefLatitude - mSelf.FormaSelecionada().ReferenciaLatitude();
        var variacaoLong = novaRefLongitude - mSelf.FormaSelecionada().ReferenciaLongitude();

        if ((variacaoLat >= -2 && variacaoLat <= 2) && (variacaoLong >= -2 && variacaoLong <= 2)) {
            mSelf.ConfiguracoesClick(args);
            return;
        }

        abrirDialogModal({
            resizable: false,
            width: 400,
            height: 300,
            modal: true,
            close: function () {
                $(".slick-row").removeClass("ui-state-active");
                $(".ordem-html-" + mSelf.LinhaSelecionada()).parent().parent().addClass("ui-state-active");
            },
            buttons: {
                "Sim": function () {
                    $(this).dialog("close");
                    mSelf.SalvarAlteracaoPontoReferencia(linha, args);
                },
                "Não": function () {
                    $(this).dialog("close");
                    if (linha)
                        mSelf.SelecionarLinha(linha);
                    else {
                        mSelf.PilhaFormas.LimparPilha();

                        mSelf.PlotarForma(mSelf.grid.getDataItem(args.row));
                    }
                    mSelf.ControleMapa.Markers.markerAlvo.position.lat(mSelf.FormaSelecionada().ReferenciaLatitude());
                    mSelf.ControleMapa.Markers.markerAlvo.position.lng(mSelf.FormaSelecionada().ReferenciaLongitude());
                }
            }
        }, "Salvar Ponto de Referência", "Foi alterado o ponto de referência, deseja salvar as alterações?");
    };

    mSelf.SalvarAlteracoesForma = function (linha) {

        if (mSelf.forma.tipo == 3) {
            mSelf.FormaSelecionada().CentroLatitude(mSelf.forma.center.lat());
            mSelf.FormaSelecionada().CentroLongitude(mSelf.forma.center.lng());
        }

        if (mSelf.ValidarForma()) {
            var forma = {
                'Codigo': mSelf.FormaSelecionada().Codigo(),
                'Coordenadas': mSelf.formataCoordenadas(),
                'Cor': mSelf.FormaSelecionada().Cor(),
                'CentroLatitude': mSelf.FormaSelecionada().CentroLatitude() != null ? mSelf.FormataCoordenada(mSelf.FormaSelecionada().CentroLatitude().toString()) : null,
                'CentroLongitude': mSelf.FormaSelecionada().CentroLatitude() != null ? mSelf.FormataCoordenada(mSelf.FormaSelecionada().CentroLongitude().toString()) : null,
                'Raio': mSelf.forma.tipo == 3 ? mSelf.forma.getRadius() : 0,
                'Tipo': mSelf.FormaSelecionada().Tipo(),
                'Descricao': mSelf.FormaSelecionada().Descricao(),
                'Identificador': mSelf.FormaSelecionada().Identificador()
            }

            $(".loading-inlog").fadeIn();

            $.ajax({
                url: urlGlobal + "GestaoFormas/SalvarForma",
                contentType: 'application/json; charset=utf-8',
                dataType: "json",
                type: "POST",
                data: JSON.stringify(forma),
                success: function (data) {
                    if (data != null && data.Sucesso) {
                        mSelf.forma.setMap(null);

                        mSelf.FormaIndefinida(false);

                        //limpar a pilha de alterações da forma
                        mSelf.LimparPilhaFormas();

                        var ferramenta = vm.GetFerramenta("FerramentaFiltro");
                        if (ferramenta) {
                            ferramenta.Data().FiltrarAposSalvar(linha);
                        }

                        google.maps.event.clearListeners(mSelf.ControleMapa.map, 'click');

                    } else {
                        abrirDialogModal(null, "Salvar forma", "Erro ao salvar forma.");
                    }
                },
                error: function () {
                    $(".loading-inlog").fadeOut();
                    abrirDialogModal(null, "Salvar forma", "Erro ao salvar forma.");
                }
            });
        } else {
            abrirDialogModal(null, "Salvar forma", "Verifique o tamanho da forma.");
        }
    };

    mSelf.FormataCoordenada = function (valor) {
        if (valor.length > 9) {
            return parseInt(valor * 1000000);
        }
        return parseInt(valor);
    };

    mSelf.SalvarAlteracaoPontoReferencia = function (linha, args) {
        var forma = {
            'Codigo': mSelf.FormaSelecionada().Codigo(),
            'Coordenadas': null,
            'Cor': mSelf.FormaSelecionada().Cor(),
            'ReferenciaLatitude': mSelf.ControleMapa.Markers.markerAlvo.position.lat() * 1000000,
            'ReferenciaLongitude': mSelf.ControleMapa.Markers.markerAlvo.position.lng() * 1000000,
            'Raio': mSelf.FormaSelecionada().Raio(),
            'Tipo': mSelf.FormaSelecionada().Tipo(),
            'Descricao': mSelf.FormaSelecionada().Descricao(),
            'Identificador': mSelf.FormaSelecionada().Identificador()
        }

        $(".loading-inlog").fadeIn();

        $.ajax({
            url: urlGlobal + "GestaoFormas/SalvarForma",
            contentType: 'application/json; charset=utf-8',
            dataType: "json",
            type: "POST",
            data: JSON.stringify(forma),
            success: function (data) {
                if (data != null && data.Sucesso) {

                    mSelf.FormaIndefinida(true);

                    var formaRetorno = ko.mapping.fromJS(data.Objeto);

                    var ferramenta = vm.GetFerramenta("FerramentaFiltro");
                    if (ferramenta) {
                        if (args) {
                            mSelf.ConfiguracoesClick(args);
                        }
                        ferramenta.Data().FiltrarAposSalvar(linha, args);
                    }

                    google.maps.event.clearListeners(mSelf.ControleMapa.map, 'click');

                    //limpar a pilha de alterações da forma
                    mSelf.LimparPilhaFormas();

                } else {
                    abrirDialogModal(null, "Salvar Ponto de Referência", "Erro ao salvar o ponto de referência.")
                }
            },
            complete: function () {
            },
            error: function () {
                abrirDialogModal(null, "Salvar Ponto de Referência", "Erro ao salvar o ponto de referência.")
            }
        });
    };

    mSelf.ValidarForma = function (forma) {
        switch (mSelf.forma.tipo) {
            case 1:
                break;
            case 2:
                if (mSelf.forma.radius <= 50)
                    return false;
                break;
            default:
                return true;
        }
        return true;
    };

    mSelf.formataCoordenadas = function () {
        var arrayCoord = [];
        if (mSelf.forma.tipo != 3) {
            for (var i in mSelf.forma.getPath().getArray()) {
                var index = mSelf.forma.getPath().getArray()[i];

                arrayCoord.push({
                    'Latitude': index.lat() * 1000000,
                    'Longitude': index.lng() * 1000000,
                    'Sequencia': i,
                    'CodigoForma': mSelf.FormaSelecionada().Codigo()
                });
            }
        }

        return arrayCoord;
    };

    mSelf.SelecionarLinha = function (linha) {
        if (linha == "proxima") {
            mSelf.SelecionaProximaLinha();
        }
        else {
            mSelf.SelecionaLinhaAnterior();
        }
    };

    mSelf.SubstituiForma = function (forma) {
        var formaLista = ko.utils.arrayFirst(mSelf.Formas(), function (item) {
            return item.Codigo() == forma.Codigo();
        });

        var index = mSelf.Formas.indexOf(formaLista);

        mSelf.Formas.replace(mSelf.Formas()[index], forma);

    };

    mSelf.ExcluirForma = function (forma) {

        var paramsExcluirForma = {
            codigoForma: forma.Codigo(),
            codigoGrupoEntidade: forma.CodigoGrupoEntidade()
        };

        $(".loading-inlog").fadeIn();

        $.ajax({
            url: urlGlobal + "GestaoFormas/ExcluirForma",
            dataType: "json",
            type: "POST",
            data: paramsExcluirForma,
            success: function (data) {
                if (data && data.Sucesso) {
                    abrirDialogModal(null, "Excluir forma", "Forma excluida com sucesso.");

                    //atualizar grid de formas
                    var ferramenta = vm.GetFerramenta("FerramentaFiltro");
                    if (ferramenta) {
                        ferramenta.Data().FiltrarAposSalvar();
                    }
                } else {
                    abrirDialogModal(null, "Excluir forma", data.MensagemErro);
                }
            },
            error: function () {
                abrirDialogModal(null, "Excluir forma", "Erro ao excluir forma.");
            },
            complete: function () {
            }
        });
    };

    mSelf.CalculaPixelsToLatLng = function (offsetx, offsety) {

        // latlng is the apparent centre-point
        // offsetx is the distance you want that point to move to the right, in pixels
        // offsety is the distance you want that point to move upwards, in pixels
        // offset can be negative
        // offsetx and offsety are both optional

        var scale = Math.pow(2, vm.Perspectiva.ControleMapa.map.getZoom());
        var nw = new google.maps.LatLng(
            vm.Perspectiva.ControleMapa.map.getBounds().getNorthEast().lat(),
            vm.Perspectiva.ControleMapa.map.getBounds().getSouthWest().lng()
        );

        var worldCoordinateCenter = vm.Perspectiva.ControleMapa.map.getProjection().fromLatLngToPoint(vm.Perspectiva.ControleMapa.map.getCenter());
        var pixelOffset = new google.maps.Point((offsetx / scale) || 0, (offsety / scale) || 0)

        var worldCoordinateNewCenter = new google.maps.Point(
            worldCoordinateCenter.x - pixelOffset.x,
            worldCoordinateCenter.y + pixelOffset.y
        );

        return vm.Perspectiva.ControleMapa.map.getProjection().fromPointToLatLng(worldCoordinateNewCenter);

        return map.getProjection().fromPointToLatLng(new google.maps.Point(newLngInPx, newLatInPx));
    }

    mSelf.CriarPolilinha = function () {
        if (mSelf.forma)
            mSelf.forma.setMap(null);

        mSelf.FormaSelecionada().Tipo(2);

        mSelf.forma = new google.maps.Polyline({
            map: mSelf.ControleMapa.map,
            tipo: 2,
            editable: true
        });

        var fn = mSelf.AddLatLong

        google.maps.event.clearListeners(mSelf.ControleMapa.map, 'click');

        google.maps.event.addListener(mSelf.ControleMapa.map, 'click', fn);

        mSelf.LimparPilhaFormas();

        google.maps.event.clearInstanceListeners(mSelf.forma);

        google.maps.event.addListener(mSelf.forma.getPath(), "insert_at", mSelf.CapturarAcao);

        google.maps.event.addListener(mSelf.forma.getPath(), "set_at", mSelf.CapturarAcao);

        google.maps.event.addListener(mSelf.forma.getPath(), "remove_at", mSelf.CapturarAcao);

        $("#btn_color path").css("fill", mSelf.HexToRgb(null));
    };

    mSelf.AddLatLong = function (event) {
        if (mSelf.forma.tipo === 2) {
            var path = mSelf.forma.getPath();
            path.push(event.latLng);
        }
    };

    mSelf.AtivarForma = function (forma) {
        var paramsAtivarForma = {
            codigoForma: forma.Codigo(),
            codigoGrupoEntidade: forma.CodigoGrupoEntidade()
        };

        $.ajax({
            url: urlGlobal + "GestaoFormas/AtivarForma",
            dataType: "json",
            type: "POST",
            data: paramsAtivarForma,
            success: function (data) {
                if (data && data.Sucesso) {
                    abrirDialogModal(null, "Ativar forma", "Forma ativada com sucesso.");

                    //atualizar grid de formas
                    var ferramenta = vm.GetFerramenta("FerramentaFiltro");
                    if (ferramenta) {
                        ferramenta.Data().Filtrar();
                    }
                } else {
                    abrirDialogModal(null, "Ativar forma", data.MensagemErro);
                }
            },
            error: function () {
                abrirDialogModal(null, "Ativar forma", "Erro ao ativar forma.");
            },
            complete: function () {
                $(".loading-inlog").fadeOut();
            }
        });
    };
}