public void TestFormConverter() { //Form conversions (Unit ingredients) var unitIng = new Ingredient() {ConversionType = UnitType.Unit, UnitWeight = 200}; //Ingredient sold by units (unit weighs 200g) var unitIng_UnitForm = new IngredientForm() {FormAmount = new Amount(50, Units.Gram), ConversionMultiplier = 1, FormUnitType = Units.Unit}; //Form expressed in units (unit in this form weighs 50g) var unitIng_WeightForm = new IngredientForm() {ConversionMultiplier = 1, FormUnitType = Units.Ounce}; //Form expressed by weight var unitIng_VolForm = new IngredientForm() {FormUnitType = Units.Cup, ConversionMultiplier = 1, FormAmount = new Amount(20, Units.Gram)}; //Each cup weighs 20g) var unitIng_UnitUsage = new IngredientUsage() {Amount = new Amount(4, Units.Unit), Form = unitIng_UnitForm, Ingredient = unitIng}; var unitIng_WeightUsage = new IngredientUsage() {Amount = new Amount(300, Units.Gram), Form = unitIng_WeightForm, Ingredient = unitIng}; var unitIng_VolUsage = new IngredientUsage() {Amount = new Amount(160, Units.Tablespoon), Form = unitIng_VolForm, Ingredient = unitIng}; //10 cups var unitIng_UnitAmt = FormConversion.GetNativeAmountForUsage(unitIng, unitIng_UnitUsage); var unitIng_WeightAmt = FormConversion.GetNativeAmountForUsage(unitIng, unitIng_WeightUsage); var unitIng_VolAmt = FormConversion.GetNativeAmountForUsage(unitIng, unitIng_VolUsage); Assert.AreEqual(1.0f, unitIng_UnitAmt.SizeHigh); //4 units in this form should convert to 1 unit of ingredient Assert.AreEqual(Units.Unit, unitIng_UnitAmt.Unit); Assert.AreEqual(2.0f, unitIng_WeightAmt.SizeHigh); //300g of this form should convert to 1.5 units of ingredient, however we round up to whole units Assert.AreEqual(Units.Unit, unitIng_WeightAmt.Unit); //TODO: Fix //Assert.AreEqual(1.0f, unitIng_VolAmt.SizeHigh); //10 cups of this form should convert to 1 unit of ingredient //Assert.AreEqual(Units.Unit, unitIng_VolAmt.Unit); //Form conversions (Volume ingredients) var volIng = new Ingredient() {ConversionType = UnitType.Volume}; //Ingredient sold by volume var volIng_UnitForm = new IngredientForm() {FormUnitType = Units.Unit, ConversionMultiplier = 1, FormAmount = new Amount(5, Units.Teaspoon)}; var volIng_WeightForm = new IngredientForm() {FormUnitType = Units.Ounce, ConversionMultiplier = 1, FormAmount = new Amount(2, Units.Teaspoon)}; var volIng_UnitUsage = new IngredientUsage() {Amount = new Amount(2, Units.Unit), Form = volIng_UnitForm, Ingredient = volIng}; var volIng_WeightUsage = new IngredientUsage() {Amount = new Amount(0.25f, Units.Pound), Form = volIng_WeightForm, Ingredient = volIng}; //4oz var volIng_UnitAmt = FormConversion.GetNativeAmountForUsage(volIng, volIng_UnitUsage); var volIng_WeightAmt = FormConversion.GetNativeAmountForUsage(volIng, volIng_WeightUsage); Assert.AreEqual(10.0f, volIng_UnitAmt.SizeHigh); Assert.AreEqual(Units.Teaspoon, volIng_UnitAmt.Unit); Assert.AreEqual(8.0f, volIng_WeightAmt.SizeHigh); Assert.AreEqual(Units.Teaspoon, volIng_WeightAmt.Unit); //Form conversions (Weight ingredients) var weightIng = new Ingredient() {ConversionType = UnitType.Weight}; //Ingredient sold by weight var weightIng_UnitForm = new IngredientForm() {ConversionMultiplier = 1, FormUnitType = Units.Unit, FormAmount = new Amount(100, Units.Gram)}; var weightIng_VolForm = new IngredientForm() {ConversionMultiplier = 1, FormUnitType = Units.Cup, FormAmount = new Amount(50, Units.Gram)}; var weightIng_UnitUsage = new IngredientUsage() {Amount = new Amount(5, Units.Unit), Form = weightIng_UnitForm, Ingredient = weightIng}; var weightIng_VolUsage = new IngredientUsage() {Amount = new Amount(144, Units.Teaspoon), Form = weightIng_VolForm, Ingredient = weightIng}; //3 cups var weightIng_UnitAmt = FormConversion.GetNativeAmountForUsage(weightIng, weightIng_UnitUsage); var weightIng_VolAmt = FormConversion.GetNativeAmountForUsage(weightIng, weightIng_VolUsage); Assert.AreEqual(500.0f, weightIng_UnitAmt.SizeHigh); Assert.AreEqual(Units.Gram, weightIng_UnitAmt.Unit); Assert.AreEqual(150.0f, weightIng_VolAmt.SizeHigh); Assert.AreEqual(Units.Gram, weightIng_VolAmt.Unit); }
public IngredientUsage(Ingredient ingredient, IngredientForm form, Amount amount, string prepnote) { Ingredient = ingredient; Form = form; Amount = amount; PrepNote = prepnote; }
public IngredientUsage(Ingredient ingredient, IngredientForm form, Amount amount, string preparationNote) { this.Ingredient = ingredient; this.Form = form; this.Amount = amount; this.PreparationNote = preparationNote; }
public IngredientAdder AddIngredient(Ingredient ingredient, Amount amount, string prepNote = null) { var usage = new IngredientUsage(ingredient, null, amount, prepNote); var addedIngredient = this.AddIngredientUsage(usage); return addedIngredient; }
public IngredientAggregation(Ingredient ingredient) { this.Ingredient = ingredient; this.Amount = new Amount { Unit = Unit.GetDefaultUnitType(ingredient.ConversionType) }; }
public IngredientAggregation(Ingredient ingredient) { this.Ingredient = ingredient; if (ingredient != null) { this.Amount = new Amount(); this.Amount.Unit = Unit.GetDefaultUnitType(ingredient.ConversionType); } }
public static IngredientBinding Create(Guid ingId, Guid recipeId, Single? qty, Units usageUnit, UnitType convType, Int32 unitWeight, Units formUnit, Single equivAmount, Units equivUnit) { var rawUnit = KitchenPC.Unit.GetDefaultUnitType(convType); if (qty.HasValue && rawUnit != usageUnit) { if (UnitConverter.CanConvert(usageUnit, rawUnit)) { qty = UnitConverter.Convert(qty.Value, usageUnit, rawUnit); } else { var ing = new Ingredient { Id = ingId, ConversionType = convType, UnitWeight = unitWeight }; var form = new IngredientForm { FormUnitType = formUnit, FormAmount = new Amount(equivAmount, equivUnit), IngredientId = ingId }; var usage = new Ingredients.IngredientUsage { Form = form, Ingredient = ing, Amount = new Amount(qty.Value, usageUnit) }; try { var newAmt = FormConversion.GetNativeAmountForUsage(ing, usage); qty = UnitConverter.Convert(newAmt.SizeHigh, newAmt.Unit, rawUnit); //Ingredient graph only stores high amounts } catch (Exception e) { throw new DataLoadException(e); } } } return new IngredientBinding { RecipeId = recipeId, IngredientId = ingId, Qty = qty.HasValue ? (float?) Math.Round(qty.Value, 3) : null, Unit = rawUnit }; }
public IngredientAggregation(Ingredient ingredient, Amount baseAmount) { this.Ingredient = ingredient; this.Amount = baseAmount; }
public IngredientToken(Ingredient ing) { this.ing = ing; }
public IngredientAdder AddIngredient(Ingredient ingredient, string prepNote = null) { var result = this.AddIngredient(ingredient, null, prepNote); return result; }
public ProfileCreator AddBlacklistedIngredient(Ingredient ingredient) { blacklistIng.Add(ingredient.Id); return this; }
public ShoppingListResult CreateShoppingList(string name, Recipe[] recipes, Ingredient[] ingredients, IngredientUsage[] usages, string[] items) { throw new NotImplementedException(); }
public static Amount GetNativeAmountForUsage(Ingredient ingredient, IngredientUsage usage) { var amount = new Amount(); var usageConvType = Unit.GetConvertedType(usage.Form.FormUnitType); // This is the type we must convert to switch (ingredient.ConversionType) { case UnitType.Unit: amount.Unit = Units.Unit; // Unit to unit version if (usageConvType == UnitType.Unit) { // Grams this form is equivelent to var equivelentGrams = UnitConverter.Convert(usage.Form.FormAmount, Units.Gram); amount.SizeHigh = (float)Math.Ceiling((equivelentGrams.SizeHigh * usage.Amount.SizeHigh) / ingredient.UnitWeight); return amount; } // Weight to unit conversion if (usageConvType == UnitType.Weight) { var grams = UnitConverter.Convert(usage.Amount, Units.Gram); amount.SizeHigh = (float)Math.Ceiling(grams.SizeHigh / ingredient.UnitWeight); return amount; } // Volume to unit conversion if (usageConvType == UnitType.Volume) { var likeAmount = UnitConverter.Convert(usage.Amount, usage.Form.FormUnitType); // Round up when dealing with whole units amount.SizeHigh = (float)Math.Ceiling((likeAmount.SizeHigh * usage.Form.FormAmount.SizeHigh) / usage.Ingredient.UnitWeight); return amount; } break; case UnitType.Weight: amount.Unit = Units.Gram; // Unit to weight conversion if (usageConvType == UnitType.Unit) { // NOTE: FormAmount will always be in Grams when Ingredient ConvType is weight amount.SizeHigh = usage.Amount.SizeHigh * usage.Form.FormAmount.SizeHigh; return amount; } // Volume to weight conversion if (usageConvType == UnitType.Volume) { var likeAmount = UnitConverter.Convert(usage.Amount, usage.Form.FormUnitType); // NOTE: FormAmount will always be in Grams when Ingredient ConvType is weight amount.SizeHigh = likeAmount.SizeHigh * usage.Form.FormAmount.SizeHigh; return amount; } break; case UnitType.Volume: amount.Unit = Units.Teaspoon; // Unit to volume conversion if (usageConvType == UnitType.Unit) { // NOTE: FormAmount will always be in tsp when Ingredient ConvType is volume amount.SizeHigh = usage.Amount.SizeHigh * usage.Form.FormAmount.SizeHigh; return amount; } // Weight to volume conversion if (usageConvType == UnitType.Weight) { var likeAmount = UnitConverter.Convert(usage.Amount, usage.Form.FormUnitType); // NOTE: FormAmount will always be in teaspoons when Ingredient ConvType is Volume amount.SizeHigh = likeAmount.SizeHigh * usage.Form.FormAmount.SizeHigh; return amount; } break; } throw new Exception("Cannot convert an IngredientUsage into its native form."); }
public ShoppingListAddAction AddIngredient(Ingredient ingredient) { adder.Ingredients.Add(ingredient); return this; }
public IngredientUsageCreator WithIngredient(Ingredient ingredient) { this.Usage.Ingredient = ingredient; return this; }
public ShoppingListItem(Ingredient ingredient) : base(ingredient) { }
/// <summary> /// Aggregates one or more recipes into a set of aggregated ingredients. This is normally used to create a list of items needed to buy for multiple recipes without having to create a shopping list. /// </summary> /// <param name="recipeIds">A list of recipe IDs to aggregate.</param> /// <returns>A list of IngredientAggregation objects, one per unique ingredient in the set of recipes</returns> public virtual IList<IngredientAggregation> AggregateRecipes(params Guid[] recipeIds) { using (InitLock.ReadLock()) { var ingredients = new Dictionary<Guid, IngredientAggregation>(); // List of all ingredients and total usage foreach (var id in recipeIds) { // Lookup ingredient through modeler cache var recipeNode = this.modeler.FindRecipe(id); if (recipeNode == null) { // Our cache is out of date, skip this result continue; } foreach (var usage in recipeNode.Ingredients) { var ingredientId = usage.Ingredient.IngredientId; string ingredientName = this.ingredientParser.GetIngredientById(ingredientId); var ingredient = new Ingredient(ingredientId, ingredientName); ingredient.ConversionType = usage.Ingredient.ConversionType; IngredientAggregation aggregation; if (!ingredients.TryGetValue(ingredientId, out aggregation)) { aggregation = new IngredientAggregation(ingredient) { Amount = new Amount(0, usage.Unit) }; ingredients.Add(ingredientId, aggregation); } // TODO: If usage.Unit is different than agg.Amount.Unit then we have a problem, throw an exception if that happens? if (aggregation.Amount == null) { // This aggregation contains an empty amount, so we can't aggregate continue; } else if (!usage.Amount.HasValue) { // This amount is null, cancel aggregation aggregation.Amount = null; } else { aggregation.Amount += usage.Amount.Value; } } } return ingredients.Values.ToList(); } }
/// <summary> /// Creates a new shopping list for the current user. /// </summary> /// <param name="name">The name of the new shopping list.</param> /// <param name="recipes">Zero or more recipes to add to this list.</param> /// <param name="ingredients">Zero or more ingredients to add to this list.</param> /// <param name="usages">Zero or more ingredient usages to add to this list.</param> /// <param name="items">Zero or more raw usages. Raw usages will be parsed using NLP, and unsuccessful matches will be added to the list as raw items.</param> /// <returns>A fully aggregated shopping list, with like items combined and forms normalized.</returns> public virtual ShoppingListResult CreateShoppingList( string name, Recipe[] recipes, Ingredient[] ingredients, IngredientUsage[] usages, string[] items) { var parsedIngredients = Parser.ParseAll(items).ToList(); var recipeAggregation = this.AggregateRecipes(recipes.Select(r => r.Id).ToArray()); var ingredientsAggregation = ingredients.Select(i => new IngredientAggregation(i, null)); var ingredientUsages = this.AggregateIngredients(usages); var parsedUsages = this.AggregateIngredients(parsedIngredients.Where(u => u is Match).Select(u => u.Usage).ToArray()); var rawInputs = parsedIngredients.Where(u => u is NoMatch).Select(u => new ShoppingListItem(u.Input)); var allItems = recipeAggregation .Concat(ingredientsAggregation) .Concat(ingredientUsages) .Concat(parsedUsages) .Concat(rawInputs); var list = new ShoppingList(null, name, allItems); return this.CreateShoppingList(list); }
public static Amount GetNativeAmountForUsage(Ingredient ingredient, IngredientUsage usage) { var amount = new Amount(); var usageConvertionType = Unit.GetConvertionType(usage.Form.FormUnitType); switch (ingredient.ConversionType) { case UnitType.Unit: { amount.Unit = Units.Unit; switch (usageConvertionType) { case UnitType.Unit: { // Unit to unit version var equivalentGrams = UnitConverter.Convert(usage.Form.FormAmount, Units.Gram); amount.SizeHigh = (float)Math.Ceiling((equivalentGrams.SizeHigh * usage.Amount.SizeHigh) / ingredient.UnitWeight); return amount; } case UnitType.Volume: { // Volume to unit conversion var likeAmount = UnitConverter.Convert(usage.Amount, usage.Form.FormUnitType); amount.SizeHigh = (float)Math.Ceiling((likeAmount.SizeHigh * usage.Form.FormAmount.SizeHigh) / usage.Ingredient.UnitWeight); return amount; } case UnitType.Weight: { // Weight to unit conversion var grams = UnitConverter.Convert(usage.Amount, Units.Gram); amount.SizeHigh = (float)Math.Ceiling(grams.SizeHigh / ingredient.UnitWeight); return amount; } } break; } case UnitType.Weight: { amount.Unit = Units.Gram; switch (usageConvertionType) { case UnitType.Unit: { // Unit to weight conversion amount.SizeHigh = usage.Amount.SizeHigh * usage.Form.FormAmount.SizeHigh; return amount; } case UnitType.Volume: { // Volume to weight conversion var likeAmount = UnitConverter.Convert(usage.Amount, usage.Form.FormUnitType); amount.SizeHigh = likeAmount.SizeHigh * usage.Form.FormAmount.SizeHigh; return amount; } } break; } case UnitType.Volume: { amount.Unit = Units.Teaspoon; switch (usageConvertionType) { case UnitType.Unit: { // Unit to volume conversion amount.SizeHigh = usage.Amount.SizeHigh * usage.Form.FormAmount.SizeHigh; return amount; } case UnitType.Weight: { // Weight to volume conversion var likeAmount = UnitConverter.Convert(usage.Amount, usage.Form.FormUnitType); amount.SizeHigh = likeAmount.SizeHigh * usage.Form.FormAmount.SizeHigh; return amount; } } break; } } throw new IngredientAggregationDatabaseException(string.Format("Cannot convert an IngredientUsage into its native form.", ingredient, usage)); }
public IngredientToken(Ingredient ingredient) { this.ingredient = ingredient; }
public IngredientAdder AddIngredient(Ingredient ingredient, string prepNote = null) { return this.AddIngredient(ingredient, null, prepNote); }
public InvalidFormException(Ingredient ingredient, IngredientForm form) { this.Ingredient = ingredient; this.Form = form; }
public PartialMatch(string input, Ingredient ingredient, string prep) : base(input, null) { this.usage = new IngredientUsage(ingredient, null, null, prep); }
public InvalidFormException(Ingredient ing, IngredientForm form) { Ingredient = ing; Form = form; }
/// <summary> /// Aggregates one or more recipes into a set of aggregated ingredients. This is normally used to create a list of items needed to buy for multiple recipes without having to create a shopping list. /// </summary> /// <param name="recipeIds">A list of recipe IDs to aggregate.</param> /// <returns>A list of IngredientAggregation objects, one per unique ingredient in the set of recipes</returns> public IList<IngredientAggregation> AggregateRecipes(params Guid[] recipeIds) { var ings = new Dictionary<Guid, IngredientAggregation>(); //List of all ingredients and total usage foreach (var id in recipeIds) { //Lookup ingredient through modeler cache var rNode = ModelerProxy.FindRecipe(id); if (rNode == null) //Our cache is out of date, skip this result continue; foreach (var usage in rNode.Ingredients) { var ingId = usage.Ingredient.IngredientId; var ingName = ingParser.GetIngredientById(ingId); var ing = new Ingredient(ingId, ingName); ing.ConversionType = usage.Ingredient.ConvType; IngredientAggregation agg; if (!ings.TryGetValue(ingId, out agg)) { ings.Add(ingId, agg = new IngredientAggregation(ing) { Amount = new Amount(0, usage.Unit) }); } //TODO: If usage.Unit is different than agg.Amount.Unit then we have a problem, throw an exception if that happens? if (agg.Amount == null) //This aggregation contains an empty amount, so we can't aggregate continue; else if (!usage.Amt.HasValue) //This amount is null, cancel aggregation agg.Amount = null; else agg.Amount += usage.Amt.Value; } } return ings.Values.ToList(); }
public ProfileCreator AddFavoriteIngredient(Ingredient ingredient) { favIngs.Add(ingredient.Id); return this; }