package org.jboss.resteasy.client.jaxrs.cache;

import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.MultivaluedMap;

public class MapCache implements BrowserCache {
    protected Map<String, Map<String, Entry>> cache = null;

    public MapCache() {
        this(new ConcurrentHashMap<String, Map<String, Entry>>());
    }

    public MapCache(final Map<String, Map<String, Entry>> cache) {
        this.cache = cache;
    }

    protected Map<String, Map<String, Entry>> createCache() {
        return new ConcurrentHashMap<String, Map<String, Entry>>();
    }

    public Entry get(String key, MediaType accept) {
        Map<String, Entry> parent = cache.get(key);
        if (parent == null || parent.isEmpty()) {
            return null;
        }
        if (accept.isWildcardType()) {
            // if the client accepts */*, return just the first entry for requested URL
            return parent.entrySet().iterator().next().getValue();
        } else if (accept.isWildcardSubtype()) {
            // if the client accepts <media>/*, return the first entry which media type starts with <media>/
            for (Map.Entry<String, Entry> parentEntry : parent.entrySet()) {
                if (parentEntry.getKey().startsWith(accept.getType() + "/")) {
                    return parentEntry.getValue();
                }
            }
        }
        return parent.get(accept.toString());
    }

    public Entry getAny(String key) {
        Map<String, Entry> parent = cache.get(key);
        if (parent == null)
            return null;
        Iterator<Entry> iterator = parent.values().iterator();
        if (iterator.hasNext())
            return iterator.next();
        return null;
    }

    public Entry getEntry(String key, MediaType accept) {
        Map<String, Entry> parent = cache.get(key);
        if (parent == null)
            return null;
        return parent.get(accept.toString());
    }

    public Entry remove(String key, MediaType type) {
        Map<String, Entry> data = cache.get(key);
        if (data == null)
            return null;
        Entry removed = data.remove(type.toString());
        if (data.isEmpty()) {
            cache.remove(key);
        } else {
            cache.put(key, data);
        }
        return removed;
    }

    public void clear() {
        cache.clear();
    }

    public Entry put(CacheEntry cacheEntry) {
        Map<String, Entry> map = cache.get(cacheEntry.getKey());
        if (map == null) {
            map = new ConcurrentHashMap<String, Entry>();
        }
        map.put(cacheEntry.getMediaType().toString(), cacheEntry);
        cache.put(cacheEntry.getKey(), map);
        return cacheEntry;
    }

    public Entry put(String key, MediaType mediaType,
            MultivaluedMap<String, String> headers, byte[] cached, int expires,
            String etag, String lastModified) {
        return put(new CacheEntry(key, headers, cached, expires, etag, lastModified, mediaType));
    }
}
