protected virtual CategoryFacetCounts BuildCategoryFacetCounts(CreateProductSearchResultsViewModelParam <TParam> param)
        {
            if (param.CategoryFacetCountsResult == null)
            {
                return(new CategoryFacetCounts()
                {
                    TotalCount = param.SearchResult.TotalCount
                });
            }

            return(new CategoryFacetCounts
            {
                TotalCount = param.CategoryFacetCountsResult.TotalCount,
                Facets = param.CategoryFacetCountsResult.Facets.Where(f => !f.FieldName.EndsWith("_Facet")).Select(f =>
                                                                                                                   new Facet
                {
                    FieldName = f.FieldName,
                    FacetValues = f.Values.Select(fv => new Facets.FacetValue()
                    {
                        Value = fv.Value,
                        Quantity = fv.Count
                    }).ToList()
                }).ToList()
            });
        }
        /// <summary>
        ///     Searches the available products based on the given search criteria.
        /// </summary>
        /// <param name="param">The criteria.</param>
        /// <returns></returns>
        /// <exception cref="System.ArgumentNullException"></exception>
        /// <exception cref="System.ArgumentException"></exception>
        protected virtual async Task <ProductSearchResultsViewModel> SearchAsync(TParam param)
        {
            if (param == null)
            {
                throw new ArgumentNullException(nameof(param));
            }
            if (param.Criteria == null)
            {
                throw new ArgumentException(GetMessageOfNull(nameof(param.Criteria)), nameof(param));
            }
            if (param.Criteria.CultureInfo == null)
            {
                throw new ArgumentException(GetMessageOfNull(nameof(param.Criteria.CultureInfo)), nameof(param));
            }
            if (string.IsNullOrWhiteSpace(param.Criteria.Scope))
            {
                throw new ArgumentException(GetMessageOfNullWhiteSpace(nameof(param.Criteria.Scope)), nameof(param));
            }

            var searchResult = await SearchRepository.SearchProductAsync(param.Criteria).ConfigureAwait(false);

            var cloneParam = (TParam)param.Clone();

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

            var imageUrls = await DamProvider.GetProductMainImagesAsync(GetImagesParam(searchResult.Documents)).ConfigureAwait(false);

            var createSearchViewModelParam = new CreateProductSearchResultsViewModelParam <TParam>
            {
                SearchParam  = cloneParam,
                ImageUrls    = imageUrls,
                SearchResult = searchResult
            };

            if (param.Criteria.IncludeFacets &&
                param.Criteria.SelectedFacets != null &&
                param.Criteria.SelectedFacets.Any(s => s.Name?.StartsWith(SearchConfiguration.CategoryFacetFiledNamePrefix) ?? false))
            {
                createSearchViewModelParam.CategoryFacetCountsResult = await SearchRepository.GetCategoryFacetCountsAsync(param.Criteria).ConfigureAwait(false);
            }

            return(await CreateProductSearchResultsViewModelAsync(createSearchViewModelParam).ConfigureAwait(false));
        }
        /// <summary>
        ///     Searches the available products based on the given search criteria.
        /// </summary>
        /// <param name="param">The criteria.</param>
        /// <returns></returns>
        /// <exception cref="System.ArgumentNullException"></exception>
        /// <exception cref="System.ArgumentException"></exception>
        protected virtual async Task <ProductSearchResultsViewModel> SearchAsync(TParam param)
        {
            if (param == null)
            {
                throw new ArgumentNullException(nameof(param));
            }
            if (param.Criteria == null)
            {
                throw new ArgumentException(GetMessageOfNull(nameof(param.Criteria)), nameof(param));
            }
            if (param.Criteria.CultureInfo == null)
            {
                throw new ArgumentException(GetMessageOfNull(nameof(param.Criteria.CultureInfo)), nameof(param));
            }
            if (string.IsNullOrWhiteSpace(param.Criteria.Scope))
            {
                throw new ArgumentException(GetMessageOfNullWhiteSpace(nameof(param.Criteria.Scope)), nameof(param));
            }

            var searchResult = await SearchRepository.SearchProductAsync(param.Criteria).ConfigureAwait(false);

            var cloneParam = (TParam)param.Clone();

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

            var imageUrls = await DamProvider.GetProductMainImagesAsync(GetImagesParam(searchResult.Documents)).ConfigureAwait(false);

            var createSearchViewModelParam = new CreateProductSearchResultsViewModelParam <TParam>
            {
                SearchParam  = cloneParam,
                ImageUrls    = imageUrls,
                SearchResult = searchResult
            };

            return(await CreateProductSearchResultsViewModelAsync(createSearchViewModelParam).ConfigureAwait(false));
        }
        public async Task <SearchQueryViewModel> GetSearchQueryViewModelAsync(GetSearchQueryViewModelParams param)
        {
            SearchQueryViewModel viewModel;

            if (param == null)
            {
                throw new ArgumentNullException(nameof(param));
            }
            if (param.CultureInfo == null)
            {
                throw new ArgumentException(GetMessageOfNull(nameof(param.CultureInfo)), nameof(param));
            }
            if (param.Criteria == null)
            {
                throw new ArgumentException(GetMessageOfNull(nameof(param.Criteria)), nameof(param));
            }

            var searchQueryProducts = await SearchQueryRepository.SearchQueryProductAsync(new SearchQueryProductParams
            {
                CultureName = param.CultureInfo.Name,
                QueryName   = param.QueryName,
                QueryType   = param.QueryType,
                ScopeId     = param.Scope,
                Criteria    = param.Criteria
            }).ConfigureAwait(false);

            var documents = searchQueryProducts.Result.Documents.Select(ToProductDocument).ToList();

            var inventoryLocations = await InventoryRepository.GetInventoryLocationStatusesBySkus(
                new GetInventoryLocationStatuseParam()
            {
                Skus    = documents.Select(d => d.Sku).ToList(),
                ScopeId = param.Scope,
                InventoryLocationIds = param.InventoryLocationIds
            }).ConfigureAwait(false);

            FixInventories(documents, inventoryLocations);
            documents = await FixInventoryFilter(documents, param.Scope).ConfigureAwait(false);

            var getImageParam = new GetProductMainImagesParam
            {
                ImageSize            = SearchConfiguration.DefaultImageSize,
                ProductImageRequests = documents
                                       .Select(document => new ProductImageRequest
                {
                    ProductId = document.ProductId,
                    Variant   = document.PropertyBag.ContainsKey(VariantPropertyBagKey)
                            ? new VariantKey {
                        Id = document.PropertyBag[VariantPropertyBagKey].ToString()
                    }
                            : VariantKey.Empty,
                    ProductDefinitionName = document.PropertyBag.ContainsKey("DefinitionName")
                            ? document.PropertyBag["DefinitionName"].ToString()
                            : string.Empty,
                    PropertyBag = document.PropertyBag
                }).ToList()
            };

            var imageUrls = await DamProvider.GetProductMainImagesAsync(getImageParam).ConfigureAwait(false);



            var newCriteria = param.Criteria.Clone();

            var createSearchViewModelParam = new CreateProductSearchResultsViewModelParam <SearchParam>
            {
                SearchParam = new SearchParam()
                {
                    Criteria = newCriteria
                },
                ImageUrls    = imageUrls,
                SearchResult = new ProductSearchResult()
                {
                    Documents  = documents,
                    TotalCount = searchQueryProducts.Result.TotalCount,
                    Facets     = searchQueryProducts.Result.Facets
                }
            };

            viewModel = new SearchQueryViewModel
            {
                SelectedFacets =
                    await GetSelectedFacetsAsync(createSearchViewModelParam.SearchParam).ConfigureAwait(false),
                ProductSearchResults =
                    await CreateProductSearchResultsViewModelAsync(createSearchViewModelParam).ConfigureAwait(false),
            };

            if (searchQueryProducts.SelectedFacets != null)
            {
                foreach (var facet in searchQueryProducts.SelectedFacets)
                {
                    foreach (var value in facet.Values)
                    {
                        if (viewModel.SelectedFacets.Facets.All(f => f.Value != value))
                        {
                            viewModel.SelectedFacets.Facets.Add(new SelectedFacet()
                            {
                                Value       = value,
                                FieldName   = facet.FacetName,
                                DisplayName = value,
                                IsRemovable = false
                            });
                        }
                    }
                }

                foreach (var selectedFacet in searchQueryProducts.SelectedFacets)
                {
                    foreach (var facet in viewModel.ProductSearchResults.Facets.Where(d => d.FieldName == selectedFacet.FacetName))
                    {
                        foreach (var facetValue in selectedFacet.Values.Select(value => facet.FacetValues.FirstOrDefault(f => f.Value == value)).Where(facetValue => facetValue != null))
                        {
                            facetValue.IsSelected = true;
                        }
                    }
                }
            }

            viewModel.Context[nameof(viewModel.ProductSearchResults.SearchResults)] = viewModel.ProductSearchResults.SearchResults;
            viewModel.Context[nameof(SearchConfiguration.MaxItemsPerPage)]          = SearchConfiguration.MaxItemsPerPage;
            viewModel.Context["ListName"] = "Search Query";

            return(viewModel);
        }
        protected virtual async Task <ProductSearchViewModel> CreateProductSearchViewModelAsync(ProductDocument productDocument, CreateProductSearchResultsViewModelParam <TParam> createSearchViewModelParam, IDictionary <Tuple <string, string>, ProductMainImage> imgDictionary)
        {
            var cultureInfo = createSearchViewModelParam.SearchParam.Criteria.CultureInfo;

            string variantId = null;

            if (productDocument.PropertyBag.ContainsKey(VariantPropertyBagKey))
            {
                variantId = productDocument.PropertyBag[VariantPropertyBagKey] as string;
            }

            var productSearchVm = ViewModelMapper.MapTo <ProductSearchViewModel>(productDocument, cultureInfo);

            productSearchVm.BrandId = ExtractLookupId("Brand_Facet", productDocument.PropertyBag);

            MapProductSearchViewModelInfos(productSearchVm, productDocument, cultureInfo);
            MapProductSearchViewModelUrl(productSearchVm, variantId, cultureInfo, createSearchViewModelParam.SearchParam.Criteria.BaseUrl);
            MapProductSearchViewModelImage(productSearchVm, imgDictionary);
            productSearchVm.IsAvailableToSell = await GetProductSearchViewModelAvailableForSell(productSearchVm, productDocument).ConfigureAwait(false);

            productSearchVm.Pricing = await PriceProvider.GetPriceAsync(productSearchVm.HasVariants, productDocument).ConfigureAwait(false);

            productSearchVm.IsEligibleForRecurring = RecurringOrdersSettings.Enabled && productDocument.PropertyBag.IsEligibleForRecurring();

            productSearchVm.Context["IsEligibleForRecurring "] = productSearchVm.IsEligibleForRecurring;

            return(productSearchVm);
        }
        /// <summary>
        ///     Creates the product search results view model.
        /// </summary>
        /// <createSearchViewModelParam name="createSearchViewModelParam">The parameter.</createSearchViewModelParam>
        /// <returns></returns>
        protected virtual async Task <ProductSearchResultsViewModel> CreateProductSearchResultsViewModelAsync(CreateProductSearchResultsViewModelParam <TParam> param)
        {
            //TODO: Implement by calling the ViewModelMapper instead.
            var searchResultViewModel = new ProductSearchResultsViewModel
            {
                SearchResults        = new List <ProductSearchViewModel>(),
                Keywords             = param.SearchParam.Criteria.Keywords,
                TotalCount           = param.SearchResult.TotalCount,
                CorrectedSearchTerms = param.SearchResult.CorrectedSearchTerms,
                Suggestions          = new List <Suggestion>()
            };

            if (param.SearchResult.Suggestions != null)
            {
                foreach (var suggestion in param.SearchResult.Suggestions)
                {
                    var cloneParam = param.SearchParam.Criteria.Clone();
                    cloneParam.Keywords = suggestion.Title;

                    searchResultViewModel.Suggestions.Add(new Suggestion
                    {
                        Title = suggestion.Title,
                        Url   = SearchUrlProvider.BuildSearchUrl(new BuildSearchUrlParam
                        {
                            SearchCriteria = cloneParam
                        })
                    });
                }
            }

            var imgDictionary = LineItemHelper.BuildImageDictionaryFor(param.ImageUrls);


            // Populate search results
            foreach (var resultItem in param.SearchResult.Documents)
            {
                var productSearchVm = await CreateProductSearchViewModelAsync(resultItem, param, imgDictionary).ConfigureAwait(false);

                searchResultViewModel.SearchResults.Add(productSearchVm);
            }

            var facets = BuildFacets(param.SearchParam.Criteria, param.SearchResult);

            searchResultViewModel.Facets              = facets;
            searchResultViewModel.Pagination          = BuildPaginationForSearchResults(param.SearchResult, param.SearchParam, SearchConfiguration.MaximumPages);
            searchResultViewModel.PromotedFacetValues = BuildPromotedFacetValues(facets);

            // TODO: Fix this
            new SearchSortByResolver <TParam>(LocalizationProvider, GetSearchSortByList(SearchType), GenerateUrl)
            .Resolve(searchResultViewModel, param.SearchParam);

            searchResultViewModel.BaseUrl = param.SearchParam.Criteria.BaseUrl;

            return(searchResultViewModel);
        }
        public async Task <SearchQueryViewModel> GetSearchQueryViewModelAsync(GetSearchQueryViewModelParams param)
        {
            SearchQueryViewModel viewModel;

            if (param == null)
            {
                throw new ArgumentNullException(nameof(param));
            }
            if (param.CultureInfo == null)
            {
                throw new ArgumentException(GetMessageOfNull(nameof(param.CultureInfo)), nameof(param));
            }
            if (param.Criteria == null)
            {
                throw new ArgumentException(GetMessageOfNull(nameof(param.Criteria)), nameof(param));
            }

            var searchQueryProducts = await SearchQueryRepository.SearchQueryProductAsync(new SearchQueryProductParams
            {
                CultureName = param.CultureInfo.Name,
                QueryName   = param.QueryName,
                QueryType   = param.QueryType,
                ScopeId     = param.Scope,
                Criteria    = param.Criteria
            }).ConfigureAwait(false);

            var documents = searchQueryProducts.Result.Documents.Select(ToProductDocument).ToList();

            var inventoryLocations = await InventoryRepository.GetInventoryLocationStatusesBySkus(
                new GetInventoryLocationStatuseParam()
            {
                Skus    = documents.Select(d => d.Sku).ToList(),
                ScopeId = param.Scope,
                InventoryLocationIds = param.InventoryLocationIds
            }).ConfigureAwait(false);

            FixInventories(documents, inventoryLocations);
            documents = await FixInventoryFilter(documents, param.Scope).ConfigureAwait(false);

            var getImageParam = new GetProductMainImagesParam
            {
                ImageSize            = SearchConfiguration.DefaultImageSize,
                ProductImageRequests = documents
                                       .Select(document => new ProductImageRequest
                {
                    ProductId = document.ProductId,
                    Variant   = document.PropertyBag.ContainsKey(VariantPropertyBagKey)
                            ? new VariantKey {
                        Id = document.PropertyBag[VariantPropertyBagKey].ToString()
                    }
                            : VariantKey.Empty,
                    ProductDefinitionName = document.PropertyBag.ContainsKey("DefinitionName")
                            ? document.PropertyBag["DefinitionName"].ToString()
                            : string.Empty,
                    PropertyBag = document.PropertyBag
                }).ToList()
            };

            var imageUrls = await DamProvider.GetProductMainImagesAsync(getImageParam).ConfigureAwait(false);

            var newCriteria = param.Criteria.Clone();

            var createSearchViewModelParam = new CreateProductSearchResultsViewModelParam <SearchParam>
            {
                SearchParam = new SearchParam()
                {
                    Criteria = newCriteria
                },
                ImageUrls    = imageUrls,
                SearchResult = new ProductSearchResult()
                {
                    Documents  = documents,
                    TotalCount = searchQueryProducts.Result.TotalCount,
                    Facets     = searchQueryProducts.Result.Facets,
                },
            };

            if (param.QueryType != Overture.ServiceModel.SearchQueries.SearchQueryType.ProductSet &&
                param.Criteria.IncludeFacets &&
                param.Criteria.SelectedFacets != null &&
                param.Criteria.SelectedFacets.Any(s => s.Name?.StartsWith(SearchConfiguration.CategoryFacetFiledNamePrefix) ?? false))
            {
                createSearchViewModelParam.CategoryFacetCountsResult = await SearchQueryRepository.GetCategoryFacetCountsAsync(param.Criteria, searchQueryProducts).ConfigureAwait(false);
            }

            viewModel = new SearchQueryViewModel
            {
                QueryName     = param.QueryName,
                QueryType     = param.QueryType,
                FacetSettings = new FacetSettingsViewModel()
                {
                    SelectedFacets =
                        await GetSelectedFacetsAsync(createSearchViewModelParam.SearchParam).ConfigureAwait(false),
                },
                ProductSearchResults =
                    await CreateProductSearchResultsViewModelAsync(createSearchViewModelParam).ConfigureAwait(false),
                ListName = "Search Query"
            };

            ProcessFacets(viewModel, searchQueryProducts);

            viewModel.FacetSettings.CategoryFacetValuesTree = await BuildCategoryFacetValuesTree(viewModel.ProductSearchResults.Facets,
                                                                                                 viewModel.FacetSettings.SelectedFacets,
                                                                                                 viewModel.ProductSearchResults.CategoryFacetCounts).ConfigureAwait(false);

            if (viewModel.FacetSettings.CategoryFacetValuesTree != null)
            {
                viewModel.FacetSettings.CategoryFacetValuesTree.TotalCount = createSearchViewModelParam.CategoryFacetCountsResult != null ? createSearchViewModelParam.CategoryFacetCountsResult.TotalCount : viewModel.ProductSearchResults.TotalCount;
                viewModel.FacetSettings.Context["CategoryFacetValuesTree"] = viewModel.FacetSettings.CategoryFacetValuesTree;
            }

            // Json context for Facets
            viewModel.FacetSettings.Context["SelectedFacets"]      = viewModel.FacetSettings.SelectedFacets;
            viewModel.FacetSettings.Context["Facets"]              = viewModel.ProductSearchResults.Facets.Where(f => !f.FieldName.StartsWith(SearchConfiguration.CategoryFacetFiledNamePrefix));
            viewModel.FacetSettings.Context["PromotedFacetValues"] = viewModel.ProductSearchResults.PromotedFacetValues;

            viewModel.Context[nameof(viewModel.ProductSearchResults.SearchResults)] = viewModel.ProductSearchResults.SearchResults;
            viewModel.Context[nameof(viewModel.MaxItemsPerPage)] = viewModel.MaxItemsPerPage;
            viewModel.Context["ListName"] = viewModel.ListName;

            return(viewModel);
        }