package co.smartreceipts.android.persistence.database.controllers.impl;
import android.support.annotation.NonNull;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicReference;
import co.smartreceipts.android.analytics.Analytics;
import co.smartreceipts.android.analytics.events.ErrorEvent;
import co.smartreceipts.android.model.Trip;
import co.smartreceipts.android.persistence.database.controllers.TableController;
import co.smartreceipts.android.persistence.database.controllers.TableEventsListener;
import co.smartreceipts.android.persistence.database.controllers.TripForeignKeyTableEventsListener;
import co.smartreceipts.android.persistence.database.controllers.alterations.TableActionAlterations;
import co.smartreceipts.android.persistence.database.tables.TripForeignKeyAbstractSqlTable;
import co.smartreceipts.android.utils.log.Logger;
import io.reactivex.Scheduler;
import io.reactivex.disposables.Disposable;
import io.reactivex.exceptions.Exceptions;
/**
* Provides a top-level implementation of the {@link TableController} contract for {@link TripForeignKeyAbstractSqlTable}
* instances
*
* @param <ModelType> the model object type that this will be used to create
*/
public class TripForeignKeyAbstractTableController<ModelType> extends AbstractTableController<ModelType> {
private final CopyOnWriteArrayList<TripForeignKeyTableEventsListener<ModelType>> mForeignTableEventsListeners = new CopyOnWriteArrayList<>();
protected final TripForeignKeyAbstractSqlTable<ModelType, ?> mTripForeignKeyTable;
public TripForeignKeyAbstractTableController(@NonNull TripForeignKeyAbstractSqlTable<ModelType, ?> table, @NonNull Analytics analytics) {
super(table, analytics);
mTripForeignKeyTable = table;
}
public TripForeignKeyAbstractTableController(@NonNull TripForeignKeyAbstractSqlTable<ModelType, ?> table, @NonNull TableActionAlterations<ModelType> tableActionAlterations, @NonNull Analytics analytics) {
super(table, tableActionAlterations, analytics);
mTripForeignKeyTable = table;
}
TripForeignKeyAbstractTableController(@NonNull TripForeignKeyAbstractSqlTable<ModelType, ?> table, @NonNull TableActionAlterations<ModelType> tableActionAlterations, @NonNull Analytics analytics, @NonNull Scheduler subscribeOnScheduler, @NonNull Scheduler observeOnScheduler) {
super(table, tableActionAlterations, analytics, subscribeOnScheduler, observeOnScheduler);
mTripForeignKeyTable = table;
}
@Override
public synchronized void subscribe(@NonNull TableEventsListener<ModelType> tableEventsListener) {
super.subscribe(tableEventsListener);
if (tableEventsListener instanceof TripForeignKeyTableEventsListener) {
mForeignTableEventsListeners.add((TripForeignKeyTableEventsListener<ModelType>) tableEventsListener);
}
}
@Override
public synchronized void unsubscribe(@NonNull TableEventsListener<ModelType> tableEventsListener) {
if (tableEventsListener instanceof TripForeignKeyTableEventsListener) {
mForeignTableEventsListeners.remove(tableEventsListener);
}
super.unsubscribe(tableEventsListener);
}
/**
* Retrieves list of all objects that are stored within this table for a particular {@link Trip}
*
* @param trip the {@link Trip} parameter that should be treated as a foreign key
*/
public synchronized void get(@NonNull Trip trip) {
get(trip, true);
}
/**
* Retrieves list of all objects that are stored within this table for a particular {@link Trip}
*
* @param trip the {@link Trip} parameter that should be treated as a foreign key
* @param isDescending {@code true} for descending order, {@code false} for ascending
*/
public synchronized void get(@NonNull final Trip trip, final boolean isDescending) {
// TODO: #preGet should really have the foreign key param... Which means all tables should be foreign key friendly...
Logger.info(this, "#get: {}", trip);
final AtomicReference<Disposable> subscriptionRef = new AtomicReference<>();
final Disposable disposable = mTableActionAlterations.preGet()
.andThen(mTripForeignKeyTable.get(trip, isDescending))
.subscribeOn(mSubscribeOnScheduler)
.doOnSuccess(modelTypes -> {
try {
mTableActionAlterations.postGet(modelTypes);
} catch (Exception e) {
throw Exceptions.propagate(e);
}
})
.observeOn(mObserveOnScheduler)
.subscribe(modelTypes -> {
if (modelTypes != null) {
Logger.debug(TripForeignKeyAbstractTableController.this, "#onGetSuccess - onSuccess");
for (final TripForeignKeyTableEventsListener<ModelType> foreignTableEventsListener : mForeignTableEventsListeners) {
foreignTableEventsListener.onGetSuccess(modelTypes, trip);
}
}
else {
Logger.debug(TripForeignKeyAbstractTableController.this, "#onGetFailure - onSuccess");
for (final TripForeignKeyTableEventsListener<ModelType> foreignTableEventsListener : mForeignTableEventsListeners) {
foreignTableEventsListener.onGetFailure(null, trip);
}
}
unsubscribeReference(subscriptionRef);
}, throwable -> {
mAnalytics.record(new ErrorEvent(TripForeignKeyAbstractTableController.this, throwable));
Logger.error(TripForeignKeyAbstractTableController.this, "#onGetFailure - onError");
for (final TripForeignKeyTableEventsListener<ModelType> foreignTableEventsListener : mForeignTableEventsListeners) {
foreignTableEventsListener.onGetFailure(throwable, trip);
}
unsubscribeReference(subscriptionRef);
});
subscriptionRef.set(disposable);
compositeDisposable.add(disposable);
}
}