package com.novoda.downloadmanager.demo;

import android.content.res.AssetManager;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;

import com.novoda.downloadmanager.SqlDatabaseWrapper;
import com.novoda.notils.exception.DeveloperError;
import com.novoda.notils.logger.simple.Log;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;

class VersionOneDatabaseCloner {

    private static final int BUFFER_SIZE = 1024;
    private static final byte[] BUFFER = new byte[BUFFER_SIZE];

    private static final String DATABASE_NAME = "downloads.db";
    private static final String DOWNLOAD_FILE_NAME_FORMAT = "%s.zip";
    private static final String ORIGINAL_FILE_LOCATION_QUERY = "SELECT _data FROM Downloads WHERE _data IS NOT NULL";
    private static final int ORIGINAL_FILE_LOCATION_COLUMN_INDEX = 0;

    private final AssetManager assetManager;
    private final Executor executor;
    private final CloneCallback cloneCallback;
    private final String originalDatabaseLocation;

    VersionOneDatabaseCloner(AssetManager assetManager,
                             Executor executor,
                             CloneCallback cloneCallback,
                             String originalDatabaseLocation) {
        this.assetManager = assetManager;
        this.executor = executor;
        this.cloneCallback = cloneCallback;
        this.originalDatabaseLocation = originalDatabaseLocation;
    }

    interface CloneCallback {
        void onUpdate(String updateMessage);
    }

    void cloneDatabaseWithDownloadSize(final String selectedFileSize) {
        executor.execute(new Runnable() {
            @Override
            public void run() {
                cloneDatabase();
                cloneDownloadFilesWithSize(selectedFileSize);
                cloneCallback.onUpdate("Cloning Complete");
            }
        });
    }

    private void cloneDatabase() {
        cloneCallback.onUpdate("Cloning Database...");
        File outputFile = new File(originalDatabaseLocation);
        createFileIfDoesNotExist(outputFile);
        copyAssetToFile(DATABASE_NAME, outputFile);
    }

    private void createFileIfDoesNotExist(File outputFile) {
        boolean parentPathDoesNotExist = !outputFile.getParentFile().exists();
        if (parentPathDoesNotExist) {
            Log.w(String.format("path: %s doesn't exist, creating parent directories...", outputFile.getAbsolutePath()));
            outputFile.getParentFile().mkdirs();
            parentPathDoesNotExist = !outputFile.getParentFile().exists();
        }

        if (parentPathDoesNotExist) {
            throw new DeveloperError("Unable to create path: " + outputFile.getParentFile().getAbsolutePath());
        }
    }

    private void copyAssetToFile(String assetName, File outputFile) {
        InputStream inputStream;
        OutputStream myOutput;
        int length;
        try {
            inputStream = assetManager.open(assetName);
            myOutput = new FileOutputStream(outputFile, true);
            while ((length = inputStream.read(BUFFER)) > 0) {
                myOutput.write(BUFFER, 0, length);
            }
            myOutput.close();
            myOutput.flush();
            inputStream.close();

            Log.d(getClass().getSimpleName(), "Copied asset: " + assetName);
        } catch (IOException e) {
            e.printStackTrace();
            Log.e("Failed to copy asset: " + assetName, e);
        }
    }

    private void cloneDownloadFilesWithSize(String selectedFileSize) {
        cloneCallback.onUpdate("Cloning Files...");
        List<String> localFileLocations = localFileLocations();
        String fileName = String.format(DOWNLOAD_FILE_NAME_FORMAT, selectedFileSize);

        for (String localFileLocation : localFileLocations) {
            File outputFile = new File(localFileLocation);

            createFileIfDoesNotExist(outputFile);
            copyAssetToFile(fileName, outputFile);
        }
    }

    private List<String> localFileLocations() {
        SQLiteDatabase sqLiteDatabase = SQLiteDatabase.openDatabase(originalDatabaseLocation, null, 0);
        SqlDatabaseWrapper database = new SqlDatabaseWrapper(sqLiteDatabase);
        Cursor originalFileLocationsCursor = database.rawQuery(ORIGINAL_FILE_LOCATION_QUERY);
        List<String> originalFileLocations = new ArrayList<>();

        while (originalFileLocationsCursor.moveToNext()) {
            String originalFileLocation = originalFileLocationsCursor.getString(ORIGINAL_FILE_LOCATION_COLUMN_INDEX);
            originalFileLocations.add(originalFileLocation);
        }
        database.close();
        return originalFileLocations;
    }

}

@@ -2613,16 +2613,42 @@
         
+parentPathDoesNotExist = !
 outputFi
@@ -2680,83 +2680,8 @@
 ();%0A
-            parentPathDoesNotExist = !outputFile.getParentFile().exists();%0A
     
@@ -2955,16 +2955,23 @@
 utStream
+ = null
 ;%0A      
@@ -2993,16 +2993,23 @@
 myOutput
+ = null
 ;%0A      
@@ -3286,102 +3286,8 @@
   %7D%0A
-            myOutput.close();%0A            myOutput.flush();%0A            inputStream.close();%0A%0A
     
@@ -3422,24 +3422,24 @@
 ackTrace();%0A
-
             
@@ -3482,24 +3482,442 @@
 etName, e);%0A
+        %7D finally %7B%0A            try %7B%0A                if (myOutput != null) %7B%0A                    myOutput.close();%0A                    myOutput.flush();%0A                %7D%0A%0A                if (inputStream != null) %7B%0A                    inputStream.close();%0A                %7D%0A            %7D catch (IOException e) %7B%0A                e.printStackTrace();%0A                Log.e(%22Failed to close streams.%22, e);%0A            %7D%0A
         %7D%0A  

Fix findbugs.