package agilpizza.controlador.util;

import java.io.IOException;
import java.io.Serializable;
import java.util.ResourceBundle;

import javax.faces.application.FacesMessage;
import javax.faces.component.UIViewRoot;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.servlet.ServletContext;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

public final class JSFUtil implements Serializable {
	/**
	 * Adiciona uma mensagem informativa (de sucesso) global no request.
	 * rendered="#{! empty facesContext.maximumSeverity}"
	 * 
	 * @param mensagem
	 *            Mensagem.
	 */
	public static void mensagem(String mensagem) {
		FacesContext facesContext = FacesContext.getCurrentInstance();
		facesContext.addMessage(null, new FacesMessage(
				FacesMessage.SEVERITY_INFO, mensagem, mensagem));
	}

	/**
	 * Adiciona uma mensagem informativa (de sucesso) no request para o
	 * componente de id clientId.
	 * 
	 * @param clientId
	 *            Id do componente.
	 * @param mensagem
	 *            Mensagem.
	 */
	public static void mensagem(String clientId, String mensagem) {
		FacesContext facesContext = FacesContext.getCurrentInstance();
		facesContext.addMessage(clientId, new FacesMessage(
				FacesMessage.SEVERITY_INFO, mensagem, mensagem));
	}

	/**
	 * Adiciona um aviso (resultado imperfeito) global no request.
	 * 
	 * @param mensagem
	 *            Mensagem.
	 */
	public static void aviso(String mensagem) {
		FacesContext facesContext = FacesContext.getCurrentInstance();
		facesContext.addMessage(null, new FacesMessage(
				FacesMessage.SEVERITY_WARN, mensagem, mensagem));
	}

	/**
	 * Adiciona um aviso (resultado imperfeito) no request.
	 * 
	 * @param clientId
	 *            Id do componente.
	 * @param mensagem
	 *            Mensagem.
	 */
	public static void aviso(String clientId, String mensagem) {
		FacesContext facesContext = FacesContext.getCurrentInstance();
		facesContext.addMessage(clientId, new FacesMessage(
				FacesMessage.SEVERITY_WARN, mensagem, mensagem));
	}

	/**
	 * Adiciona uma mensagem de erro (erro grave) global no request.
	 * 
	 * @param mensagem
	 *            Mensagem.
	 */
	public static void mensagemDeErro(String mensagem) {
		FacesContext facesContext = FacesContext.getCurrentInstance();
		facesContext.addMessage(null, new FacesMessage(
				FacesMessage.SEVERITY_ERROR, mensagem, mensagem));
	}

	/**
	 * Adiciona uma mensagem de erro (erro grave) no request.
	 * 
	 * @param clientId
	 *            Id do componente.
	 * @param mensagem
	 *            Mensagem.
	 */
	public static void mensagemDeErro(String clientId, String mensagem) {
		FacesContext facesContext = FacesContext.getCurrentInstance();
		facesContext.addMessage(clientId, new FacesMessage(
				FacesMessage.SEVERITY_ERROR, mensagem, mensagem));
	}

	/**
	 * Pega um objeto do contexto.
	 * 
	 * @param nomeDaVariavel
	 *            Nome da variavel do jsp que mapeia o objeto.
	 * @return Retorna o objeto mapeado pela variavel.
	 */
	public static Object pegarObjetoDoContexto(String nomeDaVariavel) {
		FacesContext facesContext = FacesContext.getCurrentInstance();
		ExternalContext externalContext = facesContext.getExternalContext();
		return externalContext.getRequestMap().get(nomeDaVariavel);
	}

	/**
	 * Pega um bean definido no arquivo de configuracao do Faces.
	 * 
	 * @param nomeDoBean
	 *            Nome da instancia do bean, definido no faces.xml
	 * @return Retorna o bean.
	 */
	public static Object pegarBean(String nomeDoBean) {
		FacesContext fc = FacesContext.getCurrentInstance();
		return fc.getApplication().createValueBinding("#{" + nomeDoBean + "}")
				.getValue(fc);
	}

	/**
	 * Instancia um bean definido no arquivo de configuracao do Faces.
	 * 
	 * @param nomeDoBean
	 *            Nome da instancia do bean, definido no faces.xml
	 * @return Retorna o bean.
	 */
	public static void criarBean(String nomeDoBean) {
		FacesContext context = FacesContext.getCurrentInstance();
		Class clazz = context.getApplication().createValueBinding(
				"#{" + nomeDoBean + "}").getType(context);
		System.out.println(clazz);
		try {
			context.getApplication()
					.createValueBinding("#{" + nomeDoBean + "}").setValue(
							context, clazz.newInstance());
		} catch (Exception e) {
			throw new RuntimeException("Falha ao criar um Bean");
		}
	}

