package org.keycloak.models.sessions.infinispan.initializer;

import org.infinispan.Cache;
import org.infinispan.configuration.cache.CacheMode;
import org.infinispan.configuration.cache.Configuration;
import org.infinispan.configuration.cache.ConfigurationBuilder;
import org.infinispan.configuration.global.GlobalConfigurationBuilder;
import org.infinispan.manager.DefaultCacheManager;
import org.infinispan.manager.EmbeddedCacheManager;
import org.infinispan.notifications.Listener;
import org.infinispan.notifications.cachelistener.annotation.CacheEntriesEvicted;
import org.infinispan.notifications.cachelistener.annotation.CacheEntryInvalidated;
import org.infinispan.notifications.cachelistener.annotation.CacheEntryRemoved;
import org.infinispan.notifications.cachelistener.event.CacheEntriesEvictedEvent;
import org.infinispan.notifications.cachelistener.event.CacheEntryInvalidatedEvent;
import org.infinispan.notifications.cachelistener.event.CacheEntryRemovedEvent;
import org.junit.Ignore;
import org.junit.Test;
import org.keycloak.connections.infinispan.InfinispanConnectionProvider;

/**
 * Just a simple test to see how distributed caches work
 *
 * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
 * @version $Revision: 1 $
 */
@Ignore
public class ClusteredCacheBehaviorTest {
    public EmbeddedCacheManager createManager() {
        GlobalConfigurationBuilder gcb = new GlobalConfigurationBuilder();

        boolean clustered = true;
        boolean async = false;
        boolean allowDuplicateJMXDomains = true;

        if (clustered) {
            gcb.transport().defaultTransport();
        }
        gcb.globalJmxStatistics().allowDuplicateDomains(allowDuplicateJMXDomains);

        EmbeddedCacheManager cacheManager = new DefaultCacheManager(gcb.build());


        ConfigurationBuilder invalidationConfigBuilder = new ConfigurationBuilder();
        if (clustered) {
            invalidationConfigBuilder.clustering().cacheMode(async ? CacheMode.INVALIDATION_ASYNC : CacheMode.INVALIDATION_SYNC);
        }
        Configuration invalidationCacheConfiguration = invalidationConfigBuilder.build();

        cacheManager.defineConfiguration(InfinispanConnectionProvider.REALM_CACHE_NAME, invalidationCacheConfiguration);
        return cacheManager;

    }

    @Listener
    public static class CacheListener {
        String name;

        public CacheListener(String name) {
            this.name = name;
        }



        @CacheEntryRemoved
        public void removed(CacheEntryRemovedEvent<String, Object> event) {
            if (event.isPre()) {
                System.out.println("Listener '" + name + "' entry removed");
            }
        }

        @CacheEntryInvalidated
        public void removed(CacheEntryInvalidatedEvent<String, Object> event) {
            if (event.isPre()) {
                System.out.println("Listener '" + name + "' entry invalidated");

            }
        }

        @CacheEntriesEvicted
        public void evicted(CacheEntriesEvictedEvent<String, Object> event) {
            System.out.println("Listener '" + name + "' entry evicted");

        }

    }

    @Test
    public void testListener() throws Exception {
        EmbeddedCacheManager node1 = createManager();
        EmbeddedCacheManager node2 = createManager();
        Cache<String, Object> node1Cache = node1.getCache(InfinispanConnectionProvider.REALM_CACHE_NAME);
        node1Cache.addListener(new CacheListener("node1"));
        Cache<String, Object> node2Cache = node2.getCache(InfinispanConnectionProvider.REALM_CACHE_NAME);
        node2Cache.addListener(new CacheListener("node2"));

        System.out.println("node1 create entry");
        node1Cache.put("key", "node1");
        System.out.println("node2 create entry");
        node2Cache.put("key", "node2");
        System.out.println("node1 remove entry");
        node1Cache.remove("key");
        System.out.println("node2 remove entry");
        node2Cache.remove("key");
        System.out.println("node2 put entry");
        node2Cache.put("key", "node2");
        System.out.println("node2 evict entry");
        node2Cache.evict("key");
        System.out.println("node1/node2 putExternal entry");
        node1Cache.putForExternalRead("key", "common");
        node2Cache.putForExternalRead("key", "common");
        System.out.println("node2 remove entry");
        node2Cache.remove("key");


    }
}
