/*
 * Copyright (C) 2015-2016 Jacksgong(blog.dreamtobe.cn)
 *
 * 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 cn.dreamtobe.threadpool;

import android.annotation.TargetApi;
import android.os.Build;

import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * The factory of RealExecutor.
 */

public class RealExecutors {
    private static final IExecutor TEMPORARY_CACHED_THREAD_POOL = ThreadPools.
            newCachedPool(5L, TimeUnit.SECONDS, "GlobalCachedThreadPool");

    public static class NoCoreExecutor extends RealExecutor {

        @TargetApi(Build.VERSION_CODES.GINGERBREAD)
        public NoCoreExecutor(int threadCount, long keepAliveTime, TimeUnit unit,
                              String prefixName) {
            super(threadCount, threadCount, keepAliveTime, unit,
                    new LinkedBlockingQueue<Runnable>(),
                    new AbortPolicy(),//never meet
                    prefixName);

            allowCoreThreadTimeOut(true);
        }
    }

    public static class ExceedWaitExecutor extends RealExecutor {
        private final static String TAG = "ExceedWait";

        public ExceedWaitExecutor(int corePoolSize,
                                  int maximumPoolSize, long keepAliveTime, TimeUnit unit, String prefixName,
                                  ExceedWait.Queue queue, ExceedWait.RejectedHandler rejectedHandler) {
            super(corePoolSize, maximumPoolSize, keepAliveTime, unit,
                    queue, rejectedHandler, prefixName);
        }

        public ExceedWaitExecutor(int corePoolSize,
                                  int maximumPoolSize, long keepAliveTime, TimeUnit unit, String prefixName) {
            this(corePoolSize, maximumPoolSize, keepAliveTime, unit, prefixName,
                    new ExceedWait.Queue(), new ExceedWait.RejectedHandler());
        }

        @Override
        public void execute(Runnable command) {
            final ExceedWait.Queue queue = (ExceedWait.Queue) getQueue();
            if (!isShutdown() && queue.exceedSize() > 0) {
                queue.putExceed(command, this);
                ThreadPoolLog.d(TAG, "put the rejected command to the exceed queue in " +
                        "the execute method: %s", command);
                return;
            }
            super.execute(command);
        }

        @Override
        public List<Runnable> shutdownNow() {
            List<Runnable> tasks = super.shutdownNow();
            tasks.addAll(((ExceedWait.Queue) getQueue()).drainExceedQueue());
            return tasks;
        }

        @Override
        public long getTaskCount() {
            return super.getTaskCount() + ((ExceedWait.Queue) getQueue()).exceedSize();
        }
    }

    static class ExceedDiscardExecutor extends RealExecutor {

        public ExceedDiscardExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime,
                                     TimeUnit unit, String prefixName) {
            super(corePoolSize, maximumPoolSize, keepAliveTime, unit,
                    new SynchronousQueue<Runnable>(true),
                    new DiscardPolicy(), prefixName);
        }
    }

    static class ExceedCallerRunsExecutor extends RealExecutor {

        public ExceedCallerRunsExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime,
                                        TimeUnit unit, String prefixName) {
            super(corePoolSize, maximumPoolSize, keepAliveTime, unit,
                    new SynchronousQueue<Runnable>(true),
                    new CallerRunsPolicy(), prefixName);
        }
    }

    static class ExceedCallImmediatelyExecutor extends RealExecutor {

        public ExceedCallImmediatelyExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime,
                                             TimeUnit unit, String prefixName) {

            super(corePoolSize, maximumPoolSize, keepAliveTime, unit,
                    new SynchronousQueue<Runnable>(true),
                    new RejectedExecutionHandler() {
                        @Override
                        public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
                            if (!executor.isShutdown()) {
                                TEMPORARY_CACHED_THREAD_POOL.
                                        execute(((RealExecutor) executor).getCommandNameMap().get(r),
                                                r);
                            }
                        }
                    }, prefixName);
        }
    }

    static class SinglePoolExecutor extends RealExecutor {

        public SinglePoolExecutor(String prefixName) {
            super(1, 1, 0L, TimeUnit.MILLISECONDS,
                    new LinkedBlockingQueue<Runnable>(), // unbound queue.
                    new AbortPolicy(), // never meet the policy.
                    prefixName);
        }
    }

    static class FixedPoolExecutor extends RealExecutor {

        public FixedPoolExecutor(int threadCount, String prefixName) {
            super(threadCount, threadCount, 0L, TimeUnit.MILLISECONDS,
                    new LinkedBlockingQueue<Runnable>(), // unbound queue.
                    new AbortPolicy(), // never meet the policy.
                    prefixName);
        }
    }

    static class CachedPoolExecutor extends RealExecutor {

        public CachedPoolExecutor(long keepAliveTime, TimeUnit unit, String prefixName) {
            super(0, Integer.MAX_VALUE, keepAliveTime, unit, new SynchronousQueue<Runnable>(true),
                    new AbortPolicy(), // never meet the policy.
                    prefixName);
        }
    }

}

@@ -1780,64 +1780,8 @@
 or %7B
-%0A        private final static String TAG = %22ExceedWait%22;
 %0A%0A  
@@ -2519,490 +2519,8 @@
  %7D%0A%0A
-        @Override%0A        public void execute(Runnable command) %7B%0A            final ExceedWait.Queue queue = (ExceedWait.Queue) getQueue();%0A            if (!isShutdown() && queue.exceedSize() %3E 0) %7B%0A                queue.putExceed(command, this);%0A                ThreadPoolLog.d(TAG, %22put the rejected command to the exceed queue in %22 +%0A                        %22the execute method: %25s%22, command);%0A                return;%0A            %7D%0A            super.execute(command);%0A        %7D%0A%0A
     

fix low case for stack overflow when ExceedWait no active and exceed-queue more then one wait job