
package managedbean.common;

import java.io.IOException;

import javax.faces.application.FacesMessage;
import javax.persistence.PersistenceException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.omnifaces.util.Exceptions;

import common.UserType;
import common.Utils;

@WebFilter(filterName = "AuthFilter", urlPatterns = { "*.xhtml" })
public class AuthorizationFilter implements Filter {

	public AuthorizationFilter() {
	}

	@Override
	public void init(FilterConfig filterConfig) throws ServletException {

	}

	private boolean isAJAXRequest(HttpServletRequest request) {
		boolean check = false;
		String facesRequest = request.getHeader("Faces-Request");
		if (facesRequest != null && facesRequest.equals("partial/ajax")) {
			check = true;
		}
		return check;
	}

	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
		HttpServletRequest req = null;
		HttpServletResponse resp = null;
		HttpSession ses = null;
		try {

			req = (HttpServletRequest) request;
			String reqURI = req.getRequestURI();

			resp = (HttpServletResponse) response;
			ses = req.getSession(false);

			// Para recursos publicos permitimos el acceso exista sesión o no.
			if (reqURI.indexOf("/login.xhtml") >= 0 || reqURI.indexOf("/profile/RegisterUser.xhtml") >= 0 || reqURI.indexOf("/home.xhtml") >= 0
					|| reqURI.indexOf("/error.xhtml") >= 0 || reqURI.indexOf("/public/") >= 0 || reqURI.contains("javax.faces.resource")) {
				chain.doFilter(request, response);
				return;
			}

			if (this.isAJAXRequest(req) == true) {
				chain.doFilter(request, response);
				return;
			}

			// Sesión expirada
			if (req.isRequestedSessionIdValid() == false && req.getRequestedSessionId() != null) {
				resp.sendRedirect(req.getContextPath() + "/error.xhtml?type=expired");
				return;
			}

			// Si el usuario está logeado comprobamos si está autorizado a ver la página solicitada.
			if (SessionUtils.isLogedIn(ses) == true) {
				UserType tipoUsuario = SessionUtils.getUserType(ses);
				boolean authorized = false;

				switch (tipoUsuario) {
				case ADMINISTRATOR:
					if (reqURI.indexOf("/systemAdmin/ManageSpecialties") > 0)
						authorized = true;
					if (reqURI.indexOf("/systemAdmin/ManageHealthCareCenters") > 0)
						authorized = true;
					if (reqURI.indexOf("/systemAdmin/ListDoctorsByCenter") > 0)
						authorized = true;
					if (reqURI.indexOf("/visit/VisitView") > 0)
						authorized = true;
					if (reqURI.indexOf("/visit/UpdateVisit") > 0)
						authorized = true;
					break;
				case PATIENT:
					if (reqURI.indexOf("/visit/VisitView") > 0)
						authorized = true;
					if (reqURI.indexOf("/visit/AddVisit") > 0)
						authorized = true;
					if (reqURI.indexOf("/visit/UpdateVisit") > 0)
						authorized = true;
					if (reqURI.indexOf("/visit/CancelVisit") > 0)
						authorized = true;
					if (reqURI.indexOf("/medicaltest/Questions") > 0)
						authorized = true;
					if (reqURI.indexOf("/medicaltest/ViewMedicalTest") > 0)
						authorized = true;
					if (reqURI.indexOf("/medicaltest/MedicalTests") > 0)
						authorized = true;
					if (reqURI.indexOf("/medicaltest/SearchSpecialistBySpecialty") > 0)
						authorized = true;
					if (reqURI.indexOf("/profile/UpdateProfile") > 0)
						authorized = true;
					if (reqURI.indexOf("/profile/ChangeFamilyDoctor") > 0)
						authorized = true;
					break;
				case FAMILY_DOCTOR:
					if (reqURI.indexOf("/visit/VisitView") > 0)
						authorized = true;
					if (reqURI.indexOf("/visit/VisitAddResult") > 0)
						authorized = true;
					if (reqURI.indexOf("/visit/VisitList") > 0)
						authorized = true;
					if (reqURI.indexOf("/medicaltest/MedicalTests") > 0)
						authorized = true;
					if (reqURI.indexOf("/medicaltest/Questions") > 0)
						authorized = true;
					if (reqURI.indexOf("/medicaltest/ViewMedicalTest") > 0)
						authorized = true;
					if (reqURI.indexOf("/profile/UpdateProfile") > 0)
						authorized = true;
					if (reqURI.indexOf("/profile/ChangePrimaryHealthCareCenter") > 0)
						authorized = true;
					break;
				case SPECIALIST_DOCTOR:
					if (reqURI.indexOf("/medicaltest/MedicalTests") > 0)
						authorized = true;
					if (reqURI.indexOf("/medicaltest/AddMedicalTest") > 0)
						authorized = true;
					if (reqURI.indexOf("/medicaltest/ViewMedicalTest") > 0)
						authorized = true;
					if (reqURI.indexOf("/medicaltest/AddImageToMedicalTest") > 0)
						authorized = true;
					if (reqURI.indexOf("/profile/UpdateProfile") > 0)
						authorized = true;
					break;
				}

				if (authorized == true) {
					chain.doFilter(request, response);
					return;
				} else {
					SessionUtils.addMessage(ses, FacesMessage.SEVERITY_ERROR,
							"No está autorizado a acceder a la página solicitada. Por favor, utilice el menú principal de la aplicación.",
							String.format("Se ha producido una expción de autorización, su usuario no está autorizado a acceder a la página: (%s).", reqURI));
					resp.sendRedirect(req.getContextPath() + "/error.xhtml?type=auth");
					return;
				}

			}

			resp.sendRedirect(req.getContextPath() + "/home.xhtml");
		} catch (Exception e) {
			if (Exceptions.is(e, PersistenceException.class) == true) {
				if (ses != null)
					SessionUtils.addMessage(ses, FacesMessage.SEVERITY_ERROR, "Error al intentar acceder a la base de datos", Utils.getExceptionRootCause(e).getLocalizedMessage());

				resp.sendRedirect(req.getContextPath() + "/error.xhtml?type=sql");
			} else
				resp.sendRedirect(req.getContextPath() + "/error.xhtml");
		}
	}

	@Override
	public void destroy() {
		System.out.println("Sessión destruida");
	}
}
