package com.miguelgaeta.bootstrap.mg_preference;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.miguelgaeta.bootstrap.mg_delay.MGDelay;
import com.miguelgaeta.bootstrap.mg_log.MGLog;
import com.miguelgaeta.bootstrap.mg_rest.MGRestClient;
import com.miguelgaeta.bootstrap.mg_rx.MGRxError;

import lombok.RequiredArgsConstructor;
import rx.Subscription;

/**
 * Created by mrkcsc on 3/9/15.
 */
@RequiredArgsConstructor(staticName = "create")
class MGPreferenceData<T> {

    /**
     * Standard delay to prevent stacked serialize calls
     * from using up too much memory and OOM.
     */
    private static final int SERIALIZATION_DELAY = 10000;

    private final String key;

    private final TypeToken<?> typeToken;

    private final T defaultValue;

    private T value;

    private final boolean versioned;

    private Subscription delayedSerialization;

    private final Gson gson = MGRestClient.getGson();

    /**
     * If value is not already in memory, attempt to fetch
     * it from the data store.  If still cannot be
     * found, emit the default value.
     */
    @SuppressWarnings("unchecked")
    public T get() {

        if (value == null && delayedSerialization == null) {
            value = (T)MGPreference.getDataStore().get(key, typeToken.getRawType(), versioned) ;

            if (value == null && defaultValue != null) {

                return defaultValue;
            }
        }

        return value;
    }

    /**
     * Updates value in memory and also persists to cache.  If versioned
     * field, persist on delay, otherwise persist immediately.  This is
     * not really a very good heuristic so should be revised to happen in a
     * more intelligent fashion.
     *
     * TODO: Delay flag should be configurable and off by default.
     */
    public void set(T value) {

        this.value = value;

        if (delayedSerialization != null) {
            delayedSerialization.unsubscribe();
        }

        if (versioned) {

            delayedSerialization = MGDelay.delay(SERIALIZATION_DELAY).observeOn(MGPreference.getScheduler()).subscribe(r -> {

                set();

                delayedSerialization = null;

            }, MGRxError.create(null, "Unable to serialize preference."));

        } else {

            set();
        }
    }

    private void set() {

        MGPreference.getDataStore().set(key, serializeValue(), typeToken.getType(), versioned);
    }

    public void clear() {

        set(defaultValue);
    }

    private String serializeValue() {

        try {

            return value == null ? null : gson.toJson(value, typeToken.getType());

        } catch (OutOfMemoryError e) {

            // Alert of any preferences that become too large.
            MGLog.e("Out of memory while trying to serialize: " + key);

            throw e;
        }
    }
}

@@ -169,55 +169,8 @@
 ay;%0A
-import com.miguelgaeta.bootstrap.mg_log.MGLog;%0A
 impo
@@ -2108,20 +2108,85 @@
         
-set(
+MGPreference.getDataStore().set(key, value, typeToken.getType(), true
 );%0A%0A    
@@ -2329,66 +2329,8 @@
     
-        set();%0A        %7D%0A    %7D%0A%0A    private void set() %7B%0A%0A
     
@@ -2370,32 +2370,21 @@
 et(key, 
-serializeV
+v
 alue
-()
 , typeTo
@@ -2402,19 +2402,25 @@
 (), 
-versioned);
+false);%0A        %7D
 %0A   
@@ -2486,359 +2486,7 @@
    %7D
-%0A%0A    private String serializeValue() %7B%0A%0A        try %7B%0A%0A            return value == null ? null : gson.toJson(value, typeToken.getType());%0A%0A        %7D catch (OutOfMemoryError e) %7B%0A%0A            // Alert of any preferences that become too large.%0A            MGLog.e(%22Out of memory while trying to serialize: %22 + key);%0A%0A            throw e;%0A        %7D%0A    %7D
 %0A%7D%0A

Remove unused method.