/**
 * Magnolia and its source-code is licensed under the LGPL. You may copy, adapt,
 * and redistribute this file for commercial or non-commercial use. When
 * copying, adapting, or redistributing this document in keeping with the
 * guidelines above, you are required to provide proper attribution to obinary.
 * If you reproduce or distribute the document without making any substantive
 * modifications to its content, please use the following attribution line:
 * Copyright 1993-2005 obinary Ltd. (http://www.obinary.com) All rights
 * reserved.
 */
package info.magnolia.cms.security;

import info.magnolia.cms.beans.config.ContentRepository;
import info.magnolia.cms.core.Content;
import info.magnolia.cms.core.HierarchyManager;
import info.magnolia.cms.i18n.MessagesManager;

import javax.jcr.PathNotFoundException;
import javax.jcr.RepositoryException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;

/**
 * @author Sameer Charles
 * @version 2.0
 */
public final class Authenticator {

	/**
	 * Logger.
	 */
	private static Logger logger = Logger.getLogger(Authenticator.class);

	/**
	 * Session attribute holding the magnolia user node from the jcr repository.
	 */
	private static final String ATTRIBUTE_USER_NODE = "mgnlUserNode"; //$NON-NLS-1$

	/**
	 * Utility class, don't instantiate.
	 */
	private Authenticator() {
		// unused
	}

	/**
	 * Authenticate authorization request with the usersRepository.
	 * 
	 * @param req
	 *            as received by the servlet engine
	 * @return boolean
	 */
	public static boolean authenticate(HttpServletRequest req)
			throws ServletException {
		logger.debug("authenticate");
		return isValidMagnoliaUser(req);
	}

	public static String getCredentials(HttpServletRequest request) {
		logger.debug("getCredentials");
		return request.getHeader("Authorization"); //$NON-NLS-1$
	}

	/**
	 * checks is the credentials exist in the repository
	 * 
	 * @param request
	 *            current HttpServletRequest
	 */
	public static boolean isValidMagnoliaUser(HttpServletRequest request)
			throws ServletException {
		logger.debug("isValidMagnoliaUser");
		String user = getUserId(request);
		logger.debug("user:" + user);
		if (StringUtils.isEmpty(user)) {
			return false;
		}
		HierarchyManager hm = ContentRepository
				.getHierarchyManager(ContentRepository.USERS);
		HttpSession session = request.getSession();
		try {

			Content userPage = hm.getContent(user);
			if (logger.isDebugEnabled()) {
				logger.debug("userPage = " + userPage);
			}
			session.setAttribute(ATTRIBUTE_USER_NODE, userPage);
			setupUserLanguage(session, userPage);
			return true;
		} catch (PathNotFoundException e) {
			throw new ServletException(
					"Unable to locate user ["
							+ Authenticator.getUserId(request)
							+ "], authentication failed. "
							+ "You need to create the user manually in Magnolia before trying to log in", e); //$NON-NLS-1$ //$NON-NLS-2$

		} catch (RepositoryException e) {
			throw new ServletException("Unable to locate user [" //$NON-NLS-1$
					+ Authenticator.getUserId(request)
					+ "], authentication failed due to a " //$NON-NLS-1$
					+ e.getClass().getName(), e);
		}

	}

	private static void setupUserLanguage(HttpSession session, Content userPage) {
		//       we must set the language because the JSTL will not use our
		// classes
		String lang = userPage.getNodeData("language").getString(); //$NON-NLS-1$
		if (StringUtils.isEmpty(lang)) {
			lang = MessagesManager.getDefaultLocale().getLanguage();
		}
		MessagesManager.setUserLanguage(lang, session);
	}

	/**
	 * @param request
	 *            current HttpServletRequest
	 * @return String , current logged in user
	 */
	public static String getUserId(HttpServletRequest request) {
		String user = (String) request.getSession().getAttribute(
				"edu.yale.its.tp.cas.client.filter.user");
		return user;
	}

	/**
	 * @param request
	 *            current HttpServletRequest
	 * @return current logged in user page
	 */
	public static Content getUserPage(HttpServletRequest request) {
		return (Content) request.getSession().getAttribute(ATTRIBUTE_USER_NODE);
	}

	/**
	 * @param request
	 *            current HttpServletRequest
	 * @return the current user object
	 */
	public static User getUser(HttpServletRequest request) {
		return new User(getUserPage(request));
	}

	/**
	 * checks user session for attribute "user node"
	 * 
	 * @param request
	 *            current HttpServletRequest
	 * @return <code>true</code> if the user is authenticated,
	 *         <code>false</code> otherwise
	 */
	public static boolean isAuthenticated(HttpServletRequest request) {
		// don't force a creation of a new session
		HttpSession session = request.getSession(false);
		if (session != null) {
			try {
				return session.getAttribute(ATTRIBUTE_USER_NODE) != null;
			} catch (IllegalStateException e) {
				// can happen if the session has just been invalidated
				logger.debug("IllegalStateException caught"); //$NON-NLS-1$
				return false;
			}
		}

		return false;
	}
}
