/*
 * Copyright 2006-2007 Queplix Corp.
 *
 * Licensed under the Queplix Public License, Version 1.1.1 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.queplix.com/solutions/commercial-open-source/queplix-public-license/
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 *
 */
package com.queplix.core.integrator.security;

import com.queplix.core.client.app.vo.LoginRequestObject;
import com.queplix.core.modules.config.utils.SysPropertyManager;
import com.queplix.core.utils.SystemHelper;
import com.queplix.core.utils.log.AbstractLogger;
import com.queplix.core.utils.log.Log;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

/**
 * Helper class for web login-related operations.
 *
 * @author Kozmin Sergey
 * @since 16.01.2007
 */
public final class WebLoginManager {
    // ====================================================== System properties.

    /**
     * Customer hosts list (system property).
     */
    public static final String CUSTOMER_HOSTS_PROP = "CustomerHosts";

    private static final String SESSION_TIMEOUT_PROP = "SESSION_TIMEOUT";
    private static final String SESSION_TIMEOUT_WARN_BEFORE_PROP
            = "SESSION_TIMEOUT_WARN_BEFORE";

    // ======================================================== Other constants

    // Logger reference.
    private static final AbstractLogger logger = Log.getLog(
            WebLoginManager.class);

    // Session attributes.
    // Logon data (HTTP session attribute).
    public static final String LOGON_SESSION_ATTR = "security.session";

    /* todo uncomment one if you need it or remove at all
   // Login name (HTTP session attribute).
   private static final String LOGIN_ATTR = "logon.loginName";

   // User data HTTP session attribute).
   private static final String USER_ATTR = "logon.user";

   // Roles list (HTTP session attribute).
   private static final String ROLES_ATTR = "logon.roles";

   // Selected role HTTP session attribute).
   private static final String SELECTED_ROLE_ATTR = "logon.selected.role";

   // Error message (HTTP session attribute).
   private static final String ERROR_ATTR = "logon.errorMessage";

   // GUI focuses cache (HTTP session attribute).
   private static final String FOCUS_CACHE_ATTR = "focus.cache";

   // Language ID (HTTP session attribute).
   private static final String LANGUAGE_ID_ATTR = "languageID";
    */
    // ========================================================= Public methods

    /**
     * LogonSession getter.
     *
     * @param request HTTP request
     * @return user logon session
     */
    public static LogonSession getLogonSession(HttpServletRequest request) {
        // Get HTTP session.
        HttpSession session = getHttpSession(request);
        if(session == null) {
            throw new SessionExpiredException();
        }

        // Get logon session.
        Object attr = session.getAttribute(LOGON_SESSION_ATTR);
        if(attr == null || !(attr instanceof LogonSession)) {
            throw new IllegalStateException("Logon session is expired. ");
        }

        // Ok.
        return (LogonSession) attr;
    }

    /**
     * Current language getter.
     *
     * @param ls logon session
     * @return the language ID
     */
    public static String getLogonLanguage(LogonSession ls) {
        // Take language from logon session.
        String languageID = ls.getUser().getLangID();

        // Return current language or default one, if none found.
        return (languageID != null ? languageID:SystemHelper.DEFAULT_LANGUAGE);
    }

    /**
     * LogonSession setter.
     * <p/>
     * Makes a new user logon session and stores it in the HTTP session.
     * </p>
     *
     * @param request  HTTP request
     * @param login    user login
     * @param password user password
     * @return LogonSession logon session
     * @throws NoSuchUserException thrown if user with the given login and password doesn't exist.
     */
    public static LogonSession setLogonSession(HttpServletRequest request,
                                               LoginRequestObject lro)
            throws BadNameOrPasswordException {
        User user = AccessRightsManager.getUser(lro.getLogin(), lro.getPassword());
        cleanHttpSession(request);
        HttpSession session = getHttpSession(request);

        LogonSession logonSession = new LogonSession(user, session.getId());
        logonSession.setHost(request.getLocalAddr());
        logonSession.setRemoteAddress(request.getRemoteAddr());
        logonSession.setPortalType(lro.getPortalType());
        session.setAttribute(LOGON_SESSION_ATTR, logonSession);
        int sessionTimeoutSeconds = getSessionTimeoutSeconds();
        if(sessionTimeoutSeconds > 0) {
            session.setMaxInactiveInterval(sessionTimeoutSeconds);
        }

        return logonSession;
    }

    /**
     * HTTP session getter.
     *
     * @param request HTTP request
     * @return an HTTP session (might be <b>null</b>)
     */
    public static HttpSession getHttpSession(HttpServletRequest request) {
        return request.getSession();
    }

    /**
     * Clean a HTTP session.
     *
     * @param request HTTP request
     */
    public static void cleanHttpSession(HttpServletRequest request) {
        HttpSession session = request.getSession(false);
        if(session != null) {
            session.invalidate();
        }
    }

    private static int getSessionTimeoutSeconds() {
        return getSessionTimeoutMinutes() * 60;
    }

    /**
     * User logon session timeout system property.
     *
     * @return property value in minutes
     */
    public static int getSessionTimeoutMinutes() {
        return getSessionTimeoutProperty(SESSION_TIMEOUT_PROP);
    }

    /**
     * How many minutes before session timeout display a warning.
     *
     * @return property value
     */
    public static int getSessionTimeoutWarnBeforeMinutes() {
        return getSessionTimeoutProperty(SESSION_TIMEOUT_WARN_BEFORE_PROP);
    }

    private static int getSessionTimeoutProperty(String propertyName) {
        int res;
        String property = SysPropertyManager.getProperty(propertyName);
        try {
            res = Integer.parseInt(property);
        } catch (NumberFormatException nfe) {
            res = 0;
        }
        return res;
    }
}
