private decimal GetCheapestTotal(TrolleyVM trolley, List <SpecialVM> potentialSpecials, TrolleyCheckout trolleyCheckout)
        {
            int     indexCheapest = 0;
            decimal cheapest      = 0;

            for (int i = 0; i < potentialSpecials.Count; i++)
            {
                var special            = potentialSpecials[i];
                var checkoutForSpecial = new TrolleyCheckout(trolleyCheckout.Total);
                var trolleyForSpecial  = new TrolleyVM(trolley);

                checkoutForSpecial.Total += special.Total;
                ApplySpecial(special, trolleyForSpecial.Quantities);

                // Recursive call to continue calculating with reduced items
                var totalForSpecial = GetTrolleyTotal(trolleyForSpecial, checkoutForSpecial);

                if (i == 0)
                {
                    cheapest = totalForSpecial;
                }
                else if (totalForSpecial < cheapest)
                {
                    indexCheapest = i;
                    cheapest      = totalForSpecial;
                }
            }

            // Apply the special that has cheapest end value
            return(cheapest);
        }
        public IActionResult CalculateTrolley(TrolleyVM trolley)
        {
            //var total = await _manager.CalculateTrolleyTotal(trolley);
            var total = _manager.CalculateTrolleyTotal(trolley);

            return(Ok(total));
        }
        private List <SpecialVM> GetPotentialSpecials(TrolleyVM trolley)
        {
            // Keep track of potential specials since there can be overlap of specials that include the same item
            var potentialSpecials = new List <SpecialVM>();
            // Deep clone of specials to search through below so no specials are repeated
            List <SpecialVM> specialsToSearchThrough = trolley.Specials.Clone().ToList();

            // In reality there can be more specials than checkout, so loop through checkout items to determine which ones apply.
            foreach (ProductQuantityVM item in trolley.Quantities)
            {
                // Check if item applies and if it does also remove it from the specials to look through.
                // Loop through backwards since removing list being iterated
                for (int i = specialsToSearchThrough.Count - 1; i >= 0; i--)
                {
                    var special = specialsToSearchThrough[i];
                    // Only add special to list of potentials
                    if (DoesSpecialIncludeItem(special, item.Name) && DoesSpecialApplyToTrolley(special, trolley.Quantities))
                    {
                        potentialSpecials.Add(special);
                        specialsToSearchThrough.RemoveAt(i);
                    }
                }
            }

            return(potentialSpecials);
        }
        // Get total for current trolley - Recursive function
        private decimal GetTrolleyTotal(TrolleyVM trolley, TrolleyCheckout trolleyCheckout)
        {
            // 1. Get all specials that apply to trolley.
            var potentialSpecials = GetPotentialSpecials(trolley);

            // 2. Calculate end cost of each potential special to get the cheapest result
            if (potentialSpecials.Count > 0)
            {
                return(GetCheapestTotal(trolley, potentialSpecials, trolleyCheckout));
            }
            else
            {
                return(GetSingularItemsTotal(trolley, trolleyCheckout));
            }
        }
        private decimal GetSingularItemsTotal(TrolleyVM trolley, TrolleyCheckout trolleyCheckout)
        {
            // finally calculate the remaining trolley items
            foreach (ProductQuantityVM item in trolley.Quantities)
            {
                var product = trolley.Products.Find(p => p.Name == item.Name);
                if (product == null)
                {
                    throw new Exception("Item in trolley is not listed as a product");
                }

                trolleyCheckout.Total += item.Quantity * product.Price;
                item.Quantity          = 0;
            }

            return(trolleyCheckout.Total);
        }
        public decimal CalculateTrolleyTotal(TrolleyVM trolleyVM)
        {
            var trolleyCheckout = new TrolleyCheckout();

            return(GetTrolleyTotal(trolleyVM, trolleyCheckout));
        }
        public async Task <decimal> CalculateTrolleyTotalAsync(TrolleyVM trolleyVM)
        {
            var trolley = _mapper.Map <Trolley>(trolleyVM);

            return(await _service.CalculateTrolleyTotal(trolley));
        }