package com.novoda.downloadmanager;

import android.annotation.TargetApi;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.Binder;
import android.os.Build;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.util.Log;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import static com.novoda.downloadmanager.MigrationStatus.Status;

public class LiteDownloadMigrationService extends Service implements DownloadMigrationService {

    private static final String TAG = "MigrationService";
    private static ExecutorService executor;

    private IBinder binder;
    private NotificationChannelCreator notificationChannelCreator;
    private NotificationCreator<MigrationStatus> notificationCreator;
    private NotificationManager notificationManager;

    @Override
    public void onCreate() {
        Log.d(TAG, "onCreate");
        if (executor == null) {
            executor = Executors.newSingleThreadExecutor();
        }

        binder = new MigrationDownloadServiceBinder();
        notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

        super.onCreate();
    }

    @Override
    public void setNotificationChannelCreator(NotificationChannelCreator notificationChannelCreator) {
        this.notificationChannelCreator = notificationChannelCreator;
    }

    @Override
    public void setNotificationCreator(NotificationCreator<MigrationStatus> notificationCreator) {
        this.notificationCreator = notificationCreator;
    }

    @Override
    public void startMigration(MigrationCallback migrationCallback) {
        createNotificationChannel();
        MigrationJob migrationJob = new MigrationJob(getApplicationContext(), getDatabasePath("downloads.db"));
        migrationJob.addCallback(migrationCallback);
        migrationJob.addCallback(notificationMigrationCallback);
        executor.execute(migrationJob);
    }

    private void createNotificationChannel() {
        Optional<NotificationChannel> notificationChannel = notificationChannelCreator.createNotificationChannel();
        String channelName = notificationChannelCreator.getNotificationChannelName();

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && notificationChannel.isPresent() && notificationChannelDoesNotExist(channelName)) {
            notificationManager.createNotificationChannel(notificationChannel.get());
        }
    }

    class MigrationDownloadServiceBinder extends Binder {
        DownloadMigrationService getService() {
            return LiteDownloadMigrationService.this;
        }
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return binder;
    }

    @TargetApi(Build.VERSION_CODES.O)
    private boolean notificationChannelDoesNotExist(String channelName) {
        return notificationManager.getNotificationChannel(channelName) == null;
    }

    private final MigrationCallback notificationMigrationCallback = new MigrationCallback() {
        @Override
        public void onUpdate(MigrationStatus migrationStatus) {
            String channelName = notificationChannelCreator.getNotificationChannelName();
            NotificationInformation notification = notificationCreator.createNotification(channelName, migrationStatus);

            if (migrationStatus.status() == Status.COMPLETE || migrationStatus.status() == Status.DB_NOT_PRESENT) {
                stackNotification(notification);
            } else {
                updateNotification(notification);
            }
        }

        private void updateNotification(NotificationInformation notificationInformation) {
            startForeground(notificationInformation.getId(), notificationInformation.getNotification());
        }

        private void stackNotification(NotificationInformation notificationInformation) {
            stopForeground(true);
            Notification notification = notificationInformation.getNotification();
            notificationManager.notify(notificationInformation.getId(), notification);
        }
    };

}

@@ -1349,32 +1349,310 @@
 reate();%0A    %7D%0A%0A
+    class MigrationDownloadServiceBinder extends Binder %7B%0A        DownloadMigrationService getService() %7B%0A            return LiteDownloadMigrationService.this;%0A        %7D%0A    %7D%0A%0A    @Nullable%0A    @Override%0A    public IBinder onBind(Intent intent) %7B%0A        return binder;%0A    %7D%0A%0A
     @Override%0A  
@@ -2905,286 +2905,8 @@
  %7D%0A%0A
-    class MigrationDownloadServiceBinder extends Binder %7B%0A        DownloadMigrationService getService() %7B%0A            return LiteDownloadMigrationService.this;%0A        %7D%0A    %7D%0A%0A    @Nullable%0A    @Override%0A    public IBinder onBind(Intent intent) %7B%0A        return binder;%0A    %7D%0A%0A
     

Reorder service methods based on lifecycle.