/// <summary>
        /// Initializes a new instance of the <see cref="ProductOptionWrapper"/> class.
        /// </summary>
        /// <param name="display">
        /// The display.
        /// </param>
        /// <param name="_parent">
        /// The parent content.
        /// </param>
        /// <param name="contentType">
        /// The content Type.
        /// </param>
        public ProductOptionWrapper(ProductOptionDisplay display, IPublishedContent _parent, PublishedContentType contentType = null)
        {
            _display = display;
            _contentType = contentType;

            Initialize(_parent);
        }
        /// <summary>
        /// The product option as product option wrapper.
        /// </summary>
        /// <param name="display">
        /// The display.
        /// </param>
        /// <param name="parent">
        /// The parent node
        /// </param>
        /// <param name="optionContentTypes">
        /// The option content types.
        /// </param>
        /// <returns>
        /// The <see cref="IProductOptionWrapper"/>.
        /// </returns>
        internal static IProductOptionWrapper ProductOptionAsProductOptionWrapper(this ProductOptionDisplay display, IPublishedContent parent, IDictionary <Guid, PublishedContentType> optionContentTypes)
        {
            // Find the associated content type if it exists
            var contentType = optionContentTypes.ContainsKey(display.DetachedContentTypeKey) ?
                              optionContentTypes[display.DetachedContentTypeKey] :
                              null;

            // This is a hack for the special case when HasProperty and HasValue extensions are called
            // and a content type is not assigned. - so we will default to the product content type
            // if there is none.  The detachedDataValues collection should be empty -
            var ct = contentType ?? parent.ContentType;

            return(new ProductOptionWrapper(display, parent, contentType));
        }
        internal static IProductOption ToProductOption(this ProductOptionDisplay productOptionDisplay, IProductOption destinationProductOption)
        {
            if (productOptionDisplay.Key != Guid.Empty)
            {
                destinationProductOption.Key = productOptionDisplay.Key;
            }
            destinationProductOption.Required  = productOptionDisplay.Required;
            destinationProductOption.SortOrder = productOptionDisplay.SortOrder;


            // Fix with option deletion here #M-161 #M-150
            // remove any product choices that exist in destination and do not exist in productDisplay
            var removers = destinationProductOption.Choices.Where(x => !productOptionDisplay.Choices.Select(pd => pd.Key).Contains(x.Key)).Select(x => x.Key).ToArray();

            foreach (var remove in removers)
            {
                destinationProductOption.Choices.RemoveItem(remove);
            }

            foreach (var choice in productOptionDisplay.Choices)
            {
                // Sets the sku if it is empty - fixes M-170
                // http://issues.merchello.com/youtrack/issue/M-170
                if (string.IsNullOrEmpty(choice.Sku))
                {
                    choice.Sku = Regex.Replace(choice.Name, "[^0-9a-zA-Z]+", "");
                }

                IProductAttribute destinationProductAttribute;


                if (destinationProductOption.Choices.Contains(choice.Sku))
                {
                    destinationProductAttribute = destinationProductOption.Choices[choice.Key];

                    destinationProductAttribute = choice.ToProductAttribute(destinationProductAttribute);
                }
                else
                {
                    destinationProductAttribute = new ProductAttribute(choice.Name, choice.Sku);

                    destinationProductAttribute = choice.ToProductAttribute(destinationProductAttribute);
                }

                destinationProductOption.Choices.Add(destinationProductAttribute);
            }

            return(destinationProductOption);
        }
        public IEnumerable<ProductOptionDisplay> FilterOptionChoices(Guid productKey, Guid productAttributeKey)
        {
            var product = _merchello.Query.Product.GetByKey(productKey);

            if (product == null)
            {
                var nullReference = new NullReferenceException("Product with key " + productKey + " returned null");
                LogHelper.Error<BazaarSiteApiController>("MerchelloHelper failed to retrieve product.", nullReference);
                throw nullReference;
            }

            // TODO move this to a service

            var returnOptions = new List<ProductOptionDisplay>();

            // this is the option the was just used in a selection
            var activeOption = product.ProductOptions.FirstOrDefault(po => po.Choices.Any(c => c.Key == productAttributeKey));

            if (activeOption == null) return returnOptions;

            ProductVariantDisplay[] variants;

            // special case for a product with a single option
            // TODO clean this up
            if (1 == product.ProductOptions.Count())
            {
                variants = product.ProductVariants.Where(pv => pv.Available).ToArray();

                var addOption = new ProductOptionDisplay()
                                    {
                                        SortOrder = activeOption.SortOrder,
                                        Key = activeOption.Key,
                                        Name = activeOption.Name
                                    };
                var optionChoices = new List<ProductAttributeDisplay>();

                foreach (var choice in activeOption.Choices)
                {
                    if (ValidateOptionChoice(variants, choice.Key))
                    {
                        optionChoices.Add(new ProductAttributeDisplay()
                        {
                            Key = choice.Key,
                            Name = choice.Name,
                            Sku = choice.Sku,
                            OptionKey = choice.OptionKey,
                            SortOrder = choice.SortOrder
                        });
                    }
                }
                addOption.Choices = optionChoices;
                returnOptions.Add(addOption);
                return returnOptions;
            }

            returnOptions.Add(activeOption);

            var otherOptions = product.ProductOptions.Where(x => !x.Key.Equals(activeOption.Key)).ToArray();

            variants = product.ProductVariants.Where(pv => pv.Available && pv.Attributes.Any(att => att.Key == productAttributeKey)).ToArray();

            foreach (var option in otherOptions)
            {
                var addOption = new ProductOptionDisplay()
                                    {
                                        SortOrder = option.SortOrder,
                                        Key = option.Key,
                                        Name = option.Name
                                    };

                var optionChoices = new List<ProductAttributeDisplay>();

                foreach (var choice in option.Choices)
                {
                    if (ValidateOptionChoice(variants, choice.Key))
                    {
                        optionChoices.Add(new ProductAttributeDisplay()
                                            {
                                                Key = choice.Key,
                                                Name = choice.Name,
                                                Sku = choice.Sku,
                                                OptionKey = choice.OptionKey,
                                                SortOrder = choice.SortOrder
                                            });
                    }
                }

                addOption.Choices = optionChoices;

                returnOptions.Add(addOption);
            }

            return returnOptions;
        }
        public ProductOptionDisplay PutProductOption(ProductOptionDisplay option)
        {
            var destination = _productOptionService.GetByKey(option.Key);

            destination = option.ToProductOption(destination);
            _productOptionService.Save(destination);

            return destination.ToProductOptionDisplay(DetachedValuesConversionType.Editor);
        }
        public ProductOptionDisplay PostProductOption(ProductOptionDisplay option)
        {
            var productOption = option.ToProductOption(new ProductOption(option.Name));
            _productOptionService.Save(productOption);

            return productOption.ToProductOptionDisplay(DetachedValuesConversionType.Editor);
        }