package com.njnu.kai.practice.lock;

import android.os.Bundle;
import android.os.SystemClock;
import android.view.View;

import com.njnu.kai.support.BaseTestListFragment;
import com.njnu.kai.support.TestFunction;

import java.util.Calendar;
import java.util.Locale;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @author kai
 * @since 17/4/4
 */
public class LockTestFragment extends BaseTestListFragment {

    public static final int N = 6;
    private Executor mExecutor;

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        mExecutor = new ThreadPoolExecutor(8, 8, 5L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(16));
    }

    @TestFunction("CountDownLatch等待任务都结束")
    public void onTest01() {
        CountDownLatch doneSignal = new CountDownLatch(N);

        setResult(nowTime() + "begin test01");
        for (int i = 0; i < N; ++i) { // create and start threads
            mExecutor.execute(new WorkerRunnable1(doneSignal, i));
        }
        mExecutor.execute(new WaitRunnable(doneSignal));
    }

    @TestFunction("CountDownLatch等待一起开始等待结束")
    public void onTest02() {
    }


    @Override
    public void onDestroyView() {
        super.onDestroyView();
        mExecutor = null;
    }

    private class WorkerRunnable1 implements Runnable {
        private final CountDownLatch doneSignal;
        private final int i;

        WorkerRunnable1(CountDownLatch doneSignal, int i) {
            this.doneSignal = doneSignal;
            this.i = i;
        }

        public void run() {
            doWork();
            doneSignal.countDown();
            appendAsync(i + ": end work");
        }

        void doWork() {
            appendAsync(i + ": begin work");
            SystemClock.sleep(i * 1000);
        }
    }

    private class WaitRunnable implements Runnable {

        private final CountDownLatch doneSignal;

        private WaitRunnable(CountDownLatch doneSignal) {
            this.doneSignal = doneSignal;
        }

        @Override
        public void run() {
            try {
                appendAsync("await");
                doneSignal.await();
                appendAsync("await finish");
            } catch (InterruptedException e) {
                appendAsync("await exception: " + e.getMessage());
                e.printStackTrace();
            }
        }
    }

    public static String nowTime() {
        Calendar instance = Calendar.getInstance();
        return String.format(Locale.getDefault(), "%02d:%02d.%03d "
                , instance.get(Calendar.MINUTE), instance.get(Calendar.SECOND), instance.get(Calendar.MILLISECOND));
    }

    public void appendAsync(String text) {
        getView().post(new Runnable() {
            @Override
            public void run() {
                appendResult(nowTime() + text);
            }
        });
    }
}

@@ -1215,32 +1215,66 @@
  i));%0A        %7D%0A
+        SystemClock.sleep(2_400);%0A
         mExecuto
@@ -1404,423 +1404,1785 @@
     
-%7D%0A%0A%0A    @Override%0A    public void onDestroyView() %7B%0A        super.onDestroyView();%0A        mExecutor = null;%0A    %7D%0A%0A    private class WorkerRunnable1 implements Runnable %7B%0A        private final CountDownLatch doneSignal;%0A        private final int i;%0A%0A        WorkerRunnable1(CountDownLatch doneSignal, int i) %7B%0A            this.doneSignal = doneSignal;%0A            this.i = i;%0A        %7D%0A%0A        public void run() %7B
+    CountDownLatch doneSignal = new CountDownLatch(N);%0A        CountDownLatch startSignal = new CountDownLatch(1);%0A        setResult(nowTime() + %22begin test02%22);%0A        for (int i = 0; i %3C N; ++i) %7B // create and start threads%0A            mExecutor.execute(new WorkerRunnable2(startSignal, doneSignal, i));%0A        %7D%0A        SystemClock.sleep(2_400);%0A        appendAsync(%22will await%22);%0A        startSignal.countDown();%0A        mExecutor.execute(new WaitRunnable(doneSignal));%0A    %7D%0A%0A%0A    @Override%0A    public void onDestroyView() %7B%0A        super.onDestroyView();%0A        mExecutor = null;%0A    %7D%0A%0A    private class WorkerRunnable1 implements Runnable %7B%0A        private final CountDownLatch doneSignal;%0A        private final int i;%0A%0A        WorkerRunnable1(CountDownLatch doneSignal, int i) %7B%0A            this.doneSignal = doneSignal;%0A            this.i = i;%0A        %7D%0A%0A        public void run() %7B%0A            doWork();%0A            doneSignal.countDown();%0A            appendAsync(i + %22: end work%22);%0A        %7D%0A%0A        void doWork() %7B%0A            appendAsync(i + %22: begin work%22);%0A            SystemClock.sleep(i * 1000);%0A        %7D%0A    %7D%0A%0A    private class WorkerRunnable2 implements Runnable %7B%0A        private final CountDownLatch startSignal;%0A        private final CountDownLatch doneSignal;%0A        private final int i;%0A%0A        WorkerRunnable2(CountDownLatch startSignal, CountDownLatch doneSignal, int i) %7B%0A            this.startSignal = startSignal;%0A            this.doneSignal = doneSignal;%0A            this.i = i;%0A        %7D%0A%0A        public void run() %7B%0A            try %7B%0A                startSignal.await();%0A            %7D catch (InterruptedException e) %7B%0A                e.printStackTrace();%0A                appendAsync(i + %22: run await: %22 + e.getMessage());%0A            %7D
 %0A   

test countdownlatch again