package org.pac4j.play.store;

import javax.inject.Inject;
import javax.inject.Singleton;

import com.google.inject.Provider;
import org.pac4j.core.context.Pac4jConstants;
import org.pac4j.core.context.session.SessionStore;
import org.pac4j.core.util.CommonHelper;
import org.pac4j.play.PlayWebContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import play.cache.SyncCacheApi;
import play.mvc.Http;

import java.util.HashMap;
import java.util.Map;

/**
 * This session store internally uses the {@link PlayCacheStore} which uses the Play Cache, only an identifier is saved into the Play session.
 *
 * @author Jerome Leleu
 * @since 2.0.0
 */
@Singleton
public class PlayCacheSessionStore implements PlaySessionStore {

    private static final Logger logger = LoggerFactory.getLogger(PlayCacheSessionStore.class);

    private final static String SEPARATOR = "$";

    // prefix for the cache
    private String prefix = "";

    // store
    private final PlayCacheStore<String, Map<String, Object>> store;

    @Inject
    public PlayCacheSessionStore(final SyncCacheApi cache) {
        this.store = new PlayCacheStore<>(cache);
        setDefaultTimeout();
    }

    public PlayCacheSessionStore(final Provider<SyncCacheApi> cacheProvider) {
        this.store = new PlayCacheStore<>(cacheProvider);
        setDefaultTimeout();
    }

    String getKey(final String sessionId, final String key) {
        return prefix + SEPARATOR + sessionId + SEPARATOR + key;
    }

    @Override
    public String getOrCreateSessionId(final PlayWebContext context) {
        final Http.Session session = context.getJavaSession();
        // get current sessionId
        String sessionId = session.get(Pac4jConstants.SESSION_ID);
        logger.trace("retrieved sessionId: {}", sessionId);
        // if null, generate a new one
        if (sessionId == null) {
            // generate id for session
            sessionId = java.util.UUID.randomUUID().toString();
            logger.debug("generated sessionId: {}", sessionId);
            // and save it to session
            session.put(Pac4jConstants.SESSION_ID, sessionId);
        }
        return sessionId;
    }

    @Override
    public Object get(final PlayWebContext context, final String key) {
        final String sessionId = getOrCreateSessionId(context);
        final Map<String, Object> values = store.get(sessionId);
        if (values != null) {
            return values.get(key);
        }
        return null;
    }

    @Override
    public void set(final PlayWebContext context, final String key, final Object value) {
        final String sessionId = getOrCreateSessionId(context);
        Map<String, Object> values = store.get(sessionId);
        if (values == null) {
            values = new HashMap<>();
        }
        values.put(key, value);
        store.set(sessionId, values);
    }

    @Override
    public boolean destroySession(final PlayWebContext context) {
        final Http.Session session = context.getJavaSession();
        final String sessionId = session.get(Pac4jConstants.SESSION_ID);
        if (sessionId != null) {
            session.clear();
            return true;
        }
        return false;
    }

    @Override
    public Object getTrackableSession(final PlayWebContext context) {
        return context.getJavaSession().get(Pac4jConstants.SESSION_ID);
    }

    @Override
    public SessionStore<PlayWebContext> buildFromTrackableSession(final PlayWebContext context, final Object trackableSession) {
        context.getJavaSession().put(Pac4jConstants.SESSION_ID, (String) trackableSession);
        return this;
    }

    @Override
    public boolean renewSession(final PlayWebContext context) {
        final String oldSessionId = this.getOrCreateSessionId(context);
        final Map<String, Object> oldData = store.get(oldSessionId);

        final Http.Session session = context.getJavaSession();
        session.remove(Pac4jConstants.SESSION_ID);

        final String newSessionId = this.getOrCreateSessionId(context);
        if (oldData != null) {
            store.set(newSessionId, oldData);
        }

        logger.debug("Renewing session: {} -> {}", oldSessionId, newSessionId);
        return true;
    }

    public String getPrefix() {
        return prefix;
    }

    public void setPrefix(final String prefix) {
        this.prefix = prefix;
    }

    public int getTimeout() {
        return this.store.getTimeout();
    }

    public void setTimeout(final int timeout) {
        this.store.setTimeout(timeout);
    }

    public PlayCacheStore<String, Map<String, Object>> getStore() {
        return store;
    }

    protected void setDefaultTimeout() {
        // 1 hour = 3600 seconds
        this.store.setTimeout(3600);
    }

    @Override
    public String toString() {
        return CommonHelper.toNiceString(this.getClass(), "store", store, "prefix", prefix, "timeout", getTimeout());
    }
}

@@ -2382,32 +2382,61 @@
 get(sessionId);%0A
+        Object value = null;%0A
         if (valu
@@ -2461,22 +2461,23 @@
         
-return
+value =
  values.
@@ -2488,32 +2488,116 @@
 key);%0A        %7D%0A
+        logger.trace(%22get, sessionId = %7B%7D, key = %7B%7D -%3E %7B%7D%22, sessionId, key, value);%0A
         return n
@@ -2595,20 +2595,21 @@
  return 
-null
+value
 ;%0A    %7D%0A
@@ -2906,32 +2906,122 @@
 %3C%3E();%0A        %7D%0A
+        logger.trace(%22set, sessionId = %7B%7D, key = %7B%7D, value = %7B%7D%22, sessionId, key, value);%0A
         values.p

Add TRACE logs in the PlayCacheSessionStore