package br.gov.mj.sislegis.app.service.ejbs;
import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.Set;
import java.util.concurrent.Future;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.ejb.AsyncResult;
import javax.ejb.Asynchronous;
import javax.ejb.Schedule;
import javax.ejb.Singleton;
import javax.ejb.Timeout;
import javax.ejb.Timer;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.apache.commons.mail.EmailException;
import br.gov.mj.sislegis.app.enumerated.Origem;
import br.gov.mj.sislegis.app.model.Comissao;
import br.gov.mj.sislegis.app.model.Usuario;
import br.gov.mj.sislegis.app.model.pautacomissao.AgendaComissao;
import br.gov.mj.sislegis.app.model.pautacomissao.Sessao;
import br.gov.mj.sislegis.app.model.pautacomissao.SituacaoSessao;
import br.gov.mj.sislegis.app.parser.ReuniaoBean;
import br.gov.mj.sislegis.app.parser.camara.ParserPautaCamara;
import br.gov.mj.sislegis.app.parser.senado.ParserPautaSenado;
import br.gov.mj.sislegis.app.service.AbstractPersistence;
import br.gov.mj.sislegis.app.service.AgendaComissaoService;
import br.gov.mj.sislegis.app.service.ComissaoService;
import br.gov.mj.sislegis.app.service.UsuarioService;
import br.gov.mj.sislegis.app.util.SislegisUtil;
/**
* Implementa o gerenciamento de agendas de comissoes seguidas
*
* @author coutinho
*
*/
@Singleton
public class AgendaComissaoServiceEjb extends AbstractPersistence<AgendaComissao, Long> implements
AgendaComissaoService {
@Inject
ComissaoService comissaoService;
@PersistenceContext
private EntityManager em;
@Inject
private UsuarioService usuarioService;
public AgendaComissaoServiceEjb() {
super(AgendaComissao.class);
}
@Override
protected EntityManager getEntityManager() {
return em;
}
@Override
public AgendaComissao getAgenda(Origem casa, String comissao) {
return getAgenda(casa, comissao, false);
}
@Override
public AgendaComissao getAgenda(Origem casa, String comissao, boolean forceload) {
try {
AgendaComissao agenda = (AgendaComissao) em.createNamedQuery("getByCasaComissao")
.setParameter("casa", casa).setParameter("comissao", comissao).getSingleResult();
if (forceload) {
agenda.getSessoes().size();
}
return agenda;
} catch (javax.persistence.NoResultException e) {
return null;
} catch (Exception e) {
Logger.getLogger(SislegisUtil.SISLEGIS_LOGGER).log(Level.SEVERE, "Falhou ao buscar agenda", e);
return null;
}
}
public List<AgendaComissao> listAgendasSeguidas() {
List<AgendaComissao> seguidas = em.createNamedQuery("getAllAgendasSeguidas", AgendaComissao.class)
.getResultList();
return seguidas;
}
public List<Usuario> listSeguidoresAgenda(AgendaComissao agenda) {
List<Usuario> seguidas = em.createNamedQuery("getSeguidoresAgenda", Usuario.class)
.setParameter("idAgenda", agenda.getId()).getResultList();
return seguidas;
}
Comparator<Sessao> changeDetectpr = new Comparator<Sessao>() {
@Override
public int compare(Sessao o1, Sessao o2) {
if (o1.getData().equals(o2.getData())) {
if (o1.getSituacao().equals(o2.getSituacao())) {
if (o1.getTitulo().equals(o2.getTitulo())) {
return 0;
}
}
}
return 1;
}
};
@Timeout
public void timeout(Timer timer) {
Logger.getLogger(SislegisUtil.SISLEGIS_LOGGER).warning(
"Timeout na execução da atualização de agenda " + timer.getInfo());
}
@Override
public void unfollowComissao(Origem casa, String comissao, Usuario user) {
AgendaComissao agenda = getAgenda(casa, comissao);
if (agenda == null) {
Logger.getLogger(SislegisUtil.SISLEGIS_LOGGER).warning(
"Tentativa de remover notificacoes de comissao nao seguida");
return;
}
user = usuarioService.loadComAgendasSeguidas(user.getId());
user.removeAgendaSeguida(agenda);
usuarioService.save(user);
}
@Override
public void followComissao(Origem casa, String comissao, Usuario user) {
AgendaComissao agenda = getAgenda(casa, comissao);
if (agenda == null) {
agenda = new AgendaComissao(casa, comissao, getNextMonday().getTime());
agenda = save(agenda);
}
user = usuarioService.loadComAgendasSeguidas(user.getId());
if (user.getAgendasSeguidas().contains(agenda)) {
return;
}
user.addAgendaSeguida(agenda);
usuarioService.save(user);
}
/**
* Busca a próxima segunda feira
* */
private Calendar getNextMonday() {
return getNextMondayAfter(Calendar.getInstance());
}
private Calendar getNextMondayAfter(Calendar date1) {
while (date1.get(Calendar.DAY_OF_WEEK) != Calendar.MONDAY) {
date1.add(Calendar.DATE, 1);
}
date1.set(Calendar.HOUR_OF_DAY, 0);
date1.set(Calendar.MINUTE, 0);
date1.set(Calendar.SECOND, 0);
date1.set(Calendar.MILLISECOND, 0);
return date1;
}
/**
* Tarefa principara para monitoramento de pautas da camara e senado.<br>
* Primeiro ela carrega quais pautas estão sendo seguidas. E então checa por
* alterações nessas pautas.<br>
* Se é a 1a vez que essa agenda está sendo seguida, ou houver mudança de
* semana, nenhum email é enviado.
*/
@Schedule(minute = "*/5", hour = "*", persistent = false, info = "Atualiza status pautas")
public void atualizaStatusAgendas() {
Set<AgendaComissao> atualizadas = new HashSet<AgendaComissao>();
Calendar nextMonday = getNextMonday();
Calendar weekEnd = Calendar.getInstance();
weekEnd.setTime(nextMonday.getTime());
weekEnd.add(Calendar.DATE, 6);// Até o domingo
try {
SimpleDateFormat dataFormatter = new SimpleDateFormat("yyyyMMdd");
String semanaDo = dataFormatter.format(nextMonday.getTime());
String semanaAte = dataFormatter.format(weekEnd.getTime());
ParserPautaSenado parserSenado = new ParserPautaSenado();
ParserPautaCamara parserCamara = new ParserPautaCamara();
List<Comissao> comissoesCamara = comissaoService.listarComissoesCamara();
List<AgendaComissao> agendasSeguidas = listAgendasSeguidas();
Logger.getLogger(SislegisUtil.SISLEGIS_LOGGER).info("Há " + agendasSeguidas.size() + " comissões seguidas");
for (Iterator<AgendaComissao> iteratorAgendas = agendasSeguidas.iterator(); iteratorAgendas.hasNext();) {
AgendaComissao agenda = iteratorAgendas.next();
Set<Sessao> sessoes = agenda.getSessoes();
if (!agenda.getDataReferencia().equals(nextMonday.getTime())) {
agenda.setDataReferencia(nextMonday.getTime());
}
List<ReuniaoBean> reunioes = new ArrayList<ReuniaoBean>();
switch (agenda.getCasa()) {
case CAMARA:
Comissao comissaoCamara = getComissaoCamara(agenda.getComissao(), comissoesCamara);
if (comissaoCamara == null) {
Logger.getLogger(SislegisUtil.SISLEGIS_LOGGER).severe(
"Não foi possível carregar o id da comissao " + agenda.getComissao());
continue;
}
reunioes.addAll(parserCamara.getReunioes(comissaoCamara.getId(), semanaDo, semanaAte));
break;
case SENADO:
reunioes.addAll(parserSenado.getReunioes(agenda.getComissao(), semanaDo, semanaAte));
break;
default:
throw new IllegalArgumentException("Origem invalida");
}
Logger.getLogger(SislegisUtil.SISLEGIS_LOGGER).info(
"Atualizando " + agenda.getComissao() + " há " + reunioes.size() + " reunioes");
for (Iterator<ReuniaoBean> iteratorReunioes = reunioes.iterator(); iteratorReunioes.hasNext();) {
ReuniaoBean reuniaoBean = (ReuniaoBean) iteratorReunioes.next();
Sessao sessaoWS = reuniaoBean.getSessao();
Sessao sessaoDb = null;
for (Iterator<Sessao> iterator = sessoes.iterator(); iterator.hasNext();) {
Sessao sess = (Sessao) iterator.next();
if (sess.getIdentificadorExterno().equals(sessaoWS.getIdentificadorExterno())) {
sessaoDb = sess;
break;
}
}
if (sessaoDb == null) {
Logger.getLogger(SislegisUtil.SISLEGIS_LOGGER).fine("Sessão não existia.");
agenda.addSessao(sessaoWS);
} else {
if (changeDetectpr.compare(sessaoWS, sessaoDb) != 0) {
Logger.getLogger(SislegisUtil.SISLEGIS_LOGGER).info(
"Mudança detectada em " + agenda.getComissao());
sessaoDb.popula(sessaoWS);
agenda.addSessao(sessaoDb);
agenda.setPautasAtualizadas();
if (SituacaoSessao.Agendada.equals(sessaoWS.getSituacao())) {
atualizadas.add(agenda);
}
}
}
}
agenda.setConsultada();
if (atualizadas.contains(agenda)) {
notifyUsuariosPautaMudou(agenda);
}
save(agenda);
}
} catch (Exception e) {
e.printStackTrace();
Logger.getLogger(SislegisUtil.SISLEGIS_LOGGER).log(Level.SEVERE, "Erro checando agendas externas ", e);
}
}
private Map<String, Comissao> mapComissao = null;
private Object mutexMap = new Object();
/**
* Retorna um objeto Comissao baseado na sua sigla. Na primeira utilização
* cria-se um Map para tornar mais rápidas as subsequentes.
*
* @param comissao
* @param comissoesCamara
* @return
*/
private Comissao getComissaoCamara(String comissao, List<Comissao> comissoesCamara) {
if (mapComissao == null) {
synchronized (mutexMap) {
if (mapComissao == null) {
mapComissao = new HashMap<String, Comissao>();
for (Iterator<Comissao> iterator = comissoesCamara.iterator(); iterator.hasNext();) {
Comissao comissaoCamara = (Comissao) iterator.next();
Logger.getLogger(SislegisUtil.SISLEGIS_LOGGER).fine(
"comissaoCamara '" + comissaoCamara.getSigla() + "'");
mapComissao.put(comissaoCamara.getSigla().trim(), comissaoCamara);
}
}
}
}
Logger.getLogger(SislegisUtil.SISLEGIS_LOGGER).fine("Procurando '" + comissao + "'");
return mapComissao.get(comissao.trim());
}
/**
* Envia email notificando da alteração de pauta para todos os seguidores de
* uma comissão
*
* @param agenda
* @return
*/
@Asynchronous
public Future<String> notifyUsuariosPautaMudou(AgendaComissao agenda) {
String status = "";
ResourceBundle res = ResourceBundle.getBundle("messages");
String assunto = MessageFormat.format(res.getString("email.mudanca_pauta.assunto"), agenda.getComissao());
List<Usuario> seguidores = usuarioService.listUsuariosSeguidoresDeComissao(agenda);
if (seguidores != null && !seguidores.isEmpty()) {
for (Iterator<Usuario> iterator = seguidores.iterator(); iterator.hasNext();) {
Usuario usuario = (Usuario) iterator.next();
Logger.getLogger(SislegisUtil.SISLEGIS_LOGGER).warning("Notificando " + usuario.getEmail());
String body = MessageFormat.format(res.getString("email.mudanca_pauta.body"), usuario.getNome(),
agenda.getComissao());
try {
SislegisUtil.sendEmail(usuario.getEmail(), usuario.getNome(), assunto, body);
} catch (EmailException e) {
Logger.getLogger(SislegisUtil.SISLEGIS_LOGGER).log(Level.SEVERE,
"Erro ao enviar email para " + usuario.getEmail(), e);
}
}
status = "OK+";
} else {
Logger.getLogger(SislegisUtil.SISLEGIS_LOGGER).warning(
"Nenhum usuário seguindo a agenda " + agenda.getComissao());
status = "OK";
}
return new AsyncResult<String>(status);
}
}