function FerramentaLocalizacaoViewModel(data) {
    const mSelf = this;
    mSelf.Data = ko.observable(new LocalizacaoFerramentaOpcoes(mSelf));
    mSelf.FerramentaId = data.FerramentaId;
    mSelf.Template = data.Template;
    mSelf.Nome = data.Nome;
    mSelf.Titulo = data.Titulo;
    mSelf.NomeBotao = data.NomeBotao;
    mSelf.Icone = data.Icone;
    mSelf.Ordem = 7;
    mSelf.Visivel = ko.observable(true);

    mSelf.Init = () => {
        if (vm.usarGeoGoogle) {
            new google.maps.places.Autocomplete($('#localizacaoEndName')[0], {
                types: ['geocode']
            });
        }
    }
}

function LocalizacaoFerramentaOpcoes() {
    const mSelf = this;
    mSelf.GeoCodeAtivo = ko.observable(false);
    mSelf.btnPontoPartidaAtivo = ko.observable(false);
    mSelf.btnPontoChegadaAtivo = ko.observable(false);
    mSelf.btnRotearAtivo = ko.observable(false);
    mSelf.GeoCodeLabel = ko.observable((mSelf.GeoCodeAtivo() ? 'Desativar' : 'Ativar') + ' GeoCode');
    mSelf.PontoPartidaSelecionado = null;
    mSelf.PontoChegadaSelecionado = null;

    mSelf.btnBuscar = () => {
        if ($('#localizacaoEndName').val().trim().length > 0) {
            const busca = $('#localizacaoEndName').val();
            if (vm.usarGeoGoogle) {
                const geocoder = new google.maps.Geocoder();
                geocoder.geocode({ 'address': busca }, (results, status) => {
                    if (status == google.maps.GeocoderStatus.OK) {
                        const googleLatLng = results[0].geometry.location;
                        mSelf.GeocodeSuccess([googleLatLng.lat(), googleLatLng.lng()]);
                    }
                    else alert('Nenhum resultado encontrado!');
                });
            } else {
                $('.loading-inlog').fadeIn();
                $.ajax({
                    url: urlGlobal + 'Comum/Comum/BuscarGeocode',
                    data: { endereco: busca },
                    dataType: 'json',
                    type: 'GET',
                    success: (data) => {
                        if (data) {
                            const latlng = [data.Latitude, data.Longitude];
                            mSelf.GeocodeSuccess(latlng);
                            $('.loading-inlog').fadeOut();
                        }
                        else alert('Nenhum resultado encontrado!');
                    }
                });
            }
        }
    };

    mSelf.GeocodeSuccess = (latlng) => {
        vm.currentMap.setZoom(12);
        mSelf.DesenhaMarker('geocode', latlng);
        vm.currentMap.setCenter(latlng);
    }

    mSelf.BuscarGeocodeReverso = (event, handler) => {
        if (vm.usarGeoGoogle) {
            const geocoder = new google.maps.Geocoder();
            geocoder.geocode({ 'latLng': new google.maps.LatLng(event.latlng[0], event.latlng[1]) },
                (results, status) => {
                    if (status == google.maps.GeocoderStatus.OK) {
                        if (results[0]) {
                            handler(event.latlng, results[0].formatted_address);
                        }
                        else alert('Nenhum resultado encontrado!');
                    }
                    else alert('Problema encontrado no serviço do google, contate o suporte!');
                });
        } else {
            $('.loading-inlog').fadeIn();
            $.ajax({
                url: urlGlobal + 'Comum/Comum/BuscarEndereco',
                data: { lat: event.latlng[0], lng: event.latlng[1] },
                dataType: 'json',
                type: 'GET',
                success: (data) => {
                    if (data) {
                        handler(event.latlng, data.EnderecoCompleto);
                        $('.loading-inlog').fadeOut();
                    }
                    else alert('Nenhum resultado encontrado!');
                }
            });
        }
    }

    mSelf.btnPontoPartida = () => {
        if (mSelf.GeoCodeAtivo()) {
            mSelf.btnAtivarGeoCodeReverso();
        }

        mSelf.btnPontoPartidaAtivo(true);
        vm.currentMap.removeEventMap(InlogMaps.MapEventType.Click);
        vm.currentMap.addEventMap(InlogMaps.MapEventType.Click,
            (latLng) => mSelf.BuscarGeocodeReverso(latLng, mSelf.OnMapClickPontoPartida));
    };

    mSelf.OnMapClickPontoPartida = async (latlng, endereco) => {
        const tipo = 'pontoPartida';
        const urlIcon = 'https://chart.apis.google.com/chart?chst=d_map_pin_letter&chld=%E2%80%A2|0000ff';
        const iconSize = await vm.getIconSize(urlIcon);
        const icon = new InlogMaps.MarkerIcon(urlIcon, iconSize);
        mSelf.DesenhaMarker(tipo, latlng, icon);

        const popupOptions = new InlogMaps.PopupOptions(null, endereco, tipo);
        popupOptions.notCalledByMap = true;
        vm.currentMap.drawPopup(tipo, popupOptions);

        mSelf.PontoPartidaSelecionado = latlng;
    }

    mSelf.btnPontoChegada = () => {
        if (mSelf.PontoPartidaSelecionado) {
            mSelf.btnPontoChegadaAtivo(true);

            vm.currentMap.removeEventMap(InlogMaps.MapEventType.Click);
            vm.currentMap.addEventMap(InlogMaps.MapEventType.Click,
                (latLng) => mSelf.BuscarGeocodeReverso(latLng, mSelf.OnMapClickPontoChegada));

            mSelf.btnRotearAtivo(true);
        }
        else vm.ShowMensagemAlerta('O ponto de partida não foi selecionado!');
    };

    mSelf.OnMapClickPontoChegada = async (latlng, endereco) => {
        const tipo = 'pontoChegada';
        const urlIcon = 'https://chart.apis.google.com/chart?chst=d_map_pin_letter&chld=%E2%80%A2|ffd966';
        const iconSize = await vm.getIconSize(urlIcon);
        const icon = new InlogMaps.MarkerIcon(urlIcon, iconSize);
        mSelf.DesenhaMarker(tipo, latlng, icon);

        const popupOptions = new InlogMaps.PopupOptions(null, endereco, tipo);
        popupOptions.notCalledByMap = true;
        vm.currentMap.drawPopup(tipo, popupOptions);

        mSelf.PontoChegadaSelecionado = latlng;
    }

    mSelf.btnRotear = () => {
        if (mSelf.PontoChegadaSelecionado && mSelf.PontoPartidaSelecionado) {
            if (vm.usarGeoGoogle) {
                const inicio = mSelf.PontoPartidaSelecionado;
                const fim = mSelf.PontoChegadaSelecionado

                const request = {
                    origin: new google.maps.LatLng(inicio[0], inicio[1]),
                    destination: new google.maps.LatLng(fim[0], fim[1]),
                    travelMode: google.maps.TravelMode.DRIVING
                };

                const directionsService = new google.maps.DirectionsService();
                directionsService.route(request, (response, status) => {
                    if (status == google.maps.DirectionsStatus.OK) {
                        let path = [];
                        const paths = response.routes[0].legs[0].steps.map(x => x.lat_lngs.map(y => [y.lat(), y.lng()]));
                        paths.forEach(item => path = path.concat(item));

                        mSelf.PlotarRota(path);
                        mSelf.FinalRotear();
                    }
                });
            } else {
                const list = [{
                    Latitude: mSelf.PontoPartidaSelecionado[0],
                    Longitude: mSelf.PontoPartidaSelecionado[1]
                },
                {
                    Latitude: mSelf.PontoChegadaSelecionado[0],
                    Longitude: mSelf.PontoChegadaSelecionado[1]
                }];

                $('.loading-inlog').fadeIn();
                $.ajax({
                    url: urlGlobal + 'Comum/Comum/BuscarRota',
                    contentType: 'application/json; charset=utf-8',
                    data: ko.toJSON(list),
                    dataType: 'json',
                    type: 'POST',
                    success: (data) => {
                        if (data && data.length) {
                            const path = [];

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

                                path.push(latLng);
                            }

                            mSelf.PlotarRota(path);
                            mSelf.FinalRotear();
                        } else alert('Nenhum resultado encontrado!');
                        $('.loading-inlog').fadeOut();
                    }
                });
            }
        }
        else vm.ShowMensagemAlerta('O ponto de chegada não foi selecionado!');
    };

    mSelf.PlotarRota = (path) => {
        vm.currentMap.removePolylines('rota');

        const options = new InlogMaps.PolylineOptions(path, true, true);
        options.style = InlogMaps.PolylineType.Arrow;
        options.color = '#333';
        vm.currentMap.drawPolyline('rota', options);
    }

    mSelf.btnLimpar = () => {
        mSelf.btnPontoPartidaAtivo(false);
        mSelf.btnPontoChegadaAtivo(false);
        mSelf.btnRotearAtivo(false);

        mSelf.PontoPartidaSelecionado = null;
        mSelf.PontoChegadasSelecionado = null;

        vm.currentMap.removeMarkers('geocode');
        vm.currentMap.removeMarkers('geocodeReverso');
        vm.currentMap.closePopup('geocodeReverso');
        vm.currentMap.removeMarkers('pontoPartida');
        vm.currentMap.closePopup('pontoPartida');
        vm.currentMap.removeMarkers('pontoChegada');
        vm.currentMap.closePopup('pontoChegada');
        vm.currentMap.removePolylines('rota');
        vm.currentMap.removeEventMap(InlogMaps.MapEventType.Click);

        $('#localizacaoEndName').val('');
    };

    mSelf.FinalRotear = () => {
        mSelf.btnPontoPartidaAtivo(false);
        mSelf.btnPontoChegadaAtivo(false);
        mSelf.btnRotearAtivo(false);
        vm.currentMap.removeMarkers('pontoPartida');
        vm.currentMap.closePopup('pontoPartida');
        vm.currentMap.removeMarkers('pontoChegada');
        vm.currentMap.closePopup('pontoChegada');
        vm.currentMap.removeEventMap(InlogMaps.MapEventType.Click);
    };

    mSelf.btnAtivarGeoCodeReverso = () => {
        mSelf.GeoCodeAtivo(!mSelf.GeoCodeAtivo());
        vm.currentMap.removeEventMap(InlogMaps.MapEventType.Click);

        if (mSelf.GeoCodeAtivo()) {
            vm.currentMap.addEventMap(InlogMaps.MapEventType.Click,
                (latLng) => mSelf.BuscarGeocodeReverso(latLng, mSelf.OnMapClickGeocode));
        }

        mSelf.GeoCodeLabel((mSelf.GeoCodeAtivo() ? 'Desativar' : 'Ativar') + ' GeoCode');
    };

    mSelf.OnMapClickGeocode = (latlng, endereco) => {
        const tipo = 'geocodeReverso';
        mSelf.DesenhaMarker(tipo, latlng);

        const popupOptions = new InlogMaps.PopupOptions(null, endereco, tipo);
        popupOptions.notCalledByMap = true;
        vm.currentMap.drawPopup(tipo, popupOptions);
    }

    mSelf.DesenhaMarker = (tipo, latlng, icon) => {
        if (vm.currentMap.markerExists(tipo)) {
            vm.currentMap.alterMarkerPosition(tipo, latlng);
            vm.currentMap.toggleMarkers(true, tipo);
        } else {
            const options = new InlogMaps.MarkerOptions(latlng, true);
            options.icon = icon;
            vm.currentMap.drawMarker(tipo, options);
        }
    }
};