package com.customfit.ctg.model; import java.util.*; import com.customfit.ctg.controller.*; /** * A Recipe holds all of the individual components of a recipe. * * @author Drew, David */ public class Recipe { /** * The name of the recipe. */ private String name = "New Recipe"; /** * The instructions for the recipe. */ private String instructions = "Insert your recipe here."; /** * The serving size for the recipe (for each of the number of servings). */ private Measurement servingSize = new Measurement(1.0, "unit"); /** * The number of servings the recipe makes. */ private double servings = 1.0; /** * The recipe rating (voting system). */ private double rating = 0.0; /** * The list of ingredients in the recipe. */ private List<RecipeIngredient> ingredients = new ArrayList<RecipeIngredient>(); /** * The nutrition information for the recipe. */ private NutritionFacts nutritionInformation = new NutritionFacts(); /** * Constructs an empty Recipe with some default parameters. */ public Recipe(Recipe recipe) { this.name = recipe.name; this.instructions = recipe.instructions; this.servingSize = recipe.servingSize; this.servings = recipe.servings; this.rating = recipe.rating; this.ingredients = recipe.ingredients; this.nutritionInformation = recipe.nutritionInformation; } /** * Constructs an exsting Recipe by copying fields. */ public Recipe() { } /** * Constructs a recipe object with all parameters. * * @param name The name of the recipe. * @param instructions The instructions for the recipe. * @param servingSize The serving size for the recipe (for each of the number of servings). * @param servings The number of servings the recipe makes. * @param rating The recipe rating (voting system). * @param ingredients The list of ingredients in the recipe. * @param nutrition The nutrition information for the recipe. */ public Recipe(String name, String instructions, Measurement servingSize, double servings, double rating, List<RecipeIngredient> ingredients, NutritionFacts nutritionInformation ){ this.name = name; this.instructions = instructions; this.servingSize = servingSize; this.servings = servings; this.rating = rating; this.ingredients = ingredients; this.nutritionInformation = nutritionInformation; } /** * Sets the name of the recipe. * @param name The name of the recipe. */ public void setName(String name) { this.name = name; } /** * Gets the name of the recipe. * * @param name The name of the recipe. */ public String getName() { return name; } /** * Sets the instructions for the recipe. * * @param instructions The instructions for the recipe. */ public void setInstructions(String instructions) { this.instructions = instructions; } /** * Gets the instructions for the recipe. * * @return The instructions for the recipe. */ public String getInstructions() { return instructions; } /** * Gets the serving size for the recipe (for each of the number of servings). * * @return The serving size for the recipe (for each of the number of servings). */ public Measurement getServingSize() { return servingSize; } /** * Sets the serving size for the recipe (for each of the number of servings). * * @param servingSize The serving size for the recipe (for each of the number of servings). */ public void setServingSize(Measurement servingSize) { this.servingSize = servingSize; } /** * Gets the number of servings the recipe makes. * * @return The number of servings the recipe makes. */ public double getServings() { return servings; } /** * Sets the number of servings the recipe makes. * * @param servings The number of servings the recipe makes. */ public void setServings(double servings) { this.servings = servings; } /** * Sets the recipe rating (voting system). * * @param The recipe rating (voting system). */ public void setRating(double rating) { this.rating = rating; } /** * Gets the recipe rating (voting system). * * @return The recipe rating (voting system). */ public double getRating() { return rating; } /** * Sets the list of ingredients in the recipe. * * @param ingredients The list of ingredients in the recipe. */ protected void setIngredients(List<RecipeIngredient> ingredients) { this.ingredients = ingredients; } /** * Gets the list of ingredients in the recipe. * * @return The list of ingredients in the recipe. */ public List<RecipeIngredient> getIngredients() { return ingredients; } /** * Sets the nutrition information for the recipe. * @param nutrition The nutrition information for the recipe. */ public void setNutritionInformation(NutritionFacts nutritionInformation) { this.nutritionInformation = nutritionInformation; } /** * Gets the nutrition information for the recipe. * @return The nutrition information for the recipe. */ public NutritionFacts getNutritionInformation() { return nutritionInformation; } /** * Prints the name of the Recipe. */ @Override public String toString() { return this.getName(); } /** * Scales a Recipe's Ingredients, Serving Size, and Nutritional Information * to match the scaled factor. * * @param recipe Recipe to scale. * @param scaleFactor The factor to scale it by. * * @return A new Recipe object with scaled fields. */ public static Recipe scaleRecipe(Recipe recipe, double scaleFactor) { //rebuild and scale ingredients ArrayList<RecipeIngredient> newIngredientsList = new ArrayList<RecipeIngredient>(); for (RecipeIngredient ingredient: recipe.getIngredients()) { if (ingredient.getAmount() == null) newIngredientsList.add(ingredient); else newIngredientsList.add(ingredient.scale(scaleFactor)); } //build the new Recipe and return return new Recipe( recipe.getName(), recipe.getInstructions(), recipe.getServingSize().scale(scaleFactor), recipe.getServings(), recipe.getRating(), newIngredientsList, recipe.getNutritionInformation().scale(scaleFactor)); } /** * Scales this Recipe's Ingredients, Serving Size, and Nutritional Information * to match the scaled factor. * * @param scaleFactor The factor to scale the Recipe by. * * @return A new Recipe object with scaled fields. */ public Recipe scale(double scaleFactor) { return Recipe.scaleRecipe(this, scaleFactor); } /** * Scales a Recipe to a certain number of servings. * * This method scales the Ingredient List amount and * the NutritionFacts nutrient fields' quantities to match * the new size of the Recipe. * * Serving size will be unaffected. The new servings amount * will be stored in the mutated object. * * @param recipe The Recipe to scale. * @param toServings The number of servings to scale to. * * @return A new Recipe that has been scaled. */ public static Recipe scaleRecipeToServings(Recipe recipe, double toServings) { //get the scale factor, which is (fromServings / toServings) double scaleFactor = recipe.getServings() / toServings; //scale it Recipe newRecipe = recipe.scale(scaleFactor); //then fix the serving size back, it was servings count that we were tampering newRecipe.servingSize = recipe.servingSize; newRecipe.servings = toServings; //return adjusted Recipe return newRecipe; } /** * Scales this Recipe to a certain number of servings. * * @param recipe The Recipe to scale. * @param toServings The number of servings to scale to. * * @return A new Recipe that has been scaled. */ public Recipe scaleToServings(int toServings) { return Recipe.scaleRecipeToServings(this, toServings); } /** * Scales a Recipe to a nutritional target. This assumes that the member * will eat that one meal for the day, and that's it. * * If this is not the case and the member plans on eating more than one meal * for the day, then just call .scale(double factor) behind it with some fraction like * 1.0/3.0'rd of the day. * * @param nutrientName The nutrient to scale to recipe to. * @param goal The member's nutritional target. * * @return The ideal Recipe for the nutritional goal specified. */ public static Recipe scaleToNutritionalTarget(Recipe recipe, String nutrientName, Measurement goal) { //get the nutrient from the recipe Measurement nutrient = recipe.nutritionInformation.getNutrient(nutrientName); //check for nutrient existance, it may not exist. if it doesn't, then there is nothing to scale toward if (nutrient != null) { //gather information double recipeNutrientQuantity = nutrient.getQuantity(); double goalQuantity = goal.getQuantity(); //calculate how many times you would have to make a recipe to reach your exact goal double scaleFactor = goalQuantity / recipeNutrientQuantity; //now scale the Recipe return recipe.scale(scaleFactor); } else //nothing else to do here, make a copy of self and go on return new Recipe(recipe); } /** * Scales this Recipe to a nutritional target. This assumes that the member * will eat that one meal for the day, and that's it. * * If this is not the case and the member plans on eating more than one meal * for the day, then just call .scale(double factor) behind it with some fraction like * 1.0/3.0'rd of the day. * * @param nutrientName The nutrient to scale to recipe to. * @param goal The member's nutritional target. * * @return The ideal Recipe for the nutritional goal specified. */ public Recipe scaleToNutritionalTarget(String nutrientName, Measurement goal) { return Recipe.scaleToNutritionalTarget(this, nutrientName, goal); } @Override public boolean equals(Object object) { Recipe recipe = (Recipe)object; if (this.name.equals(recipe.name) && this.instructions.equals(recipe.instructions) && this.servings == recipe.servings && this.servingSize.equals(recipe.servingSize) && this.rating == recipe.rating && this.ingredients.size() == recipe.ingredients.size() && this.nutritionInformation.equals(recipe.nutritionInformation)) { for (int ingredient = 0; ingredient < this.ingredients.size(); ingredient++) { if (!this.ingredients.get(ingredient).equals(recipe.ingredients.get(ingredient))) return false; } return true; } return false; } /** * Adds two Recipe objects together into a new Recipe object. * * It merges ingredients, summing them if they are on both sides. * It adds servings together into the output. * It also accumulates nutrition information for both Recipes. * * @param recipeLeft A recipe object. * @param recipeRight Another recipe object. * * @return A new Recipe object with the fields summed together. */ public static Recipe addRecipes(Recipe recipeLeft, Recipe recipeRight) { //copy the left recipe to a new container object Recipe newRecipe = new Recipe(recipeLeft); //add servings from both newRecipe.servings += recipeRight.servings; //add nutrition info from both newRecipe.nutritionInformation.add(recipeRight.nutritionInformation); //assemble new ingredients newRecipe.ingredients = new ArrayList<RecipeIngredient>(); //step one: add known ingredients together for (RecipeIngredient ingredientLeft: recipeLeft.ingredients) //get the ingredient on the right that matches the one on the left for (RecipeIngredient ingredientRight: recipeRight.ingredients) //if the two ingredients have matching names if (ingredientLeft.getName().equals(ingredientRight.getName())) //then add them together on the newIngredients list newRecipe.ingredients.add(ingredientLeft.add(ingredientRight)); //step two: add unknown ingredients from right to left as is for (RecipeIngredient ingredientRight: recipeRight.ingredients) //if the ingredient is unknown if (!newRecipe.ingredients.contains(ingredientRight)) //then add it newRecipe.ingredients.add(ingredientRight); //return new recipe return newRecipe; } /** * Adds a Recipe object to this one and returns a new Recipe object * to the output. * * It merges ingredients, summing them if they are on both sides. * It adds servings together into the output. * It also accumulates nutrition information for both Recipes. * * @param recipeLeft A recipe object to add with this one. * * @return A new Recipe object with the fields summed together. */ public Recipe add(Recipe recipe) { return Recipe.addRecipes(this, recipe); } }