package com.novoda.downloadmanager;

import android.os.Handler;

import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;

import static com.novoda.downloadmanager.DownloadBatchStatus.Status.*;

class LiteDownloadManagerDownloader {

    private final Object waitForDownloadService;
    private final ExecutorService executor;
    private final Handler callbackHandler;
    private final FileOperations fileOperations;
    private final DownloadsBatchPersistence downloadsBatchPersistence;
    private final DownloadsFilePersistence downloadsFilePersistence;
    private final NotificationCreator notificationCreator;
    private final List<DownloadBatchCallback> callbacks;
    private final CallbackThrottleCreator callbackThrottleCreator;

    private DownloadService downloadService;

    LiteDownloadManagerDownloader(Object waitForDownloadService,
                                  ExecutorService executor,
                                  Handler callbackHandler,
                                  FileOperations fileOperations,
                                  DownloadsBatchPersistence downloadsBatchPersistence,
                                  DownloadsFilePersistence downloadsFilePersistence,
                                  NotificationCreator notificationCreator,
                                  List<DownloadBatchCallback> callbacks,
                                  CallbackThrottleCreator callbackThrottleCreator) {
        this.waitForDownloadService = waitForDownloadService;
        this.executor = executor;
        this.callbackHandler = callbackHandler;
        this.fileOperations = fileOperations;
        this.downloadsBatchPersistence = downloadsBatchPersistence;
        this.downloadsFilePersistence = downloadsFilePersistence;
        this.notificationCreator = notificationCreator;
        this.callbacks = callbacks;
        this.callbackThrottleCreator = callbackThrottleCreator;
    }

    public void download(Batch batch, Map<DownloadBatchId, DownloadBatch> downloadBatchMap) {
        DownloadBatch runningDownloadBatch = downloadBatchMap.get(batch.getDownloadBatchId());
        if (runningDownloadBatch != null) {
            return;
        }

        CallbackThrottle callbackThrottle = callbackThrottleCreator.create();

        DownloadBatch downloadBatch = DownloadBatchFactory.newInstance(
                batch,
                fileOperations,
                downloadsBatchPersistence,
                downloadsFilePersistence,
                callbackThrottle
        );

        downloadBatch.persist();
        download(downloadBatch, downloadBatchMap);
    }

    public void download(DownloadBatch downloadBatch, Map<DownloadBatchId, DownloadBatch> downloadBatchMap) {
        downloadBatchMap.put(downloadBatch.getId(), downloadBatch);
        if (downloadService == null) {
            ensureDownloadServiceExistsAndDownload(downloadBatch);
        } else {
            executeDownload(downloadBatch);
        }
    }

    private void ensureDownloadServiceExistsAndDownload(final DownloadBatch downloadBatch) {
        executor.submit(new Runnable() {
            @Override
            public void run() {
                waitForDownloadService();
                executeDownload(downloadBatch);
            }
        });
    }

    private void waitForDownloadService() {
        try {
            synchronized (waitForDownloadService) {
                if (downloadService == null) {
                    waitForDownloadService.wait();
                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private void executeDownload(final DownloadBatch downloadBatch) {
        updateStatusToQueuedIfNeeded(downloadBatch);
        downloadService.download(downloadBatch, downloadBatchCallback());
    }

    private void updateStatusToQueuedIfNeeded(DownloadBatch downloadBatch) {
        InternalDownloadBatchStatus liteDownloadBatchStatus = downloadBatch.status();

        if (liteDownloadBatchStatus.status() != PAUSED) {
            liteDownloadBatchStatus.markAsQueued(downloadsBatchPersistence);
        }
    }

    private DownloadBatchCallback downloadBatchCallback() {
        return new DownloadBatchCallback() {
            @Override
            public void onUpdate(final DownloadBatchStatus downloadBatchStatus) {
                callbackHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        for (DownloadBatchCallback callback : callbacks) {
                            callback.onUpdate(downloadBatchStatus);
                        }
                        updateNotification(downloadBatchStatus, downloadService);
                    }
                });
            }
        };
    }

    private void updateNotification(DownloadBatchStatus liteDownloadBatchStatus, DownloadService downloadService) {
        NotificationInformation notificationInformation = notificationCreator.createNotification(
                liteDownloadBatchStatus.getDownloadBatchTitle(),
                liteDownloadBatchStatus.percentageDownloaded(),
                (int) liteDownloadBatchStatus.bytesTotalSize(),
                (int) liteDownloadBatchStatus.bytesDownloaded()
        );

        downloadService.updateNotification(notificationInformation);

        if (liteDownloadBatchStatus.status() != DOWNLOADING) {
            downloadService.updateNotification(notificationInformation);
        }

        if (liteDownloadBatchStatus.status() == DOWNLOADED) {
            downloadService.makeNotificationDismissible(notificationInformation);
        }
    }

    void setDownloadService(DownloadService downloadService) {
        this.downloadService = downloadService;
    }
}

@@ -221,9 +221,94 @@
 tus.
-*
+DOWNLOADED;%0Aimport static com.novoda.downloadmanager.DownloadBatchStatus.Status.PAUSED
 ;%0A%0Ac
@@ -5473,155 +5473,8 @@
 );%0A%0A
-        if (liteDownloadBatchStatus.status() != DOWNLOADING) %7B%0A            downloadService.updateNotification(notificationInformation);%0A        %7D%0A%0A
     

Remove redundant double call to update notification.