	/**
	 * Reseta um bean de sessao.
	 * 
	 * @param nomeDoBean
	 *            Nome do bean que aparece no managedBean.xml
	 */
	public static void destruirSessionBean(String nomeDoBean) {
		FacesContext context = FacesContext.getCurrentInstance();
		context.getApplication().createValueBinding("#{" + nomeDoBean + "}")
				.setValue(context, null);
	}

	/**
	 * Retorna o contexto da aplicacao.
	 * 
	 * @return Contexto.
	 */
	public static String getContexto() {
		return FacesContext.getCurrentInstance().getExternalContext()
				.getRequestContextPath();
	}

	public static ServletContext getServletContext() {
		return (ServletContext) FacesContext.getCurrentInstance()
				.getExternalContext().getContext();
	}

	/**
	 * Retorna a sessão.
	 * 
	 * @return Sessão
	 */
	public static HttpSession getHttpSession() {
		FacesContext facesContext = FacesContext.getCurrentInstance();
		return (HttpSession) facesContext.getExternalContext()
				.getSession(false);
	}

	/**
	 * Retorna o request.
	 * 
	 * @return Request
	 */
	public static HttpServletRequest getHttpRequest() {
		FacesContext facesContext = FacesContext.getCurrentInstance();
		return (HttpServletRequest) facesContext.getExternalContext()
				.getRequest();
	}

	/**
	 * /Janus/paginas/.../pagina.jsf
	 * 
	 * @return pagina.jsf
	 */
	public static String getNomeArquivoDaPagina() {
		// /Janus/paginas/.../pagina.jsf
		return getHttpRequest().getRequestURI().replaceAll(".*/", "");
	}

	/**
	 * 
	 * @return /Janus/paginas/.../pagina.jsf
	 */
	public static String getPaginaAtual() {
		// /Janus/paginas/.../pagina.jsf
		return getHttpRequest().getRequestURI();
	}

	/**
	 * Fecha a sessao.
	 */
	public static void invalidarSessao() {
		getHttpSession().invalidate();
	}

	/**
	 * Cria uma nova sessao, para nao dar sessao expirada ao fazer logout
	 */
	public static void novaSessao() {
		FacesContext facesContext = FacesContext.getCurrentInstance();
		facesContext.getExternalContext().getSession(true);
	}

	/**
	 * HttpSession.getAttribute(chave);
	 * 
	 * @param chave
	 * @return
	 */
	public static Object getSessionAttribute(String chave) {
		return getHttpSession().getAttribute(chave);
	}

	/**
	 * Recebe uma chave do arquivo 'recursos.JanusMensagens.properties' e
	 * retorna a mensagem correspondente.
	 * 
	 * @param chaveDaMensagem
	 *            Chave da mensagem.
	 * @return Mensagem (valor) correspondente a chave.
	 */
	public static String conseguirMensagem(String chaveDaMensagem) {
		FacesContext context = FacesContext.getCurrentInstance();
		ResourceBundle bundle = ResourceBundle.getBundle(
				"recursos.JanusMensagens", context.getViewRoot().getLocale());
		return bundle.getString(chaveDaMensagem);
	}

	/**
	 * Ex: JSP: <h:commandLink action="#{action...}" value="..."> <f:param
	 * value="#{valor...}" name="parametro"/> </h:commandLink>
	 * 
	 * @param parametro
	 *            Nome do parametro
	 * @return Valor do parametro
	 */
	public static Object getParametroDoRequest(String parametro) {
		FacesContext context = FacesContext.getCurrentInstance();
		HttpServletRequest req = (HttpServletRequest) context
				.getExternalContext().getRequest();
		return req.getParameter(parametro);
	}

	/**
	 * Ex: http://pos.usp.br/janus/pagina.jsf?id=777
	 * 
	 * @param parametro
	 *            Ex: id
	 * @return Ex: 777 No jsp, usar: <h:outputText value="#{param['id']}"/>
	 */
	public static Object getParametroDaUrl(String parametro) {
		FacesContext fc = FacesContext.getCurrentInstance();
		return fc.getExternalContext().getRequestParameterMap().get(parametro);
	}

	/**
	 * Recebe um context-param do web.xml e retorna seu valor.
	 * 
	 * @param parametro
	 *            Parametro.
	 * @return Valor correspondente ao parametro.
	 */
	public static String getParametroInicializacao(String parametro) {
		FacesContext context = FacesContext.getCurrentInstance();
		return context.getExternalContext().getInitParameter(parametro);
	}

