
package de.ivu.elect.jee.faces;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.faces.event.PhaseEvent;
import javax.faces.event.PhaseId;
import javax.faces.event.PhaseListener;

/**
 * Quelle: http://ocpsoft.com/java/persist-and-pass-facesmessages-over-page-redirects/
 */
public class RedirectMessagesSupport implements PhaseListener {

  private static final long serialVersionUID = 1L;

  private static final String SESSION_TOKEN = "REDIRECT_MESSAGES_SUPPORT";

  @Override
  public PhaseId getPhaseId() {
    return PhaseId.ANY_PHASE;
  }

  @Override
  public void beforePhase(final PhaseEvent event) {
    FacesContext facesContext = event.getFacesContext();
    saveMessages(facesContext);

    if (PhaseId.RENDER_RESPONSE.equals(event.getPhaseId()) && !facesContext.getResponseComplete()) {
      restoreMessages(facesContext);
    }
  }

  /*
   * Save messages into the session after every phase.
   */
  @Override
  public void afterPhase(final PhaseEvent event) {
    if (!PhaseId.RENDER_RESPONSE.equals(event.getPhaseId())) {
      FacesContext facesContext = event.getFacesContext();
      saveMessages(facesContext);
    }
  }

  @SuppressWarnings("unchecked")
  private int saveMessages(final FacesContext facesContext) {
    List<FacesMessage> messages = new ArrayList<>();

    for (Iterator<FacesMessage> iter = facesContext.getMessages(null); iter.hasNext();) {
      messages.add(iter.next());
      iter.remove();
    }

    if (messages.isEmpty()) {
      return 0;
    }

    Map<String, Object> sessionMap = facesContext.getExternalContext().getSessionMap();
    List<FacesMessage> existingMessages = (List<FacesMessage>) sessionMap.get(SESSION_TOKEN);
    if (existingMessages == null) {
      sessionMap.put(SESSION_TOKEN, messages);
    } else {
      existingMessages.addAll(messages);
    }
    return messages.size();
  }

  @SuppressWarnings("unchecked")
  private int restoreMessages(final FacesContext facesContext) {
    Map<String, Object> sessionMap = facesContext.getExternalContext().getSessionMap();
    List<FacesMessage> messages = (List<FacesMessage>) sessionMap.remove(SESSION_TOKEN);

    if (messages == null) {
      return 0;
    }

    for (Object element : messages) {
      facesContext.addMessage(null, (FacesMessage) element);
    }
    return messages.size();
  }
}
