package com.google.common.base;

import com.google.common.annotations.Beta;
import com.google.common.annotations.GwtCompatible;
import com.google.common.annotations.VisibleForTesting;
import java.io.Serializable;
import java.util.concurrent.TimeUnit;
import javax.annotation.Nullable;

@GwtCompatible
public final class Suppliers {
   private Suppliers() {
   }

   public static <F, T> Supplier<T> compose(Function<? super F, T> function, Supplier<F> supplier) {
      Preconditions.checkNotNull(function);
      Preconditions.checkNotNull(supplier);
      return new Suppliers.SupplierComposition(function, supplier);
   }

   public static <T> Supplier<T> memoize(Supplier<T> delegate) {
      return (Supplier)(delegate instanceof Suppliers.MemoizingSupplier ? delegate : new Suppliers.MemoizingSupplier((Supplier)Preconditions.checkNotNull(delegate)));
   }

   public static <T> Supplier<T> memoizeWithExpiration(Supplier<T> delegate, long duration, TimeUnit unit) {
      return new Suppliers.ExpiringMemoizingSupplier(delegate, duration, unit);
   }

   public static <T> Supplier<T> ofInstance(@Nullable T instance) {
      return new Suppliers.SupplierOfInstance(instance);
   }

   public static <T> Supplier<T> synchronizedSupplier(Supplier<T> delegate) {
      return new Suppliers.ThreadSafeSupplier((Supplier)Preconditions.checkNotNull(delegate));
   }

   @Beta
   public static <T> Function<Supplier<T>, T> supplierFunction() {
      Suppliers.SupplierFunction<T> sf = Suppliers.SupplierFunctionImpl.INSTANCE;
      return sf;
   }

   private static enum SupplierFunctionImpl implements Suppliers.SupplierFunction<Object> {
      INSTANCE;

      public Object apply(Supplier<Object> input) {
         return input.get();
      }

      public String toString() {
         return "Suppliers.supplierFunction()";
      }
   }

   private interface SupplierFunction<T> extends Function<Supplier<T>, T> {
   }

   private static class ThreadSafeSupplier<T> implements Supplier<T>, Serializable {
      final Supplier<T> delegate;
      private static final long serialVersionUID = 0L;

      ThreadSafeSupplier(Supplier<T> delegate) {
         this.delegate = delegate;
      }

      public T get() {
         synchronized(this.delegate) {
            return this.delegate.get();
         }
      }

      public String toString() {
         String var1 = String.valueOf(String.valueOf(this.delegate));
         return (new StringBuilder(32 + var1.length())).append("Suppliers.synchronizedSupplier(").append(var1).append(")").toString();
      }
   }

   private static class SupplierOfInstance<T> implements Supplier<T>, Serializable {
      final T instance;
      private static final long serialVersionUID = 0L;

      SupplierOfInstance(@Nullable T instance) {
         this.instance = instance;
      }

      public T get() {
         return this.instance;
      }

      public boolean equals(@Nullable Object obj) {
         if (obj instanceof Suppliers.SupplierOfInstance) {
            Suppliers.SupplierOfInstance<?> that = (Suppliers.SupplierOfInstance)obj;
            return Objects.equal(this.instance, that.instance);
         } else {
            return false;
         }
      }

      public int hashCode() {
         return Objects.hashCode(this.instance);
      }

      public String toString() {
         String var1 = String.valueOf(String.valueOf(this.instance));
         return (new StringBuilder(22 + var1.length())).append("Suppliers.ofInstance(").append(var1).append(")").toString();
      }
   }

   @VisibleForTesting
   static class ExpiringMemoizingSupplier<T> implements Supplier<T>, Serializable {
      final Supplier<T> delegate;
      final long durationNanos;
      transient volatile T value;
      transient volatile long expirationNanos;
      private static final long serialVersionUID = 0L;

      ExpiringMemoizingSupplier(Supplier<T> delegate, long duration, TimeUnit unit) {
         this.delegate = (Supplier)Preconditions.checkNotNull(delegate);
         this.durationNanos = unit.toNanos(duration);
         Preconditions.checkArgument(duration > 0L);
      }

      public T get() {
         long nanos = this.expirationNanos;
         long now = Platform.systemNanoTime();
         if (nanos == 0L || now - nanos >= 0L) {
            synchronized(this) {
               if (nanos == this.expirationNanos) {
                  T t = this.delegate.get();
                  this.value = t;
                  nanos = now + this.durationNanos;
                  this.expirationNanos = nanos == 0L ? 1L : nanos;
                  return t;
               }
            }
         }

         return this.value;
      }

      public String toString() {
         String var1 = String.valueOf(String.valueOf(this.delegate));
         long var2 = this.durationNanos;
         return (new StringBuilder(62 + var1.length())).append("Suppliers.memoizeWithExpiration(").append(var1).append(", ").append(var2).append(", NANOS)").toString();
      }
   }

   @VisibleForTesting
   static class MemoizingSupplier<T> implements Supplier<T>, Serializable {
      final Supplier<T> delegate;
      transient volatile boolean initialized;
      transient T value;
      private static final long serialVersionUID = 0L;

      MemoizingSupplier(Supplier<T> delegate) {
         this.delegate = delegate;
      }

      public T get() {
         if (!this.initialized) {
            synchronized(this) {
               if (!this.initialized) {
                  T t = this.delegate.get();
                  this.value = t;
                  this.initialized = true;
                  return t;
               }
            }
         }

         return this.value;
      }

      public String toString() {
         String var1 = String.valueOf(String.valueOf(this.delegate));
         return (new StringBuilder(19 + var1.length())).append("Suppliers.memoize(").append(var1).append(")").toString();
      }
   }

   private static class SupplierComposition<F, T> implements Supplier<T>, Serializable {
      final Function<? super F, T> function;
      final Supplier<F> supplier;
      private static final long serialVersionUID = 0L;

      SupplierComposition(Function<? super F, T> function, Supplier<F> supplier) {
         this.function = function;
         this.supplier = supplier;
      }

      public T get() {
         return this.function.apply(this.supplier.get());
      }

      public boolean equals(@Nullable Object obj) {
         if (!(obj instanceof Suppliers.SupplierComposition)) {
            return false;
         } else {
            Suppliers.SupplierComposition<?, ?> that = (Suppliers.SupplierComposition)obj;
            return this.function.equals(that.function) && this.supplier.equals(that.supplier);
         }
      }

      public int hashCode() {
         return Objects.hashCode(this.function, this.supplier);
      }

      public String toString() {
         String var1 = String.valueOf(String.valueOf(this.function));
         String var2 = String.valueOf(String.valueOf(this.supplier));
         return (new StringBuilder(21 + var1.length() + var2.length())).append("Suppliers.compose(").append(var1).append(", ").append(var2).append(")").toString();
      }
   }
}
