package com.github.phantomthief.util;

import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.util.concurrent.RateLimiter.create;

import java.util.Iterator;
import java.util.ServiceLoader;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.util.concurrent.RateLimiter;

/**
 * @author w.vela
 * Created on 2018-06-13.
 */
public class MoreReflection {

    private static final Logger logger = LoggerFactory.getLogger(MoreReflection.class);

    private static final RateLimiter RATE_LIMITER = create(1);

    private static final StackTraceProvider STACK_TRACE_PROVIDER;

    static {
        StackTraceProvider temp = null;
        try {
            ServiceLoader<StackTraceProvider> loader = ServiceLoader.load(StackTraceProvider.class);
            Iterator<StackTraceProvider> iterator = loader.iterator();
            if (iterator.hasNext()) {
                temp = iterator.next();
            }
        } catch (UnsupportedClassVersionError e) {
            logger.info("failed to use jdk9's [JEP 259: Stack-Walking API] as caller tracker.");
        } catch (Throwable e) {
            logger.warn("failed to use jdk9's [JEP 259: Stack-Walking API] as caller tracker.", e);
        }
        if (temp == null) {
            temp = new StackTraceProviderJdk8();
        }
        STACK_TRACE_PROVIDER = temp;
        logger.info("using [{}] as caller tracker implementation.", STACK_TRACE_PROVIDER.getClass().getName());
    }

    /**
     * @param message should contains {} for output placeholder.
     */
    public static void logDeprecated(@Nonnull String message) {
        if (RATE_LIMITER.tryAcquire()) {
            checkNotNull(message);
            StackTraceElement stack = getCallerPlace();
            if (stack != null) {
                logger.info(message, stack.getFileName() + ":" + stack.getLineNumber());
            }
        }
    }

    @Nullable
    public static StackTraceElement getCallerPlace() {
        return getCallerPlace(MoreReflection.class);
    }

    @Nullable
    public static StackTraceElement getCallerPlace(Class<?> locationAwareClass) {
        return STACK_TRACE_PROVIDER.getCallerPlace(locationAwareClass);
    }

    static StackTraceProvider getStackTraceProvider() {
        return STACK_TRACE_PROVIDER;
    }
}

@@ -100,76 +100,8 @@
 ull;
-%0Aimport static com.google.common.util.concurrent.RateLimiter.create;
 %0A%0Aim
@@ -288,63 +288,8 @@
 y;%0A%0A
-import com.google.common.util.concurrent.RateLimiter;%0A%0A
 /**%0A
@@ -481,16 +481,22 @@
 c final 
+Simple
 RateLimi
@@ -514,16 +514,34 @@
 MITER = 
+SimpleRateLimiter.
 create(1

use SimpleRateLimiter instead of RateLimiter for performances.