package com.novoda.todoapp.tasks.data.source;
import com.google.common.collect.ImmutableList;
import com.novoda.todoapp.task.data.model.Id;
import com.novoda.todoapp.task.data.model.Task;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import rx.Observable;
import rx.Subscriber;
import rx.functions.Action1;
import rx.functions.Func0;
import rx.schedulers.Schedulers;
public final class InMemoryRemoteTaskDataSource implements RemoteTasksDataSource {
private final int remoteDelay;
private final TimeUnit remoteDelayUnit;
private final Map<Id, Task> dataSourceTasks = new HashMap<>();
public static RemoteTasksDataSource newInstance() {
InMemoryRemoteTaskDataSource dataSource = new InMemoryRemoteTaskDataSource(2, TimeUnit.SECONDS);
populateFakeTasks(dataSource);
return dataSource;
}
private static void populateFakeTasks(InMemoryRemoteTaskDataSource dataSource) {
ImmutableList<Task> remoteTasks = ImmutableList.<Task>of(
Task.builder()
.id(Id.from("42"))
.title("First Task")
.description("Hardcoded stuff")
.build(),
Task.builder()
.id(Id.from("24"))
.title("Second Task")
.description("Hardcoded stuff again")
.build(),
Task.builder()
.id(Id.from("424"))
.title("Third Task")
.description("Hardcoded stuff once more")
.build()
);
for (Task task : remoteTasks) {
dataSource.dataSourceTasks.put(task.id(), task);
}
}
private InMemoryRemoteTaskDataSource(int remoteDelay, TimeUnit remoteDelayUnit) {
this.remoteDelay = remoteDelay;
this.remoteDelayUnit = remoteDelayUnit;
}
@Override
public Observable<List<Task>> getTasks() {
return Observable.defer(new Func0<Observable<List<Task>>>() {
@Override
public Observable<List<Task>> call() {
List<Task> tasks = ImmutableList.copyOf(dataSourceTasks.values());
if (tasks.isEmpty()) {
return Observable.empty();
} else {
return Observable.just(tasks);
}
}
}).delay(remoteDelay, remoteDelayUnit, Schedulers.immediate());
}
@Override
public Observable<Task> getTask(Id taskId) {
if (dataSourceTasks.containsKey(taskId)) {
return Observable.just(dataSourceTasks.get(taskId))
.delay(remoteDelay, remoteDelayUnit, Schedulers.immediate());
} else {
return Observable.<Task>empty()
.delay(remoteDelay, remoteDelayUnit, Schedulers.immediate());
}
}
@Override
public Observable<List<Task>> saveTasks(final List<Task> tasks) {
return Observable.create(new Observable.OnSubscribe<List<Task>>() {
@Override
public void call(Subscriber<? super List<Task>> subscriber) {
dataSourceTasks.clear();
for (Task task : tasks) {
dataSourceTasks.put(task.id(), task);
}
subscriber.onNext(tasks);
subscriber.onCompleted();
}
});
}
@Override
public Observable<Task> saveTask(Task task) {
return updateTask(task);
}
private Observable<Task> updateTask(Task task) {
return Observable.just(task)
.doOnNext(new Action1<Task>() {
@Override
public void call(Task task) {
dataSourceTasks.put(task.id(), task);
}
})
.delay(remoteDelay, remoteDelayUnit, Schedulers.immediate());
}
@Override
public Observable<List<Task>> clearCompletedTasks() {
return Observable.defer(new Func0<Observable<List<Task>>>() {
@Override
public Observable<List<Task>> call() {
Iterator<Map.Entry<Id, Task>> it = dataSourceTasks.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<Id, Task> entry = it.next();
if (entry.getValue().isCompleted()) {
it.remove();
}
}
List<Task> tasks = ImmutableList.copyOf(dataSourceTasks.values());
return Observable.just(tasks);
}
}).delay(remoteDelay, remoteDelayUnit, Schedulers.immediate());
}
@Override
public Observable<Void> deleteAllTasks() {
return Observable.defer(new Func0<Observable<Void>>() {
@Override
public Observable<Void> call() {
dataSourceTasks.clear();
return Observable.empty();
}
}).delay(remoteDelay, remoteDelayUnit, Schedulers.immediate());
}
@Override
public Observable<Void> deleteTask(final Id taskId) {
return Observable.defer(new Func0<Observable<Void>>() {
@Override
public Observable<Void> call() {
dataSourceTasks.remove(taskId);
return Observable.empty();
}
}).delay(remoteDelay, remoteDelayUnit, Schedulers.immediate());
}
}