public static EventoStagging duplicarEventoProducao(string matricula, int seguradoraId, string dtInicio, string hInicio, Mutex mutex = null)
        {
            ValorSistemaRepository valoresSistemaRepository = new ValorSistemaRepository();
            List<ValorSistema> tiposErro = valoresSistemaRepository.GetPorTipologia("TIPO_ERRO", mutex);
            List<ValorSistema> estadosEvento = valoresSistemaRepository.GetPorTipologia("ESTADO_EVENTO_STAGGING", mutex);

            DateTime dataInicio;
            TimeSpan horaInicio;

            DateTime dataHoraInicio;

            List<ErroEventoStagging> errosEventoStagging = new List<ErroEventoStagging>();

            if (matricula == null || matricula == string.Empty)
            {
                errosEventoStagging.Add(new ErroEventoStagging { campo = "matricula", descricao = "Matrícula Inválida", tipologiaId = tiposErro.Where(e => e.valor == "GENERICO").Single().valorSistemaId });
            }
            if (!DateTime.TryParseExact(dtInicio, "yyyyMMdd", new CultureInfo("pt-PT"), DateTimeStyles.None, out dataInicio))
            {
                errosEventoStagging.Add(new ErroEventoStagging { campo = "dataInicio", descricao = "Data de início de período Inválida", tipologiaId = tiposErro.Where(e => e.valor == "GENERICO").Single().valorSistemaId });
            }
            if (!TimeSpan.TryParseExact(hInicio, "hhmmss", new CultureInfo("pt-PT"), TimeSpanStyles.None, out horaInicio))
            {
                errosEventoStagging.Add(new ErroEventoStagging { campo = "horaInicio", descricao = "Hora de início de período Inválida", tipologiaId = tiposErro.Where(e => e.valor == "GENERICO").Single().valorSistemaId });
            }

            if (errosEventoStagging.Count > 0)
                throw new ErroEventoStaggingException { errosEventoStagging = errosEventoStagging };

            dataHoraInicio = dataInicio.Add(horaInicio);

            ApoliceRepository apolicesRepository = new ApoliceRepository();

            List<Apolice> apolicesProducao = apolicesRepository.All.Include("veiculo").Include("veiculo.categoria").Include("tomador")
                                                    .Include("concelho").Include("eventoHistorico").Where(e =>
                                                        e.veiculo.numeroMatricula == matricula
                                                        && e.entidadeId == seguradoraId
                                                        && e.dataInicio == dataHoraInicio).ToList();

            if (apolicesProducao == null || apolicesProducao.Count == 0)
            {
                return new EventoStagging { entidadeId = seguradoraId};
                //return new EventoStagging() - Construtor vazio nao tem base
            }

            if (apolicesProducao.Count > 1)
            {
                //Erro interno; Não deveria existir esta situação
            }

            return new EventoStagging(apolicesProducao.First(), estadosEvento.Where(e=>e.valor == "PENDENTE").Single().valorSistemaId);
            //return new EventoStagging(eventosProducao.First())
        }
        public static EventoStagging duplicarEventoStagging(string matricula, int seguradoraId, string dtInicio, string hInicio, string operacao, Mutex mutex = null)
        {
            ValorSistemaRepository valoresSistemaRepository = new ValorSistemaRepository();

            List<ValorSistema> tiposErro = valoresSistemaRepository.GetPorTipologia("TIPO_ERRO", mutex);

            List<ErroEventoStagging> errosEventoStagging = new List<ErroEventoStagging>();

            if (matricula == null || matricula == string.Empty)
            {
                errosEventoStagging.Add(new ErroEventoStagging { campo = "matricula", descricao = "Matrícula Inválida", tipologiaId = tiposErro.Where(e => e.valor == "GENERICO").Single().valorSistemaId });
            }
            if (dtInicio == null || dtInicio == string.Empty)
            {
                errosEventoStagging.Add(new ErroEventoStagging { campo = "dataInicio", descricao = "Data de início de período Inválida", tipologiaId = tiposErro.Where(e => e.valor == "GENERICO").Single().valorSistemaId });
            }
            if (hInicio == null || hInicio == string.Empty)
            {
                errosEventoStagging.Add(new ErroEventoStagging { campo = "horaInicio", descricao = "Hora de início de período Inválida", tipologiaId = tiposErro.Where(e => e.valor == "GENERICO").Single().valorSistemaId });
            }

            if (errosEventoStagging.Count > 0)
                throw new ErroEventoStaggingException { errosEventoStagging = errosEventoStagging};

            EventoStaggingRepository eventosStaggingRepository = new EventoStaggingRepository();

            List<EventoStagging> eventosStagging =  eventosStaggingRepository.All.Where(e => 
                                                    e.matricula == matricula 
                                                    && e.entidadeId == seguradoraId 
                                                    && e.dataInicioCobertura == dtInicio 
                                                    && e.horaInicioCobertura == hInicio 
                                                    && e.estadoEvento.valor == "ERRO"
                                                    && e.arquivado == false
                                                    && e.codigoOperacao == operacao).ToList();

            if (eventosStagging == null || eventosStagging.Count == 0)
            {
                return null;
                //return new EventoStagging() - Construtor vazio nao tem base
            }

            if (eventosStagging.Count > 1)
            {
                //Erro interno; Não deveria existir esta situação
            }

            return new EventoStagging(eventosStagging.First());
            //new EventoStagging(eventosStagging.First())
            //Adicionar Erros
        }
        private void timer_Tick(object source, ElapsedEventArgs e)
        {
            //eventLog.WriteEntry("FNMPAS Notification Agent Timer Tick"); 
            INotificacaoRepository notificacaoRepository = new NotificacaoRepository();
            IValorSistemaRepository valoresSistemaRepository = new ValorSistemaRepository();

            var smtpValues = valorSistemaRepository.All.Where(v => v.tipologia == "SMTP_SERVER" || v.tipologia == "SMTP_PORT" || v.tipologia == "SMTP_USER" || v.tipologia == "SMTP_PASSWORD").ToList();
            string smtpServer = smtpValues.Where(s => s.tipologia == "SMTP_SERVER").Single().valor;
            int smtpPort = int.Parse(smtpValues.Where(s => s.tipologia == "SMTP_PORT").Single().valor);
            string smtpUser = smtpValues.Where(s => s.tipologia == "SMTP_USER").Single().valor;
            string smtpPassword = smtpValues.Where(s => s.tipologia == "SMTP_PASSWORD").Single().valor;

            IQueryable<Notificacao> query = null;
            query = notificacaoRepository.All.Include("entidade").Where(n => n.email == true && n.enviadaEmail == false && n.dataEnvioEmail == null).OrderBy(notif => notif.dataCriacao);

            foreach (Notificacao notif in query.ToList())
            {
                
                try
                {
                    bool result = enviaNotificacao(notif, smtpServer, smtpPort, smtpUser, smtpPassword);

                    if (result)
                    {
                        notif.enviadaEmail = true;
                        notif.dataEnvioEmail = DateTime.Now;
                    }

                    notificacaoRepository.Save();
                }
                catch (ErroNotificacaoException ex)
                {
                    notif.enviadaEmail = true;
                    notificacaoRepository.Save();
                    continue;
                }
                catch (Exception ex)
                {
                    notificacaoRepository.Save();
                    continue;
                }
            }
        }
        private void timer_Tick(object source, ElapsedEventArgs e)
        {
            //eventLog.WriteEntry("FNMPAS File Agent Timer Tick"); 
            FicheiroIsentosRepository ficheiroIsentosRepository = new FicheiroIsentosRepository();
            ValorSistemaRepository valoresSistemaRepository = new ValorSistemaRepository();

            List<ValorSistema> estadosFicheiro = valoresSistemaRepository.GetPorTipologia("ESTADO_FICHEIRO");

            IQueryable<FicheiroIsentos> query = null;
            query = ficheiroIsentosRepository.All.Where(f => f.estado.valor == "PENDENTE").OrderBy(file => file.dataAlteracao);

            foreach (FicheiroIsentos file in query.ToList())
            {
                //file.estadoId = estadosFicheiro.Where(ef => ef.valor == "EM_PROCESSAMENTO").Single().valorSistemaId;
                
                List<ErroFicheiro> errosFicheiro = new List<ErroFicheiro>();
                try
                {
                    file.validar();
                    ProcessadorFicheiros.processaFicheiroIsentos(file);
                    //file.totalRegistos = file.Count();
                }
                catch (ErroFicheiroException ex)
                {
                    //file.errosFicheiro = ex.errosFicheiro;
                    //file.estadoId = estadosFicheiro.Where(ef => ef.valor == "ERRO").Single().valorSistemaId;
                    //ficheiroRepository.Save();
                    continue;
                }
                catch (Exception ex)
                {

                }

                ficheiroIsentosRepository.InsertOrUpdate(file);
                ficheiroIsentosRepository.Save();
            }


        }
        public static void processaFicheiroIsentos(FicheiroIsentos ficheiro)
        {
            //FicheiroIsentosRepository ficheirosIsentosRepository = new FicheiroIsentosRepository();
            ValorSistemaRepository valoresSistemaRepository = new ValorSistemaRepository();
            ApoliceIsentoRepository apolicesIsentoRepository = new ApoliceIsentoRepository();
            NotificacaoRepository notificacoesRepository = new NotificacaoRepository();
            
            //List<ValorSistema> valoresSistema = valoresSistemaRepository.All.Where(v => v.tipologia == "TIPO_AVISO" || v.tipologia == "ESTADO_FICHEIRO").ToList();
            //ValorSistema tipoNotificacao = valoresSistema.Where(v => v.tipologia == "TIPO_AVISO" && v.valor == "GENERICO").Single();
            //ValorSistema valErroFicheiro = valoresSistema.Where(v => v.tipologia == "ESTADO_FICHEIRO" && v.valor == "ERRO").Single();
            //ValorSistema valProcessadoFicheiro = valoresSistema.Where(v => v.tipologia == "ESTADO_FICHEIRO" && v.valor == "PROCESSADO").Single();

            ValorSistema tipoNotificacao = valoresSistemaRepository.GetPorTipologia("TIPO_AVISO").Where(v => v.valor == "GENERICO").Single();
            ValorSistema valErroFicheiro = valoresSistemaRepository.GetPorTipologia("ESTADO_FICHEIRO").Where(v => v.valor == "ERRO").Single();
            ValorSistema valProcessadoFicheiro = valoresSistemaRepository.GetPorTipologia("ESTADO_FICHEIRO").Where(v => v.valor == "PROCESSADO").Single();

            //Insere os novos registos de períodos isentos que são reportados no ficheiro
            bool erroFicheiro = false;
            DateTime dataRegisto = DateTime.Now;
            DateTime dataInicioTemp;
            DateTime? dataFimTemp;
            DateTime dataAux;
            var excel = new ExcelQueryFactory(ficheiro.localizacao);
            excel.AddMapping<RegistoExcelMatriculaIsenta>(x => x.matricula, "MATRICULA"); // ou excel.AddMapping("matricula", "MATRICULA");
            excel.AddMapping<RegistoExcelMatriculaIsenta>(x => x.mensagem, "MENSAGEM");
            excel.AddMapping<RegistoExcelMatriculaIsenta>(x => x.entidadeResponsavel, "ENTIDADE");
            excel.AddMapping<RegistoExcelMatriculaIsenta>(x => x.dataInicio, "DATA_INICIO");
            excel.AddMapping<RegistoExcelMatriculaIsenta>(x => x.dataFim, "DATA_FIM");
            excel.AddMapping<RegistoExcelMatriculaIsenta>(x => x.confidencial, "CONFIDENCIAL"); 
            
            var matriculasIsentas = from m in excel.Worksheet<RegistoExcelMatriculaIsenta>("Resultados")
                                   select m;
            
            foreach (RegistoExcelMatriculaIsenta mat in matriculasIsentas)
            {
                if (mat.matricula == null || mat.matricula == string.Empty || ! DateTime.TryParseExact(mat.dataInicio, "yyyyMMdd", new CultureInfo("pt-PT"), DateTimeStyles.None, out dataInicioTemp))
                {
                    erroFicheiro = true;
                    break;
                }
                
                if (DateTime.TryParseExact(mat.dataFim, "yyyyMMdd", new CultureInfo("pt-PT"), DateTimeStyles.None, out dataAux))
                    dataFimTemp = dataAux;
                else
                    dataFimTemp = null;

                ApoliceIsento isento = new ApoliceIsento()
                {
                    entidadeId = ficheiro.entidadeId.Value,
                    matricula = mat.matricula,
                    matriculaCorrigida = mat.matricula.Replace("-",""),
                    entidadeResponsavel = mat.entidadeResponsavel,
                    mensagem = mat.mensagem,
                    dataInicio = dataInicioTemp,
                    dataFim = dataFimTemp,
                    confidencial = mat.confidencial,
                    origemFicheiro = true,
                    arquivo = false,
                    dataReporte = ficheiro.dataUpload,
                    dataCriacao = dataRegisto,
                    dataModificacao = dataRegisto,
                };

                ficheiro.apolicesIsentos.Add(isento);
            }

            Notificacao notif = new Notificacao();
            if (!erroFicheiro)
            {

                //Coloca para arquivo todos os registos de períodos isentos que foram inseridos via ficheiro.
                List<ApoliceIsento> periodosAtivos = apolicesIsentoRepository.All.Where(m => m.arquivo == false && m.origemFicheiro == true && m.dataCriacao < dataRegisto).ToList();
                if (periodosAtivos != null && periodosAtivos.Count > 0)
                {
                    foreach(ApoliceIsento isento in periodosAtivos)
                    {
                        isento.arquivo = true;
                        apolicesIsentoRepository.InsertOrUpdate(isento);
                    }
                }

                apolicesIsentoRepository.Save();

                string mensagemNotificacao = string.Format("O ficheiro de reporte e matriculas isentas de seguro com o nome {0} e submetido na data {1}, " +
                                                            "foi processado com sucesso sendo registados {2} matriculas.",
                                                            ficheiro.nomeFicheiro, 
                                                            ficheiro.dataUpload.ToString(),
                                                            ficheiro.apolicesIsentos.Count);

                notif.dataCriacao = DateTime.Now;
                notif.email = false;
                notif.entidadeId = ficheiro.entidadeId;
                notif.mensagem = mensagemNotificacao;
                notif.tipologiaId = tipoNotificacao.valorSistemaId;
                ficheiro.estadoId = valProcessadoFicheiro.valorSistemaId;
            }
            else
            {
                string mensagemNotificacao = string.Format("O ficheiro de reporte e matriculas isentas de seguro com o nome {0} e submetido na data {1}, " +
                                                            "não foi processado devido a um erro da informação relativa ao número de matrícula ou à data de início do período.",
                                                            ficheiro.nomeFicheiro, ficheiro.dataUpload.ToString());
                
                notif.dataCriacao = DateTime.Now;
                notif.email = false;
                notif.entidadeId = ficheiro.entidadeId;
                notif.mensagem = mensagemNotificacao;
                notif.tipologiaId = tipoNotificacao.valorSistemaId;
                               
                ficheiro.estadoId = valErroFicheiro.valorSistemaId;
            }

            notificacoesRepository.InsertOrUpdate(notif);
            notificacoesRepository.Save();
            //ficheirosIsentosRepository.InsertOrUpdate(ficheiro);
            //ficheirosIsentosRepository.Save();
        }
        public static void processaFicheiro(Ficheiro ficheiro){

            ValorSistemaRepository valoresSistemaRepository = new ValorSistemaRepository();

            //List<ValorSistema> valSistema = valoresSistemaRepository.All.Where(v => v.tipologia == "ESTADO_EVENTO_STAGGING" || v.tipologia == "OPERACAO_EVENTO").ToList();

            //List<ValorSistema> estadosEvento = valSistema.Where(v => v.tipologia == "ESTADO_EVENTO_STAGGING").ToList();
            //List<ValorSistema> operacoesEvento = valSistema.Where(v => v.tipologia == "OPERACAO_EVENTO").ToList();

            List<ValorSistema> estadosEvento = valoresSistemaRepository.GetPorTipologia("ESTADO_EVENTO_STAGGING");
            List<ValorSistema> operacoesEvento = valoresSistemaRepository.GetPorTipologia("OPERACAO_EVENTO");
            List<ValorSistema> tiposErro = valoresSistemaRepository.GetPorTipologia("TIPO_ERRO");
            List<ValorSistema> estadosFicheiro = valoresSistemaRepository.GetPorTipologia("ESTADO_FICHEIRO");

            ReporteOcorrenciasMatricula reporte;

            XmlSerializer serializer = new XmlSerializer(typeof(ReporteOcorrenciasMatricula));
            using (FileStream fileStream = new FileStream(ficheiro.localizacao, FileMode.Open))
            {
                reporte = (ReporteOcorrenciasMatricula)serializer.Deserialize(fileStream);
            }

            if (reporte.Cabecalho.CodigoEstatistico != ficheiro.entidade.codigoEntidade)
            {
                ErroFicheiro erroFicheiro = new ErroFicheiro(){ dataValidacao = DateTime.Now, 
                                                                tipologiaId = tiposErro.Single(e => e.valor == "GENERICO").valorSistemaId,
                                                                descricao = "Ficheiro reportado pela entidade com código '" + ficheiro.entidade.codigoEntidade + "' e com registos relativos à entidade '" + reporte.Cabecalho.CodigoEstatistico + "'.",
                                                                ficheiroId = ficheiro.ficheiroId };

                ErroFicheiroException ex = new ErroFicheiroException();
                ex.errosFicheiro.Add(erroFicheiro);

                throw ex;
            }

            ReporteOcorrenciasFNMPAS reporteOcorrenciasFNMPAS = new ReporteOcorrenciasFNMPAS(reporte);
            reporteOcorrenciasFNMPAS.ordenaOcorrencias();
           

            for (int i = 0; i < reporteOcorrenciasFNMPAS.OcorrenciaOrdenada.Count(); i++)
            {
                ReporteOcorrenciasMatriculaOcorrenciaOrdenada ocorrencia = reporteOcorrenciasFNMPAS.OcorrenciaOrdenada[i];

                //evento Duplicado e esmagado com os novos dados. (C M - stagging/producao) (A - producao/stagging) 
                //Não foi ainda inserido na Base de dados nem houve delete logico do anterior. 
                //Fazer deletes logicos, e inserções após verificações.
                //Anulações podem necessitar logica adicional caso a validação falhe. (duplicar registo em stagging)
                EventoStagging evento = new EventoStagging();
                
                int codigoOperacaoId = 0;
                switch (ocorrencia.CodigoOperacao)
                {
                    case ReporteOcorrenciasMatriculaOcorrenciaCodigoOperacao.C: codigoOperacaoId = operacoesEvento.Where(o=> o.valor =="C").Single().valorSistemaId; break;
                    case ReporteOcorrenciasMatriculaOcorrenciaCodigoOperacao.M: codigoOperacaoId = operacoesEvento.Where(o=> o.valor =="M").Single().valorSistemaId; break;
                    case ReporteOcorrenciasMatriculaOcorrenciaCodigoOperacao.A: codigoOperacaoId = operacoesEvento.Where(o=> o.valor =="A").Single().valorSistemaId; break;
                    default: codigoOperacaoId = operacoesEvento.Where(o => o.valor == "C").Single().valorSistemaId; break;
                }
                evento.esmagaDados(ocorrencia, ficheiro, codigoOperacaoId);

                evento.estadoEventoId = estadosEvento.Where(e => e.valor == "PENDENTE").Single().valorSistemaId;

                ficheiro.eventosStagging.Add(evento);
            }

            //EventoStaggingRepository eventosStaggingRepository = new EventoStaggingRepository();
            //eventosStaggingRepository.InsertOrUpdate(evento);
            //eventosStaggingRepository.Save();
        }
        public static bool validarNegocio(EventoStagging eventoStagging, Mutex mutex = null)
        {
            ApoliceRepository apolicesRepository = new ApoliceRepository();
            ValorSistemaRepository valoresSistemaRepository = new ValorSistemaRepository();

            List<ValorSistema> tiposErro = valoresSistemaRepository.GetPorTipologia("TIPO_ERRO", mutex);
            List<ValorSistema> tiposAviso = valoresSistemaRepository.GetPorTipologia("TIPO_AVISO", mutex);

            int tipoErroGenerico = tiposErro.Where(e => e.valor == "GENERICO").Single().valorSistemaId;
            int tipoAvisoGenerico = tiposAviso.Where(e => e.valor == "GENERICO").Single().valorSistemaId;

            List<Apolice> listaApolices;

            DateTime dataInicio;
            DateTime dataFim;

            TimeSpan horaInicio;
            TimeSpan horaFim;

            DateTime.TryParseExact(eventoStagging.dataInicioCobertura, "yyyyMMdd", new CultureInfo("pt-PT"), DateTimeStyles.None, out dataInicio);
            DateTime.TryParseExact(eventoStagging.dataFimCobertura, "yyyyMMdd", new CultureInfo("pt-PT"), DateTimeStyles.None, out dataFim);
            TimeSpan.TryParseExact(eventoStagging.horaInicioCobertura, "hhmmss", new CultureInfo("pt-PT"), TimeSpanStyles.None, out horaInicio);
            TimeSpan.TryParseExact(eventoStagging.horaFimCobertura, "hhmmss", new CultureInfo("pt-PT"), TimeSpanStyles.None, out horaFim);

            dataInicio = dataInicio.Add(horaInicio);
            dataFim = dataFim.Add(horaFim);

            listaApolices = apolicesRepository.All.Include("veiculo").Where(a => a.dataInicio == dataInicio &&
                                 a.entidadeId == eventoStagging.entidadeId && a.veiculo.numeroMatricula == eventoStagging.matricula).ToList();

            //ERROS
            //Criação para uma chave de registo já existente. - check
            if (listaApolices != null && listaApolices.Count > 0 && eventoStagging.codigoOperacao == "C")
            {
                eventoStagging.errosEventoStagging.Add(new ErroEventoStagging
                {
                    campo = "Chave",
                    descricao = "O registo de cobertura já existe. Não é possível efectuar nova criação.", 
                    tipologiaId = tipoErroGenerico , eventoStagging = eventoStagging });
            }

            //Data Fim (data + hora) menor ou igual que data de início. - check
            if(dataFim <= dataInicio){
                eventoStagging.errosEventoStagging.Add(new ErroEventoStagging
                {
                    campo = "DataFim",
                    descricao = "A data/hora de fim da cobertura tem de ser posterior à data/hora de início de cobertura.",
                    tipologiaId = tipoErroGenerico,
                    eventoStagging = eventoStagging
                });
            }

            //Datas de início inferiores a 01-01-1900. - check
            if (dataInicio < new DateTime(1900, 01, 01))
            {
                eventoStagging.errosEventoStagging.Add(new ErroEventoStagging
                {
                    campo = "DataInício",
                    descricao = "A data de início da cobertura tem de ser posterior à data de 01-01-1900.",
                    tipologiaId = tipoErroGenerico,
                    eventoStagging = eventoStagging
                });
            }

            //Modificação e Anulação para uma chave de registo não existente - check
            if ((eventoStagging.codigoOperacao == "A" || eventoStagging.codigoOperacao == "M")
                && listaApolices.Count == 0)
            {
                eventoStagging.errosEventoStagging.Add(new ErroEventoStagging
                {
                    campo = "Chave",
                    descricao = "O registo de cobertura não existe. Não é possível efectuar modificações ou anulações.",
                    tipologiaId = tipoErroGenerico,
                    eventoStagging = eventoStagging
                });
            }

            //Modificações com alteração de data/hora Fim. - check
            if (listaApolices.Count > 0)
            {
                if (eventoStagging.codigoOperacao == "M" &&
                    dataFim != listaApolices.First().dataFim)
                {
                    eventoStagging.errosEventoStagging.Add(new ErroEventoStagging
                    {
                        campo = "DataFim",
                        descricao = "Operações de modificação não podem alterar a data/hora de fim de cobertura.",
                        tipologiaId = tipoErroGenerico,
                        eventoStagging = eventoStagging
                    });
                }
            }

            //Anulação para uma data posterior à data fim planeada. - check
            if (listaApolices.Count > 0)
            {
                if (eventoStagging.codigoOperacao == "A" &&
                    dataFim > listaApolices.First().dataFimPlaneada)
                {
                    eventoStagging.errosEventoStagging.Add(new ErroEventoStagging
                    {
                        campo = "DataFim",
                        descricao = "Anulação não pode alterar a data/hora de fim de cobertura para data posterior à planeada na criação.",
                        tipologiaId = tipoErroGenerico,
                        eventoStagging = eventoStagging
                    });
                }
            }


            //AVISOS
            //Caso a matricula já se encontre associada a outra seguradora que se intercepte o periodo a reportar. - check
            //registos que originem mais que um seguro válido (inter ou intra seguradoras)
            if(eventoStagging.codigoOperacao == "C"){
                listaApolices = apolicesRepository.All.Include("veiculo").Where(a => a.veiculo.numeroMatricula == eventoStagging.matricula).ToList();
                List<Apolice> apolicesCruzadas = new List<Apolice>();

                foreach (Apolice ap in listaApolices)
                {
                    if ((dataInicio >= ap.dataInicio && dataInicio <= ap.dataFim) ||
                        (dataFim >= ap.dataInicio && dataFim <= ap.dataFim) ||
                        (dataInicio <= ap.dataInicio && dataFim >= ap.dataFim))
                    {
                        if (!(dataInicio == ap.dataInicio && eventoStagging.entidadeId == ap.entidadeId && eventoStagging.matricula == ap.veiculo.numeroMatricula))
                        {
                            apolicesCruzadas.Add(ap);
                        }
                    }
                }

                if (apolicesCruzadas.Count > 0)
                {
                    eventoStagging.avisosEventoStagging.Add(new Aviso
                    {
                        campo = "Matricula",
                        descricao = "O periodo de cobertura apresenta registos cruzados.",
                        tipologiaId = tipoAvisoGenerico,
                        eventoStagging = eventoStagging
                    });
                }
            }

            if (eventoStagging.errosEventoStagging.Count > 0)
            {
                return false;
            }

            return true;
        }
        public static bool validarCampos(EventoStagging eventoStagging, Mutex mutex = null)
        {
            ValorSistemaRepository valoresSistemaRepository = new ValorSistemaRepository();
            CategoriaRepository categoriasRepository = new CategoriaRepository();
            ConcelhoRepository concelhosRepository = new ConcelhoRepository();

            List<ValorSistema> tiposErro = valoresSistemaRepository.GetPorTipologia("TIPO_ERRO", mutex);
            List<ValorSistema> tiposAviso = valoresSistemaRepository.GetPorTipologia("TIPO_AVISO", mutex);

            int tipoErroGenerico = tiposErro.Where(e => e.valor == "GENERICO").Single().valorSistemaId;
            int tipoAvisoGenerico = tiposAviso.Where(e => e.valor == "GENERICO").Single().valorSistemaId;

            DateTime aux;
            int intAux;

            //ERROS
            //tem Operação válida
            if (eventoStagging.codigoOperacao == null)
            {
                eventoStagging.errosEventoStagging.Add(new ErroEventoStagging { campo = "CodigoOperacao",
                    descricao = "Código de operação '" + eventoStagging.codigoOperacao + "' inválido.",
                                                                                tipologiaId = tipoErroGenerico,
                                                                                eventoStagging = eventoStagging
                });
            }
            //tem matrícula válida - check
            if (eventoStagging.matricula == null || !Regex.Match(eventoStagging.matricula, "[-\\/?#() A-Za-z0-9]+").Success)
            {
                eventoStagging.errosEventoStagging.Add(new ErroEventoStagging { campo = "NumeroMatricula",
                    descricao = "Número de matrícula '" + eventoStagging.matricula + "' inválido.",
                                                                                tipologiaId = tipoErroGenerico,
                                                                                eventoStagging = eventoStagging
                });
            }
            //tem data inicio válida - check
           
            if (eventoStagging.dataInicioCobertura == null || eventoStagging.dataInicioCobertura == string.Empty || !DateTime.TryParseExact(eventoStagging.dataInicioCobertura, "yyyyMMdd", new CultureInfo("pt-PT"), DateTimeStyles.None, out aux))
            {
                eventoStagging.errosEventoStagging.Add(new ErroEventoStagging { campo = "DataInicio",
                    descricao = "Data de início do período de cobertura '" + eventoStagging.dataInicioCobertura + "' inválida.",
                                                                                tipologiaId = tipoErroGenerico,
                                                                                eventoStagging = eventoStagging
                });
            }
            //tem data fim válida - check
            if (eventoStagging.dataFimCobertura == null || eventoStagging.dataFimCobertura == string.Empty || !DateTime.TryParseExact(eventoStagging.dataFimCobertura, "yyyyMMdd", new CultureInfo("pt-PT"), DateTimeStyles.None, out aux))
            {
                eventoStagging.errosEventoStagging.Add(new ErroEventoStagging { campo = "DataFim",
                    descricao = "Data de fim do período de cobertura '" + eventoStagging.dataInicioCobertura + "' inválida.",
                                                                                tipologiaId = tipoErroGenerico,
                                                                                eventoStagging = eventoStagging
                });
            }
            //sem numero de apolice e sem certificado provisório - check
            if (eventoStagging.nrApolice == null || eventoStagging.nrApolice == string.Empty)
            {
                if (eventoStagging.nrCertificadoProvisorio == null || eventoStagging.nrCertificadoProvisorio == string.Empty)
                {
                    eventoStagging.errosEventoStagging.Add(new ErroEventoStagging { campo = "NumeroApolice",
                        descricao = "Número de apólice ou Número de certificado provisório em falta.",
                                                                                    tipologiaId = tipoErroGenerico,
                                                                                    eventoStagging = eventoStagging
                    });
                }
            }

            //AVISOS
            //tem marca - check
            if (eventoStagging.marca == null || eventoStagging.marca == string.Empty)
            {
                eventoStagging.avisosEventoStagging.Add(new Aviso { campo = "MarcaVeiculo",
                    descricao = "Marca de veiculo '"+eventoStagging.marca+"' inválida.",
                                                                    tipologiaId = tipoAvisoGenerico,
                                                                    eventoStagging = eventoStagging
                });
            }
            //tem modelo - check
            if (eventoStagging.modelo == null || eventoStagging.modelo == string.Empty)
            {
                eventoStagging.avisosEventoStagging.Add(new Aviso { campo = "ModeloVeiculo",
                    descricao = "Modelo de veiculo '"+eventoStagging.modelo+"' inválido.",
                                                                    tipologiaId = tipoAvisoGenerico,
                                                                    eventoStagging = eventoStagging
                });
            }
            //tem ano construção válido - check
            if (eventoStagging.anoConstrucao == null || eventoStagging.anoConstrucao == string.Empty || !int.TryParse(eventoStagging.anoConstrucao, out intAux) /*|| intAux < 0 || intAux > (DateTime.Now.Year+2)*/)
            {
                eventoStagging.avisosEventoStagging.Add(new Aviso { campo = "AnoConstrucaoVeiculo",
                    descricao = "Ano de construção do veiculo '"+eventoStagging.anoConstrucao+"' inválido.",
                                                                    tipologiaId = tipoAvisoGenerico,
                                                                    eventoStagging = eventoStagging
                });
            }
            //tem categoria válida - check
            if (eventoStagging.codigoCategoriaVeiculo == null || eventoStagging.codigoCategoriaVeiculo == string.Empty)
            {
                //TODO: verificar se a categoria existe. Forçar para categoria desconhecida caso não exista.
                eventoStagging.avisosEventoStagging.Add(new Aviso
                {
                    campo = "CódigoCategoriaVeiculo",
                    descricao = "Código de categoria do veiculo '" + eventoStagging.codigoCategoriaVeiculo + "' inválido.",
                    tipologiaId = tipoAvisoGenerico,
                    eventoStagging = eventoStagging
                });
            }
            else
            {
                List<Categoria> queryCategoria = categoriasRepository.All.Where(c => c.codigoCategoriaVeiculo == eventoStagging.codigoCategoriaVeiculo).ToList();
                if (queryCategoria.Count == 0)
                {
                    //TODO: verificar se a categoria existe. Forçar para categoria desconhecida caso não exista.
                    eventoStagging.avisosEventoStagging.Add(new Aviso
                    {
                        campo = "CódigoCategoriaVeiculo",
                        descricao = "Código de categoria do veiculo '" + eventoStagging.codigoCategoriaVeiculo + "' inválido.",
                        tipologiaId = tipoAvisoGenerico,
                        eventoStagging = eventoStagging
                    });
                }
            }
            //tem concelho de circulação habitual válido - check
            if (eventoStagging.codigoConcelhoCirculacao == null || eventoStagging.codigoConcelhoCirculacao == string.Empty)
            {
                //TODO: verificar se o concelho existe. Forçar para concelho desconhecido caso não exista.
                eventoStagging.avisosEventoStagging.Add(new Aviso { campo = "ConcelhoCirculacao",
                    descricao = "Concelho de circulação '"+eventoStagging.codigoConcelhoCirculacao+"' inválido.",
                                                                    tipologiaId = tipoAvisoGenerico,
                                                                    eventoStagging = eventoStagging
                });
            }
            else
            {
                List<Concelho> queryCategoria = concelhosRepository.All.Where(c => c.codigoConcelho == eventoStagging.codigoConcelhoCirculacao).ToList();
                if (queryCategoria.Count == 0)
                {
                    //TODO: verificar se a categoria existe. Forçar para categoria desconhecida caso não exista.
                    eventoStagging.avisosEventoStagging.Add(new Aviso
                    {
                        campo = "ConcelhoCirculacao",
                        descricao = "Concelho de circulação '" + eventoStagging.codigoConcelhoCirculacao + "' inválido.",
                        tipologiaId = tipoAvisoGenerico,
                        eventoStagging = eventoStagging
                    });
                }
            }
            //tem nome de tomador de seguro - check
            if (eventoStagging.nomeTomadorSeguro == null || eventoStagging.nomeTomadorSeguro == string.Empty)
            {
                eventoStagging.avisosEventoStagging.Add(new Aviso { campo = "NomeTomador",
                    descricao = "Nome de tomador de seguro '"+eventoStagging.nomeTomadorSeguro+"' inválido.",
                                                                    tipologiaId = tipoAvisoGenerico,
                                                                    eventoStagging = eventoStagging
                });
            }
            //tem morada de tomador de seguro - check
            if (eventoStagging.moradaTomadorSeguro == null || eventoStagging.moradaTomadorSeguro == string.Empty)
            {
                eventoStagging.avisosEventoStagging.Add(new Aviso { campo = "MoradaTomador",
                    descricao = "Morada do tomador de seguro '"+eventoStagging.moradaTomadorSeguro+"' inválida.",
                                                                    tipologiaId = tipoAvisoGenerico,
                                                                    eventoStagging = eventoStagging
                });
            }
            //TODO: talvez remover visto não estar na lista de validações
            //tem codigo postal válido do tomador de seguro
            if (eventoStagging.codigoPostalTomador == null || eventoStagging.codigoPostalTomador == string.Empty)
            {
                //TODO: verificar se o código postal existe.
                eventoStagging.avisosEventoStagging.Add(new Aviso { campo = "CodigoPostalTomador",
                    descricao = "Código postal do tomador de seguro '" + eventoStagging.codigoPostalTomador + "' inválido.",
                                                                    tipologiaId = tipoAvisoGenerico,
                                                                    eventoStagging = eventoStagging
                });
            }
            //Tem NIF válido do tomador do seguro - check
            if (eventoStagging.nifTomadorSeguro == null || eventoStagging.nifTomadorSeguro == string.Empty || !ValidacaoEventos.NifValido(eventoStagging.nifTomadorSeguro))
            {
                eventoStagging.avisosEventoStagging.Add(new Aviso { campo = "NifTomador",
                    descricao = "Nif do tomador de seguro '"+eventoStagging.nifTomadorSeguro+"' inválido.",
                                                                    tipologiaId = tipoAvisoGenerico,
                                                                    eventoStagging = eventoStagging
                });
            }
            //Tem número de identificação do tomador de seguro - check
            if (eventoStagging.nrIdentificacaoTomadorSeguro == null || eventoStagging.nrIdentificacaoTomadorSeguro == string.Empty)
            {
                eventoStagging.avisosEventoStagging.Add(new Aviso { campo = "NumeroIdentificacaoTomador",
                    descricao = "Número de identificação do tomador de seguro '"+eventoStagging.nrIdentificacaoTomadorSeguro+"' inválido.",
                                                                    tipologiaId = tipoAvisoGenerico,
                                                                    eventoStagging = eventoStagging
                });
            }

            if (eventoStagging.errosEventoStagging.Count > 0)
            {
                return false;
            }

            return true;
        }
        private void timer_Tick(object source, ElapsedEventArgs e)
        {
            //eventLog.WriteEntry("FNMPAS File Agent Timer Tick"); 
            FicheiroRepository ficheiroRepository = new FicheiroRepository();
            NotificacaoRepository notificacaoRepository = new NotificacaoRepository();
            ValorSistemaRepository valoresSistemaRepository = new ValorSistemaRepository();
            UserProfileRepository userProfileRepository = new UserProfileRepository();

            List<ValorSistema> estadosFicheiro = valoresSistemaRepository.GetPorTipologia("ESTADO_FICHEIRO");
            List<ValorSistema> tiposNotificacao = valoresSistemaRepository.GetPorTipologia("TIPO_NOTIFICACAO");

            IQueryable<Ficheiro> query = null;
            query = ficheiroRepository.All.Include("entidade").Where(f => f.estado.valor == "PENDENTE").OrderBy(file => file.dataAlteracao);

            foreach (Ficheiro file in query.ToList())
            {
                file.estadoId = estadosFicheiro.Where(ef => ef.valor == "EM_PROCESSAMENTO").Single().valorSistemaId;

                //List<ErroFicheiro> errosFicheiro = new List<ErroFicheiro>();
                try
                {
                    file.validar();
                    ProcessadorFicheiros.processaFicheiro(file);
                    file.totalRegistos = file.eventosStagging.Count();
                }
                catch (ErroFicheiroException ex)
                {
                    file.errosFicheiro = ex.errosFicheiro;
                    file.estadoId = estadosFicheiro.Single(ef => ef.valor == "ERRO").valorSistemaId;

                    string mensagemNotificacao = "O 'Ficheiro Nacional de Matrículas do Parque Automóvel Seguro' com nome '" + file.nomeFicheiro + "' e data de reporte '" +
                                file.dataUpload.ToShortDateString() + "' foi processado com erro: \n";

                    foreach (ErroFicheiro erro in ex.errosFicheiro)
                    {
                        mensagemNotificacao += erro.descricao;
                    }

                    Notificacao notif = new Notificacao(){ dataCriacao = DateTime.Now,
                                                        email = true,
                                                        entidadeId = file.entidadeId,
                                                        mensagem = mensagemNotificacao,
                                                        tipologiaId = tiposNotificacao.Single(n => n.valor == "ERRO_PROCESSAMENTO_FICHEIRO").valorSistemaId};
                    
                    notificacaoRepository.InsertOrUpdate(notif);

                    UserProfile utilizadorFicheiro = userProfileRepository.All.Single(u => u.UserName == file.userName);
                    if (utilizadorFicheiro.entidadeId != file.entidadeId)
                    {
                        Notificacao notif2 = new Notificacao()
                        {
                            dataCriacao = DateTime.Now,
                            email = true,
                            entidadeId = utilizadorFicheiro.entidadeId,
                            mensagem = mensagemNotificacao,
                            tipologiaId = tiposNotificacao.Single(n => n.valor == "ERRO_PROCESSAMENTO_FICHEIRO").valorSistemaId
                        };

                        notificacaoRepository.InsertOrUpdate(notif2);
                    }


                }
                catch (Exception ex)
                {

                }

                ficheiroRepository.InsertOrUpdate(file);
                ficheiroRepository.Save();
                notificacaoRepository.Save();
            }

            
        }
        public static EventoStagging criarEventoStagging(EventoStagging eventoPendente, Mutex mutex = null)
        {
            ValorSistemaRepository valoresSistemaRepository = new ValorSistemaRepository();
            List<ValorSistema> tiposErro = valoresSistemaRepository.GetPorTipologia("TIPO_ERRO", mutex);

            EventoStagging novoEvento = null;

            if (eventoPendente.codigoOperacao == null)
            {
                throw new ErroEventoStaggingException { errosEventoStagging = new List<ErroEventoStagging> { new ErroEventoStagging { campo = "CodigoOperacao", descricao = "Código de Operação Inválido", tipologiaId = tiposErro.Where(e => e.valor == "GENERICO").Single().valorSistemaId } } };
            }

            try
            {              
                novoEvento = EventoStaggingFactory.duplicarEventoStagging(eventoPendente.matricula, (int)eventoPendente.entidadeId, eventoPendente.dataInicioCobertura, eventoPendente.horaInicioCobertura, eventoPendente.codigoOperacao, mutex);

                //Caso não exista registo em stagging duplica-se o Registo em Producao               
                //novoEvento = EventoStaggingFactory.duplicarEventoProducao(eventoPendente.matricula, (int)eventoPendente.entidadeId, eventoPendente.dataInicioCobertura, eventoPendente.horaInicioCobertura);
                
                //Caso este também não exista, trata-se de uma nova ocorrência.
                //Poderiamos concluir que se não é uma criação é um erro, mas validemos isto juntamente com as validações de negócio.
                if (novoEvento == null)
                {
                    novoEvento = new EventoStagging();

                    if (eventoPendente.ficheiroID != null)
                    {
                        novoEvento.dataReporte = eventoPendente.ficheiro.dataAlteracao;
                        novoEvento.dataUltimaAlteracaoErro = eventoPendente.ficheiro.dataAlteracao;
                    }
                }
            }
            catch (ErroEventoStaggingException erros)
            {
                novoEvento = new EventoStagging();
                if (eventoPendente.ficheiroID != null)
                {
                    novoEvento.dataReporte = eventoPendente.ficheiro.dataAlteracao;
                    novoEvento.dataUltimaAlteracaoErro = eventoPendente.ficheiro.dataAlteracao;
                }
                
                foreach (ErroEventoStagging erro in erros.errosEventoStagging)
                {
                    erro.eventoStagging = novoEvento;
                    novoEvento.errosEventoStagging.Add(erro);
                }
            }

            novoEvento.esmagaDados(eventoPendente);

            return novoEvento;
        }
        public void Worker()
        {
            EventoStaggingRepository eventosStaggingRepository = new EventoStaggingRepository();
            ConcelhoRepository concelhosRepository = new ConcelhoRepository();
            CategoriaRepository categoriasRepository = new CategoriaRepository();
            ApoliceRepository apolicesRepository = new ApoliceRepository();
            AvisoRepository avisosRepository = new AvisoRepository();
            ApoliceHistoricoRepository apolicesHistoricoRepository = new ApoliceHistoricoRepository();
            EntidadeRepository entidadesRepository = new EntidadeRepository();
            NotificacaoRepository notificacoesRepository = new NotificacaoRepository();
            ValorSistemaRepository valoresSistemaRepository = new ValorSistemaRepository();
            UserProfileRepository userProfileRepository = new UserProfileRepository();

            List<ValorSistema> estadosEvento = valoresSistemaRepository.GetPorTipologia("ESTADO_EVENTO_STAGGING", cacheMutex);
            List<ValorSistema> estadosFicheiro = valoresSistemaRepository.GetPorTipologia("ESTADO_FICHEIRO", cacheMutex);
            List<ValorSistema> tipoNotificacao = valoresSistemaRepository.GetPorTipologia("TIPO_NOTIFICACAO", cacheMutex);
            List<ValorSistema> operacoesEvento = valoresSistemaRepository.GetPorTipologia("OPERACAO_EVENTO", cacheMutex);
            List<Concelho> listaConcelhos = concelhosRepository.All.ToList();
            List<Categoria> listaCategorias = categoriasRepository.All.ToList();


            int horaLimiteSLA = int.Parse(valoresSistemaRepository.GetPorTipologia("PARAM_HORA_LIMITE_SLA", cacheMutex).Single().valor);
            int horaExtensaoSLA = int.Parse(valoresSistemaRepository.GetPorTipologia("PARAM_HORA_EXTENSAO_SLA", cacheMutex).Single().valor);

            int estadoEmProcessamento = estadosEvento.Where(e => e.valor == "EM_PROCESSAMENTO").Single().valorSistemaId;
            int estadoPendente = estadosEvento.Where(e => e.valor == "PENDENTE").Single().valorSistemaId;
            int estadoErro = estadosEvento.Where(e => e.valor == "ERRO").Single().valorSistemaId;
            int estadoProcessado = estadosEvento.Where(e => e.valor == "PROCESSADO").Single().valorSistemaId;
            int estadoFicheiroProcessado = estadosFicheiro.Where(e => e.valor == "PROCESSADO").Single().valorSistemaId;

            EventoStagging eventoPendente = null;
            int eventoPendenteId = default(int);

            while ((eventoPendenteId = adquireEventoPendente(estadoPendente, estadoEmProcessamento)) != default(int))
            {
                eventoPendente = eventosStaggingRepository.Find(eventoPendenteId);

                if (isAgentStopping)
                {
                    releaseEventoPendente();
                    return;
                }

                eventoPendente.estadoEventoId = estadoEmProcessamento;    
                eventosStaggingRepository.InsertOrUpdate(eventoPendente);
                

                EventoStagging evento = EventoStaggingFactory.criarEventoStagging(eventoPendente, cacheMutex);
                EventoStagging eventoProcessar = null;

                if (evento.errosEventoStagging.Count == 0)
                {
                    try
                    {
                        eventoProcessar = EventoStaggingFactory.duplicarEventoProducao(evento.matricula, (int)evento.entidadeId, evento.dataInicioCobertura, evento.horaInicioCobertura, cacheMutex);
                        eventoProcessar.esmagaDados(evento);
                    }
                    catch (ErroEventoStaggingException e)
                    {

                        foreach (ErroEventoStagging erro in e.errosEventoStagging)
                        {
                            evento.errosEventoStagging.Add(new ErroEventoStagging { campo = erro.campo, descricao = erro.descricao, tipologiaId = erro.tipologiaId, eventoStaggingId = erro.eventoStaggingId });
                        }
                    }
                }

                if (eventoProcessar == null || !ValidacaoEventos.validarEvento(eventoProcessar, cacheMutex))
                {
                    //if (evento.CodigoOperacao == EventoStagging.operacaoEventoStagging.A)
                    //{
                    //    //anulação foi testada em producao e falhou.
                    //    //esmaga evento em stagging e adiciona-se como erro.
                    //    evento = EventoStaggingFactory.duplicarEventoStagging(eventoPendente.matricula, (int)eventoPendente.entidadeId, eventoPendente.dataInicioCobertura, eventoPendente.horaInicioCobertura);
                    //    if (evento == null)
                    //    {
                    //        evento = new EventoStagging();
                    //        evento.CodigoOperacao = EventoStagging.operacaoEventoStagging.A;
                    //    }
                    //    evento.esmagaDados(eventoPendente);
                    //    ValidacaoEventos.validarEvento(evento); //reconstruir avisos e erros. Sabemos que vai falhar.
                    //}
                    // validação falhou definitivamente

                    evento.estadoEventoId = estadoErro;

                    if (eventoProcessar != null)
                    {
                        foreach (ErroEventoStagging e in eventoProcessar.errosEventoStagging)
                        {
                            evento.errosEventoStagging.Add(new ErroEventoStagging { campo = e.campo, descricao = e.descricao, tipologiaId = e.tipologiaId, eventoStaggingId = e.eventoStaggingId });
                        }
                        eventoProcessar.errosEventoStagging.Clear();

                        if (eventoProcessar.codigoOperacao != "A")
                        {
                            foreach (Aviso a in eventoProcessar.avisosEventoStagging)
                            {
                                evento.avisosEventoStagging.Add(new Aviso { campo = a.campo, descricao = a.descricao, tipologiaId = a.tipologiaId, eventoStaggingId = a.eventoStaggingId });
                            }
                        }
                        eventoProcessar.avisosEventoStagging.Clear();
                    }

                    evento.totalAvisosCumulativo += evento.totalAvisosCumulativo + evento.avisosEventoStagging.Count;
                    evento.totalErrosCumulativo += evento.totalErrosCumulativo + evento.errosEventoStagging.Count;

                    List<EventoStagging> errosStagging = eventosStaggingRepository.All.Include("estadoEvento").Where(e => e.entidadeId == evento.entidadeId && e.dataInicioCobertura == evento.dataInicioCobertura &&
                    e.horaInicioCobertura == evento.horaInicioCobertura && e.matricula == evento.matricula && e.estadoEvento.valor == "ERRO"
                    && e.codigoOperacao == evento.codigoOperacao && e.arquivado == false).ToList();

                    foreach (EventoStagging erro in errosStagging)
                    {
                        erro.arquivado = true;
                        eventosStaggingRepository.InsertOrUpdate(erro);
                    }

                    eventosStaggingRepository.InsertOrUpdate(evento);                      
                }
                else
                {
                    Concelho concelho = listaConcelhos.Where(c => c.codigoConcelho == eventoProcessar.codigoConcelhoCirculacao).FirstOrDefault();
                    Categoria categoria = listaCategorias.Where(c => c.codigoCategoriaVeiculo == eventoProcessar.codigoCategoriaVeiculo).FirstOrDefault();
                    int? concelhoId = concelho == null ? (int?)null : concelho.concelhoId;
                    int? categoriaId = categoria == null ? (int?)null : categoria.categoriaId;

                    ValorSistema operacao = operacoesEvento.Single(c => c.valor == eventoProcessar.codigoOperacao);

                    Apolice apoliceValidada = new Apolice(eventoProcessar, concelhoId, categoriaId, operacao.valorSistemaId, horaLimiteSLA, horaExtensaoSLA);

                    List<Apolice> apoliceAnterior = apolicesRepository.All.Include("avisosApolice").Where(a => a.dataInicio == apoliceValidada.dataInicio &&
                                            a.entidadeId == apoliceValidada.entidadeId &&
                                            a.veiculo.numeroMatricula == apoliceValidada.veiculo.numeroMatricula).ToList();

                    foreach (Apolice a in apoliceAnterior)
                    {
                        int avisosNum = a.avisosApolice.Count;

                        foreach (Aviso aviso in a.avisosApolice)
                        {
                            avisosRepository.Delete(aviso.avisoId);
                        }
                        //a.avisosApolice.Clear();

                        ApoliceHistorico historico = new ApoliceHistorico(a);
                        historico.dataArquivo = DateTime.Now;
                        historico.utilizadorArquivo = apoliceValidada.utilizadorReporte;

                        apolicesHistoricoRepository.InsertOrUpdate(historico);
                        apolicesHistoricoRepository.Save();

                        int idApoliceHistorico = historico.apoliceId;
                        a.avisosApolice.ForEach(aviso => aviso.apoliceHistoricoId = idApoliceHistorico);

                        apolicesRepository.Delete(a.apoliceId);
                    }

                    apolicesRepository.InsertOrUpdate(apoliceValidada);
                    apolicesRepository.Save();
             
                    List<EventoStagging> errosStagging = eventosStaggingRepository.All.Include("estadoEvento").Where(e => e.entidadeId == evento.entidadeId && e.dataInicioCobertura == evento.dataInicioCobertura &&
                    e.horaInicioCobertura == evento.horaInicioCobertura && e.matricula == evento.matricula && e.estadoEvento.valor == "ERRO"
                    && e.codigoOperacao == eventoProcessar.codigoOperacao && e.arquivado == false).ToList();

                    foreach (EventoStagging erro in errosStagging)
                    {
                        erro.dataCorrecaoErro = DateTime.Now;
                        erro.arquivado = true;
                        eventosStaggingRepository.InsertOrUpdate(erro);
                    }   
                    
                    verificaOutrasOperacoes(eventoProcessar);

                }


                eventoPendente.estadoEventoId = estadoProcessado;
                eventosStaggingRepository.InsertOrUpdate(eventoPendente);
                eventosStaggingRepository.Save();

                FicheiroRepository ficheirosRepository = null;
                Ficheiro ficheiro = null;
                if (eventoPendente.ficheiroID != null)
                {
                    fileMutex.WaitOne();
                    try
                    {
                        ficheirosRepository = new FicheiroRepository();
                        ficheiro = ficheirosRepository.Find((int)eventoPendente.ficheiroID);

                        if (evento.errosEventoStagging.Count > 0)
                        {
                            ficheiro.numEventosErro++;
                        }
                        if (eventoPendente == null || eventoPendente.avisosEventoStagging.Count > 0 || evento.avisosEventoStagging.Count > 0)
                        {
                            ficheiro.numEventosAviso++;
                        }
                        ficheiro.totalRegistosProcessados++;
                        //int theadNumber = threadPool.IndexOf(Thread.CurrentThread);
                        if (ficheiro.totalRegistos == ficheiro.totalRegistosProcessados)
                        {
                            ficheiro.estadoId = estadoFicheiroProcessado;

                            int tipoNotificacaoId;
                            string mensagemNotificacao;

                            if (ficheiro.numEventosErro > 0)
                            {
                                tipoNotificacaoId = tipoNotificacao.Where(t => t.valor == "ERRO_PROCESSAMENTO_FICHEIRO").Single().valorSistemaId;
                                mensagemNotificacao = "O 'Ficheiro Nacional de Matrículas do Parque Automóvel Seguro' com nome '" + ficheiro.nomeFicheiro + "' e data de reporte '" +
                                    ficheiro.dataUpload.ToShortDateString() + "' foi processado com  " +
                                    ficheiro.numEventosErro + " ocorrências de erro e " + ficheiro.numEventosAviso + " de aviso " +
                                    "num total de " + ficheiro.totalRegistos + " registos.";
                            }
                            else
                            {
                                if (ficheiro.numEventosAviso > 0)
                                {
                                    tipoNotificacaoId = tipoNotificacao.Where(t => t.valor == "AVISO_PROCESSAMENTO_FICHEIRO").Single().valorSistemaId;

                                    mensagemNotificacao = "O 'Ficheiro Nacional de Matrículas do Parque Automóvel Seguro' com nome '" + ficheiro.nomeFicheiro + "' e data de reporte '" +
                                    ficheiro.dataUpload.ToShortDateString() + "' foi processado com  " +
                                    ficheiro.numEventosAviso + " ocorrências de aviso " +
                                    "num total de " + ficheiro.totalRegistos + " registos.";
                                }
                                else
                                {
                                    tipoNotificacaoId = tipoNotificacao.Where(t => t.valor == "SUCESSO_PROCESSAMENTO_FICHEIRO").Single().valorSistemaId;

                                    mensagemNotificacao = "O 'Ficheiro Nacional de Matrículas do Parque Automóvel Seguro' com nome '" + ficheiro.nomeFicheiro + "' e data de reporte '" +
                                    ficheiro.dataUpload.ToShortDateString() + "' foi processado com sucesso em " +
                                    ficheiro.totalRegistos + " ocorrências.";
                                }
                            }


                            Notificacao notificacao = new Notificacao
                            {
                                dataCriacao = DateTime.Now,
                                email = true,
                                entidadeId = ficheiro.entidadeId,
                                tipologiaId = tipoNotificacaoId,
                                mensagem = mensagemNotificacao,
                            };

                            Entidade entidade = entidadesRepository.Find((int)notificacao.entidadeId);
                            entidade.notificacoes.Add(notificacao);
                            entidadesRepository.InsertOrUpdate(entidade);



                            UserProfile utilizadorFicheiro = userProfileRepository.All.Single(u => u.UserName == ficheiro.userName);
                            if (utilizadorFicheiro.entidadeId != ficheiro.entidadeId)
                            {
                                Notificacao notificacao2 = new Notificacao()
                                {
                                    dataCriacao = DateTime.Now,
                                    email = true,
                                    entidadeId = utilizadorFicheiro.entidadeId,
                                    tipologiaId = tipoNotificacaoId,
                                    mensagem = mensagemNotificacao,
                                };

                                notificacoesRepository.InsertOrUpdate(notificacao2);
                            }


                            entidadesRepository.Save();
                            notificacoesRepository.Save();
                                                       
                        }

                        ficheirosRepository.InsertOrUpdate(ficheiro);
                        ficheirosRepository.Save();
                    }
                    finally
                    {
                        fileMutex.ReleaseMutex();
                    }
                }

                releaseEventoPendente();
            }
        }