package com.njzscloud.common.cache;

import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.function.Supplier;

public class DualCache implements Cache {
    private final FirstCache FIRST_CACHE;
    private final SecondCache SECOND_CACHE;
    private final ReentrantReadWriteLock DUAL_CACHE_LOCK = new ReentrantReadWriteLock();

    public DualCache(int capacity, long firstTimeout, long secondTimeout) {
        FIRST_CACHE = new FirstCache(capacity, firstTimeout);
        SECOND_CACHE = new SecondCache(secondTimeout);
    }

    public <T> T get(String key) {
        DUAL_CACHE_LOCK.readLock().lock();
        try {
            return FIRST_CACHE.get(key, () -> SECOND_CACHE.get(key));
        } finally {
            DUAL_CACHE_LOCK.readLock().unlock();
        }
    }

    public <T> T get(String key, Supplier<T> supplier) {
        DUAL_CACHE_LOCK.readLock().lock();
        try {
            return (T) FIRST_CACHE.get(key, () -> SECOND_CACHE.get(key, supplier));
        } finally {
            DUAL_CACHE_LOCK.readLock().unlock();
        }
    }

    @Override
    public <T> T get(String key, long timeout, Supplier<T> supplier) {
        DUAL_CACHE_LOCK.readLock().lock();
        try {
            return (T) FIRST_CACHE.get(key, timeout, () -> SECOND_CACHE.get(key, timeout, supplier));
        } finally {
            DUAL_CACHE_LOCK.readLock().unlock();
        }
    }

    public void put(String key, Object value) {
        DUAL_CACHE_LOCK.writeLock().lock();
        try {
            FIRST_CACHE.put(key, value);
            SECOND_CACHE.put(key, value);
        } finally {
            DUAL_CACHE_LOCK.writeLock().unlock();
        }
    }

    public void put(String key, Object value, long timeout) {
        DUAL_CACHE_LOCK.writeLock().lock();
        try {
            FIRST_CACHE.put(key, value);
            SECOND_CACHE.put(key, value, timeout);
        } finally {
            DUAL_CACHE_LOCK.writeLock().unlock();
        }
    }

    public void remove(String key) {
        DUAL_CACHE_LOCK.writeLock().lock();
        try {
            FIRST_CACHE.remove(key);
            SECOND_CACHE.remove(key);
        } finally {
            DUAL_CACHE_LOCK.writeLock().unlock();
        }
    }
}


