package org.gcube.application.cms.caches;

import lombok.Getter;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.gcube.application.geoportal.common.model.rest.ConfigurationException;

import java.time.LocalDateTime;
import java.time.temporal.TemporalAmount;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
@RequiredArgsConstructor
public abstract class TimedMap <K,V>   implements Cache<K,V> {

    protected ConcurrentHashMap<K, TTLObject<V>> scopeMap=new ConcurrentHashMap<K,TTLObject<V>>();

    @Setter
    @Getter
    protected TemporalAmount TTL=null;

    @NonNull
    protected String name;

    @Override
    public V get(K key) throws ConfigurationException {
        log.trace(name+" : obtaining object by  "+key);

        TTLObject<V> found=scopeMap.get(key);

        if(found== null){
            log.debug(name+" : init object for key "+key);
            TTLObject<V> toPut=new TTLObject<V>(LocalDateTime.now(),retrieveObject(key));
            scopeMap.put(key, toPut);
            return toPut.getTheObject();
        }

        if(getTTL()!=null) {
            if(found.getCreationTime().plus(getTTL()).isBefore(LocalDateTime.now())) {
                log.debug(name+" : elapsed TTL, disposing..");
                dispose(found.getTheObject());
                TTLObject<V> newer=new TTLObject<V>(LocalDateTime.now(),retrieveObject(key));
                scopeMap.put(key, newer);
                found=scopeMap.get(key);
            }
        }else {log.trace(name+" : TTL is null, never disposing..");}
        log.trace(name+"Returning {} ",found);
        return found.getTheObject();
    }

    protected abstract V retrieveObject(K key) throws ConfigurationException;
    protected void dispose(V toDispose){};
}
