context: using System;
  using System.Collections.Generic;
  using System.Data;
  using System.Linq;
  using System.Linq.Expressions;
  using System.ServiceModel.Syndication;
  using System.Web.Mvc;
  using SmartStore.Collections;
  using SmartStore.Core;
  using SmartStore.Core.Caching;
  using SmartStore.Core.Data;
  using SmartStore.Core.Domain.Catalog;
  using SmartStore.Core.Domain.Common;
  using SmartStore.Core.Domain.Customers;
  using SmartStore.Core.Domain.Localization;
  using SmartStore.Core.Domain.Media;
  using SmartStore.Core.Domain.Orders;
  using SmartStore.Core.Domain.Security;
  using SmartStore.Core.Domain.Stores;
  using SmartStore.Core.Events;
  using SmartStore.Services.Localization;
  using SmartStore.Services.Media;
  using SmartStore.Services.Messages;
  using SmartStore.Services.Orders;
  using SmartStore.Services.Seo;
  using SmartStore.Utilities;
  
  namespace SmartStore.Services.Catalog
  {
      /// <summary>
      /// Product service
      /// </summary>
      public partial class ProductService : IProductService
  	{
  		#region Constants
  
  		private const string PRODUCTS_BY_ID_KEY = "SmartStore.product.id-{0}";
  		private const string PRODUCTS_PATTERN_KEY = "SmartStore.product.";
  
  		#endregion
  
  		#region Fields
  
  		private readonly IRepository<Product> _productRepository;
          private readonly IRepository<RelatedProduct> _relatedProductRepository;
          private readonly IRepository<CrossSellProduct> _crossSellProductRepository;
          private readonly IRepository<TierPrice> _tierPriceRepository;
          private readonly IRepository<LocalizedProperty> _localizedPropertyRepository;
          private readonly IRepository<AclRecord> _aclRepository;
  		private readonly IRepository<StoreMapping> _storeMappingRepository;
          private readonly IRepository<ProductPicture> _productPictureRepository;
          private readonly IRepository<ProductSpecificationAttribute> _productSpecificationAttributeRepository;
          private readonly IRepository<ProductVariantAttributeCombination> _productVariantAttributeCombinationRepository;
  		private readonly IRepository<ProductBundleItem> _productBundleItemRepository;
          private readonly IProductAttributeService _productAttributeService;
          private readonly IProductAttributeParser _productAttributeParser;
          private readonly ILanguageService _languageService;
          private readonly IWorkflowMessageService _workflowMessageService;
          private readonly IDataProvider _dataProvider;
          private readonly IDbContext _dbContext;
  		private readonly ICacheManager _cacheManager;
          private readonly LocalizationSettings _localizationSettings;
          private readonly CommonSettings _commonSettings;
  		private readonly ICommonServices _services;
  		private readonly CatalogSettings _catalogSettings;
  		private readonly MediaSettings _mediaSettings;
  		private readonly IPictureService _pictureService;
  
          #endregion
  
          #region Ctor
  
          /// <summary>
          /// Ctor
          /// </summary>
          /// <param name="cacheManager">Cache manager</param>
          /// <param name="productRepository">Product repository</param>
          /// <param name="relatedProductRepository">Related product repository</param>
          /// <param name="crossSellProductRepository">Cross-sell product repository</param>
          /// <param name="tierPriceRepository">Tier price repository</param>
          /// <param name="localizedPropertyRepository">Localized property repository</param>
          /// <param name="aclRepository">ACL record repository</param>
  		/// <param name="storeMappingRepository">Store mapping repository</param>
          /// <param name="productPictureRepository">Product picture repository</param>
          /// <param name="productSpecificationAttributeRepository">Product specification attribute repository</param>
          /// <param name="productAttributeService">Product attribute service</param>
          /// <param name="productAttributeParser">Product attribute parser service</param>
          /// <param name="languageService">Language service</param>
          /// <param name="workflowMessageService">Workflow message service</param>
          /// <param name="dataProvider">Data provider</param>
          /// <param name="dbContext">Database Context</param>
          /// <param name="workContext">Work context</param>
  		/// <param name="storeContext">Store context</param>
          /// <param name="localizationSettings">Localization settings</param>
          /// <param name="commonSettings">Common settings</param>
          /// <param name="eventPublisher">Event published</param>
          public ProductService(
              IRepository<Product> productRepository,
              IRepository<RelatedProduct> relatedProductRepository,
              IRepository<CrossSellProduct> crossSellProductRepository,
              IRepository<TierPrice> tierPriceRepository,
              IRepository<ProductPicture> productPictureRepository,
              IRepository<LocalizedProperty> localizedPropertyRepository,
              IRepository<AclRecord> aclRepository,
  			IRepository<StoreMapping> storeMappingRepository,
              IRepository<ProductSpecificationAttribute> productSpecificationAttributeRepository,
              IRepository<ProductVariantAttributeCombination> productVariantAttributeCombinationRepository,
  			IRepository<ProductBundleItem> productBundleItemRepository,
              IProductAttributeService productAttributeService,
              IProductAttributeParser productAttributeParser,
              ILanguageService languageService,
              IWorkflowMessageService workflowMessageService,
              IDataProvider dataProvider,
  			IDbContext dbContext,
  			ICacheManager cacheManager,
              LocalizationSettings localizationSettings,
  			CommonSettings commonSettings,
  			ICommonServices services,
  			CatalogSettings catalogSettings,
  			MediaSettings mediaSettings,
  			IPictureService pictureService)
          {
              this._productRepository = productRepository;
              this._relatedProductRepository = relatedProductRepository;
              this._crossSellProductRepository = crossSellProductRepository;
              this._tierPriceRepository = tierPriceRepository;
              this._productPictureRepository = productPictureRepository;
              this._localizedPropertyRepository = localizedPropertyRepository;
              this._aclRepository = aclRepository;
  			this._storeMappingRepository = storeMappingRepository;
              this._productSpecificationAttributeRepository = productSpecificationAttributeRepository;
              this._productVariantAttributeCombinationRepository = productVariantAttributeCombinationRepository;
  			this._productBundleItemRepository = productBundleItemRepository;
              this._productAttributeService = productAttributeService;
              this._productAttributeParser = productAttributeParser;
              this._languageService = languageService;
              this._workflowMessageService = workflowMessageService;
              this._dataProvider = dataProvider;
              this._dbContext = dbContext;
  			this._cacheManager = cacheManager;
              this._localizationSettings = localizationSettings;
              this._commonSettings = commonSettings;
  			this._services = services;
  			this._catalogSettings = catalogSettings;
  			this._mediaSettings = mediaSettings;
  			this._pictureService = pictureService;
  
  			this.QuerySettings = DbQuerySettings.Default;
          }
  
  		public DbQuerySettings QuerySettings { get; set; }
  
          #endregion
  
  		#region Utilities
  
  		protected virtual int EnsureMutuallyRelatedProducts(List<int> productIds)
  		{
  			int count = 0;
  
  			foreach (int id1 in productIds)
  			{
  				var mutualAssociations = (
  					from rp in _relatedProductRepository.Table
  					join p in _productRepository.Table on rp.ProductId2 equals p.Id
  					where !p.Deleted && rp.ProductId2 == id1
  					select rp).ToList();
  
  				foreach (int id2 in productIds)
  				{
  					if (id1 == id2)
  						continue;
  
  					if (!mutualAssociations.Any(x => x.ProductId1 == id2))
  					{
  						int maxDisplayOrder = _relatedProductRepository.TableUntracked
  							.Where(x => x.ProductId1 == id2)
  							.OrderByDescending(x => x.DisplayOrder)
  							.Select(x => x.DisplayOrder)
  							.FirstOrDefault();
  
  						var newRelatedProduct = new RelatedProduct
  						{
  							ProductId1 = id2,
  							ProductId2 = id1,
  							DisplayOrder = maxDisplayOrder + 1
  						};
  
  						InsertRelatedProduct(newRelatedProduct);
  						++count;
  					}
  				}
  			}
  
  			return count;
  		}
  
  		protected virtual int EnsureMutuallyCrossSellProducts(List<int> productIds)
  		{
  			int count = 0;
  
  			foreach (int id1 in productIds)
  			{
  				var mutualAssociations = (
  					from rp in _crossSellProductRepository.Table
  					join p in _productRepository.Table on rp.ProductId2 equals p.Id
  					where !p.Deleted && rp.ProductId2 == id1
  					select rp).ToList();
  
  				foreach (int id2 in productIds)
  				{
  					if (id1 == id2)
  						continue;
  
  					if (!mutualAssociations.Any(x => x.ProductId1 == id2))
  					{
  						var newCrossSellProduct = new CrossSellProduct
  						{
  							ProductId1 = id2,
  							ProductId2 = id1
  						};
  
  						InsertCrossSellProduct(newCrossSellProduct);
  						++count;
  					}
  				}
  			}
  
  			return count;
  		}
  
  		#endregion
  
  		#region Methods
  
  		#region Products
  
  		/// <summary>
          /// Delete a product
          /// </summary>
          /// <param name="product">Product</param>
          public virtual void DeleteProduct(Product product)
          {
              if (product == null)
                  throw new ArgumentNullException("product");
  
              product.Deleted = true;
  			product.DeliveryTimeId = null;
  			product.QuantityUnitId = null;
  
              UpdateProduct(product);
          }
  
          /// <summary>
          /// Gets all products displayed on the home page
          /// </summary>
          /// <returns>Product collection</returns>
          public virtual IList<Product> GetAllProductsDisplayedOnHomePage()
          {
              var query = 
  				from p in _productRepository.Table
  				orderby p.HomePageDisplayOrder
  				where p.Published && !p.Deleted && p.ShowOnHomePage
  				select p;
  
              var products = query.ToList();
              return products;
          }
  
          public virtual IList<Product> GetAllProducts()
          {
              var query =
                  from p in _productRepository.Table
                  orderby p.HomePageDisplayOrder
                  where p.Published && !p.Deleted
                  select p;
  
              var products = query.ToList();
              return products;
          }
  
          /// <summary>
          /// Gets product
          /// </summary>
          /// <param name="productId">Product identifier</param>
          /// <returns>Product</returns>
          public virtual Product GetProductById(int productId)
          {
              if (productId == 0)
                  return null;
  
              string key = string.Format(PRODUCTS_BY_ID_KEY, productId);
              return _cacheManager.Get(key, () =>
              { 
                  return _productRepository.GetById(productId); 
              });
          }
  
          /// <summary>
          /// Get products by identifiers
          /// </summary>
          /// <param name="productIds">Product identifiers</param>
          /// <returns>Products</returns>
          public virtual IList<Product> GetProductsByIds(int[] productIds)
          {
              if (productIds == null || productIds.Length == 0)
  
gt:                 return new List<Product>();