package ru.bgcrm.servlet.filter;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

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.http.HttpServletRequest;

import org.bgerp.app.cfg.Setup;
import org.bgerp.app.l10n.Localization;
import org.bgerp.app.l10n.Localizer;
import org.bgerp.app.servlet.Interface;
import org.bgerp.app.servlet.filter.AuthFilter;
import org.bgerp.app.servlet.jsp.UiFunction;
import org.bgerp.app.servlet.util.ServletUtils;
import org.bgerp.cache.CustomerGroupCache;
import org.bgerp.cache.ParameterCache;
import org.bgerp.cache.ProcessQueueCache;
import org.bgerp.cache.ProcessTypeCache;
import org.bgerp.cache.UserCache;
import org.bgerp.cache.UserGroupRoleCache;
import org.bgerp.dao.expression.Expression;
import org.bgerp.util.Log;
import org.bgerp.util.sql.pool.ConnectionPool;

import ru.bgcrm.model.process.ProcessType;
import ru.bgcrm.model.user.User;
import ru.bgcrm.plugin.PluginManager;

public class SetRequestParamsFilter implements Filter {
    public static final String REQUEST_KEY_LOCALIZER = "l";

    private static final class JSP {
        private static final Log log = Log.getLog();
    }

    public void destroy() {}

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        Map<String, Object> variables = getContextVariables((HttpServletRequest) request);
        Expression.setExpressionContextUtils(variables);

        for (Map.Entry<String, Object> me : variables.entrySet())
            request.setAttribute(me.getKey(), me.getValue());

        // 'l' object is set only for action calls and open URLs like /process/nnn, but not to JSP after them
        if (!ServletUtils.getRequestURI((HttpServletRequest) request).endsWith(".jsp") ||
                // exception is the 'usermob' interface, where JSP templates might be called directly
                Interface.USER_MOB.equals(Interface.getIface((HttpServletRequest) request)))
            request.setAttribute(REQUEST_KEY_LOCALIZER, getLocalizer(request));

        request.setAttribute("ui", UiFunction.INSTANCE);

        request.setAttribute("log", JSP.log);

