package org.cache2k.benchmark.thirdparty;

/*
 * #%L
 * cache2k-benchmark-thirdparty
 * %%
 * Copyright (C) 2013 - 2016 headissue GmbH, Munich
 * %%
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as
 * published by the Free Software Foundation, either version 3 of the 
 * License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public 
 * License along with this program.  If not, see
 * <http://www.gnu.org/licenses/gpl-3.0.html>.
 * #L%
 */

import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.config.CacheConfiguration;
import net.sf.ehcache.config.PersistenceConfiguration;
import net.sf.ehcache.constructs.blocking.CacheEntryFactory;
import net.sf.ehcache.constructs.blocking.SelfPopulatingCache;
import net.sf.ehcache.store.MemoryStoreEvictionPolicy;
import org.cache2k.benchmark.BenchmarkCache;
import org.cache2k.benchmark.BenchmarkCacheFactory;

/**
 * @author Jens Wilke; created: 2013-12-08
 */
public class EhCacheFactory extends BenchmarkCacheFactory {

  static final String CACHE_NAME = "testCache";

  Algorithm algorithm = Algorithm.DEFAULT;

  @Override
  public BenchmarkCache<Integer, Integer> create(int _maxElements) {
    return this.create(null, _maxElements);
  }

  @Override
  public BenchmarkCache<Integer, Integer> create(Source _source, int _maxElements) {
    return new MyBenchmarkCache(_source, createCacheConfiguration(_maxElements));
  }

  protected CacheManager getManager() {
    return CacheManager.getInstance();
  }

  protected CacheConfiguration createCacheConfiguration(int _maxElements) {
    MemoryStoreEvictionPolicy _policy = MemoryStoreEvictionPolicy.LRU;
    switch (algorithm) {
      case CLOCK: _policy = MemoryStoreEvictionPolicy.CLOCK; break;
    }
    CacheConfiguration c = new CacheConfiguration(CACHE_NAME, _maxElements)
      .memoryStoreEvictionPolicy(_policy)
      .eternal(true)
      .diskExpiryThreadIntervalSeconds(0)
      .persistence(new PersistenceConfiguration().strategy(PersistenceConfiguration.Strategy.NONE));
    if (withExpiry) {
      c.setEternal(false);
      c.setTimeToLiveSeconds(5 * 60);
    }
    return c;
  }

  public EhCacheFactory algorithm(Algorithm v) {
    algorithm = v;
    return this;
  }

  static class MyCacheEntryFactory implements CacheEntryFactory {

    int missCount;

    @Override
    public Object createEntry(Object key) throws Exception {
      missCount++;
      return key;
    }

  }

  static class DelegatingEntryFactory extends MyCacheEntryFactory {

    Source source;

    DelegatingEntryFactory(Source source) {
      this.source = source;
    }

    @Override
    public Object createEntry(Object key) throws Exception {
      missCount++;
      return source.get((Integer) key);
    }

  }

  class MyBenchmarkCache extends BenchmarkCache<Integer, Integer> {

    CacheConfiguration config;
    MyCacheEntryFactory entryFactory;
    SelfPopulatingCache cache;

    MyBenchmarkCache(Source _source, CacheConfiguration v) {
      this.config = v;
      Cache _testCache = new net.sf.ehcache.Cache(v);
      getManager().addCache(_testCache);
      if (_source != null) {
        entryFactory = new DelegatingEntryFactory(_source);
      } else {
        entryFactory = new MyCacheEntryFactory();
      }
      cache = new SelfPopulatingCache(_testCache, entryFactory);
    }

    @Override
    public int getCacheSize() {
      return (int) config.getMaxEntriesLocalHeap();
    }

    @Override
    public Integer get(Integer key) {
      return (Integer) cache.get(key).getObjectValue();
    }

    @Override
    public void destroy() {
      CacheManager.getInstance().removeCache("testCache");
    }

    @Override
    public int getMissCount() {
      return entryFactory.missCount;
    }
  }

  public enum Algorithm { DEFAULT, CLOCK }

}

@@ -884,16 +884,47 @@
 anager;%0A
+import net.sf.ehcache.Ehcache;%0A
 import n
@@ -3296,31 +3296,19 @@
 ry;%0A    
-SelfPopulatingC
+Ehc
 ache cac

use EHCache interface