package com.cesarferreira.rxpaper;

import android.content.Context;
import android.text.TextUtils;

import com.cesarferreira.rxpaper.exceptions.UnableToPerformOperationException;

import io.paperdb.Paper;
import rx.Observable;
import rx.Subscriber;

public class RxPaper {

    private Context mContext;
    private static RxPaper mRxPaper;
    private static String mCustomBook;


    public static RxPaper with(Context context) {
        return init(context, "");
    }

    public static RxPaper with(Context context, String customBook) {
        return init(context, customBook);
    }

    private static RxPaper init(Context context, String customBook) {
        mRxPaper = new RxPaper(context, customBook);
        Paper.init(context);
        return mRxPaper;
    }

    private RxPaper(Context context, String customBook) {
        this.mContext = context;
        mCustomBook = customBook;

    }

    private static boolean hasBook() {
        return !TextUtils.isEmpty(mCustomBook);
    }


    /**
     * Saves any types of POJOs or collections in Book storage.
     *
     * @param key   object key is used as part of object's file name
     * @param value object to save, must have no-arg constructor, can't be null.
     * @return this Book instance
     */
    public <T> Observable<Boolean> write(final String key, final T value) {

        return Observable.create(new Observable.OnSubscribe<Boolean>() {
            @Override
            public void call(Subscriber<? super Boolean> subscriber) {

                if (!subscriber.isUnsubscribed()) {
                    try {
                        if (hasBook()) {
                            Paper.book(mCustomBook).write(key, value);
                        } else {
                            Paper.book().write(key, value);
                        }

                        subscriber.onNext(true);
                    } catch (Exception e) {
                        subscriber.onError(new UnableToPerformOperationException("Can't write"));
                    }
                    subscriber.onCompleted();

                }
            }
        });


    }

    /**
     * Instantiates saved object using original object class (e.g. LinkedList). Support limited
     * backward and forward compatibility: removed fields are ignored, new fields have their
     * default values.
     * <p/>
     * All instantiated objects must have no-arg constructors.
     *
     * @param key          object key to read
     * @param defaultValue will be returned if key doesn't exist
     * @return the saved object instance observable or null
     */
    public <T> Observable<T> read(final String key, final T defaultValue) {

        return Observable.create(new Observable.OnSubscribe<T>() {
            @Override
            public void call(Subscriber<? super T> subscriber) {

                if (!subscriber.isUnsubscribed()) {

                    T value;

                    if (hasBook()) {
                        value = Paper.book(mCustomBook).read(key, defaultValue);
                    } else {
                        value = Paper.book().read(key, defaultValue);
                    }

                    if (value == null) {
                        subscriber.onError(new UnableToPerformOperationException(key + " is empty"));
                    } else {
                        subscriber.onNext(value);
                    }
                    subscriber.onCompleted();

                }
            }
        });
    }

    /**
     * Instantiates saved object using original object class (e.g. LinkedList). Support limited
     * backward and forward compatibility: removed fields are ignored, new fields have their
     * default values.
     * <p/>
     * All instantiated objects must have no-arg constructors.
     *
     * @param key object key to read
     * @return an Observable with the saved object instance or null
     */
    public <T> Observable<T> read(final String key) {

        return Observable.create(new Observable.OnSubscribe<T>() {
            @Override
            public void call(Subscriber<? super T> subscriber) {

                if (!subscriber.isUnsubscribed()) {

                    T value;

                    if (hasBook()) {
                        value = Paper.book(mCustomBook).read(key);
                    } else {
                        value = Paper.book().read(key);
                    }

                    if (value == null) {
                        subscriber.onError(new UnableToPerformOperationException(key + " is empty"));
                    } else {
                        subscriber.onNext(value);
                    }

                    subscriber.onCompleted();

                }
            }
        });


    }


    /**
     * Delete saved object for given key if it is exist.
     *
     * @param key object key
     */
    public Observable<Boolean> delete(final String key) {

        return Observable.create(new Observable.OnSubscribe<Boolean>() {
            @Override
            public void call(Subscriber<? super Boolean> subscriber) {

                if (!subscriber.isUnsubscribed()) {

                    try {
                        if (hasBook()) {
                            Paper.book(mCustomBook).delete(key);
                        } else {
                            Paper.book().delete(key);
                        }
                        subscriber.onNext(true);
                    } catch (Exception e) {
                        subscriber.onError(new UnableToPerformOperationException("Can't delete"));
                    }

                    subscriber.onCompleted();
                }
            }
        });


    }

    public Observable<Boolean> destroy() {
        return Observable.create(new Observable.OnSubscribe<Boolean>() {
            @Override
            public void call(Subscriber<? super Boolean> subscriber) {
                if (!subscriber.isUnsubscribed()) {
                    try {
                        if (hasBook()) {
                            Paper.book(RxPaper.mCustomBook).destroy();
                        } else {
                            Paper.book().destroy();
                        }
                        subscriber.onNext(true);
                    } catch (Exception e) {
                        subscriber.onError(new UnableToPerformOperationException("Can't destroy"));
                    }
                    subscriber.onCompleted();

                }
            }
        });
    }
}

@@ -5717,32 +5717,1024 @@
    %7D);%0A%0A%0A    %7D%0A%0A
+    /**%0A     * Check if given key exist.%0A     *%0A     * @param key object key%0A     */%0A    public Observable%3CBoolean%3E exists(final String key) %7B%0A%0A        return Observable.create(new Observable.OnSubscribe%3CBoolean%3E() %7B%0A            @Override%0A            public void call(Subscriber%3C? super Boolean%3E subscriber) %7B%0A%0A                if (!subscriber.isUnsubscribed()) %7B%0A%0A                    try %7B%0A                        boolean exists;%0A                        if (hasBook()) %7B%0A                            exists = Paper.book(mCustomBook).exist(key);%0A                        %7D else %7B%0A                            exists = Paper.book().exist(key);%0A                        %7D%0A                        subscriber.onNext(exists);%0A                    %7D catch (Exception e) %7B%0A                        subscriber.onError(new UnableToPerformOperationException(%22Can't check if key exists%22));%0A                    %7D%0A%0A                    subscriber.onCompleted();%0A                %7D%0A            %7D%0A        %7D);%0A    %7D%0A%0A
     public Obser

add functionality to check if a key exists in a Book.