Web implementation of the Gourmet Recipe Manager
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

397 lines
8.5 KiB

package com.mousetech.gourmetj;
import java.io.ByteArrayOutputStream;
import java.io.PrintWriter;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
import javax.annotation.PostConstruct;
import javax.faces.view.ViewScoped;
import javax.inject.Inject;
import javax.inject.Named;
import org.apache.commons.lang3.StringUtils;
import org.primefaces.model.ByteArrayContent;
import org.primefaces.model.DefaultStreamedContent;
import org.primefaces.model.StreamedContent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.mousetech.gourmetj.persistence.dao.ShopcatRepository;
import com.mousetech.gourmetj.persistence.model.Ingredient;
import com.mousetech.gourmetj.persistence.model.Recipe;
import com.mousetech.gourmetj.persistence.model.Shopcat;
import com.mousetech.gourmetj.utils.YamlShoppingList;
@Named
@ViewScoped
public class ShoppingListBean implements Serializable {
public class RecipeReference {
private int count;
private Recipe recipe;
/**
* Constructor Constructor.
*
* @param r Recipe to reference (from Shopping List)
*/
public RecipeReference(Recipe r) {
count = 1;
recipe = r;
}
/**
* @return the count
*/
public int getCount() {
return count;
}
/**
* @param count the count to set
*/
public void setCount(int count) {
this.count = count;
}
/**
* @return the recipe
*/
public Recipe getRecipe() {
return recipe;
}
/**
* @param recipe the recipe to set
*/
public void setRecipe(Recipe recipe) {
this.recipe = recipe;
}
}
/**
* Serial version for session save/restore
*/
private static final long serialVersionUID =
7449440266704831598L;
/* Logger */
@SuppressWarnings("unused")
private static final Logger log =
LoggerFactory.getLogger(ShoppingListBean.class);
@Inject
private UserSession userSession;
private List<ShopIngredient> siList;
private List<RecipeReference> recipeList;
@PostConstruct
public void init() {
// Load up details on recipes
this.siList = new ArrayList<ShopIngredient>(30);
buildMaps();
}
public List<RecipeReference> getRecipeList() {
if (this.recipeList == null) {
this.recipeList = loadRecipeList();
}
return this.recipeList;
}
private List<RecipeReference> loadRecipeList() {
List<RecipeReference> list =
userSession.getShoppingList().stream()
.map(r -> new RecipeReference(r))
.collect(Collectors.toList());
return list;
}
public List<ShopIngredient> getIngredientList() {
return this.siList;
}
private void buildMaps() {
this.siList = new ArrayList<ShopIngredient>(30);
for (RecipeReference r : this.getRecipeList()) {
buildMapsFor(r);
}
// Now consolidate amounts and sort by
// shopcat/item/ingkey
optimizeIngredients(this.siList);
this.siList.sort(new ShopclassComparator());
}
/**
* Run the ingredient list for the selected recipe and add
* them to siList
*
* @param r
*
* @see #buildMaps()
*/
private void buildMapsFor(RecipeReference r) {
final int multiplier = r.getCount();
if (multiplier == 0) {
return;
}
for (Ingredient ing : r.getRecipe()
.getIngredientHash()) {
String ingkey = ing.getIngkey();
if (StringUtils.isBlank(ingkey)) {
continue;
}
String shopCatName = ing.getShopCat() != null
? ing.getShopCat().getShopcategory()
: null;
ShopIngredient sing;
try {
Double amt = ing.getAmount();
if (multiplier > 1 && (amt != null)) {
amt *= multiplier;
}
sing = new ShopIngredient(amt, ing.getUnit(),
ing.getItem(), ing.getIngkey(),
shopCatName);
siList.add(sing);
} catch (Exception e) {
log.error("Unable to create ShopIngredient for "
+ r.getRecipe() + " Ingredient " + ing);
e.printStackTrace();
}
}
}
/**
* Sort ShopIngredient list, then optimize it by
* consolidating amounts where possible.
*
* @param victim List to optimize
*
* #TestedBy @see ShoppingListBeanTest
*/
static void optimizeIngredients(
List<ShopIngredient> victim) {
victim.sort(null);
for (int i = 0; i < (victim.size() - 1); i++) {
ShopIngredient si = victim.get(i);
ShopIngredient si2 = victim.get(i + 1);
if (si.compareTo(si2) == 0) {
si.setAmount(si.getAmount() + si2.getAmount());
victim.remove(si2); // reduces size()
}
}
}
class ShopclassComparator
implements Comparator<ShopIngredient> {
@Override
public int compare(ShopIngredient ing1,
ShopIngredient ing2) {
int i = 0;
i = relate(ing1.getShopCat(), ing2.getShopCat());
if (i != 0) {
return i;
}
i = relate(ing1.getItem(), ing2.getItem());
if (i != 0) {
return i;
}
i = relate(ing1.getIngkey(), ing2.getIngkey());
if (i != 0) {
return i;
}
return 0;
}
private int relate(String item2, String item3) {
if ((item2 == null) && (item3 == null)) {
return 0;
}
if (item2 == null) {
return -1;
}
if (item3 == null) {
return 1;
}
return item2.compareTo(item3);
}
}
public StreamedContent getDlIngredientList() {
return YamlShoppingList
.createDownload(getIngredientList());
}
// =============================================
private List<String> shopcatList;
public List<String> getShopcatList() {
if (shopcatList == null) {
shopcatList = loadShopcatList();
}
return shopcatList;
}
@Inject
ShopcatRepository shopcatRepository;
private List<String> loadShopcatList() {
return shopcatRepository.findDistinctCategoryNative();
// .findAllByOrderByShopcategoryAsc();
}
private Shopcat xeditShopcat = new Shopcat();
private String oldShopcategoryName;
/**
* @return the editShopcat
*/
public Shopcat getEditShopcat() {
return xeditShopcat;
}
public void doEditShopcat(int scId) {
// xeditShopcat = null;
// final List<Shopcat> scl = getShopcatList();
// for (Shopcat sc : scl) {
// if (sc.getId() == scId) {
// xeditShopcat = sc;
// this.oldShopcategoryName = sc.getShopcategory();
// if (sc.getPosition() == null) {
// sc.setPosition(0);
// }
// return;
// }
// }
// log.error("SHOPCAT " + scId + " NOT FOUND");
}
public void ajaxOnClickShopcatIngkey() {
// Saves 1 shopcat/ingkey
this.shopcatRepository.save(xeditShopcat);
this.shopcatList = null;
}
/**
* Updates all ingredient keys for shopcat name-change. Note
* that once done, this cannot be undone!
*/
public void ajaxOnClickShopcat() {
this.shopcatRepository.UpdateShopcats(
this.oldShopcategoryName,
xeditShopcat.getShopcategory());
this.shopcatList = null;
}
/**
* Primefaces AJAX listener for changes to amount values of
* recipes the recipe list. Forces re-computation of
* ingredient requirements.
*/
public void pfAmountChange() {
buildMaps();
}
// ===
private String selectedShopcat;
/**
* @return the selectedShopcat
*/
public String getSelectedShopcat() {
return selectedShopcat;
}
/**
* @param selectedShopcat the selectedShopcat to set
*/
public void setSelectedShopcat(String selectedShopcat) {
this.selectedShopcat = selectedShopcat;
this.ingkeyList = null;
}
private List<String> selectedIngkey;
/**
* @return the selectedIngkey
*/
public List<String> getSelectedIngkey() {
return selectedIngkey;
}
/**
* @param selectedIngkey the selectedIngkey to set
*/
public void setSelectedIngkey(List<String> selectedIngkey) {
this.selectedIngkey = selectedIngkey;
}
private List<String> ingkeyList;
/**
* @return the ingkeyList
*/
public List<String> getIngkeyList() {
if (ingkeyList == null) {
ingkeyList = loadIngkeyListFor(selectedShopcat);
}
return ingkeyList;
}
private List<String> loadIngkeyListFor(
String selectedShopcat2) {
List<String> list = this.shopcatRepository
.findByIngkeySorted(selectedShopcat2);
return list;
}
private String newShopcat;
/**
* @return the newShopcat
*/
public String getNewShopcat() {
return newShopcat;
}
/**
* @param newShopcat the newShopcat to set
*/
public void setNewShopcat(String newShopcat) {
this.newShopcat = newShopcat;
}
public List<String> suggestShopcat(String query) {
return this.shopcatList;
}
public void doChangeShopcat() {
String oldCat = this.getSelectedShopcat();
String newCat = this.getNewShopcat();
if (oldCat.equals(newCat)) {
return; // effective NO-OP
}
newCat = newCat.trim();
if (StringUtils.isBlank(newCat)) {
this.shopcatRepository
.deleteShopcatFor(this.getSelectedIngkey());
} else {
this.shopcatRepository.updateShopcatFor(newCat,
this.getSelectedIngkey());
}
}
}