
package org.zarroboogs.weibo.support.asyncdrawable;

import org.zarroboogs.utils.file.FileDownloaderHttpHelper;
import org.zarroboogs.utils.file.FileLocationMethod;
import org.zarroboogs.weibo.support.utils.Utility;

import java.util.concurrent.CancellationException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

public class TaskCache {

    private static final ThreadFactory sDownloadThreadFactory = new ThreadFactory() {
        private final AtomicInteger mCount = new AtomicInteger(1);

        public Thread newThread(Runnable r) {
            return new Thread(r, "DownloadFutureTask Download #" + mCount.getAndIncrement());
        }
    };

    private static final Executor DOWNLOAD_THREAD_POOL_EXECUTOR = new ThreadPoolExecutor(4, 4, 1, TimeUnit.SECONDS,
            new LinkedBlockingDeque<Runnable>(15) {
                @Override
                public boolean offer(Runnable runnable) {
                    return super.offerFirst(runnable);
                }

            }, sDownloadThreadFactory, new ThreadPoolExecutor.DiscardOldestPolicy() {
        @Override
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            if (!e.isShutdown()) {
                LinkedBlockingDeque<Runnable> deque = (LinkedBlockingDeque) e.getQueue();
                Runnable runnable = deque.pollLast();
                if (runnable instanceof DownloadFutureTask) {
                    DownloadFutureTask futureTask = (DownloadFutureTask) runnable;
                    futureTask.cancel(true);
                    String url = futureTask.getUrl();
                    removeDownloadTask(url, futureTask);
                }
                e.execute(r);
            }
        }
    });

    private static ConcurrentHashMap<String, DownloadFutureTask> downloadTasks = new ConcurrentHashMap<String, DownloadFutureTask>();

    public static final Object backgroundWifiDownloadPicturesWorkLock = new Object();

    public static void removeDownloadTask(String url, DownloadFutureTask downloadWorker) {
        synchronized (TaskCache.backgroundWifiDownloadPicturesWorkLock) {
            downloadTasks.remove(url, downloadWorker);
            if (TaskCache.isDownloadTaskFinished()) {
                TaskCache.backgroundWifiDownloadPicturesWorkLock.notifyAll();
            }
        }

    }

    public static boolean isDownloadTaskFinished() {
        return TaskCache.downloadTasks.isEmpty();
    }

    public static boolean isThisUrlTaskFinished(String url) {
        return !downloadTasks.containsKey(url);
    }

    public static boolean waitForPictureDownload(String url, FileDownloaderHttpHelper.DownloadListener downloadListener,
                                                 String savedPath,
                                                 FileLocationMethod method) {
        while (true) {
            DownloadFutureTask downloadFutureTask = TaskCache.downloadTasks.get(url);

            if (downloadFutureTask == null) {

                DownloadFutureTask newDownloadFutureTask = DownloadFutureTask.newInstance(url, method);
                synchronized (backgroundWifiDownloadPicturesWorkLock) {
                    downloadFutureTask = TaskCache.downloadTasks.putIfAbsent(url, newDownloadFutureTask);
                }
                if (downloadFutureTask == null) {
                    downloadFutureTask = newDownloadFutureTask;
                    DOWNLOAD_THREAD_POOL_EXECUTOR.execute(downloadFutureTask);
                }

            }

            downloadFutureTask.addDownloadListener(downloadListener);

            try {
                return downloadFutureTask.get();
            } catch (InterruptedException e) {
                Utility.printStackTrace(e);
                // for better listview scroll performance
                downloadFutureTask.cancel(true);
                Thread.currentThread().interrupt();
                return false;
            } catch (ExecutionException e) {
                Utility.printStackTrace(e);
                return false;
            } catch (CancellationException e) {
                removeDownloadTask(url, downloadFutureTask);
            }

        }
    }

}
