package br.ufrgs.inf.prosoft.adaptivecaching.cachemanager.util;

import br.ufrgs.inf.prosoft.adaptivecaching.cachemanager.extensions.ehcache.EhCacheCacheManager;
import br.ufrgs.inf.prosoft.adaptivecaching.cachemanager.extensions.guava.GuavaCacheManager;
import br.ufrgs.inf.prosoft.adaptivecaching.cachemanager.model.CacheManager;
import br.ufrgs.inf.prosoft.adaptivecaching.configuration.types.CacheProviderType;
import br.ufrgs.inf.prosoft.adaptivecaching.exceptions.CacheProviderException;
import net.sf.ehcache.config.CacheConfiguration;
import net.sf.ehcache.config.PersistenceConfiguration;
import net.sf.ehcache.management.ManagementService;
import net.sf.ehcache.store.MemoryStoreEvictionPolicy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.management.MBeanServer;
import java.lang.management.ManagementFactory;

/**
 * The type Cache manager factory.
 */
public class CacheManagerFactory {
    /**
     * The Logger.
     */
    static Logger logger = LoggerFactory.getLogger(CacheManagerFactory.class);

    /**
     * Gets cache manager.
     *
     * @param cacheProviderType the cache provider type
     * @param expiryInterval    the expiry interval
     * @return the cache manager
     */
    public static CacheManager getCacheManager(CacheProviderType cacheProviderType, long expiryInterval) {
        switch (cacheProviderType) {
            case GUAVA:
                logger.debug("Cache provider is configured to Guava.");
                return new GuavaCacheManager();
//            case MEMCACHED:
//                break;
//            case REDIS:
            //redis cache manager
//        JedisConnectionFactory cf = new JedisConnectionFactory();
//        cf.setHostName("127.0.0.1");
//        cf.setPort(6379);
//        RedisTemplate<String, String> redisTemplate = new RedisTemplate<String, String>();
//        redisTemplate.setConnectionFactory(cf);
//        RedisCacheManager redisCacheManager = new RedisCacheManager(redisTemplate);
//        redisCacheManager.setDefaultExpiration(300);
//        this.cacheManager = redisCacheManager;
//        this.cache = redisCacheManager.getCache("test");
//                break;
//            case CAFFEINE:
//                break;
            case EHCACHE:
                logger.debug("Cache provider is configured to EhCache.");
                net.sf.ehcache.CacheManager cm = net.sf.ehcache.CacheManager.newInstance();

                //monitoring hit and miss ratio:
                MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
                ManagementService.registerMBeans(cm, mBeanServer, false, false, false, true);

                //Create a Cache specifying its configuration.
                net.sf.ehcache.Cache adaptiveCache = new net.sf.ehcache.Cache(
                        new CacheConfiguration("adaptivecaching", 10000)
                                .memoryStoreEvictionPolicy(MemoryStoreEvictionPolicy.LRU)
                                //.eternal(true)
                                .overflowToOffHeap(false)
                                .timeToLiveSeconds(expiryInterval)
                                .persistence(new PersistenceConfiguration().strategy(PersistenceConfiguration.Strategy.NONE)));
                cm.addCache(adaptiveCache);
                return new EhCacheCacheManager(cm);
            default:
                throw new CacheProviderException("The specified cache manager [" + cacheProviderType + "] does not have an available implementation.");
        }
    }
}
