package com.getbase.android.db.provider;
import com.google.common.base.MoreObjects;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import android.content.ContentProviderOperation;
import android.content.ContentProviderOperation.Builder;
import android.content.ContentValues;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
class BatcherImpl extends Batcher {
private final List<ConvertibleToOperation> operations = Lists.newArrayList();
private UriDecorator mUriDecorator = Utils.DUMMY_URI_DECORATOR;
private Multimap<ConvertibleToOperation, ValueBackRef> mValueBackRefs;
private Multimap<ConvertibleToOperation, SelectionBackRef> mSelectionBackRefs;
@Override
public BackRefBuilder append(ConvertibleToOperation... convertibles) {
Collections.addAll(operations, convertibles);
return new BackRefBuilder(this, convertibles);
}
@Override
public BackRefBuilder append(Iterable<ConvertibleToOperation> convertibles) {
Iterables.addAll(operations, convertibles);
return new BackRefBuilder(this, convertibles);
}
@Override
public Batcher decorateUrisWith(UriDecorator uriDecorator) {
mUriDecorator = MoreObjects.firstNonNull(uriDecorator, Utils.DUMMY_URI_DECORATOR);
return this;
}
@Override
public ArrayList<ContentProviderOperation> operations() {
ArrayList<ContentProviderOperation> providerOperations = Lists.newArrayListWithCapacity(operations.size());
BackRefResolver backRefResolver = getBackRefResolver();
for (ConvertibleToOperation convertible : operations) {
final Builder builder = convertible.toContentProviderOperationBuilder(mUriDecorator);
backRefResolver.resolveBackRefs(convertible, builder);
providerOperations.add(builder.build());
}
return providerOperations;
}
public void putValueBackRef(ConvertibleToOperation convertible, ValueBackRef valueBackRef) {
if (mValueBackRefs == null) {
mValueBackRefs = HashMultimap.create();
}
mValueBackRefs.put(convertible, valueBackRef);
}
public void putSelectionBackRef(ConvertibleToOperation convertible, SelectionBackRef selectionBackRef) {
if (mSelectionBackRefs == null) {
mSelectionBackRefs = HashMultimap.create();
}
mSelectionBackRefs.put(convertible, selectionBackRef);
}
private BackRefResolver getBackRefResolver() {
if (mValueBackRefs == null && mSelectionBackRefs == null) {
return DUMMY_BACK_REF_RESOLVER;
} else {
return new BackRefResolverImpl(mValueBackRefs, mSelectionBackRefs);
}
}
interface BackRefResolver {
void resolveBackRefs(ConvertibleToOperation convertible, Builder builder);
}
private static class BackRefResolverImpl implements BackRefResolver {
private final Multimap<ConvertibleToOperation, ValueBackRef> mValueBackRefs;
private final Multimap<ConvertibleToOperation, SelectionBackRef> mSelectionBackRefs;
private final Multimap<ConvertibleToOperation, Integer> mParentsPosition;
public BackRefResolverImpl(Multimap<ConvertibleToOperation, ValueBackRef> valueBackRefs, Multimap<ConvertibleToOperation, SelectionBackRef> selectionBackRefs) {
mValueBackRefs = valueBackRefs;
mSelectionBackRefs = selectionBackRefs;
mParentsPosition = HashMultimap.create();
}
@Override
public void resolveBackRefs(ConvertibleToOperation convertible, Builder builder) {
if (mValueBackRefs != null && mValueBackRefs.containsKey(convertible)) {
ContentValues values = new ContentValues();
for (ValueBackRef valueBackRef : mValueBackRefs.get(convertible)) {
values.put(valueBackRef.column, getParentPosition(valueBackRef.parent));
}
builder.withValueBackReferences(values);
}
if (mSelectionBackRefs != null) {
for (SelectionBackRef selectionBackRef : mSelectionBackRefs.get(convertible)) {
builder.withSelectionBackReference(
selectionBackRef.selectionArgumentIndex,
getParentPosition(selectionBackRef.parent)
);
}
}
mParentsPosition.put(convertible, mParentsPosition.size());
}
private int getParentPosition(ConvertibleToOperation parent) {
Collection<Integer> positions = mParentsPosition.get(parent);
if (positions.isEmpty()) {
throw new IllegalStateException("Could not find operation used in back reference.");
} else if (positions.size() > 1) {
throw new IllegalStateException("Ambiguous back reference; referenced operation was added to Batcher more than once.");
}
return Iterables.getOnlyElement(positions);
}
}
private static final BackRefResolver DUMMY_BACK_REF_RESOLVER = new BackRefResolver() {
@Override
public void resolveBackRefs(ConvertibleToOperation convertible, Builder builder) {
}
};
}