/// <summary>
        /// Finds a Product's Collection of Material.
        /// </summary>
        /// <param name="fetchProductDTO">DTO containing information used for querying.</param>
        /// <returns>GetAllMaterialsModelView with all of the elements in the Product's Collection of Material.</returns>
        /// <exception cref="ResourceNotFoundException">Thrown when the Product could not be found.</exception>
        public GetAllMaterialsModelView findProductMaterials(FetchProductDTO fetchProductDTO)
        {
            Product product = PersistenceContext.repositories().createProductRepository().find(fetchProductDTO.id);

            if (product == null)
            {
                throw new ResourceNotFoundException(string.Format(ERROR_UNABLE_TO_FIND_PRODUCT_BY_ID, fetchProductDTO.id));
            }

            List <Material> pricedMaterials = new List <Material>();

            if (fetchProductDTO.pricedMaterialsOnly)
            {
                MaterialPriceTableRepository materialPriceTableRepository = PersistenceContext.repositories().createMaterialPriceTableRepository();
                foreach (ProductMaterial productMaterial in product.productMaterials)
                {
                    if (materialPriceTableRepository.fetchCurrentMaterialPrice(productMaterial.materialId) != null)
                    {
                        pricedMaterials.Add(productMaterial.material);
                    }
                }
            }

            if (fetchProductDTO.pricedMaterialsOnly)
            {
                return(pricedMaterials.Count == 0 ? throw new ResourceNotFoundException(NO_PRICED_MATERIALS) : MaterialModelViewService.fromCollection(pricedMaterials));
            }

            return(MaterialModelViewService.fromCollection(product.productMaterials.Select(pm => pm.material)));
        }
        /// <summary>
        /// Finds a Product by an identifier, be it a business identifier or a persistence identifier.
        /// </summary>
        /// <param name="fetchProductDTO">DTO containing information used for querying and data conversion.</param>
        /// <returns>An instance of GetProductModelView with the Product's information.</returns>
        /// <exception cref="ResourceNotFoundException">Thrown when the Product is not found.</exception>
        public GetProductModelView findProduct(FetchProductDTO fetchProductDTO)
        {
            Product product = null;

            //if no reference value is specified, search by id
            if (Strings.isNullOrEmpty(fetchProductDTO.reference))
            {
                product = PersistenceContext.repositories().createProductRepository().find(fetchProductDTO.id);

                if (product == null)
                {
                    throw new ResourceNotFoundException(string.Format(ERROR_UNABLE_TO_FIND_PRODUCT_BY_ID, fetchProductDTO.id));
                }
            }
            else
            {
                product = PersistenceContext.repositories().createProductRepository().find(fetchProductDTO.reference);

                if (product == null)
                {
                    throw new ResourceNotFoundException(string.Format(ERROR_UNABLE_TO_FIND_PRODUCT_BY_REFERENCE, fetchProductDTO.reference));
                }
            }

            return(ProductModelViewService.fromEntity(product, fetchProductDTO.productDTOOptions.requiredUnit));
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="rawProducts"></param>
        /// <returns></returns>
        public async Task UpdateDatabaseAsync(FetchProductDTO rawProducts)
        {
            if (rawProducts.StatusCode == 200)
            {
                //loop through products
                foreach (var item in rawProducts.Body)
                {
                    //check if it exists in the DB
                    var product = await _context.Products.FindAsync(item.Id);

                    if (product != null)
                    {
                        product.Name  = item.Name;
                        product.Price = item.Price;

                        //update data
                        _context.Update(product);
                    }
                    else
                    {
                        //add new item
                        _context.Products.Add(item);
                    }
                }

                await _context.SaveChangesAsync();
            }
        }
        /// <summary>
        /// Finds a Product's Collection of Measurement.
        /// </summary>
        /// <param name="fetchProductDTO">DTO containing information used for querying and data conversion.</param>
        /// <returns>GetAllMeasurementsModelView with all of the elements in the Product's Collection of Measurement.</returns>
        /// <exception cref="ResourceNotFoundException">Thrown when the Product could not be found.</exception>
        public GetAllMeasurementsModelView findProductMeasurements(FetchProductDTO fetchProductDTO)
        {
            Product product = PersistenceContext.repositories().createProductRepository().find(fetchProductDTO.id);

            if (product == null)
            {
                throw new ResourceNotFoundException(string.Format(ERROR_UNABLE_TO_FIND_PRODUCT_BY_ID, fetchProductDTO.id));
            }

            //allow unit conversion
            return(MeasurementModelViewService.fromCollection(product.productMeasurements.Select(pm => pm.measurement), fetchProductDTO.productDTOOptions.requiredUnit));
        }
        public ActionResult find([FromQuery] string reference, [FromQuery] string unit)
        {
            if (reference == null)
            {
                return(findAll());
            }

            FetchProductDTO fetchProductDTO = new FetchProductDTO();

            fetchProductDTO.reference = reference;
            fetchProductDTO.productDTOOptions.requiredUnit = unit;

            return(findByReference(fetchProductDTO));
        }
 /// <summary>
 /// Finds a Product with a matching reference.
 /// </summary>
 /// <param name="fetchProductDTO"></param>
 /// <returns></returns>
 private ActionResult findByReference(FetchProductDTO fetchProductDTO)
 {
     try {
         GetProductModelView getProductModelView = new core.application.ProductController().findProduct(fetchProductDTO);
         return(Ok(getProductModelView));
     } catch (ResourceNotFoundException e) {
         return(NotFound(new SimpleJSONMessageService(e.Message)));
     } catch (ArgumentException e) {
         //this exception may occur if the specified unit does not exist
         return(BadRequest(new SimpleJSONMessageService(e.Message)));
     } catch (Exception) {
         return(StatusCode(500, new SimpleJSONMessageService(UNEXPECTED_ERROR)));
     }
 }
        public ActionResult findProductMaterials(long productId, [FromQuery] bool pricedMaterialsOnly)
        {
            FetchProductDTO fetchProductDTO = new FetchProductDTO();

            fetchProductDTO.id = productId;
            fetchProductDTO.pricedMaterialsOnly = pricedMaterialsOnly;
            try {
                GetAllMaterialsModelView allMaterialsModelView = new core.application.ProductController().findProductMaterials(fetchProductDTO);
                return(Ok(allMaterialsModelView));
            } catch (ResourceNotFoundException e) {
                return(NotFound(new SimpleJSONMessageService(e.Message)));
            } catch (Exception) {
                return(StatusCode(500, new SimpleJSONMessageService(UNEXPECTED_ERROR)));
            }
        }
        /// <summary>
        /// Finds a Product's ProductSlotWidths.
        /// </summary>
        /// <param name="fetchProductDTO">DTO containing information used for querying.</param>
        /// <returns>GetProductSlotWidthsModelView representing the Product's ProductSlotWidths.</returns>
        /// <exception cref="ResourceNotFoundException">Thrown when the Product could not be found.</exception>
        public GetProductSlotWidthsModelView findProductSlotWidths(FetchProductDTO fetchProductDTO)
        {
            Product product = PersistenceContext.repositories().createProductRepository().find(fetchProductDTO.id);

            if (product == null)
            {
                throw new ResourceNotFoundException(string.Format(ERROR_UNABLE_TO_FIND_PRODUCT_BY_ID, fetchProductDTO.id));
            }

            //?Should this be a BadRequest or a NotFound?
            if (!product.supportsSlots)
            {
                throw new InvalidOperationException(string.Format(ERROR_SLOTS_NOT_SUPPORTED, fetchProductDTO.id));
            }

            return(ProductSlotWidthsModelViewService.fromEntity(product.slotWidths, fetchProductDTO.productDTOOptions.requiredUnit));
        }
        public ActionResult findProductSlotWidths(long productId, [FromQuery] string unit)
        {
            FetchProductDTO fetchProductDTO = new FetchProductDTO();

            fetchProductDTO.id = productId;
            fetchProductDTO.productDTOOptions.requiredUnit = unit;
            try {
                GetProductSlotWidthsModelView productSlotWidthsMV = new core.application.ProductController().findProductSlotWidths(fetchProductDTO);
                return(Ok(productSlotWidthsMV));
            } catch (ResourceNotFoundException e) {
                return(NotFound(new SimpleJSONMessageService(e.Message)));
            } catch (InvalidOperationException e) {
                return(BadRequest(new SimpleJSONMessageService(e.Message)));
            } catch (Exception) {
                return(StatusCode(500, new SimpleJSONMessageService(UNEXPECTED_ERROR)));
            }
        }
        public ActionResult findById(long id, [FromQuery] string unit)
        {
            FetchProductDTO fetchProductDTO = new FetchProductDTO();

            fetchProductDTO.id = id;
            fetchProductDTO.productDTOOptions.requiredUnit = unit;
            try {
                GetProductModelView getProductModelView = new core.application.ProductController().findProduct(fetchProductDTO);
                return(Ok(getProductModelView));
            } catch (ResourceNotFoundException e) {
                return(NotFound(new SimpleJSONMessageService(e.Message)));
            } catch (ArgumentException e) {
                //this exception may occur if the specified unit does not exist
                return(BadRequest(new SimpleJSONMessageService(e.Message)));
            } catch (Exception) {
                return(StatusCode(500, new SimpleJSONMessageService(UNEXPECTED_ERROR)));
            }
        }
        public ActionResult findProductMeasurements(long productId, [FromQuery] string unit)
        {
            FetchProductDTO fetchProductDTO = new FetchProductDTO()
            {
                id = productId
            };

            fetchProductDTO.productDTOOptions.requiredUnit = unit;
            try {
                GetAllMeasurementsModelView allMeasurementsModelView =
                    new core.application.ProductController().findProductMeasurements(fetchProductDTO);
                return(Ok(allMeasurementsModelView));
            } catch (ArgumentException e) {
                return(BadRequest(new SimpleJSONMessageService(e.Message)));
            } catch (ResourceNotFoundException e) {
                return(NotFound(new SimpleJSONMessageService(e.Message)));
            } catch (Exception) {
                return(StatusCode(500, new SimpleJSONMessageService(UNEXPECTED_ERROR)));
            }
        }