/*
 * Copyright 2014 Rackspace
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package com.rackspacecloud.blueflood.cache;

import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.netflix.astyanax.model.ColumnFamily;
import com.rackspacecloud.blueflood.io.CassandraModel;
import com.rackspacecloud.blueflood.rollup.Granularity;
import com.rackspacecloud.blueflood.types.RollupType;
import com.rackspacecloud.blueflood.utils.TimeValue;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutionException;

public class TtlManager implements TtlProvider {
    private static final Logger log = LoggerFactory.getLogger(TtlManager.class);
    private static final String DEFAULT_TENANT = "*";
    private final LoadingCache<String, GranRollupTypeTtlMap> tenanttTtlMap;

    // these values get used in the absence of a ttl (db lookup failure, etc.).
    static final Map<String, GranRollupTypeTtlMap> SAFETY_TTLS =
            new HashMap<String, GranRollupTypeTtlMap>() {{
                GranRollupTypeTtlMap ttlMap = new GranRollupTypeTtlMap();
                for (Granularity granularity : Granularity.granularities()) {
                    for (RollupType type : RollupType.values()) {
                        ColumnFamily cf = CassandraModel.getColumnFamily(RollupType.classOf(type, granularity), granularity);

                        if (cf instanceof CassandraModel.MetricColumnFamily) {
                            CassandraModel.MetricColumnFamily metricCF = (CassandraModel.MetricColumnFamily) cf;
                            TimeValue ttl = new TimeValue(metricCF.getDefaultTTL().getValue() * 5, metricCF.getDefaultTTL().getUnit());
                            ttlMap.setTtl(granularity, type, ttl);
                        }
                    }
                }
                put(DEFAULT_TENANT, ttlMap);
            }};

    public TtlManager(TimeValue expiration, int cacheConcurrency) {
        CacheLoader<String, GranRollupTypeTtlMap> loader = new CacheLoader<String, GranRollupTypeTtlMap>() {

            @Override
            public GranRollupTypeTtlMap load(final String tenantId) throws Exception {
                // For now return the default values from config file.
                // TODO: Read from database the TTL values
                return null;
            }
        };

        tenanttTtlMap = CacheBuilder.newBuilder()
                .expireAfterWrite(expiration.getValue(), expiration.getUnit())
                .concurrencyLevel(cacheConcurrency)
                .recordStats()
                .build(loader);

    }

    @Override
    public TimeValue getTTL(String tenantId, Granularity gran, RollupType rollupType) throws Exception {
        try {
            return tenanttTtlMap.get(tenantId).getTtl(gran, rollupType);
        } catch (ExecutionException ex) {
            return SAFETY_TTLS.get(DEFAULT_TENANT).getTtl(gran, rollupType);
        }
    }

    @Override
    public void setTTL(String tenantId, Granularity gran, RollupType rollupType, TimeValue ttlValue) throws Exception {
        GranRollupTypeTtlMap ttlMap = tenanttTtlMap.get(tenantId);

        if (ttlMap == null) {
            ttlMap = new GranRollupTypeTtlMap();
            ttlMap.setTtl(gran, rollupType, ttlValue);
            tenanttTtlMap.put(tenantId, ttlMap);
            // TODO: Flush changes to database.
        }
    }

    public static class GranRollupTypeTtlMap {
        // Simple map sufficient as guava map would lock at tenant level
        private Map<Granularity, Map<RollupType, TimeValue>> ttlMap;

        public GranRollupTypeTtlMap() {
            ttlMap = new HashMap<Granularity, Map<RollupType, TimeValue>>();
        }

        public void setTtl(Granularity gran, RollupType rollupType, TimeValue ttl) {
            Map<RollupType, TimeValue> rollupTypeTtlMap = ttlMap.get(gran);

            if (rollupTypeTtlMap == null) {
               rollupTypeTtlMap = new HashMap<RollupType, TimeValue>();
            }

            rollupTypeTtlMap.put(rollupType, ttl);
        }

        public TimeValue getTtl(Granularity gran, RollupType rollupType) {
            Map<RollupType, TimeValue> rollupTypeTtlMap = ttlMap.get(gran);

            if (rollupTypeTtlMap == null) {
                return null;  // Decide what to do.
            }

            return rollupTypeTtlMap.get(rollupType);
        }
    }
}

@@ -1348,62 +1348,8 @@
 s);%0A
-    private static final String DEFAULT_TENANT = %22*%22;%0A
     
@@ -1505,16 +1505,24 @@
 .).%0A    
+private 
 static f
@@ -1529,20 +1529,8 @@
 inal
- Map%3CString,
  Gra
@@ -1546,17 +1546,16 @@
 peTtlMap
-%3E
  SAFETY_
@@ -1564,40 +1564,12 @@
 LS =
-%0A            new HashMap%3CString,
+ new
  Gra
@@ -1589,97 +1589,26 @@
 lMap
-%3E
 ()
- %7B%7B%0A                GranRollupTypeTtlMap ttlMap = new GranRollupTypeTtlMap();%0A        
+;%0A%0A    static %7B%0A
     
@@ -1685,24 +1685,16 @@
         
-        
 for (Rol
@@ -1727,32 +1727,24 @@
 values()) %7B%0A
-        
             
@@ -1862,32 +1862,24 @@
             
-     
-   
 if (cf insta
@@ -1917,32 +1917,24 @@
 mnFamily) %7B%0A
-        
             
@@ -2046,24 +2046,16 @@
         
-        
 TimeValu
@@ -2170,38 +2170,35 @@
             
-        ttlMap
+SAFETY_TTLS
 .setTtl(gran
@@ -2230,32 +2230,24 @@
             
-        
 %7D%0A          
@@ -2252,96 +2252,25 @@
     
- 
-       %7D%0A                %7D%0A                put(DEFAULT_TENANT, ttlMap);%0A            %7D%7D;
+%7D%0A        %7D%0A    %7D
 %0A%0A  
@@ -3274,28 +3274,8 @@
 TLS.
-get(DEFAULT_TENANT).
 getT

Simplify SAFETy_TTLs