package com.kickstarter.services;
import android.annotation.SuppressLint;
import android.content.Context;
import android.net.Uri;
import android.os.Parcelable;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import com.kickstarter.R;
import com.kickstarter.libs.KSString;
import com.kickstarter.libs.qualifiers.AutoGson;
import com.kickstarter.libs.utils.ObjectUtils;
import com.kickstarter.models.Category;
import com.kickstarter.models.Location;
import com.kickstarter.models.Project;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import auto.parcel.AutoParcel;
import static com.kickstarter.libs.utils.BooleanUtils.isFalse;
import static com.kickstarter.libs.utils.BooleanUtils.isTrue;
@AutoGson
@AutoParcel
public abstract class DiscoveryParams implements Parcelable {
public abstract @Nullable Integer backed();
public abstract @Nullable Category category();
public abstract @Nullable String categoryParam();
public abstract @Nullable Location location();
public abstract @Nullable String locationParam();
public abstract @Nullable Integer page();
public abstract @Nullable Integer perPage();
public abstract @Nullable Integer pledged();
public abstract @Nullable Boolean staffPicks();
public abstract @Nullable Integer starred();
public abstract @Nullable Integer social();
public abstract @Nullable Sort sort();
public abstract @Nullable Boolean recommended();
public abstract @Nullable Project similarTo();
public abstract @Nullable State state();
public abstract @Nullable String term();
public enum Sort {
HOME, POPULAR, NEWEST, ENDING_SOON, MOST_FUNDED;
@Override
public @NonNull String toString() {
switch (this) {
case HOME:
return "home";
case POPULAR:
return "popularity";
case NEWEST:
return "newest";
case ENDING_SOON:
return "end_date";
case MOST_FUNDED:
return "most_funded";
}
return "";
}
public static @Nullable Sort fromString(final @NonNull String string) {
switch (string) {
case "home":
return HOME;
case "popularity":
return POPULAR;
case "newest":
return NEWEST;
case "end_date":
return ENDING_SOON;
case "most_funded":
return MOST_FUNDED;
}
return HOME;
}
public @NonNull String refTagSuffix() {
switch (this) {
case HOME:
return "";
case POPULAR:
return "_popular";
case NEWEST:
return "_newest";
case ENDING_SOON:
return "_ending_soon";
case MOST_FUNDED:
return "_most_funded";
default:
return "";
}
}
}
@SuppressLint("DefaultLocale")
public enum State {
STARTED, SUBMITTED, LIVE, SUCCESSFUL, CANCELED, FAILED;
@Override
public @NonNull String toString() {
return name().toLowerCase();
}
public static @Nullable State fromString(final @NonNull String string) {
switch (string) {
case "started":
return STARTED;
case "submitted":
return SUBMITTED;
case "live":
return LIVE;
case "successful":
return SUCCESSFUL;
case "canceled":
return CANCELED;
case "failed":
return FAILED;
}
return null;
}
}
/**
* Returns a {@link DiscoveryParams} constructed by parsing data out of the given {@link Uri}.
*/
public static @NonNull DiscoveryParams fromUri(final @NonNull Uri uri) {
Builder builder = DiscoveryParams.builder();
if (KSUri.isDiscoverCategoriesPath(uri.getPath())) {
builder = builder.categoryParam(uri.getLastPathSegment());
}
if (KSUri.isDiscoverPlacesPath(uri.getPath())) {
builder = builder.locationParam(uri.getLastPathSegment());
}
if (KSUri.isDiscoverScopePath(uri.getPath(), "ending-soon")) {
builder = builder.sort(Sort.ENDING_SOON);
}
if (KSUri.isDiscoverScopePath(uri.getPath(), "most-funded")) {
builder = builder.sort(Sort.MOST_FUNDED);
}
if (KSUri.isDiscoverScopePath(uri.getPath(), "newest")) {
builder = builder.sort(Sort.NEWEST).staffPicks(true);
}
if (KSUri.isDiscoverScopePath(uri.getPath(), "popular")) {
builder = builder.sort(Sort.POPULAR);
}
if (KSUri.isDiscoverScopePath(uri.getPath(), "recently-launched")) {
builder = builder.sort(Sort.NEWEST);
}
if (KSUri.isDiscoverScopePath(uri.getPath(), "small-projects")) {
builder = builder.pledged(0);
}
if (KSUri.isDiscoverScopePath(uri.getPath(), "social")) {
builder = builder.social(0);
}
if (KSUri.isDiscoverScopePath(uri.getPath(), "successful")) {
builder = builder.sort(Sort.ENDING_SOON).state(State.SUCCESSFUL);
}
final Integer backed = ObjectUtils.toInteger(uri.getQueryParameter("backed"));
if (backed != null) {
builder = builder.backed(backed);
}
final String categoryParam = uri.getQueryParameter("category_id");
if (categoryParam != null) {
builder = builder.categoryParam(categoryParam);
}
final String locationParam = uri.getQueryParameter("woe_id");
if (locationParam != null) {
builder = builder.locationParam(locationParam);
}
final Integer page = ObjectUtils.toInteger(uri.getQueryParameter("page"));
if (page != null) {
builder = builder.page(page);
}
final Integer perPage = ObjectUtils.toInteger(uri.getQueryParameter("per_page"));
if (perPage != null) {
builder = builder.perPage(perPage);
}
final Integer pledged = ObjectUtils.toInteger(uri.getQueryParameter("pledged"));
if (pledged != null) {
builder = builder.pledged(pledged);
}
final Boolean recommended = ObjectUtils.toBoolean(uri.getQueryParameter("recommended"));
if (recommended != null) {
builder = builder.recommended(recommended);
}
final Integer social = ObjectUtils.toInteger(uri.getQueryParameter("social"));
if (social != null) {
builder = builder.social(social);
}
final Boolean staffPicks = ObjectUtils.toBoolean(uri.getQueryParameter("staff_picks"));
if (staffPicks != null) {
builder = builder.staffPicks(staffPicks);
}
final String sortParam = uri.getQueryParameter("sort");
if (sortParam != null) {
builder = builder.sort(Sort.fromString(sortParam));
}
final Integer starred = ObjectUtils.toInteger(uri.getQueryParameter("starred"));
if (starred != null) {
builder = builder.starred(starred);
}
final String stateParam = uri.getQueryParameter("state");
if (stateParam != null) {
builder = builder.state(State.fromString(stateParam));
}
final String term = uri.getQueryParameter("term");
if (term != null) {
builder = builder.term(term);
}
return builder.build();
}
@AutoParcel.Builder
public abstract static class Builder {
public abstract Builder backed(Integer __);
public abstract Builder category(Category __);
public abstract Builder categoryParam(String __);
public abstract Builder location(Location __);
public abstract Builder locationParam(String __);
public abstract Builder page(Integer __);
public abstract Builder perPage(Integer __);
public abstract Builder pledged(Integer __);
public abstract Builder sort(Sort __);
public abstract Builder staffPicks(Boolean __);
public abstract Builder starred(Integer __);
public abstract Builder social(Integer __);
public abstract Builder recommended(Boolean __);
public abstract Builder similarTo(Project __);
public abstract Builder state(State __);
public abstract Builder term(String __);
public abstract DiscoveryParams build();
/**
* Returns a builder containing the contents of this builder and `otherBuilder`. If a value for the same property
* exists in both builders, the returned builder will contain the value from `otherBuilder`.
*/
public @NonNull DiscoveryParams.Builder mergeWith(final @NonNull Builder otherBuilder) {
final DiscoveryParams other = otherBuilder.build();
DiscoveryParams.Builder retVal = this;
if (other.backed() != null) {
retVal = retVal.backed(other.backed());
}
if (other.category() != null) {
retVal = retVal.category(other.category());
}
if (other.categoryParam() != null) {
retVal = retVal.categoryParam(other.categoryParam());
}
if (other.location() != null) {
retVal = retVal.location(other.location());
}
if (other.page() != null) {
retVal = retVal.page(other.page());
}
if (other.perPage() != null) {
retVal = retVal.perPage(other.perPage());
}
if (other.pledged() != null) {
retVal = retVal.pledged(other.pledged());
}
if (other.social() != null) {
retVal = retVal.social(other.social());
}
if (other.staffPicks() != null) {
retVal = retVal.staffPicks(other.staffPicks());
}
if (other.starred() != null) {
retVal = retVal.starred(other.starred());
}
if (other.state() != null) {
retVal = retVal.state(other.state());
}
if (other.sort() != null) {
retVal = retVal.sort(other.sort());
}
if (other.recommended() != null) {
retVal = retVal.recommended(other.recommended());
}
if (other.similarTo() != null) {
retVal = retVal.similarTo(other.similarTo());
}
if (other.term() != null) {
retVal = retVal.term(other.term());
}
return retVal;
}
}
public static @NonNull Builder builder() {
return new AutoParcel_DiscoveryParams.Builder()
.page(1)
.perPage(15);
}
public abstract Builder toBuilder();
public @NonNull DiscoveryParams nextPage() {
final Integer page = page();
return page != null ? toBuilder().page(page + 1).build() : this;
}
public @NonNull Map<String, String> queryParams() {
return Collections.unmodifiableMap(new HashMap<String, String>() {
{
if (backed() != null) {
put("backed", String.valueOf(backed()));
}
if (category() != null) {
put("category_id", String.valueOf(category().id()));
}
if (categoryParam() != null) {
put("category_id", categoryParam());
}
if (location() != null) {
put("woe_id", String.valueOf(location().id()));
}
if (locationParam() != null) {
put("woe_id", locationParam());
}
if (page() != null) {
put("page", String.valueOf(page()));
}
if (perPage() != null) {
put("per_page", String.valueOf(perPage()));
}
if (pledged() != null) {
put("pledged", String.valueOf(pledged()));
}
if (recommended() != null) {
put("recommended", String.valueOf(recommended()));
}
if (similarTo() != null) {
put("similar_to", String.valueOf(similarTo().id()));
}
if (starred() != null) {
put("starred", String.valueOf(starred()));
}
if (social() != null) {
put("social", String.valueOf(social()));
}
final Sort sort = sort();
if (sort != null) {
put("sort", sort.toString());
}
if (staffPicks() != null) {
put("staff_picks", String.valueOf(staffPicks()));
}
final State state = state();
if (state != null) {
put("state", state.toString());
}
if (term() != null) {
put("q", term());
}
if (shouldIncludePotd()) {
put("include_potd", "true");
}
if (shouldIncludeFeatured()) {
put("include_featured", "true");
}
}
});
}
/**
* Determines if the `include_potd` flag should be included in a discovery request so that we guarantee that the
* POTD comes back.
*/
public boolean shouldIncludePotd() {
return isAllProjects()
&& page() != null
&& page() == 1
&& (sort() == null || sort() == Sort.HOME)
&& (term() == null || term().isEmpty());
}
/**
* Determines if the `include_featured` flag should be included in a discovery request so that we guarantee that the
* featured project for the category comes back.
*/
public boolean shouldIncludeFeatured() {
return category() != null && page() != null && page() == 1 && (sort() == null || sort() == Sort.HOME);
}
@Override
public @NonNull String toString() {
return queryParams().toString();
}
public @NonNull String filterString(final @NonNull Context context, final @NonNull KSString ksString) {
return filterString(context, ksString, false, false);
}
/**
* Determines the correct string to display for a filter depending on where it is shown.
*
* @param context context
* @param ksString ksString for string formatting
* @param isToolbar true if string is being displayed in the {@link com.kickstarter.ui.toolbars.DiscoveryToolbar}
* @param isParentFilter true if string is being displayed as a {@link com.kickstarter.ui.viewholders.discoverydrawer.ParentFilterViewHolder}
*
* @return the appropriate filter string
*/
public @NonNull String filterString(final @NonNull Context context, final @NonNull KSString ksString,
final boolean isToolbar, final boolean isParentFilter) {
if (isTrue(staffPicks())) {
return context.getString(R.string.Projects_We_Love);
} else if (starred() != null && starred() == 1) {
return context.getString(R.string.Saved);
} else if (backed() != null && backed() == 1) {
return context.getString(R.string.discovery_backing);
} else if (social() != null && social() == 1) {
return isToolbar ? context.getString(R.string.Following) : context.getString(R.string.Backed_by_people_you_follow);
} else if (category() != null) {
return category().isRoot() && !isParentFilter && !isToolbar
? ksString.format(context.getString(R.string.All_category_name_Projects), "category_name", category().name())
: category().name();
} else if (location() != null) {
return location().displayableName();
} else if (isTrue(recommended())) {
return isToolbar ? context.getString(R.string.Recommended) : context.getString(R.string.discovery_recommended_for_you);
} else {
return context.getString(R.string.All_Projects);
}
}
/**
* Determines if params are for All Projects, i.e. discovery without params.
* @return true if is All Projects.
*/
public boolean isAllProjects() {
return isFalse(staffPicks()) && (starred() == null || starred() != 1) && (backed() == null || backed() != 1)
&& (social() == null || social() != 1) && category() == null && location() == null && isFalse(recommended());
}
public boolean isCategorySet() {
return category() != null;
}
}