public ShoppingListAddAction AddUsage(IngredientUsage usage)
 {
     adder.Usages.Add(usage);
     return(this);
 }
Exemple #2
0
        public IngredientAdder AddIngredient(Ingredient ingredient, Amount amount, string prepNote = null)
        {
            var usage = new IngredientUsage(ingredient, null, amount, prepNote);

            return(AddIngredientUsage(usage));
        }
Exemple #3
0
 public IngredientUsageCreator(IngredientUsage usage)
 {
     this.Usage = usage;
 }
Exemple #4
0
        public static Amount GetNativeAmountForUsage(Ingredient ingredient, IngredientUsage usage)
        {
            var amount        = new Amount();
            var usageConvType = Unit.GetConvType(usage.Form.FormUnitType);

            switch (ingredient.ConversionType) //This is the type we must convert to
            {
            case UnitType.Unit:
                amount.Unit = Units.Unit;

                if (usageConvType == UnitType.Unit)                                            //Unit to unit version
                {
                    var equivGrams = UnitConverter.Convert(usage.Form.FormAmount, Units.Gram); //Grams this form is equivelent to
                    amount.SizeHigh = (float)Math.Ceiling((equivGrams.SizeHigh * usage.Amount.SizeHigh) / ingredient.UnitWeight);
                    return(amount);
                }

                if (usageConvType == 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);
                }

                if (usageConvType == 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); //Round up when dealing with whole units
                    return(amount);
                }
                break;

            case UnitType.Weight:
                amount.Unit = Units.Gram;

                if (usageConvType == UnitType.Unit)                                           //Unit to weight conversion
                {
                    amount.SizeHigh = usage.Amount.SizeHigh * usage.Form.FormAmount.SizeHigh; //NOTE: FormAmount will always be in Grams when Ingredient ConvType is weight
                    return(amount);
                }

                if (usageConvType == UnitType.Volume) //Volume to weight conversion
                {
                    var likeAmount = UnitConverter.Convert(usage.Amount, usage.Form.FormUnitType);
                    amount.SizeHigh = likeAmount.SizeHigh * usage.Form.FormAmount.SizeHigh; //NOTE: FormAmount will always be in Grams when Ingredient ConvType is weight
                    return(amount);
                }

                break;

            case UnitType.Volume:
                amount.Unit = Units.Teaspoon;

                if (usageConvType == UnitType.Unit)                                           //Unit to volume conversion
                {
                    amount.SizeHigh = usage.Amount.SizeHigh * usage.Form.FormAmount.SizeHigh; //NOTE: FormAmount will always be in tsp when Ingredient ConvType is volume
                    return(amount);
                }

                if (usageConvType == UnitType.Weight) //Weight to volume conversion
                {
                    var likeAmount = UnitConverter.Convert(usage.Amount, usage.Form.FormUnitType);
                    amount.SizeHigh = likeAmount.SizeHigh * usage.Form.FormAmount.SizeHigh; //NOTE: FormAmount will always be in teaspoons when Ingredient ConvType is Volume
                    return(amount);
                }

                break;
            }

            //throw new IngredientAggregationDatabaseException("Cannot convert an IngredientUsage into its native form.", ingredient, usage);
            throw new Exception("Cannot convert an IngredientUsage into its native form.");
        }
Exemple #5
0
 public void AddIngredient(IngredientUsage ingredient)
 {
     _ingredients.Add(ingredient);
 }
Exemple #6
0
 public AnomalousMatch(string input, AnomalousResult anomaly, IngredientUsage usage) : base(input, usage)
 {
     this.anomaly = anomaly;
 }
 public AnomalousMatch(string input, AnomalousResult anomaly, IngredientUsage usage)
     : base(input, usage)
 {
     this.anomaly = anomaly;
 }
