package productcatalog.services;
import io.sphere.sdk.categories.Category;
import io.sphere.sdk.client.PlayJavaSphereClient;
import io.sphere.sdk.products.ProductProjection;
import io.sphere.sdk.products.ProductVariant;
import io.sphere.sdk.products.queries.ProductProjectionQuery;
import io.sphere.sdk.products.search.ProductProjectionSearch;
import io.sphere.sdk.queries.PagedQueryResult;
import io.sphere.sdk.queries.PagedResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import play.libs.F;
import javax.inject.Inject;
import java.util.*;
public class ProductProjectionServiceImpl implements ProductProjectionService {
private static final Random RANDOM = new Random();
private static final Logger LOGGER = LoggerFactory.getLogger(ProductProjectionServiceImpl.class);
private final PlayJavaSphereClient sphere;
@Inject
public ProductProjectionServiceImpl(final PlayJavaSphereClient sphere) {
this.sphere = sphere;
}
public F.Promise<List<ProductProjection>> searchProducts(final int page, final int pageSize) {
final int offset = (page - 1) * pageSize;
return sphere.execute(ProductProjectionSearch.ofCurrent()
.withOffset(offset)
.withLimit(pageSize))
.map(PagedResult::getResults);
}
public F.Promise<Optional<ProductProjection>> searchProductBySlug(final Locale locale, final String slug) {
final F.Promise<Optional<ProductProjection>> productOptionalPromise = sphere.execute(ProductProjectionQuery.ofCurrent().bySlug(locale, slug))
.map(PagedQueryResult::head);
productOptionalPromise.onRedeem(productOptional -> {
if (productOptional.isPresent()) {
LOGGER.trace("Found product for slug {} in locale {} with ID {}.", slug, locale, productOptional.get().getId());
} else {
LOGGER.trace("No product found for slug {} in locale {}.", slug, locale);
}
});
return productOptionalPromise;
}
public F.Promise<List<ProductProjection>> getSuggestions(final List<Category> categories, final int numSuggestions) {
final ProductProjectionQuery productProjectionQuery = ProductProjectionQuery.ofCurrent()
.withPredicates(p -> p.categories().isIn(categories));
return sphere.execute(productProjectionQuery)
.map(PagedQueryResult::getResults)
.map(results -> pickNRandom(results, numSuggestions));
}
private boolean variantHasSku(final ProductVariant variant, final String sku) {
return Optional.ofNullable(variant.getSku()).map(variantSku -> variantSku.equals(sku)).orElse(false);
}
private <T> List<T> pickNRandom(final List<T> elements, final int n) {
return pickNRandom(RANDOM, elements, n);
}
private <T> List<T> pickNRandom(final Random random, final List<T> elements, final int n) {
if(elements.size() < n) {
return pickNRandom(elements, elements.size());
}
final List<T> picked = new ArrayList<>(n);
for(int i = 0; i < n; i++) {
final int index = random.nextInt(elements.size());
picked.add(elements.get(index));
elements.remove(index);
}
return picked;
}
}