package com.novoda.downloadmanager;

import android.os.Handler;

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

class DownloadManager implements LiteDownloadManagerCommands {

    private final Object waitForDownloadService;
    private final ExecutorService executor;
    private final Handler callbackHandler;
    private final Map<DownloadBatchId, DownloadBatch> downloadBatchMap;
    private final List<DownloadBatchCallback> callbacks;
    private final FileOperations fileOperations;
    private final DownloadsBatchPersistence downloadsBatchPersistence;
    private final LiteDownloadManagerDownloader downloader;

    private DownloadService downloadService;

    // DownloadManager is a complex object.
    @SuppressWarnings({"checkstyle:parameternumber", "PMD.ExcessiveParameterList"})
    DownloadManager(Object waitForDownloadService,
                    ExecutorService executor,
                    Handler callbackHandler,
                    Map<DownloadBatchId, DownloadBatch> downloadBatchMap,
                    List<DownloadBatchCallback> callbacks,
                    FileOperations fileOperations,
                    DownloadsBatchPersistence downloadsBatchPersistence,
                    LiteDownloadManagerDownloader downloader) {
        this.waitForDownloadService = waitForDownloadService;
        this.executor = executor;
        this.callbackHandler = callbackHandler;
        this.downloadBatchMap = downloadBatchMap;
        this.callbacks = callbacks;
        this.fileOperations = fileOperations;
        this.downloadsBatchPersistence = downloadsBatchPersistence;
        this.downloader = downloader;
    }

    void initialise(DownloadService downloadService) {
        this.downloadService = downloadService;
        downloader.setDownloadService(downloadService);
        synchronized (waitForDownloadService) {
            waitForDownloadService.notifyAll();
        }
    }

    @Override
    public void submitAllStoredDownloads(AllStoredDownloadsSubmittedCallback callback) {
        downloadsBatchPersistence.loadAsync(fileOperations, loadBatchesCallback(callback));
    }

    private DownloadsBatchPersistence.LoadBatchesCallback loadBatchesCallback(final AllStoredDownloadsSubmittedCallback callback) {
        return downloadBatches -> {
            for (DownloadBatch downloadBatch : downloadBatches) {
                downloader.download(downloadBatch, downloadBatchMap);
            }

            callbackHandler.post(callback::onAllDownloadsSubmitted);
        };
    }

    @Override
    public void download(Batch batch) {
        // if device is connected to the internet
        // and the type of the connection is allowed
        // then start immediately
        // else, schedule a job with window 1ms-1day

        // if the job fails because of network issues, then schedule a job with window 1ms-1day

        downloader.download(batch, downloadBatchMap);
    }

    @Override
    public void pause(DownloadBatchId downloadBatchId) {
        DownloadBatch downloadBatch = downloadBatchMap.get(downloadBatchId);
        if (downloadBatch == null) {
            return;
        }
        downloadBatch.pause();
    }

    @Override
    public void resume(DownloadBatchId downloadBatchId) {
        DownloadBatch downloadBatch = downloadBatchMap.get(downloadBatchId);
        if (downloadBatch == null) {
            return;
        }

        if (downloadBatch.status().status() == DownloadBatchStatus.Status.DOWNLOADING) {
            return;
        }

        downloadBatchMap.remove(downloadBatchId);
        downloadBatch.resume();

        downloader.download(downloadBatch, downloadBatchMap);
    }

    @Override
    public void delete(DownloadBatchId downloadBatchId) {
        DownloadBatch downloadBatch = downloadBatchMap.get(downloadBatchId);
        if (downloadBatch == null) {
            return;
        }
        downloadBatchMap.remove(downloadBatchId);
        downloadBatch.delete();
    }

    @Override
    public void addDownloadBatchCallback(DownloadBatchCallback downloadBatchCallback) {
        callbacks.add(downloadBatchCallback);
    }

    @Override
    public void removeDownloadBatchCallback(DownloadBatchCallback downloadBatchCallback) {
        if (callbacks.contains(downloadBatchCallback)) {
            callbacks.remove(downloadBatchCallback);
        }
    }

    @Override
    public void getAllDownloadBatchStatuses(final AllBatchStatusesCallback callback) {
        if (downloadService == null) {
            executor.submit(
                    WaitForLockRunnable.waitFor(waitForDownloadService)
                            .thenPerform(() -> executeGetAllDownloadBatchStatuses(callback))
            );
        } else {
            executeGetAllDownloadBatchStatuses(callback);
        }
    }

    private void executeGetAllDownloadBatchStatuses(final AllBatchStatusesCallback callback) {
        final List<DownloadBatchStatus> downloadBatchStatuses = new ArrayList<>(downloadBatchMap.size());

        for (DownloadBatch downloadBatch : downloadBatchMap.values()) {
            downloadBatchStatuses.add(downloadBatch.status());
        }

        callbackHandler.post(() -> callback.onReceived(downloadBatchStatuses));
    }

    @Override
    public void getDownloadStatusWithMatching(final DownloadFileId downloadFileId, final DownloadFileStatusCallback callback) {
        if (downloadService == null) {
            executor.submit(
                    WaitForLockRunnable.waitFor(waitForDownloadService)
                            .thenPerform(() -> executeFirstLocalPathForDownloadWithMatching(downloadFileId, callback))
            );
        } else {
            executeFirstLocalPathForDownloadWithMatching(downloadFileId, callback);
        }
    }

    private void executeFirstLocalPathForDownloadWithMatching(DownloadFileId downloadFileId, final DownloadFileStatusCallback callback) {
        for (DownloadBatch downloadBatch : downloadBatchMap.values()) {
            final DownloadFile downloadFile = downloadBatch.downloadFileWith(downloadFileId);
            if (downloadFile != null) {
                callbackHandler.post(() -> callback.onReceived(downloadFile.fileStatus()));
                return;
            }
        }
    }

}

@@ -2265,22 +2265,16 @@
 allback(
-final 
 AllStore
@@ -4474,38 +4474,32 @@
 adBatchStatuses(
-final 
 AllBatchStatuses
@@ -4511,32 +4511,32 @@
 ack callback) %7B%0A
+
         if (down
@@ -4911,22 +4911,16 @@
 tatuses(
-final 
 AllBatch
@@ -4956,22 +4956,16 @@
         
-final 
 List%3CDow
@@ -5342,22 +5342,16 @@
 atching(
-final 
 Download
@@ -5364,38 +5364,32 @@
  downloadFileId,
- final
  DownloadFileSta
@@ -5896,22 +5896,16 @@
 dFileId,
- final
  Downloa
@@ -6000,32 +6000,32 @@
 Map.values()) %7B%0A
+
             fina
@@ -6020,22 +6020,16 @@
         
-final 
 Download

Remove unneeded finals