// 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.common.Nullable;
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;

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);
    }
  }
}
