package com.ama.core.architecture.util.eventbus;


import android.os.Handler;
import android.os.Looper;
import android.text.TextUtils;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class TPoolAssis {
    private static final String COMMON_TP_NAME = "common_tp_name";
    private static final int COMMON_TP_THREAD_COUNT = 5;
    private static final int DEFAULT_TP_THREAD_COUNT = 1;
    private static TPoolAssis instance;


    private Map<String, TPoolEntity> mTPoolMap;
    private Handler mMainHandler = null;


    public static TPoolAssis instance() {
        if (instance == null) {
            synchronized (TPoolAssis.class) {
                if (instance == null) {
                    instance = new TPoolAssis();
                }
            }
        }
        return instance;
    }


    private TPoolAssis() {
        mTPoolMap = new ConcurrentHashMap<>();
        createTPool(COMMON_TP_NAME, COMMON_TP_THREAD_COUNT);
    }

    private void createTPool(String tpName, int threadCount) {
        if (!TextUtils.isEmpty(tpName) && !mTPoolMap.containsKey(tpName)) {
            LinkedBlockingQueue taskQueue = new LinkedBlockingQueue<>();
            ThreadPoolExecutor tPoolExecutor = new ThreadPoolExecutor(
                    threadCount, threadCount, 30,
                    TimeUnit.SECONDS, taskQueue);
            mTPoolMap.put(tpName, new TPoolEntity(tpName, tPoolExecutor, taskQueue));
        }
    }

    public void configMyTPool(String tpName, int threadCount) {
        if (TextUtils.isEmpty(tpName)
                && !tpName.equalsIgnoreCase(COMMON_TP_NAME)
                && !mTPoolMap.containsKey(tpName)) {
            createTPool(tpName, threadCount);
        }
    }

    public void runBg(Runnable runnable) {
        runBg(COMMON_TP_NAME, runnable);
    }

    public void runBg(String tpName, Runnable runnable) {
        if (!TextUtils.isEmpty(tpName) && runnable != null) {
            if (!mTPoolMap.containsKey(tpName)) {
                createTPool(tpName, DEFAULT_TP_THREAD_COUNT);
            }

            TPoolEntity tPool = mTPoolMap.get(tpName);
            if (tPool != null) {
                tPool.mTPoolExecutor.execute(new TPRunnable(runnable));
            }
        }
    }

    public int getBlockTaskCount(String tpName) {
        if (!TextUtils.isEmpty(tpName) && mTPoolMap.containsKey(tpName)) {
            return mTPoolMap.get(tpName).getBlockTaskCount();
        }
        return 0;
    }

    public void clearAllTaskByTag(String tpName) {
        if (!TextUtils.isEmpty(tpName) && mTPoolMap.containsKey(tpName)) {
            mTPoolMap.get(tpName).mTaskQueue.clear();
        }
    }


    public void runMain(Runnable runnable) {
        if (runnable != null) {
            if (mMainHandler == null) {
                synchronized (this) {
                    mMainHandler = new Handler(Looper.getMainLooper());
                }
            }
            mMainHandler.post(runnable);
        }
    }


    //****************** Inner classes ******************//
    private static class TPoolEntity {
        public String mTpName;
        public ThreadPoolExecutor mTPoolExecutor;
        public LinkedBlockingQueue<? extends Runnable> mTaskQueue;

        public int getBlockTaskCount() {
            if (mTaskQueue != null) {
                return mTaskQueue.size();
            }
            return 0;
        }

        public TPoolEntity(String tpName, ThreadPoolExecutor mTPoolExecutor,
                           LinkedBlockingQueue<? extends Runnable> mTaskQueue) {
            this.mTpName = tpName;
            this.mTPoolExecutor = mTPoolExecutor;
            this.mTaskQueue = mTaskQueue;
        }
    }


    public static class TPRunnable implements Runnable {
        private Runnable mRealRunnable;
        public TPRunnable(Runnable runnable) {
            mRealRunnable = runnable;
        }

        @Override
        public void run() {
            try {
                mRealRunnable.run();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

}