/**
 * Copyright 2013 Google Inc.
 *
 * 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.bitcoin.utils;

import com.google.common.util.concurrent.Callables;
import com.google.common.util.concurrent.CycleDetectingLockFactory;
import com.google.common.util.concurrent.Futures;

import javax.annotation.Nonnull;
import java.util.concurrent.Callable;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.ReentrantLock;

import static com.google.common.base.Preconditions.checkState;

/**
 * Various threading related utilities. Provides a wrapper around explicit lock creation that lets you control whether
 * bitcoinj performs cycle detection or not. Cycle detection is useful to detect bugs but comes with a small cost.
 * Also provides a worker thread that is designed for event listeners to be dispatched on.
 */
public class Threading {
    /**
     * An executor with one thread that is intended for running event listeners on. This ensures all event listener code
     * runs without any locks being held. It's intended for the API user to run things on. Callbacks registered by
     * bitcoinj internally shouldn't normally run here, although currently there are a few exceptions.
     */
    public static final ExecutorService USER_THREAD;

    /**
     * A dummy executor that just invokes the runnable immediately. Use this over
     * {@link com.google.common.util.concurrent.MoreExecutors#sameThreadExecutor()} because the latter creates a new
     * object each time in order to implement the more complex {@link ExecutorService} interface, which is overkill
     * for our needs.
     */
    public static final Executor SAME_THREAD;

    // For safety reasons keep track of the thread we use to run user-provided event listeners to avoid deadlock.
    private static final Thread executorThread;

    /**
     * Put a dummy task into the queue and wait for it to be run. Because it's single threaded, this means all
     * tasks submitted before this point are now completed. Usually you won't want to use this method - it's a
     * convenience primarily used in unit testing. If you want to wait for an event to be called the right thing
     * to do is usually to create a {@link com.google.common.util.concurrent.SettableFuture} and then call set
     * on it. You can then either block on that future, compose it, add listeners to it and so on.
     */
    public static void waitForUserCode() {
        // If this assert fires it means you have a bug in your code - you can't call this method inside your own
        // event handlers because it would never return. If you aren't calling this method explicitly, then that
        // means there's a bug in bitcoinj.
        checkState(executorThread != Thread.currentThread(), "waitForUserCode() run on user code thread would deadlock.");
        Futures.getUnchecked(USER_THREAD.submit(Callables.returning(null)));
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    static {
        // Default policy goes here. If you want to change this, use one of the static methods before
        // instantiating any bitcoinj objects. The policy change will take effect only on new objects
        // from that point onwards.
        throwOnLockCycles();

        USER_THREAD = Executors.newSingleThreadExecutor();
        // We can't directly get the thread that was just created, but we can fetch it indirectly. We'll use this
        // for deadlock detection by checking for waits on the user code thread.
        executorThread = Futures.getUnchecked(USER_THREAD.submit(new Callable<Thread>() {
            @Override public Thread call() throws Exception {
                Thread.currentThread().setName("bitcoinj user code thread");
                return Thread.currentThread();
            }
        }));
        SAME_THREAD = new Executor() {
            @Override
            public void execute(@Nonnull Runnable runnable) {
                runnable.run();
            }
        };
    }

    private static CycleDetectingLockFactory.Policy policy;
    public static CycleDetectingLockFactory factory;

    public static ReentrantLock lock(String name) {
        return factory.newReentrantLock(name);
    }

    public static void warnOnLockCycles() {
        setPolicy(CycleDetectingLockFactory.Policies.WARN);
    }

    public static void throwOnLockCycles() {
        setPolicy(CycleDetectingLockFactory.Policies.THROW);
    }

    public static void ignoreLockCycles() {
        setPolicy(CycleDetectingLockFactory.Policies.DISABLED);
    }

    public static void setPolicy(CycleDetectingLockFactory.Policy policy) {
        Threading.policy = policy;
        factory = CycleDetectingLockFactory.newInstance(policy);
    }

    public static CycleDetectingLockFactory.Policy getPolicy() {
        return policy;
    }
}

@@ -860,138 +860,9 @@
 ent.
-Callable;%0Aimport java.util.concurrent.Executor;%0Aimport java.util.concurrent.ExecutorService;%0Aimport java.util.concurrent.Executors
+*
 ;%0Aim
@@ -2277,28 +2277,18 @@
 tic 
-final 
 Thread 
-executo
+use
 rThr
@@ -3187,23 +3187,19 @@
 ckState(
-executo
+use
 rThread 
@@ -3833,357 +3833,245 @@
 tor(
-);%0A        // We can't directly get the thread that was just created, but we can fetch it indirectly. We'll use this%0A        // for deadlock detection by checking for waits on the user code thread.%0A        executorThread = Futures.getUnchecked(USER_THREAD.submit(new Callable%3CThread%3E() %7B%0A            @Override public Thread call() throws Exception %7B
+new ThreadFactory() %7B%0A            @Nonnull @Override public Thread newThread(@Nonnull Runnable runnable) %7B%0A                checkState(userThread == null, %22Not single threaded anymore?%22);%0A                userThread = new Thread(runnable);
 %0A   
@@ -4083,38 +4083,26 @@
         
-Thread.current
+user
 Thread
-()
 .setName
@@ -4113,29 +4113,24 @@
 tcoinj user 
-code 
 thread%22);%0A  
@@ -4147,37 +4147,69 @@
     
-return Thread.current
+userThread.setDaemon(true);%0A                return user
 Thread
-()
 ;%0A  
@@ -4212,32 +4212,32 @@
 ;%0A            %7D%0A
+
         %7D));%0A   
@@ -4230,17 +4230,16 @@
       %7D)
-)
 ;%0A      

fix the user thread to be daemon so programs can shut down properly again.