public override void Apply(Product p, ImportRow r)
        {
            var features = new List <string>();
            var images   = new List <string>();

            // select the option that this row refers, or use the default option
            // creates the named option if it does not exist.
            var optionName = (string)r[ProductColumnMappingTargets.OptionName] ?? "";

            if (null == p.Options)
            {
                p.Options = new List <ProductOption>();
            }
            var option = p.Options.FirstOrDefault(x => x.Name == optionName);

            if (null == option)
            {
                option = new ProductOption
                {
                    Name = optionName,
                };
                p.Options.Add(option);
            }

            // select the product source or use a default source
            var vendorName = (string)r[ProductColumnMappingTargets.Vendor] ?? "";

            if (null == option.Sources)
            {
                option.Sources = new List <ProductSource>();
            }
            var source = String.IsNullOrEmpty(vendorName)
                ? option.Sources.FirstOrDefault(x => x.Vendor == null)
                : option.Sources.FirstOrDefault(x => null != x.Vendor && x.Vendor.Value.Name == vendorName);

            if (null == source)
            {
                source = new ProductSource
                {
                    Pricing = new ProductPricing(),
                    Stock   = new ProductStock(),
                    Vendor  = null,
                };
                if (!String.IsNullOrEmpty(vendorName))
                {
                    var vendor = Vendors.FindVendorByName(vendorName);
                    if (null == vendor)
                    {
                        vendor = new Vendor
                        {
                            Document = new Document()
                            {
                                Id = Document.For <Vendor>(vendorName.ToSlug())
                            },
                            Name = vendorName,
                        };
                        Vendors.Save(vendor);
                        source.Vendor = Reference.To(vendor);
                    }
                }
                option.Sources.Add(source);
            }
            var pricing = source.Pricing ?? (source.Pricing = new ProductPricing());
            var stock   = source.Stock ?? (source.Stock = new ProductStock());


            for (var i = 0; i < r.Layout.Length; i++)
            {
                var value  = r.Values[i];
                var target = r.Layout[i];

                switch (target)
                {
                case ProductColumnMappingTargets.Enabled:           p.Set(x => x.Enabled, (bool)value); break;

                case ProductColumnMappingTargets.Category:          p.Set(x => x.Category, (Product.ParseCategory((string)value))); break;

                case ProductColumnMappingTargets.Name:              p.Set(x => x.Name, (string)value); break;

                case ProductColumnMappingTargets.Manufacturer:      p.Set(x => x.Manufacturer, (string)value); break;

                case ProductColumnMappingTargets.Brand:             p.Set(x => x.Brand, (string)value); break;

                case ProductColumnMappingTargets.Description:       p.Set(x => x.Description, (string)value); break;

                case ProductColumnMappingTargets.Details:           p.Set(x => x.Details, (string)value); break;

                case ProductColumnMappingTargets.Warranty:          p.Set(x => x.Warranty, (string)value); break;

                case ProductColumnMappingTargets.CountryOfOrigin:   p.Set(x => x.CountryOfOrigin, (string)value); break;

                case ProductColumnMappingTargets.Model:             p.Model = ((string)value); break;

                case ProductColumnMappingTargets.LeadTime:          stock.Leadtime = (string)value; break;

                case ProductColumnMappingTargets.Feature:           features.Add((string)value); break;

                case ProductColumnMappingTargets.Sku:               p.Set(x => x.Sku, (string)value); break;

                case ProductColumnMappingTargets.Upc:               p.Set(x => x.Upc, (string)value); break;

                case ProductColumnMappingTargets.PackageL:          (p.PackageDimensions ?? (p.PackageDimensions = new ProductDimensions())).Length = (decimal?)value; break;

                case ProductColumnMappingTargets.PackageW:          (p.PackageDimensions ?? (p.PackageDimensions = new ProductDimensions())).Width = (decimal?)value; break;

                case ProductColumnMappingTargets.PackageH:          (p.PackageDimensions ?? (p.PackageDimensions = new ProductDimensions())).Height = (decimal?)value; break;

                case ProductColumnMappingTargets.PackageWeight:     (p.PackageDimensions ?? (p.PackageDimensions = new ProductDimensions())).Weight = (decimal?)value; break;

                case ProductColumnMappingTargets.ProductL:          (p.ProductDimensions ?? (p.ProductDimensions = new ProductDimensions())).Length = (decimal?)value; break;

                case ProductColumnMappingTargets.ProductW:          (p.ProductDimensions ?? (p.ProductDimensions = new ProductDimensions())).Width = (decimal?)value; break;

                case ProductColumnMappingTargets.ProductH:          (p.ProductDimensions ?? (p.ProductDimensions = new ProductDimensions())).Height = (decimal?)value; break;

                case ProductColumnMappingTargets.ProductWeight:     (p.ProductDimensions ?? (p.ProductDimensions = new ProductDimensions())).Weight = (decimal?)value; break;

                case ProductColumnMappingTargets.Image:             images.Add((string)value); break;

                case ProductColumnMappingTargets.SourceAdded:       source.Added = (DateTime?)value; break;

                case ProductColumnMappingTargets.SourceUpdated:     source.Updated = (DateTime?)value; break;

                case ProductColumnMappingTargets.Msrp:              pricing.Msrp = (decimal?)value; break;

                case ProductColumnMappingTargets.Cost:              pricing.Cost = ((decimal?)value).Value; break;

                case ProductColumnMappingTargets.ShippingFee:       pricing.ShippingFee = (decimal?)value; break;

                case ProductColumnMappingTargets.ShippingCost:      pricing.ShippingCost = (decimal?)value; break;

                case ProductColumnMappingTargets.OptionSku:         option.Sku = (string)value; break;

                case ProductColumnMappingTargets.VendorPrice:       pricing.Cost = ((decimal?)value) ?? 0; break;
                }
            }

            if (features.Count > 0)
            {
                p.Set(x => x.Features, features.Where(x => !String.IsNullOrWhiteSpace(x)).ToArray());
            }
            if (images.Count > 0)
            {
                p.Set(x => x.Images, images.Where(x => !String.IsNullOrWhiteSpace(x)).ToArray());
            }
        }