        chain.doFilter(request, response);
    }

    private Localizer getLocalizer(ServletRequest request) {
        var result = Localization.getLocalizer((HttpServletRequest) request);
        if (result == null)
            result = Localization.getLocalizer();
        return result;
    }

    /**
     * Set the following objects into the HttpRequest or another context:<br/>
     * <b>ctxSetup</b> {@link Setup#getSetup} global configuration<br/>
     *
     * <b>ctxCustomerGroupMap</b> {@link CustomerGroupCache#getGroupMap()} Map with customer groups<br/>
     * <b>ctxCustomerGroupList</b> {@link CustomerGroupCache#getGroupList()} List with customer groups<br/>
     *
     * <b>ctxUser</b> {@link User} the current user<br/>
     *
     * <b>ctxPluginManager</b> {@link PluginManager#getInstance()}<br/>
     *
     * <b>ctxUserCache</b> static instance of {@link UserCache}</br>
     *
     * <b>ctxUserList</b> {@link UserCache#getUserList()} List of system users<br/>
     * <b>ctxUserMap</b> {@link UserCache#getUserMap()} Map of system users<br/>
     *
     * <b>ctxUserGroupRoleList</b> {@link UserGroupRoleCache#getUserGroupRoleList()} List of group roles in processes<br/>
     * <b>ctxUserGroupRoleMap</b> {@link UserGroupRoleCache#getUserGroupRoleMap()} Map of group roles in processes<br/>
     *
     * <b>ctxUserGroupList</b> {@link UserCache#getUserGroupList()} List of user groups<br/>
     * <b>ctxUserGroupMap</b> {@link UserCache#getUserGroupMap()} Map of user groups<br/>
     * <b>ctxUserGroupFullTitledList</b> {@link UserCache#getUserGroupFullTitledList()} List of user groups whose names include the full path<br/>
     * <b>ctxUserGroupFullTitledMap</b> {@link UserCache#getUserGroupFullTitledList()} Map of user groups whose names include the full path<br/>
     *
     * <b>ctxUserPermsetList</b> {@link UserCache#getUserPermsetList()} List of user permission sets<br/>
     * <b>ctxUserPermsetMap</b> {@link UserCache#getUserPermsetMap()} Map of user permission sets<br/>
     *
     * <b>ctxDataSource</b> {@link Setup#getDataSource()} DataSource — connection pool to the DB for use in JSP<br/>
     * <b>ctxSlaveDataSource</b> {@link Setup#getSlaveDataSource()} DataSource — connection pool to the Slave DB for use in JSP<br/>
     *
     * <b>ctxProcessTypeMap</b> {@link ProcessTypeCache#getProcessTypeMap()} Map with process types<br/>
     * <b>ctxProcessTypeTreeRoot</b> {@link ProcessType} — the root node of the process tree<br/>
     * <b>ctxProcessStatusList</b> {@link ProcessTypeCache#getProcessStatusList()} List of process statuses<br/>
     * <b>ctxProcessStatusMap</b> {@link ProcessTypeCache#getProcessStatusMap()} Map of process statuses<br/>
     * <b>ctxProcessQueueMap</b> {@link ProcessTypeCache#getProcessQueueMap()} Map of process queues<br/>
     * <b>ctxProcessQueueList</b> {@link ProcessTypeCache#getProcessQueueList()} List of process queues<br/>
     *
     * <b>ctxParameterCache</b> static instance of {@link ParameterCache}<br/>
     *
     * <b>ctxParameterMap</b> {@link ParameterCache#getParameterMap()} parameter Map<br/>
     */
    public static Map<String, Object> getContextVariables(HttpServletRequest request) {
        Map<String, Object> result = new HashMap<>(30);

        result.put("ctxSetup", Setup.getSetup());

        result.put("ctxCustomerGroupMap", CustomerGroupCache.getGroupMap());
        result.put("ctxCustomerGroupList", CustomerGroupCache.getGroupList());

        if (request != null) {
            result.put("ctxUser", AuthFilter.getUser(request));
            result.put("ctxIface", Interface.getIface(request));
        }

        result.put("ctxPluginManager", PluginManager.getInstance());

        result.put("ctxUserCache", UserCache.HOLDER.getInstance());

        result.put("ctxUserList", UserCache.getUserList());
        result.put("ctxUserMap", UserCache.getUserMap());

        result.put("ctxUserGroupRoleList", UserGroupRoleCache.getUserGroupRoleList());
        result.put("ctxUserGroupRoleMap", UserGroupRoleCache.getUserGroupRoleMap());

        result.put("ctxUserGroupList", UserCache.getUserGroupList());
        result.put("ctxUserGroupMap", UserCache.getUserGroupMap());
        result.put("ctxUserGroupFullTitledList", UserCache.getUserGroupFullTitledList());
        result.put("ctxUserGroupFullTitledMap", UserCache.getUserGroupFullTitledMap());

        result.put("ctxUserPermsetList", UserCache.getUserPermsetList());
        result.put("ctxUserPermsetMap", UserCache.getUserPermsetMap());

        ConnectionPool connectionPool = Setup.getSetup().getConnectionPool();

        result.put("ctxDataSource", connectionPool.getDataSource());
        result.put("ctxSlaveDataSource", connectionPool.getSlaveDataSource());

        result.put("ctxProcessTypeMap", ProcessTypeCache.getProcessTypeMap());
        result.put("ctxProcessTypeTreeRoot", ProcessTypeCache.getTypeTreeRoot());
        result.put("ctxProcessStatusList", ProcessTypeCache.getStatusList());
        result.put("ctxProcessStatusMap", ProcessTypeCache.getStatusMap());
        result.put("ctxProcessQueueMap", ProcessQueueCache.getQueueMap());
        result.put("ctxProcessQueueList", ProcessQueueCache.getQueueList());

        result.put("ctxParameterCache", ParameterCache.HOLDER.getInstance());

        result.put("ctxParameterMap", ParameterCache.getParameterMap());

        return result;
    }

    public void init(FilterConfig filterConfig) throws ServletException {}
}