package com.composum.platform.cache.component;

import com.composum.platform.cache.service.CacheManager;
import com.composum.platform.cache.service.CacheService;
import com.composum.sling.core.filter.ResourceFilter;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.resource.Resource;
import org.osgi.framework.Constants;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Modified;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.metatype.annotations.Designate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.Serializable;

/**
 * the default component cache service implementation
 */
@Component(
        property = {
                Constants.SERVICE_DESCRIPTION + "=Component Cache"
        }
)
@Designate(ocd = ComponentCacheService.Config.class)
public class ComponentCacheService implements ComponentCache {

    private static final Logger LOG = LoggerFactory.getLogger(ComponentCacheService.class);

    @Reference
    protected CacheManager cacheManager;

    protected Config config;
    protected ResourceFilter.FilterSet resourceFilterAlways;
    protected ResourceFilter.FilterSet resourceFilterAnonOnly;

    protected CacheService<String> includeCacheService;

    @Activate
    @Modified
    protected void activate(final ComponentCacheService.Config config) {
        this.config = config;
        if (config.enabled()) {
            resourceFilterAlways = new ResourceFilter.FilterSet(ResourceFilter.FilterSet.Rule.or, config.resourceFilterAlways());
            resourceFilterAnonOnly = new ResourceFilter.FilterSet(ResourceFilter.FilterSet.Rule.or, config.resourceFilterAnonOnly());
            includeCacheService = cacheManager.getCache(config.includeCache(), String.class);
        }
        LOG.info("enabled: {}, includeCache: {} ...", config.enabled(), includeCacheService);
    }

    @Override
    public Config getConfig() {
        return config;
    }

    @Override
    public boolean isIncludeCacheEnabled(ServletRequest request, ServletResponse response) {
        return !isComponentCacheDisabled(request) && includeCacheService != null &&
                request instanceof SlingHttpServletRequest && response instanceof SlingHttpServletResponse &&
                "html".equals(((SlingHttpServletRequest) request).getRequestPathInfo().getExtension());
    }

    protected boolean isComponentCacheDisabled(ServletRequest request) {
        Boolean disabled = (Boolean) request.getAttribute(ATTR_CACHE_DISABLED);
        return disabled != null && disabled;
    }

    @Override
    public CachePolicy getCachePolicy(SlingHttpServletRequest request) {
        CachePolicy embedState;
        if ((embedState = (CachePolicy) request.getAttribute(ATTR_IS_EMBEDDING)) != null) {
            return embedState;
        }
        final Resource resource = request.getResource();
        if (acceptedByAlwaysFilter(resource)) {
            return CachePolicy.always;
        } else if (acceptedByAnonOnlyFilter(resource)) {
            return CachePolicy.anonOnly;
        }
        return CachePolicy.noCache;
    }

    protected boolean acceptedByAlwaysFilter(Resource resource) {
        return resourceFilterAlways.getSet().size() > 0 && resourceFilterAlways.accept(resource);
    }

    protected boolean acceptedByAnonOnlyFilter(Resource resource) {
        return resourceFilterAnonOnly.getSet().size() > 0 && resourceFilterAnonOnly.accept(resource);
    }

    @Override
    public String getIncludeCacheContent(Serializable key) {
        return includeCacheService.get(key);
    }

    @Override
    public void setIncludeCacheContent(Serializable key, String content) {
        includeCacheService.put(key, content);
    }

    @Override
    public boolean isDebugRequest(SlingHttpServletRequest request) {
        Boolean isDebug = (Boolean) request.getAttribute(ATTR_IS_DEBUG_REQUEST);
        return isDebug != null && isDebug;
    }
}
@@ -1970,24 +1970,255 @@
 onOnly());%0D%0A
+            getIncludeCacheService();%0D%0A        %7D%0D%0A        LOG.info(%22activate.enabled: %7B%7D ...%22, config.enabled());%0D%0A    %7D%0D%0A%0D%0A    protected CacheService%3CString%3E getIncludeCacheService() %7B%0D%0A        if (includeCacheService == null) %7B%0D%0A
             
@@ -2296,39 +2296,32 @@
 ng.class);%0D%0A    
-    %7D%0D%0A
         LOG.info
@@ -2322,27 +2322,33 @@
 G.info(%22
-enabled
+cacheService
 : %7B%7D
+%22
 , includ
@@ -2357,36 +2357,44 @@
 ache
-: %7B%7D ...%22, config.enabled(),
+Service);%0D%0A        %7D%0D%0A        return
  inc
@@ -2405,25 +2405,24 @@
 CacheService
-)
 ;%0D%0A    %7D%0D%0A%0D%0A
@@ -2664,17 +2664,20 @@
 est) && 
-i
+getI
 ncludeCa
@@ -2686,16 +2686,18 @@
 eService
+()
  != null
@@ -4138,33 +4138,36 @@
 %0A        return 
-i
+getI
 ncludeCacheServi
@@ -4168,16 +4168,18 @@
 eService
+()
 .get(key
@@ -4282,33 +4282,36 @@
 ent) %7B%0D%0A        
-i
+getI
 ncludeCacheServi
@@ -4312,16 +4312,18 @@
 eService
+()
 .put(key

make cache reference independent from activations