// Path: app/src/main/java/com/jonathanpetitfrere/mvvm/repository/api/UserApi.java
// public interface UserApi {
// 
//     @GET("user/{email}")
//     Flowable<User> getUser(@Path("email") String email);
// 
//     @GET("users")
//     Flowable<List<User>> getUsers();
// 
//     @POST("user")
//     void createUser(User user);
// }
// 
// Path: app/src/main/java/com/jonathanpetitfrere/mvvm/repository/mapper/UserMapper.java
// @Singleton
// public class UserMapper {
// 
//     @Inject
//     public UserMapper() {}
// 
//     public User toModel(com.jonathanpetitfrere.mvvm.repository.persistence.entity.User userEntity) {
//         return new User(userEntity.getEmail(), userEntity.getFirstName(), userEntity.getLastName());
//     }
// 
//     public com.jonathanpetitfrere.mvvm.repository.persistence.entity.User toEntity(User userModel) {
//         return new com.jonathanpetitfrere.mvvm.repository.persistence.entity.User(userModel.getEmail(), userModel.getFirstName(), userModel.getLastName());
//     }
// 
// }
// 
// Path: app/src/main/java/com/jonathanpetitfrere/mvvm/repository/persistence/dao/UserDao.java
// @Dao
// public interface UserDao {
// 
//     @Query("SELECT * FROM user WHERE email = :email")
//     Flowable<User> loadUser(String email);
// 
//     @Insert(onConflict = OnConflictStrategy.REPLACE)
//     void saveUser(User user);
// 
//     @Query("SELECT * FROM user")
//     Flowable<List<User>> loadUsers();
// }
// 
// Path: app/src/main/java/com/jonathanpetitfrere/mvvm/repository/persistence/entity/User.java
// @Entity
// public class User {
// 
//     @PrimaryKey
//     private String email;
// 
//     @ColumnInfo(name = "first_name")
//     private String firstName;
// 
//     @ColumnInfo(name = "last_name")
//     private String lastName;
// 
//     public User(String email, String firstName, String lastName) {
//         this.email = email;
//         this.firstName = firstName;
//         this.lastName = lastName;
//     }
// 
//     public String getEmail() {
//         return email;
//     }
// 
//     public String getFirstName() {
//         return firstName;
//     }
// 
//     public String getLastName() {
//         return lastName;
//     }
// 
//     @Override
//     public boolean equals(Object object) {
//         if (this == object) return true;
//         if (object == null || getClass() != object.getClass()) return false;
// 
//         User user = (User) object;
// 
//         if (email != null ? !email.equals(user.email) : user.email != null) return false;
//         if (firstName != null ? !firstName.equals(user.firstName) : user.firstName != null)
//             return false;
//         return lastName != null ? lastName.equals(user.lastName) : user.lastName == null;
// 
//     }
// 
//     @Override
//     public int hashCode() {
//         int result = email != null ? email.hashCode() : 0;
//         result = 31 * result + (firstName != null ? firstName.hashCode() : 0);
//         result = 31 * result + (lastName != null ? lastName.hashCode() : 0);
//         return result;
//     }
// }
// 
// Path: app/src/main/java/com/jonathanpetitfrere/mvvm/util/Transformers.java
// @Singleton
// public class Transformers {
// 
//     @Inject
//     Transformers(){}
// 
//     public <T> FlowableTransformer<T, T> applySchedulersToFlowable() {
//         return flowable -> flowable.subscribeOn(Schedulers.io())
//                 .observeOn(AndroidSchedulers.mainThread());
//     }
// 
//     public CompletableTransformer applySchedulersToCompletable() {
//         return completable -> completable.subscribeOn(Schedulers.io())
//                 .observeOn(AndroidSchedulers.mainThread());
//     }
// }


