/// <summary>
        /// Returns a list of products that belong to the given group.
        /// </summary>
        /// <param name="carModelProductId"></param>
        /// <param name="optionId"></param>
        /// <returns></returns>
        public IEnumerable <CarModelOptionProduct> GetCarModelsOptionProducts(int carModelProductId, int optionId)
        {
            var option = _productOptionRepository.GetById(optionId, carModelProductId);

            if (option == null)
            {
                return(null);
            }

            var products = _productRepository.GetOptionProducts(carModelProductId, optionId)
                           .Select(optionProduct =>
            {
                // Wenn es sich um ein Standard-Produkt handelt, ist der Preis im Preis des Fahrzeugs enthalten
                var grossPrice = option.DefaultProductIds.Contains(optionProduct.Id)
                        ? 0
                        : PriceHelper.GetGrossPrice(optionProduct.NetPrice, optionProduct.VATRate);

                return(new CarModelOptionProduct(optionProduct.EAN, optionProduct.Name,
                                                 optionProduct.Description, grossPrice,
                                                 option.DefaultProductIds != null && option.DefaultProductIds.Contains(optionProduct.Id)));
            })
                           .OrderBy(x => x.Price);

            return(products);
        }
        /// <summary>
        /// Maps the database products to a car model product.
        /// </summary>
        /// <param name="product"></param>
        /// <returns></returns>
        private static CarModel MapProductToCarModel(Product product)
        {
            if (product == null)
            {
                return(null);
            }

            var grossPrice = PriceHelper.GetGrossPrice(product.NetPrice, product.VATRate);

            return(new CarModel(product.EAN, product.Name, product.Description, grossPrice));
        }
        /// <summary>
        /// Returns the summary of the current configuration for a list of selected option products.
        /// </summary>
        /// <param name="carModelEAN"></param>
        /// <param name="selectedOptionProducts"></param>
        /// <param name="code"></param>
        /// <returns></returns>
        public CarConfiguratorSummary GetSummaryForSelectedOptionProducts(string carModelEAN,
                                                                          Dictionary <int, CarModelOptionProduct> selectedOptionProducts, string code = null)
        {
            if (carModelEAN == null)
            {
                throw new Exception("Car model EAN is missing.");
            }

            if (selectedOptionProducts == null || selectedOptionProducts.Count == 0)
            {
                throw new Exception("Selected car model option products missing.");
            }

            var carModelProduct = _productRepository.GetByEAN(carModelEAN);

            if (carModelProduct == null)
            {
                throw new Exception("Unknown car model.");
            }

            decimal basePrice    = PriceHelper.GetGrossPrice(carModelProduct.NetPrice, carModelProduct.VATRate);
            decimal optionsPrice = 0;

            var validatedSelectedOptionProducts = new Dictionary <int, CarModelOptionProduct>();

            var modelAvailableOptions = _productOptionRepository.GetProductOptionsByEAN(carModelEAN);

            foreach (var availableOption in modelAvailableOptions)
            {
                var selectedEAN = selectedOptionProducts[availableOption.Id] != null
                    ? selectedOptionProducts[availableOption.Id].EAN
                    : _productRepository.GetProductsByIds(availableOption.DefaultProductIds).Select(x => x.EAN)
                                  .FirstOrDefault();

                var userSelectedProduct = _productRepository.GetByEAN(selectedEAN);
                if (userSelectedProduct == null)
                {
                    throw new Exception("Unknown product with EAN " + selectedEAN + ".");
                }

                var availableProductsForOptions =
                    GetCarModelsOptionProducts(carModelProduct.Id, availableOption.Id);
                // _productRepository.GetOptionProducts(carModelProduct.Id, availableOption.Id);


                var userSelectedOptionProduct =
                    availableProductsForOptions.FirstOrDefault(prod => prod.EAN == selectedEAN);

                // If the product is not an product of the group for the car model
                if (userSelectedOptionProduct == null)
                {
                    continue;
                }


                validatedSelectedOptionProducts.Add(availableOption.Id, userSelectedOptionProduct);

                // If it is a default product, the product price is included in the car's base price
                if (availableOption.DefaultProductIds.Contains(userSelectedProduct.Id))
                {
                    continue;
                }

                optionsPrice += PriceHelper.GetGrossPrice(userSelectedProduct.NetPrice, userSelectedProduct.VATRate);
            }

            var totalPrice = basePrice + optionsPrice;

            var summary =
                new CarConfiguratorSummary(code, basePrice, totalPrice, optionsPrice, carModelEAN,
                                           validatedSelectedOptionProducts);

            var userConfiguration = SaveConfiguration(summary);

            summary.Code = userConfiguration.Code;

            return(summary);
        }
        /// <summary>
        /// Returns a user configuration that has previously been saved by the given code.
        /// </summary>
        /// <param name="code">The code of the saved configuration</param>
        /// <returns></returns>
        public Dictionary <int, CarModelOptionProduct> GetSavedUserConfiguration(string code)
        {
            var userConfiguration = _carConfigUserConfigurationRepository.Get(code);

            if (userConfiguration == null)
            {
                throw new Exception("The code is unknown.");
            }

            var selectedProducts = new Dictionary <int, CarModelOptionProduct>();

            foreach (var userProduct in userConfiguration.Products)
            {
                var product = _productRepository.GetById(userProduct.SelectedOptionProductId);

                selectedProducts.Add(userProduct.OptionId, new CarModelOptionProduct(
                                         product.EAN, product.Name, product.Description, PriceHelper.GetGrossPrice(product.NetPrice, product.VATRate), false)
                                     );
            }

            return(selectedProducts);
        }