// Copyright (C) 2012 The Android Open Source Project
//
// 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.google.gerrit.server.cache;

import static java.util.concurrent.TimeUnit.SECONDS;

import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.Weigher;
import com.google.gerrit.extensions.annotations.PluginName;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.TypeLiteral;

import java.util.concurrent.TimeUnit;

import javax.annotation.Nullable;

class CacheProvider<K, V>
    implements Provider<Cache<K, V>>,
    CacheBinding<K, V> {
  private final CacheModule module;
  final String name;
  private final TypeLiteral<K> keyType;
  private final TypeLiteral<V> valType;
  private boolean persist;
  private long maximumWeight;
  private Long expireAfterWrite;
  private Provider<CacheLoader<K, V>> loader;
  private Provider<Weigher<K, V>> weigher;

  private String plugin;
  private MemoryCacheFactory memoryCacheFactory;
  private PersistentCacheFactory persistentCacheFactory;
  private boolean frozen;

  CacheProvider(CacheModule module,
      String name,
      TypeLiteral<K> keyType,
      TypeLiteral<V> valType) {
    this.module = module;
    this.name = name;
    this.keyType = keyType;
    this.valType = valType;
  }

  @Inject(optional = true)
  void setPluginName(@PluginName String pluginName) {
    this.plugin = pluginName;
  }

  @Inject
  void setMemoryCacheFactory(MemoryCacheFactory factory) {
    this.memoryCacheFactory = factory;
  }

  @Inject(optional = true)
  void setPersistentCacheFactory(@Nullable PersistentCacheFactory factory) {
    this.persistentCacheFactory = factory;
  }

  CacheBinding<K, V> persist(boolean p) {
    Preconditions.checkState(!frozen, "binding frozen, cannot be modified");
    persist = p;
    return this;
  }

  @Override
  public CacheBinding<K, V> maximumWeight(long weight) {
    Preconditions.checkState(!frozen, "binding frozen, cannot be modified");
    maximumWeight = weight;
    return this;
  }

  @Override
  public CacheBinding<K, V> expireAfterWrite(long duration, TimeUnit unit) {
    Preconditions.checkState(!frozen, "binding frozen, cannot be modified");
    expireAfterWrite = SECONDS.convert(duration, unit);
    return this;
  }

  @Override
  public CacheBinding<K, V> loader(Class<? extends CacheLoader<K, V>> impl) {
    Preconditions.checkState(!frozen, "binding frozen, cannot be modified");
    loader = module.bindCacheLoader(this, impl);
    return this;
  }

  @Override
  public CacheBinding<K, V> weigher(Class<? extends Weigher<K, V>> impl) {
    Preconditions.checkState(!frozen, "binding frozen, cannot be modified");
    weigher = module.bindWeigher(this, impl);
    return this;
  }

  @Override
  public String name() {
    if (!Strings.isNullOrEmpty(plugin)) {
      return plugin + "." + name;
    }
    return name;
  }

  @Override
  public TypeLiteral<K> keyType() {
    return keyType;
  }

  @Override
  public TypeLiteral<V> valueType() {
    return valType;
  }

  @Override
  public long maximumWeight() {
    return maximumWeight;
  }

  @Override
  @Nullable
  public Long expireAfterWrite(TimeUnit unit) {
   return expireAfterWrite != null
       ? unit.convert(expireAfterWrite, SECONDS)
       : null;
  }

  @Override
  @Nullable
  public Weigher<K, V> weigher() {
    return weigher != null ? weigher.get() : null;
  }

  @Override
  @Nullable
  public CacheLoader<K, V> loader() {
    return loader != null ? loader.get() : null;
  }

  @Override
  public Cache<K, V> get() {
    frozen = true;

    if (loader != null) {
      CacheLoader<K, V> ldr = loader.get();
      if (persist && persistentCacheFactory != null) {
        return persistentCacheFactory.build(this, ldr);
      }
      return memoryCacheFactory.build(this, ldr);
    } else if (persist && persistentCacheFactory != null) {
      return persistentCacheFactory.build(this);
    } else {
      return memoryCacheFactory.build(this);
    }
  }
}