Exemple #8
0
        /// <summary>Assembles a Result baesd on NLP match data for a given template.</summary>
        /// <param name="template">A passing NLP template that yieled match data</param>
        /// <param name="input">The original input string that was parsed</param>
        /// <param name="matchdata">Match data generated from the specified NLP template</param>
        /// <returns>Result describing the generated KitchenPC IngredientUsage or error code if usage could not be generated</returns>
        public static Result BuildResult(Template template, string input, MatchData matchdata)
        {
            var result = new IngredientUsage();
            var ingName = (matchdata.Ingredient.Parent == null) ? matchdata.Ingredient.IngredientName : matchdata.Ingredient.Parent.IngredientName;
            result.Ingredient = new Ingredient(matchdata.Ingredient.Id, ingName);
            result.Ingredient.ConversionType = matchdata.Ingredient.ConversionType;
            result.Ingredient.UnitWeight = matchdata.Ingredient.UnitWeight;
            result.Amount = matchdata.Amount;
            result.PreparationNote = matchdata.Preps.HasValue ? matchdata.Preps.ToString() : template.DefaultPrep;
            var pairings = matchdata.Ingredient.Pairings;

            NlpTracer.Trace(TraceLevel.Debug, "[BuildResult] Ingredient: {0}", matchdata.Ingredient.IngredientName);
            if (matchdata.Ingredient.Parent != null)
            {
                NlpTracer.Trace(TraceLevel.Debug, "[BuildResult] Re-Link to Root Ingredient: {0}", matchdata.Ingredient.Parent.IngredientName);
            }

            if (template.AllowPartial && matchdata.Amount == null)
            {
                return new PartialMatch(input, result.Ingredient, result.PreparationNote);
            }

            if (matchdata.Unit is CustomUnitNode)
            {
                IngredientForm form;
                if (UnitSynonyms.TryGetFormForIngredient(matchdata.Unit.Name, matchdata.Ingredient.Id, out form))
                {
                    NlpTracer.Trace(TraceLevel.Debug, "[BuildResult] Based on unit name {0}, linking to form id {1}", matchdata.Unit.Name, form.FormId);
                    result.Form = form;
                }
                else
                {
                    NlpTracer.Trace(TraceLevel.Debug, "[BuildResult] ERROR: Unable to find link between unit '{0}' and ingredient '{1}'.", matchdata.Unit.Name, result.Ingredient.Name);
                    return new NoMatch(input, MatchResult.UnknownUnit);
                }
            }
            else
            {
                NlpTracer.Trace(TraceLevel.Debug, "[BuildResult] No custom unit found, so cannot get form based on unit.");
            }

            if (matchdata.Form != null)
            {
                IngredientForm form;
                if (FormSynonyms.TryGetFormForIngredient(matchdata.Form.FormName, matchdata.Ingredient.Id, out form))
                {
                    NlpTracer.Trace(TraceLevel.Debug, "[BuildResult] Based on reference to form {0}, linking to form id {1}", matchdata.Form.FormName, form.FormId);
                    result.Form = form;
                }
                else
                {
                    NlpTracer.Trace(TraceLevel.Debug, "[BuildResult] ERROR: Unable to find link between form '{0}' and ingredient '{1}.", matchdata.Form.FormName, result.Ingredient.Name);
                    return new NoMatch(input, MatchResult.UnknownForm);
                }
            }
            else
            {
                NlpTracer.Trace(TraceLevel.Debug, "[BuildResult] No known form found, so cannot get form based on form synonym.");
            }

            if (result.Form == null)
            {
                if (matchdata.Unit == null || matchdata.Unit.Unit == Units.Unit) // TODO: Is second part necessary? Only Units.Unit would be custom form types, and we'd have errored out already if that didn't match
                {
                    result.Form = pairings.Unit;
                    NlpTracer.ConditionalTrace(pairings.HasUnit, TraceLevel.Debug, "[BuildResult] Linking to default Unit paired form {0}", pairings.Unit);
                }
                else
                {
                    switch (Unit.GetConvertionType(matchdata.Unit.Unit))
                    {
                        case UnitType.Volume:
                            result.Form = pairings.Volume;
                            NlpTracer.ConditionalTrace(pairings.HasVolume, TraceLevel.Debug, "[BuildResult] Linking to default paired Volume form {0}", pairings.Volume);
                            break;
                        case UnitType.Weight:
                            result.Form = pairings.Weight;
                            NlpTracer.ConditionalTrace(pairings.HasWeight, TraceLevel.Debug, "[BuildResult] Linking to default paired Weight form {0}", pairings.Weight);
                            break;
                    }
                }

                if (result.Form == null && result.Amount.Unit == Units.Ounce && pairings.HasVolume)
                {
                    result.Form = pairings.Volume;
                    result.Amount.Unit = Units.FluidOunce;
                    NlpTracer.Trace(TraceLevel.Debug, "[BuildResult] Interpretting reference to Ounces as Fluid Ounces and linking to volumetric form {0}", pairings.Volume);
                }

                if (result.Form == null)
                {
                    NlpTracer.Trace(TraceLevel.Debug, "[BuildResult] Could not find any default pairing for the unit type: {0}", result.Amount.Unit);
                }
            }

            var parsedType = Unit.GetConvertionType(result.Amount.Unit);
            if (result.Form != null && parsedType == Unit.GetConvertionType(result.Form.FormUnitType))
            {
                NlpTracer.Trace(TraceLevel.Info, "[BuildResult] SUCCESS: Linked form is compatible with usage reference.");
                return new Match(input, result);
            }

            NlpTracer.Trace(TraceLevel.Debug, "[BuildResult] Running anomalous parsing.");

            // TODO: If matchdata has multiple prep notes, we either need to only parse the user entered one or avoid duplicate matches
            if (parsedType == UnitType.Volume && matchdata.Preps.HasValue)
            {
                NlpTracer.Trace(TraceLevel.Debug, "[BuildResult] Checking for form matching prep note: {0}", matchdata.Preps);

                IngredientForm form;
                if (FormSynonyms.TryGetFormForPrep(matchdata.Preps, matchdata.Ingredient, true, out form))
                {
                    result.Form = form;

                    if (parsedType == Unit.GetConvertionType(result.Form.FormUnitType))
                    {
                        NlpTracer.Trace(TraceLevel.Debug, "[BuildResult] SUCCESS: Found matching volumetric form, allowing prep to form fall-through.");
                        result.PreparationNote = matchdata.Preps.ToString();
                        return new AnomalousMatch(input, AnomalousResult.Fallthrough, result);
                    }
                    else
                    {
                        NlpTracer.Trace(TraceLevel.Debug, "[BuildResult] Found matching form, but form is not compatible with volumetric usage.");
                    }
                }
            }
            else
            {
                NlpTracer.Trace(TraceLevel.Debug, "[BuildResult] Could not clarify form through prep note, since unit type is not volumetric or there is no prep note.");
            }

            if (result.Form != null)
            {
                NlpTracer.Trace(TraceLevel.Debug, "[BuildResult] Form and unit incompatible - attempting to auto-convert form {0}", result.Form);
                var formType = Unit.GetConvertionType(result.Form.FormUnitType);

                if (parsedType == UnitType.Weight && formType == UnitType.Volume && pairings.HasWeight)
                {
                    NlpTracer.Trace(TraceLevel.Debug, "[BuildResult] SUCCESS: Converting to default weight pairing, and setting prep note to: {0}", result.Form.FormDisplayName);
                    result.PreparationNote = result.Form.FormDisplayName;
                    result.Form = pairings.Weight;
                    return new AnomalousMatch(input, AnomalousResult.AutoConvert, result);
                }
                else if (parsedType == UnitType.Unit && formType == UnitType.Volume)
                {
                    if (pairings.HasUnit && (matchdata.Unit == null || string.IsNullOrEmpty(matchdata.Unit.Name)))
                    {
                        NlpTracer.Trace(TraceLevel.Debug, "[BuildResult] SUCCESS: Converting to default unit pairing, and setting prep note to: {0}", result.Form.FormDisplayName);
                        result.PreparationNote = result.Form.FormDisplayName;
                        result.Form = pairings.Unit;
                        return new AnomalousMatch(input, AnomalousResult.AutoConvert, result);
                    }

                    if (matchdata.Unit != null && false == string.IsNullOrEmpty(matchdata.Unit.Name))
                    {
                        IngredientForm form;
                        NlpTracer.Trace(TraceLevel.Debug, "[BuildResult] Attempting to convert volumetric usage to unit form for custom unit: {0}", matchdata.Unit.Name);
                        if (UnitSynonyms.TryGetFormForIngredient(matchdata.Unit.Name, matchdata.Ingredient.Id, out form))
                        {
                            NlpTracer.Trace(TraceLevel.Debug, "[BuildResult] SUCCESS: Converting to custom unit pairing, and setting prep note to: {0}", result.Form.FormDisplayName);
                            result.PreparationNote = result.Form.FormDisplayName;
                            result.Form = form;
                            return new AnomalousMatch(input, AnomalousResult.AutoConvert, result);
                        }
                    }
                }
            }
            else
            {
                NlpTracer.Trace(TraceLevel.Debug, "[BuildResult] Could not auto-convert form since there is no form to convert.");
            }

            if (result.Form == null)
            {
                NlpTracer.Trace(TraceLevel.Debug, "[BuildResult] ERROR: Anomalous parsing could still not find a form for this usage.");
                return new NoMatch(input, MatchResult.NoForm);
            }

            NlpTracer.Trace(TraceLevel.Debug, "[BuildResult] ERROR: Anomalous parsing could not fix form/unit incompatibility.");

            return new NoMatch(input, MatchResult.IncompatibleForm);
        }
Exemple #9
0
        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);
        }
Exemple #10
0
 public Match(string input, IngredientUsage usage)
     : base(input)
 {
     this.usage = usage;
 }