	/**
	 * Exemplo: "/Janus/alunoGeral/historico/historicos.jsf" Perde o request.
	 * 
	 * @param pagina
	 */
	public static void redirecionar(String pagina) {
		FacesContext faces = FacesContext.getCurrentInstance();
		try {
			faces.getExternalContext().redirect(pagina);
		} catch (IOException e) {
			throw new RuntimeException(
					"Não redirecionou para página solicitada.");
		}
	}

	/**
	 * Exemplo: "/alunoGeral/historico/historicos.jsf" Perde o request.
	 * 
	 * @param pagina
	 */
	public static void redirecionarSemContexto(String pagina) {
		FacesContext context = FacesContext.getCurrentInstance();
		UIViewRoot view = context.getApplication().getViewHandler().createView(
				context, pagina);
		view.setViewId(pagina);
		context.setViewRoot(view);
		context.renderResponse();
	}

	/**
	 * Recebe o conteudo e grava no response de maneira apropriada.
	 * 
	 * @param conteudo
	 *            bytes (PDF, Imagem.. ) que serao gravados no response.
	 * @param nomeDoArquivo
	 *            Nome do arquivo para quando o usuario fizer download.
	 * @throws IOException
	 *             Erro na gravacao dos bytes para o response.
	 */
	public static void gravarResponse(byte[] conteudo, String nomeDoArquivo,
			String formato, HttpServletResponse response) throws IOException {
		response.setContentType(formato);
		response.setContentLength(conteudo.length);
		response.setHeader("Content-disposition", "inline; filename=\""
				+ nomeDoArquivo + "\"");
		ServletOutputStream out;
		out = response.getOutputStream();
		out.write(conteudo);
		out.flush();
		out.close();
	}

	/**
	 * Recebe o conteudo de um PDF e grava no response de maneira apropriada.
	 * 
	 * @param conteudo
	 *            bytes do PDF que serao gravados no response.
	 * @param nomeDoArquivo
	 *            Nome do arquivo para quando o usuario fizer download.
	 * @throws IOException
	 *             Erro na gravacao dos bytes para o response.
	 */
	public static void gerarPDF(byte[] conteudo, String nomeDoArquivo) {
		if (conteudo == null) {
			throw new RuntimeException("Não foi possível gerar o PDF.");
		}
		FacesContext faces = FacesContext.getCurrentInstance();
		HttpServletResponse response = (HttpServletResponse) faces
				.getExternalContext().getResponse();
		try {
			gravarResponse(conteudo, nomeDoArquivo, "application/pdf", response);
		} catch (IOException e) {
			throw new RuntimeException("Não foi possível gerar o PDF.");
		}
		faces.responseComplete();
	}

	public static void gerarWord(byte[] conteudo, String nomeDoArquivo) {
		if (conteudo == null) {
			throw new RuntimeException("Não foi possível abrir o arquivo Word.");
		}
		FacesContext faces = FacesContext.getCurrentInstance();
		HttpServletResponse response = (HttpServletResponse) faces
				.getExternalContext().getResponse();
		try {
			gravarResponse(conteudo, nomeDoArquivo, "application/msword",
					response);
		} catch (IOException e) {
			throw new RuntimeException("Não foi possível abrir o arquivo Word.");
		}
		faces.responseComplete();
	}

	/**
	 * Recebe o conteudo de uma Imagem e grava no response de maneira
	 * apropriada.
	 * 
	 * @param conteudo
	 *            bytes da Imagem que serao gravados no response.
	 * @param nomeDoArquivo
	 *            Nome do arquivo para quando o usuario fizer download.
	 * @throws IOException
	 *             Erro na gravacao dos bytes para o response.
	 */
	public static void gerarImagem(byte[] conteudo, String nomeDoArquivo)
			throws IOException {
		FacesContext faces = FacesContext.getCurrentInstance();
		HttpServletResponse response = (HttpServletResponse) faces
				.getExternalContext().getResponse();
		gravarResponse(conteudo, nomeDoArquivo, "image/jpeg", response);
		faces.responseComplete();
	}

	/**
	 * Recebe o response do Servlet. Método para ser usado dentro de um Servlet.
	 * 
	 * @param conteudo
	 * @param nomeDoArquivo
	 * @param response
	 * @throws IOException
	 */
	public static void gerarImagemServlet(byte[] conteudo,
			String nomeDoArquivo, HttpServletResponse response)
			throws IOException {
		gravarResponse(conteudo, nomeDoArquivo, "image/jpeg", response);
	}
}