import android.arch.lifecycle.LiveData;
import android.arch.lifecycle.MutableLiveData;
import com.jonathanpetitfrere.mvvm.repository.api.UserApi;
import com.jonathanpetitfrere.mvvm.repository.mapper.UserMapper;
import com.jonathanpetitfrere.mvvm.repository.persistence.dao.UserDao;
import com.jonathanpetitfrere.mvvm.repository.persistence.entity.User;
import com.jonathanpetitfrere.mvvm.util.Transformers;
import java.util.List;
import javax.inject.Inject;
import javax.inject.Singleton;
import io.reactivex.Completable;
import timber.log.Timber;

        userApi.getUser(email)
                .compose(transformers.applySchedulersToFlowable())
                .map(mapper::toEntity)
                .subscribe(userDao::saveUser, Timber::d);

        return liveData;
    }

    public LiveData<List<User>> getUsers() {
        MutableLiveData<List<User>> liveData = new MutableLiveData<>();

        userDao.loadUsers()
                .compose(transformers.applySchedulersToFlowable())
                .subscribe(liveData::setValue, Timber::d);

        userApi.getUsers()
                .compose(transformers.applySchedulersToFlowable())
                .flatMapIterable(users -> users)
                .map(mapper::toEntity)
                .subscribe(userDao::saveUser, Timber::d);

        return liveData;
    }

    public LiveData<Boolean> saveUser(User user) {
        MutableLiveData<Boolean> liveData = new MutableLiveData<>();

        Completable.fromAction(() -> userDao.saveUser(user))
                .compose(transformers.applySchedulersToCompletable())
// Path: app/src/main/java/com/jonathanpetitfrere/mvvm/repository/api/UserApi.java
// public interface UserApi {
// 
//     @GET("user/{email}")
//     Flowable<User> getUser(@Path("email") String email);
// 
//     @GET("users")
//     Flowable<List<User>> getUsers();
// 
//     @POST("user")
//     void createUser(User user);
// }
// 
// Path: app/src/main/java/com/jonathanpetitfrere/mvvm/repository/mapper/UserMapper.java
// @Singleton
// public class UserMapper {
// 
//     @Inject
//     public UserMapper() {}
// 
//     public User toModel(com.jonathanpetitfrere.mvvm.repository.persistence.entity.User userEntity) {
//         return new User(userEntity.getEmail(), userEntity.getFirstName(), userEntity.getLastName());
//     }
// 
//     public com.jonathanpetitfrere.mvvm.repository.persistence.entity.User toEntity(User userModel) {
//         return new com.jonathanpetitfrere.mvvm.repository.persistence.entity.User(userModel.getEmail(), userModel.getFirstName(), userModel.getLastName());
//     }
// 
// }
// 
// Path: app/src/main/java/com/jonathanpetitfrere/mvvm/repository/persistence/dao/UserDao.java
// @Dao
// public interface UserDao {
// 
//     @Query("SELECT * FROM user WHERE email = :email")
//     Flowable<User> loadUser(String email);
// 
//     @Insert(onConflict = OnConflictStrategy.REPLACE)
//     void saveUser(User user);
// 
//     @Query("SELECT * FROM user")
//     Flowable<List<User>> loadUsers();
// }
// 
// Path: app/src/main/java/com/jonathanpetitfrere/mvvm/repository/persistence/entity/User.java
// @Entity
// public class User {
// 
//     @PrimaryKey
//     private String email;
// 
//     @ColumnInfo(name = "first_name")
//     private String firstName;
// 
//     @ColumnInfo(name = "last_name")
//     private String lastName;
// 
//     public User(String email, String firstName, String lastName) {
//         this.email = email;
//         this.firstName = firstName;
//         this.lastName = lastName;
//     }
// 
//     public String getEmail() {
//         return email;
//     }
// 
//     public String getFirstName() {
//         return firstName;
//     }
// 
//     public String getLastName() {
//         return lastName;
//     }
// 
//     @Override
//     public boolean equals(Object object) {
//         if (this == object) return true;
//         if (object == null || getClass() != object.getClass()) return false;
// 
//         User user = (User) object;
// 
//         if (email != null ? !email.equals(user.email) : user.email != null) return false;
//         if (firstName != null ? !firstName.equals(user.firstName) : user.firstName != null)
//             return false;
//         return lastName != null ? lastName.equals(user.lastName) : user.lastName == null;
// 
//     }
// 
//     @Override
//     public int hashCode() {
//         int result = email != null ? email.hashCode() : 0;
//         result = 31 * result + (firstName != null ? firstName.hashCode() : 0);
//         result = 31 * result + (lastName != null ? lastName.hashCode() : 0);
//         return result;
//     }
// }
// 
// Path: app/src/main/java/com/jonathanpetitfrere/mvvm/util/Transformers.java
// @Singleton
// public class Transformers {
// 
//     @Inject
//     Transformers(){}
// 
//     public <T> FlowableTransformer<T, T> applySchedulersToFlowable() {
//         return flowable -> flowable.subscribeOn(Schedulers.io())
//                 .observeOn(AndroidSchedulers.mainThread());
//     }
// 
//     public CompletableTransformer applySchedulersToCompletable() {
//         return completable -> completable.subscribeOn(Schedulers.io())
//                 .observeOn(AndroidSchedulers.mainThread());
//     }
// }


// Path: app/src/main/java/com/jonathanpetitfrere/mvvm/repository/UserRepository.java
import android.arch.lifecycle.LiveData;
import android.arch.lifecycle.MutableLiveData;
import com.jonathanpetitfrere.mvvm.repository.api.UserApi;
import com.jonathanpetitfrere.mvvm.repository.mapper.UserMapper;
import com.jonathanpetitfrere.mvvm.repository.persistence.dao.UserDao;
import com.jonathanpetitfrere.mvvm.repository.persistence.entity.User;
import com.jonathanpetitfrere.mvvm.util.Transformers;
import java.util.List;
import javax.inject.Inject;
import javax.inject.Singleton;
import io.reactivex.Completable;
import timber.log.Timber;


        userApi.getUser(email)
                .compose(transformers.applySchedulersToFlowable())
                .map(mapper::toEntity)
                .subscribe(userDao::saveUser, Timber::d);

        return liveData;
    }

    public LiveData<List<User>> getUsers() {
        MutableLiveData<List<User>> liveData = new MutableLiveData<>();

        userDao.loadUsers()
                .compose(transformers.applySchedulersToFlowable())
                .subscribe(liveData::setValue, Timber::d);

        userApi.getUsers()
                .compose(transformers.applySchedulersToFlowable())
                .flatMapIterable(users -> users)
                .map(mapper::toEntity)
                .subscribe(userDao::saveUser, Timber::d);

        return liveData;
    }

    public LiveData<Boolean> saveUser(User user) {
        MutableLiveData<Boolean> liveData = new MutableLiveData<>();

        Completable.fromAction(() -> userDao.saveUser(user))
                .compose(transformers.applySchedulersToCompletable())
                .subscribe(() -> liveData.setValue(true), throwable -> {