package com.alibaba.ttl3;

import com.alibaba.crr.composite.Backup;
import com.alibaba.crr.composite.Capture;
import com.alibaba.ttl3.spi.TtlEnhanced;
import com.alibaba.ttl3.spi.TtlWrapper;
import edu.umd.cs.findbugs.annotations.NonNull;
import edu.umd.cs.findbugs.annotations.Nullable;
import org.jetbrains.annotations.Contract;

import java.util.*;
import java.util.concurrent.atomic.AtomicReference;

import static com.alibaba.ttl3.transmitter.Transmitter.*;

/**
 * {@link TtlTimerTask} decorate {@link TimerTask} to get {@link TransmittableThreadLocal} value
 * and transmit it to the time of {@link TtlTimerTask} execution, needed when use {@link TtlTimerTask} to {@link TimerTask}.
 * <p>
 * Use factory method {@link #get(TimerTask)} to create instance.
 * <p>
 * <B><I>CAUTION:</I></B><br>
 * The {@link TtlTimerTask} make the method {@link TimerTask#scheduledExecutionTime()} in
 * the origin {@link TimerTask} lose effectiveness! Use {@code TTL Java Agent} instead.
 *
 * @author Jerry Lee (oldratlee at gmail dot com)
 * @see Timer
 * @see TimerTask
 * @see <a href="https://alibaba.github.io/Alibaba-Java-Coding-Guidelines/#concurrency">
 * Alibaba Java Coding Guidelines - Concurrency -
 * Item 10: [Mandatory] Run multiple TimeTask by using ScheduledExecutorService
 * rather than Timer because Timer will kill all running threads
 * in case of failing to catch exceptions.</a>
 * @deprecated Use {@link TtlRunnable}, {@link java.util.concurrent.ScheduledExecutorService}
 * instead of {@link Timer}, {@link TimerTask}.
 */
@Deprecated
public final class TtlTimerTask extends TimerTask implements TtlWrapper<TimerTask>, TtlEnhanced {
    private final AtomicReference<Capture> capturedRef;
    private final TimerTask timerTask;
    private final boolean releaseTtlValueReferenceAfterRun;

    private TtlTimerTask(@NonNull TimerTask timerTask, boolean releaseTtlValueReferenceAfterRun) {
        this.capturedRef = new AtomicReference<>(capture());
        this.timerTask = timerTask;
        this.releaseTtlValueReferenceAfterRun = releaseTtlValueReferenceAfterRun;
    }

    /**
     * wrap method {@link TimerTask#run()}.
     */
    @Override
    public void run() {
        final Capture captured = capturedRef.get();
        if (captured == null || releaseTtlValueReferenceAfterRun && !capturedRef.compareAndSet(captured, null)) {
            throw new IllegalStateException("TTL value reference is released after run!");
        }

        final Backup backup = replay(captured);
        try {
            timerTask.run();
        } finally {
            restore(backup);
        }
    }

    @Override
    public boolean cancel() {
        timerTask.cancel();
        return super.cancel();
    }

    /**
     * return original/unwrapped {@link TimerTask}.
     */
    @NonNull
    public TimerTask getTimerTask() {
        return unwrap();
    }

    /**
     * unwrap to original/unwrapped {@link TimerTask}.
     *
     * @see TtlWrappers#unwrap(Object)
     */
    @NonNull
    @Override
    public TimerTask unwrap() {
        return timerTask;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        TtlTimerTask that = (TtlTimerTask) o;

        return timerTask.equals(that.timerTask);
    }

    @Override
    public int hashCode() {
        return timerTask != null ? timerTask.hashCode() : 0;
    }

    @Override
    public String toString() {
        return this.getClass().getName() + " - " + timerTask.toString();
    }

    /**
     * Factory method, wrap input {@link TimerTask} to {@link TtlTimerTask}.
     * <p>
     * This method is idempotent.
     *
     * @param timerTask input {@link TimerTask}
     * @return Wrapped {@link TimerTask}
     */
    @Nullable
    @Contract(value = "null -> null; !null -> !null", pure = true)
    public static TtlTimerTask get(@Nullable TimerTask timerTask) {
        return get(timerTask, false, false);
    }

