(function () {
    'use strict';

    angular
        .module('editorRotas')
        .factory('ferramentaMedirDistancia', ferramentaMedirDistancia);

    ferramentaMedirDistancia.$inject = ['$location', 'Mapa'];

    /**
     * Factory para executar funcoes de medir distancia. Como:
     * Desenhar polyline no mapa.
     */
    function ferramentaMedirDistancia($location, Mapa) {

        /**
         * Declaracao das veriaveis Globais.
         */
        let _opcoesPolyline = { strokeColor: "#2b5c74", map: null, strokeWeight: 5, zIndex: 9999, path: [], keyboardShortcuts: false };
        let _opcoesInfoBubble = { map: null, content: '', position: null, padding: 0, backgroundColor: 'white', borderRadius: 2, arrowSize: 5, borderWidth: 2, borderColor: '#2b5c74', borderRadius: 10, disableAutoPan: true, disableAnimation: true, hideCloseButton: true, arrowPosition: 50, backgroundClassName: 'transparent label-info-bubble', shadowStyle: 3 };
        let _polylineMedirDistancia = new google.maps.Polyline(_opcoesPolyline);
        let _kmTotalMedirDistancia = 0;
        let _habilitado = false;
        let _infoBubbles = [];
        let _infoBubble = {};
        let _scope = null;

        /**
         * Metodo para habilitar a ferramenta de Medir distancia.
         */
        function habilita() {

            _habilitado = true;

            // Executa interacao para mostrar a popover na toolbar.
            _scope.HabilitaMedirDistancia(_habilitado);
            _scope.SetMedirLimpar(true);

            // Adicionar o evento de clique no mapa.
            google.maps.event.addListener(Mapa.map, 'click', eventClickReguaMap);
        };

        /**
         * Metodo para desabilitar a ferramenta de Medir distancia.
         */
        function desabilita() {

            _habilitado = false;

            // Executa interacao para esconder o popover na toolbar.
            _scope.HabilitaMedirDistancia(_habilitado);

            // Remove o evento do mapa.
            google.maps.event.clearListeners(Mapa.map, 'click');

            // Verifica se existe regua no mapa se tiver continua mostrando o botao de limpar.
            _scope.vm.medirDistancia = _polylineMedirDistancia.getPath().getLength() > 0;

            // Verificar se existe um digest em execucoa, se nao tiver executa o apply.
            if (!_scope.$$phase)
                _scope.$apply();
        };

        /**
         * Metodo para o evento de clique no mapa.
         * @param {*} event Parametro enviado pelo GoogleMaps.
         */
        function eventClickReguaMap(event) {

            if (_habilitado) {

                // Se estiver habilitado pega o path da polyline.
                let pathPolyline = _polylineMedirDistancia.getPath();

                // Qualcula a distancia para o ponto anteior de tiver mais de um ponto.
                _kmTotalMedirDistancia = pathPolyline.getLength() > 0 ? _kmTotalMedirDistancia + parseInt((google.maps.geometry.spherical.computeDistanceBetween(pathPolyline.getAt(pathPolyline.getLength() - 1), event.latLng))) : _kmTotalMedirDistancia;

                // Adiciona o novo latlng.
                pathPolyline.push(event.latLng);

                // Seta o path p
                _polylineMedirDistancia.setPath(pathPolyline);

                //Exibe a polyline no mapa casa ainda não esteja plotada
                if (!_polylineMedirDistancia.getMap()) _polylineMedirDistancia.setMap(Mapa.map);

                // Set as informações para a info bubble.
                _opcoesInfoBubble.map = Mapa.map;
                _opcoesInfoBubble.content = (_kmTotalMedirDistancia / 1000).toFixed(3).replace(".", ",") + ((_kmTotalMedirDistancia / 1000) > 1 ? " Km" : " m");
                _opcoesInfoBubble.position = event.latLng;

                // Cria e abre a info bubble.
                _infoBubble = new InfoBubble(_opcoesInfoBubble);
                _infoBubble.open();

                // Adiciona a info bubble a lista.
                _infoBubbles.push(_infoBubble);

                // Mostra polyline no mapa.
                _polylineMedirDistancia.setMap(Mapa.map);

                // Esconder limpar dimensoes.
                _scope.SetMedirLimpar(true);
            }

            // Verifica se existe regua no mapa se tiver continua mostrando o botao de limpar.
            _scope.vm.medirDistancia = _polylineMedirDistancia.getPath().getLength() > 0;

            // Verificar se existe um digest em execucoa, se nao tiver executa o apply.
            if (!_scope.$$phase)
                _scope.$apply();
        };

        /**
         * Metodo para limpar as informacoes do medir distancia.
         */
        function limpar() {

            // Esconde polyline e zera o path.
            _polylineMedirDistancia.setMap(null);
            _polylineMedirDistancia.setPath([]);

            // Esconde inforBubbles e zera variavel.
            _infoBubbles.forEach((item) => item.setMap(null));
            _infoBubbles = [];

            // Zera o km Total do medir distencia e esconte botao de limpar dimensoes.
            _kmTotalMedirDistancia = 0;
            _scope.vm.medirDistancia = false;

             // Verificar se existe um digest em execucoa, se nao tiver executa o apply.
             if (!_scope.$$phase)
             _scope.$apply();
        };

        /**
         * Retorno da factory para expor as funcoes.
         */
        return {
            Habilita: habilita,
            Desabilita: desabilita,
            Limpar: limpar,
            SetScope: (scope) => _scope = scope,
            IsHabilitado: () => _habilitado
        };
    }
})();