@ResponseBody
  @RequestMapping(value = "/facets", method = RequestMethod.GET)
  public FacetRefinement<SearchStateData> getFacets(
      @RequestParam("q") final String searchQuery,
      @RequestParam(value = "page", defaultValue = "0") final int page,
      @RequestParam(value = "show", defaultValue = "Page") final ShowMode showMode,
      @RequestParam(value = "sort", required = false) final String sortCode)
      throws CMSItemNotFoundException {
    final SearchStateData searchState = new SearchStateData();
    final SearchQueryData searchQueryData = new SearchQueryData();
    searchQueryData.setValue(searchQuery);
    searchState.setQuery(searchQueryData);

    final ProductSearchPageData<SearchStateData, ProductData> searchPageData =
        productSearchFacade.textSearch(
            searchState, createPageableData(page, getSearchPageSize(), sortCode, showMode));
    final List<FacetData<SearchStateData>> facets =
        refineFacets(
            searchPageData.getFacets(),
            convertBreadcrumbsToFacets(searchPageData.getBreadcrumbs()));
    final FacetRefinement<SearchStateData> refinement = new FacetRefinement<>();
    refinement.setFacets(facets);
    refinement.setCount(searchPageData.getPagination().getTotalNumberOfResults());
    refinement.setBreadcrumbs(searchPageData.getBreadcrumbs());
    return refinement;
  }
  @ResponseBody
  @RequestMapping(
      value = "/autocomplete/" + COMPONENT_UID_PATH_VARIABLE_PATTERN,
      method = RequestMethod.GET)
  public AutocompleteResultData getAutocompleteSuggestions(
      @PathVariable final String componentUid, @RequestParam("term") final String term)
      throws CMSItemNotFoundException {
    final AutocompleteResultData resultData = new AutocompleteResultData();

    final SearchBoxComponentModel component =
        (SearchBoxComponentModel) cmsComponentService.getSimpleCMSComponent(componentUid);

    if (component.isDisplaySuggestions()) {
      resultData.setSuggestions(
          subList(
              productSearchFacade.getAutocompleteSuggestions(term), component.getMaxSuggestions()));
    }

    if (component.isDisplayProducts()) {
      resultData.setProducts(
          subList(productSearchFacade.textSearch(term).getResults(), component.getMaxProducts()));
    }

    return resultData;
  }
  protected ProductSearchPageData<SearchStateData, ProductData> performSearch(
      final String searchQuery,
      final int page,
      final ShowMode showMode,
      final String sortCode,
      final int pageSize) {
    final PageableData pageableData = createPageableData(page, pageSize, sortCode, showMode);

    final SearchStateData searchState = new SearchStateData();
    final SearchQueryData searchQueryData = new SearchQueryData();
    searchQueryData.setValue(searchQuery);
    searchState.setQuery(searchQueryData);

    return productSearchFacade.textSearch(searchState, pageableData);
  }
  @RequestMapping(method = RequestMethod.GET, params = "!q")
  public String textSearch(
      @RequestParam(value = "text", defaultValue = "") final String searchText,
      final HttpServletRequest request,
      final Model model)
      throws CMSItemNotFoundException {
    if (StringUtils.isNotBlank(searchText)) {
      final PageableData pageableData =
          createPageableData(0, getSearchPageSize(), null, ShowMode.Page);

      final SearchStateData searchState = new SearchStateData();
      final SearchQueryData searchQueryData = new SearchQueryData();
      searchQueryData.setValue(XSSFilterUtil.filter(searchText));
      searchState.setQuery(searchQueryData);

      final ProductSearchPageData<SearchStateData, ProductData> searchPageData =
          productSearchFacade.textSearch(searchState, pageableData);
      if (searchPageData == null) {
        storeCmsPageInModel(model, getContentPageForLabelOrId(NO_RESULTS_CMS_PAGE_ID));
      } else if (searchPageData.getKeywordRedirectUrl() != null) {
        // if the search engine returns a redirect, just
        return "redirect:" + searchPageData.getKeywordRedirectUrl();
      } else if (searchPageData.getPagination().getTotalNumberOfResults() == 0) {
        model.addAttribute("searchPageData", searchPageData);
        storeCmsPageInModel(model, getContentPageForLabelOrId(NO_RESULTS_CMS_PAGE_ID));
        updatePageTitle(searchText, model);
      } else {
        storeContinueUrl(request);
        populateModel(model, searchPageData, ShowMode.Page);
        storeCmsPageInModel(model, getContentPageForLabelOrId(SEARCH_CMS_PAGE_ID));
        updatePageTitle(searchText, model);
      }
      model.addAttribute("userLocation", customerLocationService.getUserLocation());
      getRequestContextData(request).setSearch(searchPageData);
      if (searchPageData != null) {
        model.addAttribute(
            WebConstants.BREADCRUMBS_KEY,
            searchBreadcrumbBuilder.getBreadcrumbs(
                null, searchText, CollectionUtils.isEmpty(searchPageData.getBreadcrumbs())));
      }
    } else {
      storeCmsPageInModel(model, getContentPageForLabelOrId(NO_RESULTS_CMS_PAGE_ID));
    }
    model.addAttribute("pageType", PageType.PRODUCTSEARCH.name());
    model.addAttribute("metaRobots", "no-index,follow");

    final String metaDescription =
        MetaSanitizerUtil.sanitizeDescription(
            getMessageSource()
                    .getMessage(
                        "search.meta.description.results",
                        null,
                        getI18nService().getCurrentLocale())
                + " "
                + searchText
                + " "
                + getMessageSource()
                    .getMessage(
                        "search.meta.description.on", null, getI18nService().getCurrentLocale())
                + " "
                + getSiteName());
    final String metaKeywords = MetaSanitizerUtil.sanitizeKeywords(searchText);
    setUpMetaData(model, metaKeywords, metaDescription);

    return getViewForPage(model);
  }