public IHttpActionResult Search(string store, string[] priceLists, [ModelBinder(typeof(SearchParametersBinder))] SearchParameters parameters,
                                        [FromUri] coreModel.ItemResponseGroup responseGroup = coreModel.ItemResponseGroup.ItemMedium,
                                        [FromUri] string outline = "", string language = "en-us", string currency = "USD")
        {
            var context = new Dictionary <string, object>
            {
                { "StoreId", store },
            };

            var fullLoadedStore = GetStoreById(store);

            if (fullLoadedStore == null)
            {
                throw new NullReferenceException(store + " not found");
            }

            var catalog = fullLoadedStore.Catalog;

            string categoryId = null;

            var criteria = new CatalogIndexedSearchCriteria {
                Locale = language, Catalog = catalog.ToLowerInvariant()
            };

            if (!string.IsNullOrWhiteSpace(outline))
            {
                criteria.Outlines.Add(String.Format("{0}/{1}*", catalog, outline));
                categoryId = outline.Split(new[] { '/' }).Last();
                context.Add("CategoryId", categoryId);
            }

            #region Filters
            // Now fill in filters
            var filters = _browseFilterService.GetFilters(context);

            // Add all filters
            foreach (var filter in filters)
            {
                criteria.Add(filter);
            }

            // apply terms
            if (parameters.Terms != null && parameters.Terms.Count > 0)
            {
                foreach (var term in parameters.Terms)
                {
                    var filter = filters.SingleOrDefault(x => x.Key.Equals(term.Key, StringComparison.OrdinalIgnoreCase) &&
                                                         (!(x is PriceRangeFilter) || ((PriceRangeFilter)x).Currency.Equals(currency, StringComparison.OrdinalIgnoreCase)));

                    var appliedFilter = _browseFilterService.Convert(filter, term.Value);

                    criteria.Apply(appliedFilter);
                }
            }
            #endregion

            #region Facets
            // apply facet filters
            var facets = parameters.Facets;
            if (facets.Count != 0)
            {
                foreach (var key in facets.Select(f => f.Key))
                {
                    var filter = filters.SingleOrDefault(
                        x => x.Key.Equals(key, StringComparison.OrdinalIgnoreCase) &&
                        (!(x is PriceRangeFilter) ||
                         ((PriceRangeFilter)x).Currency.Equals(currency, StringComparison.OrdinalIgnoreCase)));

                    var appliedFilter = _browseFilterService.Convert(filter, facets.FirstOrDefault(f => f.Key == key).Value);
                    criteria.Apply(appliedFilter);
                }
            }
            #endregion

            //criteria.ClassTypes.Add("Product");
            criteria.RecordsToRetrieve = parameters.PageSize == 0 ? 10 : parameters.PageSize;
            criteria.StartingRecord    = parameters.StartingRecord;
            criteria.Pricelists        = priceLists;
            criteria.Currency          = currency;
            criteria.StartDateFrom     = parameters.StartDateFrom;
            criteria.SearchPhrase      = parameters.FreeSearch;

            #region sorting

            if (!string.IsNullOrEmpty(parameters.Sort))
            {
                var isDescending = "desc".Equals(parameters.SortOrder, StringComparison.OrdinalIgnoreCase);

                SearchSort sortObject = null;

                switch (parameters.Sort.ToLowerInvariant())
                {
                case "price":
                    if (criteria.Pricelists != null)
                    {
                        sortObject = new SearchSort(
                            criteria.Pricelists.Select(
                                priceList =>
                                new SearchSortField(String.Format("price_{0}_{1}", criteria.Currency.ToLower(), priceList.ToLower()))
                        {
                            IgnoredUnmapped = true,
                            IsDescending    = isDescending,
                            DataType        = SearchSortField.DOUBLE
                        })
                            .ToArray());
                    }
                    break;

                case "position":
                    sortObject =
                        new SearchSort(
                            new SearchSortField(string.Format("sort{0}{1}", catalog, categoryId).ToLower())
                    {
                        IgnoredUnmapped = true,
                        IsDescending    = isDescending
                    });
                    break;

                case "name":
                    sortObject = new SearchSort("name", isDescending);
                    break;

                case "rating":
                    sortObject = new SearchSort(criteria.ReviewsAverageField, isDescending);
                    break;

                case "reviews":
                    sortObject = new SearchSort(criteria.ReviewsTotalField, isDescending);
                    break;

                default:
                    sortObject = CatalogIndexedSearchCriteria.DefaultSortOrder;
                    break;
                }

                criteria.Sort = sortObject;
            }

            #endregion

            //Load ALL products
            var searchResults = _browseService.SearchItems(criteria, responseGroup);

            // populate inventory
            if ((responseGroup & ItemResponseGroup.ItemProperties) == ItemResponseGroup.ItemProperties)
            {
                PopulateInventory(fullLoadedStore.FulfillmentCenter, searchResults.Items);
            }

            return(this.Ok(searchResults));
        }
        public IHttpActionResult Search([FromUri] ProductSearchRequest request)
        {
            request = request ?? new ProductSearchRequest();
            request.Normalize();

            var context = new Dictionary <string, object>
            {
                { "StoreId", request.Store },
            };

            var fullLoadedStore = GetStoreById(request.Store);

            if (fullLoadedStore == null)
            {
                throw new NullReferenceException(request.Store + " not found");
            }

            var catalog = fullLoadedStore.Catalog;

            string categoryId = null;

            var criteria = new CatalogIndexedSearchCriteria {
                Locale = request.Language, Catalog = catalog.ToLowerInvariant(), IsFuzzySearch = true
            };

            if (!string.IsNullOrWhiteSpace(request.Outline))
            {
                criteria.Outlines.Add(string.Format("{0}/{1}*", catalog, request.Outline));
                categoryId = request.Outline.Split(new[] { '/' }).Last();
                context.Add("CategoryId", categoryId);
            }

            #region Filters
            // Now fill in filters
            var filters = _browseFilterService.GetFilters(context);

            // Add all filters
            foreach (var filter in filters)
            {
                criteria.Add(filter);
            }

            // apply terms
            var terms = ParseKeyValues(request.Terms);
            if (terms.Any())
            {
                var filtersWithValues = filters
                                        .Where(x => (!(x is PriceRangeFilter) || ((PriceRangeFilter)x).Currency.Equals(request.Currency, StringComparison.OrdinalIgnoreCase)))
                                        .Select(x => new { Filter = x, Values = x.GetValues() })
                                        .ToList();

                foreach (var term in terms)
                {
                    var filter = filters.SingleOrDefault(x => x.Key.Equals(term.Key, StringComparison.OrdinalIgnoreCase) &&
                                                         (!(x is PriceRangeFilter) || ((PriceRangeFilter)x).Currency.Equals(request.Currency, StringComparison.OrdinalIgnoreCase)));

                    // handle special filter term with a key = "tags", it contains just values and we need to determine which filter to use
                    if (filter == null && term.Key == "tags")
                    {
                        foreach (var termValue in term.Values)
                        {
                            // try to find filter by value
                            var foundFilter = filtersWithValues.FirstOrDefault(x => x.Values.Any(y => y.Id.Equals(termValue)));

                            if (foundFilter != null)
                            {
                                filter = foundFilter.Filter;

                                var appliedFilter = _browseFilterService.Convert(filter, term.Values);
                                criteria.Apply(appliedFilter);
                            }
                        }
                    }
                    else
                    {
                        var appliedFilter = _browseFilterService.Convert(filter, term.Values);
                        criteria.Apply(appliedFilter);
                    }
                }
            }
            #endregion

            #region Facets
            // apply facet filters
            var facets = ParseKeyValues(request.Facets);
            foreach (var facet in facets)
            {
                var filter = filters.SingleOrDefault(
                    x => x.Key.Equals(facet.Key, StringComparison.OrdinalIgnoreCase) &&
                    (!(x is PriceRangeFilter) ||
                     ((PriceRangeFilter)x).Currency.Equals(request.Currency, StringComparison.OrdinalIgnoreCase)));

                var appliedFilter = _browseFilterService.Convert(filter, facet.Values);
                criteria.Apply(appliedFilter);
            }
            #endregion

            //criteria.ClassTypes.Add("Product");
            criteria.RecordsToRetrieve = request.Take <= 0 ? 10 : request.Take;
            criteria.StartingRecord    = request.Skip;
            criteria.Pricelists        = request.Pricelists;
            criteria.Currency          = request.Currency;
            criteria.StartDateFrom     = request.StartDateFrom;
            criteria.SearchPhrase      = request.SearchPhrase;

            #region sorting

            if (!string.IsNullOrEmpty(request.Sort))
            {
                var isDescending = "desc".Equals(request.SortOrder, StringComparison.OrdinalIgnoreCase);

                SearchSort sortObject = null;

                switch (request.Sort.ToLowerInvariant())
                {
                case "price":
                    if (criteria.Pricelists != null)
                    {
                        sortObject = new SearchSort(
                            criteria.Pricelists.Select(
                                priceList =>
                                new SearchSortField(String.Format("price_{0}_{1}", criteria.Currency.ToLower(), priceList.ToLower()))
                        {
                            IgnoredUnmapped = true,
                            IsDescending    = isDescending,
                            DataType        = SearchSortField.DOUBLE
                        })
                            .ToArray());
                    }
                    break;

                case "position":
                    sortObject =
                        new SearchSort(
                            new SearchSortField(string.Format("sort{0}{1}", catalog, categoryId).ToLower())
                    {
                        IgnoredUnmapped = true,
                        IsDescending    = isDescending
                    });
                    break;

                case "name":
                    sortObject = new SearchSort("name", isDescending);
                    break;

                case "rating":
                    sortObject = new SearchSort(criteria.ReviewsAverageField, isDescending);
                    break;

                case "reviews":
                    sortObject = new SearchSort(criteria.ReviewsTotalField, isDescending);
                    break;

                default:
                    sortObject = CatalogIndexedSearchCriteria.DefaultSortOrder;
                    break;
                }

                criteria.Sort = sortObject;
            }

            #endregion

            //Load ALL products
            var searchResults = _browseService.SearchItems(criteria, request.ResponseGroup);

            // populate inventory
            if ((request.ResponseGroup & ItemResponseGroup.ItemProperties) == ItemResponseGroup.ItemProperties)
            {
                PopulateInventory(fullLoadedStore.FulfillmentCenter, searchResults.Items);
            }

            return(Ok(searchResults));
        }