package br.ufrgs.inf.prosoft.adaptivecaching.cachemanager.extensions.ehcache;

import br.ufrgs.inf.prosoft.adaptivecaching.cachemanager.extensions.AbstractCacheManager;
import br.ufrgs.inf.prosoft.adaptivecaching.cachemanager.model.Cache;
import net.sf.ehcache.Ehcache;
import net.sf.ehcache.Status;

import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedHashSet;

/**
 * CacheManager backed by an EhCache {@link net.sf.ehcache.CacheManager}.
 */
public class EhCacheCacheManager extends AbstractCacheManager {

    private net.sf.ehcache.CacheManager cacheManager;


    /**
     * Create a new EhCacheCacheManager, setting the target EhCache CacheManager
     * through the {@link #setCacheManager} bean property.
     */
    public EhCacheCacheManager() {
        setCacheManager(EhCacheManagerUtils.buildCacheManager());
        // Early cache initialization on startup
        initializeCaches();
    }

    /**
     * Create a new EhCacheCacheManager for the given backing EhCache CacheManager.
     *
     * @param cacheManager the backing EhCache {@link net.sf.ehcache.CacheManager}
     */
    public EhCacheCacheManager(net.sf.ehcache.CacheManager cacheManager) {
        this.cacheManager = cacheManager;
    }

    /**
     * Return the backing EhCache {@link net.sf.ehcache.CacheManager}.
     *
     * @return the cache manager
     */
    public net.sf.ehcache.CacheManager getCacheManager() {
        return this.cacheManager;
    }

    /**
     * Set the backing EhCache {@link net.sf.ehcache.CacheManager}.
     *
     * @param cacheManager the cache manager
     */
    public void setCacheManager(net.sf.ehcache.CacheManager cacheManager) {
        this.cacheManager = cacheManager;
    }

    @Override
    protected Collection<Cache> loadCaches() {
        Status status = getCacheManager().getStatus();
        if (!Status.STATUS_ALIVE.equals(status)) {
            throw new IllegalStateException(
                    "An 'alive' EhCache CacheManager is required - current cache is " + status.toString());
        }

        String[] names = getCacheManager().getCacheNames();
        Collection<Cache> caches = new LinkedHashSet<>(names.length);
        for (String name : names) {
            caches.add(new EhCacheCache(getCacheManager().getEhcache(name)));
        }
        return caches;
    }

    @Override
    protected Cache getMissingCache(String name) {
        // Check the EhCache cache again (in case the cache was added at runtime)
        Ehcache ehcache = getCacheManager().getEhcache(name);
        if (ehcache != null) {
            return new EhCacheCache(ehcache);
        }
        return null;
    }

    /**
     * Add cache.
     *
     * @param name the name
     */
    public void addCache(String name){
        cacheManager.addCache(name);
    }

    @Override
    public Cache getCache(String name) {
        return new EhCacheCache(cacheManager.getCache(name));
    }

    @Override
    public Collection<String> getCacheNames() {
        return Arrays.asList(cacheManager.getCacheNames());
    }
}
