/// <summary>
 /// Filter on rating
 /// </summary>
 /// <param name="search"></param>
 /// <param name="query"></param>
 /// <returns></returns>
 private ITypeSearch<Hotel> GetRatingFilter(ITypeSearch<Hotel> search, SearchQuery query)
 {
     if (query.RatingFilter > 0)
     {
         search = search.Filter(x => x.StarRating.Match(query.RatingFilter));
     }
     return search;
 }
        /// <summary>
        /// Is city filter active
        /// </summary>
        /// <param name="query"></param>
        /// <returns></returns>
        private bool IsCityFilterActive(SearchQuery query)
        {
            var cities = _popularCitiesService.GetCities();

            var city = cities.FirstOrDefault(c => c.Title.Equals(query.Query, StringComparison.InvariantCultureIgnoreCase));

            return city != null;
        }
 /// <summary>
 /// Get order by 
 /// </summary>
 /// <param name="search"></param>
 /// <param name="query"></param>
 /// <returns></returns>
 private ITypeSearch<Hotel> GetOrderBy(ITypeSearch<Hotel> search, SearchQuery query)
 {
     switch (query.SortBy)
     {
         case "price":
             return search.OrderBy(h => h.PriceUSD);
         case "ratings":
             return search.OrderByDescending(h => h.StarRating);
         case "Popularity":
             return search.OrderByDescending(h => h.StarRating);
         default:
             return search.OrderByDescending(h => h.PriceUSD);
     }
 }
 /// <summary>
 /// Filter on price
 /// </summary>
 /// <param name="search"></param>
 /// <param name="query"></param>
 /// <returns></returns>
 private ITypeSearch<Hotel> GetPriceFilter(ITypeSearch<Hotel> search, SearchQuery query)
 {
     if (query.PriceTo > 0)
     {
         search = search.Filter(x => x.PriceUSD.InRange((int)query.PriceFrom, (int)query.PriceTo));
     }
     return search;
 }
        /// <summary>
        /// Get filters
        /// </summary>
        /// <param name="search"></param>
        /// <param name="query"></param>
        /// <returns></returns>
        private ITypeSearch<Hotel> GetFilters(ITypeSearch<Hotel> search, SearchQuery query)
        {
            search = GetPriceFilter(search, query);
            search = GetRatingFilter(search, query);
            search = GetFacilityFilter(search, query);
            search = GetCityFilter(search, query);

            return search;
        }
 /// <summary>
 /// Use this to filter on the Features list. This Filter use the Match method for the filtering for each selected facility
 /// </summary>
 /// <param name="search"></param>
 /// <param name="query"></param>
 /// <returns></returns>
 private ITypeSearch<Hotel> GetFacilityFilter(ITypeSearch<Hotel> search, SearchQuery query)
 {
     if (query.FacilityFilter != null)
     {
         foreach (var item in query.FacilityFilter)
         {
             var facility = _facilityService.GetById(item);
             if (facility != null)
             {
                 search = search.Filter(x => x.Features.Match(facility.Value));
             }
         }
     }
     return search;
 }
        /// <summary>
        /// Use this to filter for only specific cities. Unfortunately there isn't a city property available. So when searching
        /// for hotels in particular city Geo search is used. For this example site a range of 20 kilometer is used. 
        /// </summary>
        /// <param name="search"></param>
        /// <param name="query"></param>
        /// <returns></returns>
        private ITypeSearch<Hotel> GetCityFilter(ITypeSearch<Hotel> search, SearchQuery query)
        {
            var cities =_popularCitiesService.GetCities();

            var city = cities.FirstOrDefault(c => c.Title.Equals(query.Query, StringComparison.InvariantCultureIgnoreCase));
            if (city != null)
            {
                search = search.Filter(h => h.GeoCoordinates.WithinDistanceFrom(
                new GeoLocation(city.Coordinates.Latitude, city.Coordinates.Longitude), 20.Kilometers()));
            }
            return search;
        }
        /// <summary>
        /// Search autocomplete
        /// First filter the LocationsString after that return the item from the Location array
        /// We would like to search on country, city etc.
        /// </summary>
        /// <param name="query"></param>
        /// <returns></returns>
        public IEnumerable<SearchResultItem> SearchAutoComplete(SearchQuery query)
        {
            if (string.IsNullOrEmpty(query.Query))
            {
                return Enumerable.Empty<SearchResultItem>();
            }

            var search = _client.Search<Hotel>().Filter(x => x.LocationsString.AnyWordBeginsWith(query.Query));

            var results = search.GetResult()
                        .Select(h => h.Locations.FirstOrDefault(x => x.IndexOf(query.Query, StringComparison.InvariantCultureIgnoreCase) != -1))
                        .Distinct()
                        .Take(_maxAutocompleteResults);

            return results.Select(q => new SearchResultItem { Title = q });
        }
        /// <summary>
        /// Search and filter on price, facilities, rating and city when selected.
        /// Default order by price
        /// Use paging functionality for the infinite scroll
        /// </summary>
        /// <param name="query"></param>
        /// <returns></returns>
        public SearchResult Search(SearchQuery query)
        {
            var search = _client.Search<Hotel>();
            if (!IsCityFilterActive(query)) // If city filter is active don't perform a search
            {
                search = search.For(query.Query);
            }

            search = GetFilters(search, query);
            search = GetOrderBy(search, query);

            var page = query.CurrentPage == 0 ? 1 : query.CurrentPage;

            var result = search.Take(_pageSize).Skip((page - 1) * 10).GetResult();

            var searchResult = new SearchResult();
            searchResult.TotalResults = result.TotalMatching;

            var totalPages = result.TotalMatching / _pageSize;
            if (result.TotalMatching % _pageSize > 0)
            {
                totalPages++;
            }

            searchResult.CurrentPage = page;
            searchResult.TotalPages = totalPages;
            searchResult.Results = result.Select(_searchResultItemBuilder.FromHotel);

            return searchResult;
        }