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 siList; private List recipeList; @PostConstruct public void init() { // Load up details on recipes this.siList = new ArrayList(30); buildMaps(); } public List getRecipeList() { if (this.recipeList == null) { this.recipeList = loadRecipeList(); } return this.recipeList; } private List loadRecipeList() { List list = userSession.getShoppingList().stream() .map(r -> new RecipeReference(r)) .collect(Collectors.toList()); return list; } public List getIngredientList() { return this.siList; } private void buildMaps() { this.siList = new ArrayList(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 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 { @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 shopcatList; public List getShopcatList() { if (shopcatList == null) { shopcatList = loadShopcatList(); } return shopcatList; } @Inject ShopcatRepository shopcatRepository; private List 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 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 selectedIngkey; /** * @return the selectedIngkey */ public List getSelectedIngkey() { return selectedIngkey; } /** * @param selectedIngkey the selectedIngkey to set */ public void setSelectedIngkey(List selectedIngkey) { this.selectedIngkey = selectedIngkey; } private List ingkeyList; /** * @return the ingkeyList */ public List getIngkeyList() { if (ingkeyList == null) { ingkeyList = loadIngkeyListFor(selectedShopcat); } return ingkeyList; } private List loadIngkeyListFor( String selectedShopcat2) { List 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 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()); } } }