(function () {
    'use strict';

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

    ferramentaImportarHistorico.$inject = ['$routeParams', '$timeout', 'FuncionalidadesMapa', 'ferramentaApagarTrecho', 'ferramentaAjustarTrecho', 'selecionarTrecho', 'ferramentaCamadaVisualizacao', 'historicoService'];

    function ferramentaImportarHistorico($routeParams, $timeout, FuncionalidadesMapa, ferramentaApagarTrecho, ferramentaAjustarTrecho, selecionarTrecho, ferramentaCamadaVisualizacao, historicoService) {

        let _codigoVeiculo = null;
        let _dataInicioPeriodo = null;
        let _dataFimPeriodo = null;
        let _Scope = null;
        let _indexHistorico = 0;
        let _historicosImportados = [];

        // Ao carregar a factory seta como callback a funcao de 'limparHistoricosImportados' para a 'selecionarTrecho'.
        FuncionalidadesMapa.SetLimparHistoricosImportados(limparHistoricosImportados);

        /**
         * Verifica se o histórico pesquisado já está plotado no mapa
         * @param codigoVeiculo {int}
         * @param dataInicioPeriodo {Date}
         * @param dataFimPeriodo {Date}
         * @returns {boolean} {}
         */
        function verificaHistoricoImportado(codigoVeiculo, dataInicioPeriodo, dataFimPeriodo) {
            return _historicosImportados.some(historico => historico.CodigoVeiculo === codigoVeiculo && historico.DataInicio === dataInicioPeriodo && historico.DataFim === dataFimPeriodo);
        }

        /**
         * Metodo para importacao de historico tanto por Veiculo quanto para Setor.
         * @param {*} codigoVeiculo Codigo do veiculo importado.
         * @param {*} dataInicioPeriodo Data inicio do periodo.
         * @param {*} dataFimPeriodo Data fim do periodo.
         */
        function importarHistorico(codigoVeiculo, dataInicioPeriodo, dataFimPeriodo) {

            // Encontra index do historico.
            let indexHistorico = _historicosImportados.findIndex(historico => historico.CodigoVeiculo === codigoVeiculo && historico.DataInicio === dataInicioPeriodo && historico.DataFim === dataFimPeriodo);

            _codigoVeiculo = codigoVeiculo;
            _dataInicioPeriodo = dataInicioPeriodo;
            _dataFimPeriodo = dataFimPeriodo;

            // Remove o historico da lista de importados.
            if (indexHistorico > -1)
                _historicosImportados.splice(indexHistorico, 1);

            // Importa historico.
            return historicoService.CarregarHistorico(codigoVeiculo, dataInicioPeriodo, dataFimPeriodo)
                .then(successImportarHistorico)
                .catch(errorRequest);
        }

        /**
         * Metodo para o sucesso da requisicao do 'CarregarHistorico'.
         * @param {*} result Resposta do servidor.
         */
        function successImportarHistorico(result) {

            // Verifica de o result tem informacao.
            if (result.data && result.data.length > 0) {

                //Se a quantidade for maior que 300.
                // if (result.data.length > 300) {
                //
                //     // Mostre a mensagem informado que pode haver lentidao
                //     $timeout(() => {
                //         _Scope.hideAll();
                //         $timeout(() => {
                //             _Scope.showWarning('O histórico do veículo para o período selecionado possui muitas informações. A navegação pode apresentar lentidão.');
                //             _Scope.$apply();
                //         }, 500);
                //     }, 2000);
                // }

                // Se tiver Um ou Nenhuma polyline no apagar trecho, limpe o polyline undo.
                if (ferramentaApagarTrecho.GetPolylinesApagarTecho().length <= 1)
                    ferramentaApagarTrecho.ResetPolyUndo();

                // Criar o codigo da rota importada e seta ela no PlotarRota.
                let codigoRotaImportada = 'V' + _codigoVeiculo + '-' + _indexHistorico;
                let rota = FuncionalidadesMapa.PlotarRota(result.data, codigoRotaImportada, false, null, false, 'Etapa01', false);

                // Seta informacoes para a nova rota.
                rota.Descricao = 'Rota Importada';
                rota.Apelido = 'Rota Importada';
                rota.Selecionado = true;

                // Seta a rota na camada de visualizacao.
                ferramentaCamadaVisualizacao.SetRotaImportada(rota, rota.Codigo);

                // Verifica se o apagar trecho nao tem polyline e existe uma rota no mapa.
                if (ferramentaApagarTrecho.GetPolylinesApagarTecho().length === 0 && FuncionalidadesMapa.GetRota($routeParams.CodigoRota) && FuncionalidadesMapa.GetRota($routeParams.CodigoRota).getPath().getLength() > 0) {
                    // Adiciona a rota plotada no apagar trecho.
                    ferramentaApagarTrecho.AdicionarPoylineApagarTrecho(FuncionalidadesMapa.GetRota($routeParams.CodigoRota));
                } else {
                    // Mostrar as polyline de apagar trecho.
                    ferramentaApagarTrecho.MostrarApagarTrecho();
                }

                // Atualiza a polyline undo.
                ferramentaApagarTrecho.AtualizarPolylineUndo();

                // Adiciona o historico no apagar trecho.
                ferramentaApagarTrecho.AdicionarPoylineApagarTrecho(rota);

                // Atualiza a rota plotada.
                ferramentaApagarTrecho.AtualizaRotaPlotada();

                // Refaz as configuracoes da camada de visualizacao.
                _Scope.vm.configuracoesGerais.Rotas = true;
                _Scope.vm.configuracoesGerais.InicioFim = true;

                // Carregar informacoes sobre o veiculo.
                return historicoService.CarregarDadosVeiculo(_codigoVeiculo)
                    .then(successCarregarDadosVeiculo)
                    .catch(errorRequest);
            } else {
                // Se nao tiver informacoes informe o usuario.
                return false;
                // throw {
                //     message: 'Não existe histórico do veículo para o período informado',
                //     target: 'modalNotificationOuter'
                // };
            }
        }

        /**
         * Metodo para sucesso da requisicao do 'CarregarDadosVeiculo'.
         * @param {*} result Resposta do servidor.
         */
        function successCarregarDadosVeiculo(result) {

            // Incrementa um no historico.
            _indexHistorico++;

            // Cria um novo objeto.
            let historico = {
                Selecionado: false,
                CodigoVeiculo: _codigoVeiculo,
                Identificador: result.data.Identificador,
                Placa: result.data.Placa,
                DataInicio: _dataInicioPeriodo,
                DataFim: _dataFimPeriodo,
                Chave: _codigoVeiculo + '_' + _indexHistorico
            };

            // Adicionar na lista de importados.
            _historicosImportados.push(historico);

            // Mostra todos as polylines do mapa.
            FuncionalidadesMapa.FitBoundsAllPolylines();

            return result;
        }

        /**
         * Metodo para limpar os historicos importados.
         */
        function limparHistoricosImportados() {
            _historicosImportados = []
        }

        function errorRequest(error) {
            throw error;
        }

        function onChangeShapeFiles() {
            var files = Array.from(_Scope.vm.shapeFiles);
            if (files && files.length) {
                if (files.map(x => x.name.substr(x.name.lastIndexOf('.'), x.name.length)).find(x => !(x.toLowerCase() === '.shp' || x.toLowerCase() === '.dbf'))) {
                    _Scope.vm.showNotification('São permitidos apenas os arquivos no formato .shp ou .dbf', 'warn');
                    return;
                }
                var filesGroupedByName = groupBy(files, (shapeFile) => shapeFile.name.substr(0, shapeFile.name.lastIndexOf('.')));
                var fileShapes = [];
                if (filesGroupedByName.size) {
                    filesGroupedByName.forEach(file => {
                        var name = file.find(x => x.name).name.toLowerCase();
                        name = name.substr(0, name.lastIndexOf('.'));

                        var shpFile = file.find(x => x.name.toLowerCase() === `${name}.shp`);
                        var dbfFile = file.find(x => x.name.toLowerCase() === `${name}.dbf`);

                        if (!shpFile && dbfFile) {
                            _Scope.vm.showNotification('Para cada arquivo .dbf deve existir um .shp com o mesmo nome', 'warn');
                            return;
                        }

                        fileShapes.push(new Shapefile({
                            shp: shpFile,
                            dbf: dbfFile
                        }, (data) => { afterParseFileShape(data, name); }));
                    });
                } else {
                    _Scope.vm.showNotification('É necessário selecionar ao menos 1 arquivo shp', 'warn');
                }
                document.getElementById('image-file').value = '';
            }
        }

        function groupBy(list, keyGetter) {
            const map = new Map();
            list.forEach((item) => {
                const key = keyGetter(item);
                const collection = map.get(key);
                if (!collection) {
                    map.set(key, [item]);
                } else {
                    collection.push(item);
                }
            });
            return map;
        }

        function afterParseFileShape(data, nameFile) {
            if (ferramentaApagarTrecho.GetPolylinesApagarTecho().length <= 1)
                ferramentaApagarTrecho.ResetPolyUndo();
            var objOptions = { editable: false, nameFile: nameFile };

            var polylines = FuncionalidadesMapa.SetFromGeoJson(data.geojson, objOptions, () => { });

            var polyline = polylines[0];

            if (polylines.length > 1) {
                var pathPolylineInicioUnificacao = [];

                polylines.forEach(polyline => polyline.getPath().getArray().forEach(path => {
                    pathPolylineInicioUnificacao.push(path);
                }));

                polyline.setPath(pathPolylineInicioUnificacao);
            }

            selecionarTrecho.InitSelecionarTrecho(polyline);
            selecionarTrecho.SetOptionsPolylineDefault(objOptions);

            if (ferramentaApagarTrecho.GetPolylinesApagarTecho().length === 0 && FuncionalidadesMapa.GetRota($routeParams.CodigoRota) && FuncionalidadesMapa.GetRota($routeParams.CodigoRota).getPath().getLength() > 0) {
                // Adiciona a rota plotada no apagar trecho.
                ferramentaApagarTrecho.AdicionarPoylineApagarTrecho(FuncionalidadesMapa.GetRota($routeParams.CodigoRota));
            } else {
                // Mostrar as polyline de apagar trecho.
                ferramentaApagarTrecho.MostrarApagarTrecho();
            }

            ferramentaApagarTrecho.AtualizarPolylineUndo();

            ferramentaApagarTrecho.AdicionarPoylineApagarTrecho(polyline);

            ferramentaApagarTrecho.AtualizaRotaPlotada();
            
            _Scope.vm.configuracoesGerais.Rotas = true;
            _Scope.vm.configuracoesGerais.InicioFim = true;

            _Scope.vm.RotaObservable.notify('enable');
        }

        function setScope(scope) {
            _Scope = scope;
            _Scope.$watch('vm.shapeFiles', onChangeShapeFiles);
            _Scope.vm.shapeFiles = [];
        }

        return {
            SetScope: setScope,
            LimparHistoricosImportados: limparHistoricosImportados,
            importarHistorico: importarHistorico,
            verificaHistoricoImportado: verificaHistoricoImportado,
        }
    }
})();
