/*
 * Created on 25.10.2004
 */
package org.opencms.i18n;

import java.io.UnsupportedEncodingException;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;

import javax.servlet.http.HttpServletRequest;

import org.opencms.file.CmsObject;
import org.opencms.file.CmsProject;
import org.opencms.file.CmsUser;
import org.opencms.i18n.CmsAcceptLanguageHeaderParser;
import org.opencms.i18n.CmsI18nInfo;
import org.opencms.i18n.CmsLocaleManager;
import org.opencms.i18n.I_CmsLocaleHandler;
import org.opencms.main.CmsException;
import org.opencms.main.I_CmsConstants;
import org.opencms.main.OpenCms;

/**
 * @author petermeier
 */
public class SessionLocaleHandler implements I_CmsLocaleHandler {

	/** A cms object that has been initialized with Admin permissions. */
	private CmsObject m_adminCmsObject;

	public static final String SESSION_ATTRIBUTE_KEY_LOCALE =
		"javax.servlet.jsp.jstl.fmt.locale.session";

	public static final String PARAM_SET_LOCALE = "__setlocale";

	public static final String ATTR_LOCALE_SET = "locale.set";

	/**
	 * Constructor, no action is required.<p>
	 */
	public SessionLocaleHandler() {
		// noop
	}

	/**
	 * @see org.opencms.i18n.I_CmsLocaleHandler#initHandler(org.opencms.file.CmsObject)
	 */
	public void initHandler(CmsObject cms) {
		m_adminCmsObject = cms;
	}

	/**
	 * @see org.opencms.i18n.I_CmsLocaleHandler#getI18nInfo(javax.servlet.http.HttpServletRequest, org.opencms.file.CmsUser, org.opencms.file.CmsProject, java.lang.String)
	 */
	public CmsI18nInfo getI18nInfo(
		HttpServletRequest req,
		CmsUser user,
		CmsProject project,
		String resourceName) {

		CmsLocaleManager localeManager = OpenCms.getLocaleManager();

		String encoding;
		List defaultLocales;
		synchronized (m_adminCmsObject) {
			// must switch project id in stored Admin context to match current project
			m_adminCmsObject.getRequestContext().setCurrentProject(project);
			// now get default m_locale names
			defaultLocales =
				localeManager.getDefaultLocales(m_adminCmsObject, resourceName);
			// get the encoding
			try {
				encoding =
					m_adminCmsObject
						.readPropertyObject(
							resourceName,
							I_CmsConstants.C_PROPERTY_CONTENT_ENCODING,
							true)
						.getValue(OpenCms.getSystemInfo().getDefaultEncoding());
			} catch (CmsException e) {
				if (OpenCms.getLog(this).isInfoEnabled()) {
					OpenCms.getLog(this).info(
						"Could not read encoding property for resource "
							+ resourceName,
						e);
				}
				encoding = OpenCms.getSystemInfo().getDefaultEncoding();
			}
		}

		if (req != null) {
			// set the request character encoding
			try {
				req.setCharacterEncoding(encoding);
			} catch (UnsupportedEncodingException e) {
				OpenCms.getLog(this).error(
					"Unsupported encoding set for request '" + encoding + "'",
					e);
			}
			// if we have a __setlocale set it as default locale
			String paramLocale = (String) req.getParameter(PARAM_SET_LOCALE);
			Object localeSet = req.getAttribute(ATTR_LOCALE_SET);
			if ((paramLocale != null) && (localeSet == null)) {
				for (int i = 0; i < defaultLocales.size(); i++) {
					if (defaultLocales.get(i).toString().equals(paramLocale))
						setUserDefinedLocale(
							(Locale) defaultLocales.get(i),
							req);
				}
				req.setAttribute(ATTR_LOCALE_SET, ATTR_LOCALE_SET);
			}
		}

		Locale locale;
		if (req.getSession().getAttribute(SESSION_ATTRIBUTE_KEY_LOCALE)
			== null) {
			// return the first default locale name 
			if ((defaultLocales != null) && (defaultLocales.size() > 0)) {
				locale = (Locale) defaultLocales.get(0);
			} else {
				locale = localeManager.getDefaultLocale();
			}
			/* Parse the HTTP request header, merge with the supported
			 * Locales if possible */
			if (defaultLocales != null && defaultLocales.size() > 0) {
				CmsAcceptLanguageHeaderParser parser =
					new CmsAcceptLanguageHeaderParser(req, locale);
				Locale l;
				Iterator it;
				while (parser.hasNext()) {
					l = (Locale) parser.next();
					it = defaultLocales.iterator();
					while (it.hasNext()) {
						if (((Locale) it.next())
							.getLanguage()
							.equals(l.getLanguage())) {
							locale = l;
							break;
						}
					}
				}
			}
		} /* User-selected locale is found in the session */
		else {
			locale =
				(Locale) req.getSession().getAttribute(
					SESSION_ATTRIBUTE_KEY_LOCALE);
		}
		return new CmsI18nInfo(locale, encoding);
	}

	/**
	 * Sets the locale to a value the user has selected
	 * @param locale The locale the user selected
	 */
	public void setUserDefinedLocale(Locale locale, HttpServletRequest req) {
		req.getSession().setAttribute(SESSION_ATTRIBUTE_KEY_LOCALE, locale);
	}

	/**
	 * Resets the locale the user has selected to the default value
	 */
	public void resetUserDefinedLocale(HttpServletRequest req) {
		req.getSession().setAttribute(
			SESSION_ATTRIBUTE_KEY_LOCALE,
			OpenCms.getLocaleManager().getDefaultLocale());
	}

}
