/*
 * Copyright 2015, Yahoo Inc.
 * Copyrights licensed under the Apache 2.0 License.
 * See the accompanying LICENSE file for terms.
 */
package com.yahoo.squidb.utility;

import android.content.ContentValues;
import android.content.Context;
import android.util.Log;

import com.yahoo.squidb.data.SquidDatabase;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Collection;
import java.util.Collections;

/**
 * Various utility functions for SquiDB
 */
public class SquidUtilities {

    public static final String LOG_TAG = "squidb";

    /**
     * Put an arbitrary object into a {@link ContentValues}
     *
     * @param target the ContentValues store
     * @param key the key to use
     * @param value the value to store
     */
    public static void putInto(ContentValues target, String key, Object value, boolean errorOnFail) {
        if (value == null) {
            target.putNull(key);
        } else if (value instanceof Boolean) {
            target.put(key, (Boolean) value);
        } else if (value instanceof Byte) {
            target.put(key, (Byte) value);
        } else if (value instanceof Double) {
            target.put(key, (Double) value);
        } else if (value instanceof Float) {
            target.put(key, (Float) value);
        } else if (value instanceof Integer) {
            target.put(key, (Integer) value);
        } else if (value instanceof Long) {
            target.put(key, (Long) value);
        } else if (value instanceof Short) {
            target.put(key, (Short) value);
        } else if (value instanceof String) {
            target.put(key, (String) value);
        } else if (value instanceof byte[]) {
            target.put(key, (byte[]) value);
        } else if (errorOnFail) {
            throw new UnsupportedOperationException("Could not handle type " + value.getClass());
        }
    }

    /**
     * A version of {@link Collection#addAll(Collection)} that works on varargs without calling Arrays.asList, which is
     * a performance and memory boost
     */
    public static <T> void addAll(Collection<T> collection, T... objects) {
        if (objects != null) {
            Collections.addAll(collection, objects);
        }
    }

    // --- serialization

    /**
     * Copy database files to the given folder. Useful for debugging.
     *
     * @param context a Context
     * @param database the SquidDatabase to copy
     * @param toFolder the directory to copy files into
     */
    public static void copyDatabase(Context context, SquidDatabase database, String toFolder) {
        File folderFile = new File(toFolder);
        if (!(folderFile.mkdirs() || folderFile.isDirectory())) {
            Log.e(LOG_TAG, "Error creating directories for database copy");
            return;
        }
        File dbFile = context.getDatabasePath(database.getName());
        try {
            copyFile(dbFile, new File(folderFile.getAbsolutePath() + File.separator + database.getName()));
        } catch (Exception e) {
            Log.e(LOG_TAG, "Error copying database " + database.getName(), e);
        }
    }

    /**
     * Copy a file from one place to another
     */
    private static void copyFile(File in, File out) throws Exception {
        FileInputStream fis = new FileInputStream(in);
        FileOutputStream fos = new FileOutputStream(out);
        try {
            copyStream(fis, fos);
        } finally {
            fis.close();
            fos.close();
        }
    }

    /**
     * Copy a stream from source to destination
     */
    private static void copyStream(InputStream source, OutputStream dest) throws IOException {
        int bytes;
        byte[] buffer;
        int BUFFER_SIZE = 1024;
        buffer = new byte[BUFFER_SIZE];
        while ((bytes = source.read(buffer)) != -1) {
            if (bytes == 0) {
                bytes = source.read();
                if (bytes < 0) {
                    break;
                }
                dest.write(bytes);
                dest.flush();
                continue;
            }

            dest.write(buffer, 0, bytes);
            dest.flush();
        }
    }
}

@@ -262,16 +262,58 @@
 l.Log;%0A%0A
+import com.yahoo.squidb.data.SquidCursor;%0A
 import c
@@ -2027,32 +2027,1386 @@
        %7D%0A    %7D%0A%0A
+    public static void dumpCursor(SquidCursor%3C?%3E cursor) %7B%0A        dumpCursor(cursor, 20);%0A    %7D%0A%0A    public static void dumpCursor(SquidCursor%3C?%3E cursor, int maxColumnWidth) %7B%0A        String%5B%5D columnNames = cursor.getColumnNames();%0A        StringBuilder rowBuilder = new StringBuilder();%0A%0A        for (String col : columnNames) %7B%0A            addColumnToRowBuilder(rowBuilder, col, maxColumnWidth);%0A        %7D%0A        rowBuilder.append('%5Cn');%0A        for (int i = 0; i %3C (maxColumnWidth + 1) * columnNames.length; i++) %7B%0A            rowBuilder.append('=');%0A        %7D%0A        rowBuilder.append('%5Cn');%0A        while (cursor.moveToNext()) %7B%0A            for (int i = 0; i %3C columnNames.length; i++) %7B%0A                addColumnToRowBuilder(rowBuilder, cursor.getString(i), maxColumnWidth);%0A            %7D%0A            rowBuilder.append('%5Cn');%0A        %7D%0A        Log.d(LOG_TAG, rowBuilder.toString());%0A    %7D%0A%0A    private static void addColumnToRowBuilder(StringBuilder builder, String value, int maxColumnWidth) %7B%0A        if (value.length() %3E maxColumnWidth) %7B%0A            builder.append(value.substring(0, maxColumnWidth - 3)).append(%22...%22);%0A        %7D else %7B%0A            builder.append(value);%0A            for (int i = 0; i %3C maxColumnWidth - value.length(); i++) %7B%0A                builder.append(' ');%0A            %7D%0A        %7D%0A        builder.append('%7C');%0A    %7D%0A%0A
     /**%0A     * A

Add a utility for printing the formatted contents of a cursor