package com.getbase.android.db.cursors;

import com.google.common.base.Function;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.LinkedHashMultimap;

import android.database.Cursor;
import android.database.CursorWrapper;

import java.util.NoSuchElementException;

/**
 * Wrapper for Android {@link android.database.Cursor} providing methods
 * for transforming Cursor into other Java types. It also wraps null Cursors
 * into valid Cursor instance with no data and no columns.
 */
public class FluentCursor extends CursorWrapper {

  public FluentCursor(Cursor cursor) {
    super(Cursors.returnSameOrEmptyIfNull(cursor));
  }

  /**
   * Transforms Cursor to FluentIterable of T applying given function
   * WARNING: This method closes cursor. Do not use this from onLoadFinished()
   *
   * @param singleRowTransform Function to apply on every single row of this cursor
   * @param <T> Type of Iterable's single element
   * @return Transformed iterable
   */
  public <T> FluentIterable<T> toFluentIterable(Function<? super Cursor, T> singleRowTransform) {
    try {
      return Cursors.toFluentIterable(this, singleRowTransform);
    } finally {
      close();
    }
  }

  /**
   * Transforms Cursor to LinkedHashMap<TKey, TValue> by applying given
   * functions. The iteration order for the returned map is the same as
   * the iteration order over rows of Cursor.
   * WARNING: This method closes cursor. Do not use this from onLoadFinished()
   *
   * @param keyTransform Function to apply on every single row of this cursor
   * to get the key of the entry representing this row.
   * @param valueTransform Function to apply on every single row of this cursor
   * to get the value of the entry representing this row.
   * @param <TKey> Type of keys in the returned multimap
   * @param <TValue> Type of values in the returned multimap
   * @return Transformed map
   */
  public <TKey, TValue> LinkedHashMultimap<TKey, TValue> toMultimap(Function<? super Cursor, TKey> keyTransform, Function<? super Cursor, TValue> valueTransform) {
    try {
      LinkedHashMultimap<TKey, TValue> result = LinkedHashMultimap.create(getCount(), 1);

      for (moveToFirst(); !isAfterLast(); moveToNext()) {
        result.put(keyTransform.apply(this), valueTransform.apply(this));
      }

      return result;
    } finally {
      close();
    }
  }

  /**
   * Returns the only row of this cursor transformed using the given function.
   * WARNING: This method closes cursor. Do not use this from onLoadFinished()
   *
   * @param singleRowTransform Function to apply on the only row of this cursor
   * @param <T> Type of returned element
   * @return Transformed first row of the cursor. If the cursor is empty,
   * NoSuchElementException is thrown. If the cursor contains more than one
   * row, IllegalArgumentException is thrown.
   */
  public <T> T toOnlyElement(Function<? super Cursor, T> singleRowTransform) {
    try {
      switch (getCount()) {
      case 0:
        throw new NoSuchElementException();
      case 1:
        moveToFirst();
        return singleRowTransform.apply(this);
      default:
        throw new IllegalArgumentException("expected one element but was: " + getCount());
      }
    } finally {
      close();
    }
  }

  /**
   * Returns the only row of this cursor transformed using the given function,
   * or the supplied default value if cursor is empty.
   * WARNING: This method closes cursor. Do not use this from onLoadFinished()
   *
   * @param singleRowTransform Function to apply on the only row of this cursor
   * @param <T> Type of returned element
   * @return Transformed first row of the cursor or the supplied default
   * value if the cursor is empty. If the cursor contains more than one
   * row, IllegalArgumentException is thrown.
   */
  public <T> T toOnlyElement(Function<? super Cursor, T> singleRowTransform, T defaultValue) {
    if (moveToFirst()) {
      return toOnlyElement(singleRowTransform);
    } else {
      close();
      return defaultValue;
    }
  }

  /**
   * Returns number of rows in this cursor and closes it.
   * WARNING: This method closes cursor. Do not use this from onLoadFinished()
   *
   * @return Row count from this cursor
   */
  public int toRowCount() {
    try {
      return getCount();
    } finally {
      close();
    }
  }
}

@@ -177,16 +177,56 @@
 timap;%0A%0A
+import android.content.ContentResolver;%0A
 import a
@@ -287,16 +287,40 @@
 Wrapper;
+%0Aimport android.net.Uri;
 %0A%0Aimport
@@ -4422,11 +4422,273 @@
    %7D%0A  %7D
+%0A%0A  /**%0A   * Sets the notification %7B@code Uri%7D on wrapped %7B@code Cursor%7D.%0A   *%0A   * @return this %7B@code FluentCursor%7D%0A   */%0A  public FluentCursor withNotificationUri(ContentResolver resolver, Uri uri) %7B%0A    setNotificationUri(resolver, uri);%0A    return this;%0A  %7D
 %0A%7D%0A

Add method to FluentCursor