/*
 * Copyright 2017 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.android.apps.muzei.gallery;

import android.arch.persistence.db.SupportSQLiteDatabase;
import android.arch.persistence.room.Database;
import android.arch.persistence.room.Room;
import android.arch.persistence.room.RoomDatabase;
import android.arch.persistence.room.migration.Migration;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.net.Uri;
import android.os.Binder;
import android.support.annotation.NonNull;
import android.util.Log;

import java.io.File;

/**
 * Database for accessing Gallery data
 */
@Database(entities = {ChosenPhoto.class, Metadata.class}, version = 6)
public abstract class GalleryDatabase extends RoomDatabase {
    private static final String TAG = "GalleryDatabase";
    private static GalleryDatabase sInstance;

    public abstract ChosenPhotoDao chosenPhotoDao();

    abstract MetadataDao metadataDao();

    public synchronized static GalleryDatabase getInstance(Context context) {
        if (sInstance == null) {
            final Context applicationContext = context.getApplicationContext();
            sInstance = Room.databaseBuilder(applicationContext, GalleryDatabase.class,
                    "gallery_source.db")
                    .addMigrations(
                            MIGRATION_1_2,
                            MIGRATION_2_3,
                            MIGRATION_3_4,
                            new Migration4_5(applicationContext),
                            MIGRATION_5_6)
                    .build();
        }
        return sInstance;
    }

    private static final Migration MIGRATION_1_2 = new Migration(1, 2) {
        @Override
        public void migrate(@NonNull SupportSQLiteDatabase database) {
            database.execSQL("DROP TABLE IF EXISTS metadata_cache");
            database.execSQL("CREATE TABLE metadata_cache ("
                    + "_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,"
                    + "uri TEXT NOT NULL,"
                    + "datetime INTEGER,"
                    + "location TEXT,"
                    + "UNIQUE (uri) ON CONFLICT REPLACE)");
        }
    };

    private static final Migration MIGRATION_2_3 = new Migration(2, 3) {
        @Override
        public void migrate(@NonNull SupportSQLiteDatabase database) {
            database.execSQL("ALTER TABLE chosen_photos"
                    + " ADD COLUMN is_tree_uri INTEGER");
        }
    };

    private static final Migration MIGRATION_3_4 = new Migration(3, 4) {
        @Override
        public void migrate(@NonNull SupportSQLiteDatabase database) {
            // Due to an issue with upgrading version 2 to 3, some users might have the
            // COLUMN_NAME_IS_TREE_URI column and some might not. Awkward.
            // We'll check if the column exists and add it if it doesn't exist
            Cursor pragma = database.query("PRAGMA table_info(chosen_photos)");
            boolean columnExists = false;
            while (pragma.moveToNext()) {
                int columnIndex = pragma.getColumnIndex("name");
                if (columnIndex != -1 &&
                        pragma.getString(columnIndex).equals("is_tree_uri")) {
                    columnExists = true;
                }
            }
            pragma.close();
            if (!columnExists) {
                database.execSQL("ALTER TABLE chosen_photos"
                        + " ADD COLUMN is_tree_uri INTEGER");
            }
        }
    };

    /**
     * Migration4_5 is a bit different since we need access to a Context in order to double check
     * that we've successfully persisted URI permissions to Uris generated by our own app.
     */
    private static class Migration4_5 extends Migration {
        private Context applicationContext;

        Migration4_5(Context context) {
            super(4, 5);
            applicationContext = context.getApplicationContext();
        }
        @Override
        public void migrate(@NonNull SupportSQLiteDatabase database) {
            // Double check all existing artwork to make sure we've
            // persisted URI permissions where possible
            ContentResolver contentResolver = applicationContext.getContentResolver();
            Cursor data = database.query("SELECT uri FROM chosen_photos");
            while (data.moveToNext()) {
                Uri imageUri = Uri.parse(data.getString(0));
                File cachedFile = GalleryProvider.getCacheFileForUri(applicationContext, imageUri);
                if (cachedFile == null || !cachedFile.exists()) {
                    // If we don't have a cached file, then we must have permission to the
                    // underlying URI
                    boolean haveUriPermission = applicationContext.checkUriPermission(imageUri,
                            Binder.getCallingPid(), Binder.getCallingUid(),
                            Intent.FLAG_GRANT_READ_URI_PERMISSION) == PackageManager.PERMISSION_GRANTED;
                    if (!haveUriPermission) {
                        // On API 25 and lower, we don't get URI permissions to URIs
                        // from our own package so we manage those URI permissions manually
                        try {
                            contentResolver.call(imageUri, "takePersistableUriPermission",
                                    imageUri.toString(), null);
                        } catch (Exception e) {
                            Log.w(TAG, "Unable to manually persist uri permissions to " + imageUri, e);
                        }
                    }
                }
            }
            data.close();
        }
    }

    private static final Migration MIGRATION_5_6 = new Migration(5, 6) {
        @Override
        public void migrate(@NonNull SupportSQLiteDatabase database) {
            // Handle Chosen Photos
            database.execSQL("UPDATE chosen_photos "
                    + "SET is_tree_uri = 0"
                    + "WHERE is_tree_uri IS NULL");
            database.execSQL("CREATE TABLE chosen_photos2 ("
                    + "_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,"
                    + "uri TEXT NOT NULL,"
                    + "is_tree_uri INTEGER NOT NULL,"
                    + "UNIQUE (uri) ON CONFLICT REPLACE)");
            database.execSQL("INSERT INTO chosen_photos2 "
                    + "SELECT * FROM chosen_photos");
            database.execSQL("DROP TABLE chosen_photos");
            database.execSQL("ALTER TABLE chosen_photos2 RENAME TO chosen_photos");
            database.execSQL("CREATE UNIQUE INDEX index_chosen_photos_uri "
                    + "ON chosen_photos (uri)");

            // Handle Metadata
            database.execSQL("CREATE TABLE metadata_cache2 ("
                    + "_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,"
                    + "uri TEXT NOT NULL,"
                    + "datetime INTEGER,"
                    + "location TEXT,"
                    + "UNIQUE (uri) ON CONFLICT REPLACE)");
            database.execSQL("INSERT INTO metadata_cache2 "
                    + "SELECT * FROM metadata_cache");
            database.execSQL("DROP TABLE metadata_cache");
            database.execSQL("ALTER TABLE metadata_cache2 RENAME TO metadata_cache");
            database.execSQL("CREATE UNIQUE INDEX index_metadata_cache_uri "
                    + "ON metadata_cache (uri)");
        }
    };
}

@@ -6633,16 +6633,17 @@
 _uri = 0
+ 
 %22%0A      

Fix SQL statement in Gallery upgrade code