    /**
     * Factory method, wrap input {@link TimerTask} to {@link TtlTimerTask}.
     * <p>
     * This method is idempotent.
     *
     * @param timerTask                        input {@link TimerTask}
     * @param releaseTtlValueReferenceAfterRun release TTL value reference after run, avoid memory leak even if {@link TtlTimerTask} is referred.
     * @return Wrapped {@link TimerTask}
     */
    @Nullable
    @Contract(value = "null, _ -> null; !null, _ -> !null", pure = true)
    public static TtlTimerTask get(@Nullable TimerTask timerTask, boolean releaseTtlValueReferenceAfterRun) {
        return get(timerTask, releaseTtlValueReferenceAfterRun, false);
    }

    /**
     * Factory method, wrap input {@link TimerTask} to {@link TtlTimerTask}.
     * <p>
     * This method is idempotent.
     *
     * @param timerTask                        input {@link TimerTask}
     * @param releaseTtlValueReferenceAfterRun release TTL value reference after run, avoid memory leak even if {@link TtlTimerTask} is referred.
     * @param idempotent                       is idempotent or not. {@code true} will cover up bugs! <b>DO NOT</b> set, only when you know why.
     * @return Wrapped {@link TimerTask}
     */
    @Nullable
    @Contract(value = "null, _, _ -> null; !null, _, _ -> !null", pure = true)
    public static TtlTimerTask get(@Nullable TimerTask timerTask, boolean releaseTtlValueReferenceAfterRun, boolean idempotent) {
        if (null == timerTask) return null;

        if (timerTask instanceof TtlEnhanced) {
            // avoid redundant decoration, and ensure idempotency
            if (idempotent) return (TtlTimerTask) timerTask;
            else throw new IllegalStateException("Already TtlTimerTask!");
        }
        return new TtlTimerTask(timerTask, releaseTtlValueReferenceAfterRun);
    }

    /**
     * Unwrap {@link TtlTimerTask} to the original/underneath one.
     * <p>
     * this method is {@code null}-safe, when input {@code TimerTask} parameter is {@code null}, return {@code null};
     * if input {@code TimerTask} parameter is not a {@link TtlTimerTask} just return input {@code TimerTask}.
     *
     * @see #get(TimerTask)
     */
    @Nullable
    @Contract(value = "null -> null; !null -> !null", pure = true)
    public static TimerTask unwrap(@Nullable TimerTask timerTask) {
        if (!(timerTask instanceof TtlTimerTask)) return timerTask;
        else return ((TtlTimerTask) timerTask).getTimerTask();
    }

    /**
     * Unwrap {@link TtlTimerTask} to the original/underneath one.
     * <p>
     * Invoke {@link #unwrap(TimerTask)} for each element in input collection.
     * <p>
     * This method is {@code null}-safe, when input {@code TimerTask} parameter is {@code null}, return a empty list.
     *
     * @see #unwrap(TimerTask)
     */
    @NonNull
    public static List<TimerTask> unwraps(@Nullable Collection<? extends TimerTask> tasks) {
        if (null == tasks) return Collections.emptyList();

        List<TimerTask> copy = new ArrayList<>();
        for (TimerTask task : tasks) {
            if (!(task instanceof TtlTimerTask)) copy.add(task);
            else copy.add(((TtlTimerTask) task).getTimerTask());
        }
        return copy;
    }
}

@@ -6493,770 +6493,7 @@
    %7D
-%0A%0A    /**%0A     * Unwrap %7B@link TtlTimerTask%7D to the original/underneath one.%0A     * %3Cp%3E%0A     * Invoke %7B@link #unwrap(TimerTask)%7D for each element in input collection.%0A     * %3Cp%3E%0A     * This method is %7B@code null%7D-safe, when input %7B@code TimerTask%7D parameter is %7B@code null%7D, return a empty list.%0A     *%0A     * @see #unwrap(TimerTask)%0A     */%0A    @NonNull%0A    public static List%3CTimerTask%3E unwraps(@Nullable Collection%3C? extends TimerTask%3E tasks) %7B%0A        if (null == tasks) return Collections.emptyList();%0A%0A        List%3CTimerTask%3E copy = new ArrayList%3C%3E();%0A        for (TimerTask task : tasks) %7B%0A            if (!(task instanceof TtlTimerTask)) copy.add(task);%0A            else copy.add(((TtlTimerTask) task).getTimerTask());%0A        %7D%0A        return copy;%0A    %7D
 %0A%7D%0A

remove uncommon collection methods of `TtlTimerTask`, make `API` more concise