public object Calculate(CalculationContext context, Calculation calculation)
        {
            Expression expression = new Expression(calculation.Formula);

            var regex = new Regex(@"\[(.*?)\]");
            var parameters = regex.Matches(calculation.Formula);

            GetValue(context, expression, parameters);

            var result = expression.Evaluate();

            SetValue(result, calculation, context);

            return result;
        }
        public void Should_Take_Value_From_ExtendedProperties_Using_Name()
        {
            CalculationContext context = new CalculationContext()
            {
                ChargeElement = new ChargeElement() { Name = "Standing Charge", NetAmount = new decimal(12.71000) },
                Bill = new Bill() { BillStartDate = new DateTime(2012, 2, 10), BillEndDate = new DateTime(2012, 3, 12), TaxPointDate = new DateTime(2012, 03, 12),ExtendedData = new List<ExtendedDataElement>(){new ExtendedDataElement(){ElementName = "PowerFactor", ElementValue = "123"}}},
                Contract = new Contract() { }
            };

            var calculation = new Calculation()
            {
                Formula = "[ChargeElement.NetAmount] / [Bill.BillPeriod] * [Bill.ExtendedData.PowerFactor]",
                Target = "ChargeElement.Quantity"
            };

            var calculationEngine = new CalculationEngine();
            calculationEngine.Calculate(context, calculation);

            Assert.AreEqual(50.43d, context.ChargeElement.Quantity);
        }
        public void ShouldTakeFormulaAndUseCorrectPropertyValues()
        {
            CalculationContext context = new CalculationContext()
            {
                ChargeElement = new ChargeElement() { Name = "Standing Charge", NetAmount = new decimal(12.71000) },
                Bill = new Bill() { BillStartDate = new DateTime(2012, 2, 10), BillEndDate = new DateTime(2012, 3, 12), TaxPointDate = new DateTime(2012, 03, 12) },
                Contract = new Contract() {}
            };

            var calculation = new Calculation()
                                 {
                                     Formula = "[ChargeElement.NetAmount] / [Bill.BillPeriod]",
                                     Target = "ChargeElement.Quantity"
                                 };

            var calculationEngine = new CalculationEngine();
            calculationEngine.Calculate(context, calculation);

            Assert.AreEqual(0.41d, context.ChargeElement.Quantity);
        }
        public void Should_Store_Value_In_Extended_Data()
        {
            CalculationContext context = new CalculationContext()
            {
                ChargeElement = new ChargeElement() { Name = "Standing Charge", NetAmount = new decimal(12.71000) },
                Bill = new Bill() { BillStartDate = new DateTime(2012, 2, 10), BillEndDate = new DateTime(2012, 3, 12), TaxPointDate = new DateTime(2012, 03, 12), ExtendedData = new List<ExtendedDataElement>() { new ExtendedDataElement() { ElementName = "PowerFactor", ElementValue = "123" } } },
                Contract = new Contract() { }
            };

            var calculation = new Calculation()
            {
                Formula = "[ChargeElement.NetAmount] / [Bill.BillPeriod]",
                Target = "Bill.ExtendedData.PowerFactor"
            };

            var calculationEngine = new CalculationEngine();
            calculationEngine.Calculate(context, calculation);

            Assert.AreEqual(0.41d, decimal.Parse(context.Bill.ExtendedData.First(x=>x.ElementName == "PowerFactor").ElementValue));
        }
        private static void SetValue(object result, Calculation calculation, CalculationContext context)
        {
            object proploc = context;

            foreach (var propName in calculation.Target.Split('.'))
            {
                PropertyInfo propInfo = proploc.GetType().GetProperty(propName);

                if (proploc.GetType().Equals(typeof(List<ExtendedDataElement>)))
                {
                    List<ExtendedDataElement> extended = (List<ExtendedDataElement>)proploc;
                    extended.First(x => x.ElementName == propName).ElementValue = result.ToString();
                    break;
                }

                if (propInfo.Name == calculation.Target.Split('.').Last())
                {
                    propInfo.SetValue(proploc, result, null);
                    break;
                }
                proploc = propInfo.GetValue(proploc, null);
            }
        }