package com.apobates.forum.utils.cache;

import java.time.LocalDateTime;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import com.apobates.forum.utils.DateTimeUtils;

/**
 * 延迟更新Map,要求Key唯一
 * 
 * @author xiaofanku
 * @since 20200726
 */
public final class DelayedUpdateMap {
    //key=SessionID, value=缓存的时间/上次保存的时间
    private final ConcurrentMap<String, LocalDateTime> mapKeyToHeavy;
    //缓存的时长(单位分钟)
    private final int cacheUnit;
    
    public DelayedUpdateMap(final int cacheUnit) {
        this.cacheUnit = cacheUnit;
        this.mapKeyToHeavy = new ConcurrentHashMap<>();
    }
    
    /**
     * 更新缓存
     * 
     * @param ele DelayedUpdateMapElement的实现
     * @return 返回值表示缓存更新是否成功,true更新成功
     */
    public boolean put(final DelayedUpdateMapElement ele){
        Objects.requireNonNull(ele);
        LocalDateTime newVal = mapKeyToHeavy.computeIfAbsent(ele.getUnionKey(), key->ele.getActiveDateTime());
        if(newVal.compareTo(ele.getActiveDateTime()) == 0){
            return true;
        }
        newVal = mapKeyToHeavy.computeIfPresent(ele.getUnionKey(), (key, oldActiveTime)->{
            if(DateTimeUtils.diffMinutes(ele.getActiveDateTime(), oldActiveTime) >= cacheUnit){
                return ele.getActiveDateTime();
            }
            return oldActiveTime;
        });
        return newVal.compareTo(ele.getActiveDateTime()) == 0;
    }
    
    /**
     * 更新缓存
     * 供测试使用
     * @param ele DelayedUpdateMapElement的实现
     * @param action 缓存更新成功后的消费动作
     */
    public void put(final DelayedUpdateMapElement ele, Consumer<LocalDateTime> action){
        if(put(ele)){
            action.accept(ele.getActiveDateTime());
        }
    }
    
    /**
     * 消费缓存中的SessionKey和更近的活跃日期
     * 供测试使用
     * @param action 消费动作
     */
    public void each(BiConsumer<String, LocalDateTime> action){
        mapKeyToHeavy.forEach(action);
    }
}
