package org.sagebionetworks.bridge.android.manager.dao;

import android.content.Context;
import android.content.SharedPreferences;
import android.support.annotation.AnyThread;

import com.google.common.base.Function;
import com.google.gson.reflect.TypeToken;

import org.sagebionetworks.bridge.rest.RestUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Persists objects in SharedPreferences via JSON serialization/deserialization. Transforms can be
 * applied to the JSON string, with the transform being applied to the JSON before saving to shared
 * prefs, or applied to the string after retrieving from saved prefs. Encryption/decryption are an
 * example of useful transforms to apply.
 */
@AnyThread
public class SharedPreferencesJsonDAO {
    private static final Logger logger = LoggerFactory.getLogger(SharedPreferencesJsonDAO.class);

    protected final SharedPreferences sharedPreferences;

    protected SharedPreferencesJsonDAO(Context applicationContext, String preferencesFile) {
        sharedPreferences = applicationContext
                .getSharedPreferences(preferencesFile, Context.MODE_PRIVATE);
    }

    protected void removeValue(String key) {
        logger.debug(getClass().getCanonicalName(), "removing key: " + key);

        sharedPreferences.edit().remove(key).apply();
    }

    protected <T> void setValue(String key, T value, Class<? super T> klass) {
        String json = RestUtils.GSON.toJson(value, klass);

        logger.debug(getClass().getCanonicalName(), "setting key: " + key + ", value: " + json);

        sharedPreferences.edit().putString(key, json).apply();
    }

    protected <T> T getValue(String key, Class<? extends T> klass) {
        String json = sharedPreferences.getString(key, null);

        logger.debug(getClass().getCanonicalName(), "getting key: " + key + ", value: " + json);

        return RestUtils.GSON.fromJson(json, klass);
    }

    protected <T> void setValue(String key, T value, TypeToken<? super T> type) {
        String json = RestUtils.GSON.toJson(value, type.getType());

        logger.debug(getClass().getCanonicalName(), "setting key: " + key + ", value: " + json);

        sharedPreferences.edit().putString(key, json).apply();
    }

    protected <T> T getValue(String key, TypeToken<? extends T> type) {
        String json = sharedPreferences.getString(key, null);

        logger.debug(getClass().getCanonicalName(), "getting key: " + key + ", value: " + json);

        return RestUtils.GSON.fromJson(json, type.getType());
    }

    protected <T> void setValue(String key, T value, TypeToken<? super T> type,
                                Function<String, String> transform) {
        String json = RestUtils.GSON.toJson(value, type.getType());

        logger.debug(getClass().getCanonicalName(), "setting key: " + key + ", value: " + json);

        json = transform.apply(json);

        sharedPreferences.edit().putString(key, json).apply();
    }

    protected <T> T getValue(String key, TypeToken<? extends T> type,
                             Function<String, String> transform) {
        String json = sharedPreferences.getString(key, null);

        json = transform.apply(json);

        logger.debug(getClass().getCanonicalName(), "getting key: " + key + ", value: " + json);

        return RestUtils.GSON.fromJson(json, type.getType());
    }

    protected <T> void setValue(String key, T value, Class<? super T> klass,
                                Function<String, String> transform) {
        String json = RestUtils.GSON.toJson(value, klass);

        logger.debug(getClass().getCanonicalName(), "setting key: " + key + ", value: " + json);

        json = transform.apply(json);

        sharedPreferences.edit().putString(key, json).apply();
    }

    protected <T> T getValue(String key, Class<? extends T> klass,
                             Function<String, String> transform) {
        String json = sharedPreferences.getString(key, null);

        json = transform.apply(json);

        logger.debug(getClass().getCanonicalName(), "getting key: " + key + ", value: " + json);

        return RestUtils.GSON.fromJson(json, klass);
    }
}

@@ -1212,39 +1212,8 @@
 bug(
-getClass().getCanonicalName(), 
 %22rem
@@ -1233,16 +1233,16 @@
 + key);%0A
+
 %0A       
@@ -1459,39 +1459,8 @@
 bug(
-getClass().getCanonicalName(), 
 %22set
@@ -1728,39 +1728,8 @@
 bug(
-getClass().getCanonicalName(), 
 %22get
@@ -2006,39 +2006,8 @@
 bug(
-getClass().getCanonicalName(), 
 %22set
@@ -2278,39 +2278,8 @@
 bug(
-getClass().getCanonicalName(), 
 %22get
@@ -2633,39 +2633,8 @@
 bug(
-getClass().getCanonicalName(), 
 %22set
@@ -3048,39 +3048,8 @@
 bug(
-getClass().getCanonicalName(), 
 %22get
@@ -3391,39 +3391,8 @@
 bug(
-getClass().getCanonicalName(), 
 %22set
@@ -3770,32 +3770,32 @@
 m.apply(json);%0A%0A
+
         logger.d
@@ -3803,39 +3803,8 @@
 bug(
-getClass().getCanonicalName(), 
 %22get

Cut down log noise from SharedPreferencesJsonDAO