private int GetNearestWondersCount(WonderModel model, double mileRadiusTo)
        {
            var usersPosition = GeographyHelper.ConvertLatLonToDbGeography(model.Longitude.Value, model.Latitude.Value);

            //DataContext.TurnOffLazyLoading();

            return(DataContext.Deals.AsNoTracking()
                   .Include(g => g.Gender)
                   .Include(t => t.Tags)
                   .Include(c => c.Company)
                   .Include(c => c.Cost)
                   .Include(c => c.Category)
                   .Include(a => a.Address)
                   .Include(l => l.Location)
                   .Include(s => s.Season)
                   .Include(a => a.Ages)
                   .Include(i => i.Images)
                   .Include(c => c.City)
                   .Include(cl => cl.City.Location)
                   .Where(w => w.Location.Geography.Distance(usersPosition) * .00062 >= 0 &&
                          w.Location.Geography.Distance(usersPosition) * .00062 <= mileRadiusTo
                          &&
                          w.Archived == false &&
                          w.Expired != true &&
                          w.Priority == false &&
                          w.Broadcast == false &&
                          _genders.Contains(w.Gender.Id) &&
                          (w.AlwaysAvailable == true || w.ExpiryDate >= DateTime.Now)).Count());
        }
        public async Task <HttpResponseMessage> PostPopularWonders(int take, [FromBody] WonderModel model)
        {
            try
            {
                if (model.UserId != null && DataContext.AspNetUsers.All(x => x.Id != model.UserId))
                {
                    return(Request.CreateErrorResponse(HttpStatusCode.Unauthorized, "This user is not recognised"));
                }

                SetUserCategories(model.UserId);
                SetUserGenders(model.UserId);

                var wonders = new List <DealModel>();
                wonders = await Task.Run(() =>
                {
                    var results = GetPopularWonders(model, take);
                    return(Mapper.Map <List <DealModel> >(results));
                });


                return(Request.CreateResponse(HttpStatusCode.OK, wonders));
            }
            catch (Exception ex)
            {
                return(Request.CreateErrorResponse(HttpStatusCode.InternalServerError, ex));
            }
        }
 private IQueryable <Data.Deal> GetPriorityWonders(WonderModel model)
 {
     return(DataContext.Deals
            .Where(w => w.Priority == true &&
                   w.CityId == model.CityId &&
                   w.Archived == false &&
                   w.Expired != true &&
                   _categories.Contains(w.Category.Id) &&
                   _genders.Contains(w.Gender.Id) &&
                   (w.AlwaysAvailable == true || w.ExpiryDate >= DateTime.Now) &&
                   w.MyRejectUsers.All(u => u.Id != model.UserId) &&
                   w.MyWonderUsers.All(u => u.Id != model.UserId)));
 }
 private IQueryable <Data.Deal> GetRandomWonders(WonderModel model, int numberToTake)
 {
     return(DataContext.Deals
            .Where(w => w.CityId == model.CityId &&
                   w.Archived == false &&
                   w.Expired != true &&
                   _categories.Contains(w.Category.Id) &&
                   _genders.Contains(w.Gender.Id) &&
                   (w.AlwaysAvailable == true || w.ExpiryDate >= DateTime.Now) &&
                   w.MyRejectUsers.All(u => u.Id != model.UserId) &&
                   w.MyWonderUsers.All(u => u.Id != model.UserId))
            .OrderBy(x => Guid.NewGuid())
            .Take(numberToTake));
 }
        private List <DealModel> GetNearestWonders(WonderModel model, double mileRadiusTo, int from, int take)
        {
            var usersPosition = GeographyHelper.ConvertLatLonToDbGeography(model.Longitude.Value, model.Latitude.Value);
            //DataContext.TurnOffLazyLoading();

            var allWonders = DataContext.Deals.AsNoTracking()
                             .Include(g => g.Gender)
                             .Include(t => t.Tags)
                             .Include(c => c.Company)
                             .Include(c => c.Cost)
                             .Include(c => c.Category)
                             .Include(a => a.Address)
                             .Include(l => l.Location)
                             .Include(s => s.Season)
                             .Include(a => a.Ages)
                             .Include(i => i.Images)
                             .Include(c => c.City)
                             .Include(cl => cl.City.Location)
                             .Where(w => w.Location.Geography.Distance(usersPosition) * .00062 >= 0 &&
                                    w.Location.Geography.Distance(usersPosition) * .00062 <= mileRadiusTo
                                    &&
                                    w.Archived == false &&
                                    w.Expired != true &&
                                    w.Priority == false &&
                                    w.Broadcast == false &&
                                    _genders.Contains(w.Gender.Id) &&
                                    (w.AlwaysAvailable == true || w.ExpiryDate >= DateTime.Now))
                             .OrderBy(o => o.Id).Skip(from).Take(take);

            return(Mapper.Map <List <DealModel> >(allWonders));

            //return mappedWonders.Where(w =>
            //{
            //    var wonderLocation =
            //        GeographyHelper.ConvertLatLonToDbGeography(w.Location.Longitude.Value, w.Location.Latitude.Value);

            //    return wonderLocation.Distance(usersPosition) * .00062 > 0 &&
            //           wonderLocation.Distance(usersPosition) * .00062 <= mileRadiusTo;
            //}).ToList();

            //return allWonders.Where(w => w.Location.Geography.Distance(usersPosition) * .00062 >= 0 &&
            //w.Location.Geography.Distance(usersPosition) * .00062 <= mileRadiusTo);

            //return GetNearestWonders(usersPosition, from: 0, to: 1);
        }
        public async Task <HttpResponseMessage> PostWonderModel(WonderModel model)
        {
            try
            {
                var wonders = new List <DealModel>();

                if (model.Latitude != null && model.Longitude != null)
                {
                    var usersPosition = GeographyHelper.ConvertLatLonToDbGeography(model.Longitude.Value, model.Latitude.Value);

                    wonders = await Task.Run(() =>
                    {
                        return(Mapper.Map <List <DealModel> >(DataContext.Deals
                                                              .Where(w => w.Location.Geography.Distance(usersPosition) * .00062 <= WonderAppConstants.DefaultRadius &&
                                                                     w.Tags.Any(x => model.TagId == x.Id) &&
                                                                     !w.Archived.Value &&
                                                                     w.MyRejectUsers.All(u => u.Id != model.UserId) &&
                                                                     w.MyWonderUsers.All(u => u.Id != model.UserId))
                                                              .Take(WonderAppConstants.DefaultMaxNumberOfWonders)));
                    });
                }
                else
                {
                    wonders = await Task.Run(() =>
                    {
                        return(Mapper.Map <List <DealModel> >(DataContext.Deals
                                                              .Where(w => !w.Archived.Value &&
                                                                     w.MyRejectUsers.All(u => u.Id != model.UserId) &&
                                                                     w.MyWonderUsers.All(u => u.Id != model.UserId) &&
                                                                     w.Tags.Any(x => model.TagId == x.Id))
                                                              .OrderByDescending(x => x.Id)
                                                              .Take(WonderAppConstants.DefaultMaxNumberOfWonders)));
                    });
                }

                return(Request.CreateResponse(HttpStatusCode.OK, wonders));
            }
            catch (Exception ex)
            {
                return(Request.CreateErrorResponse(HttpStatusCode.InternalServerError, ex));
            }
        }
        /// <summary>
        /// HTTP POST to return wonder deals. Send the following in body:
        /// Current position in latitude and longitude, cityId and userId.
        /// If there are unseen priority wonders for city then it returns all of them.
        /// If there are no priority wonders then it returns useen wonders from the following:
        /// Proximity of 1 mile, 3 miles, popularity and random.
        /// There will be no duplicates in the list.
        /// If no location just returns random and popular.
        /// Returns HTTP StatusCode 200 with JSON list of wonder deals.
        /// If error, return Http Status Code 500 with error message.
        /// </summary>
        /// <returns></returns>
        public async Task <HttpResponseMessage> PostWonders([FromBody] WonderModel model)
        {
            try
            {
                if (model.UserId != null && DataContext.AspNetUsers.All(x => x.Id != model.UserId))
                {
                    return(Request.CreateErrorResponse(HttpStatusCode.Unauthorized, "This user is not recognised"));
                }

                var wonders = new List <DealModel>();

                wonders = await Task.Run(() => GetWonders(model.UserId, model.CityId, priority : true));

                if (wonders.Count > 0)
                {
                    var priorityWonders = wonders.OrderBy(x => Guid.NewGuid()).ToList();
                    if (priorityWonders.Any(w => w.Broadcast == true))
                    {
                        var broadcastWonder = priorityWonders.First(w => w.Broadcast == true);
                        priorityWonders.Remove(broadcastWonder);
                        priorityWonders.Insert(0, broadcastWonder);
                    }

                    return(Request.CreateResponse(HttpStatusCode.OK, priorityWonders));
                }

                _wonders = await Task.Run(() => GetWonders(model.UserId, model.CityId, priority : false));

                if (model.Latitude != null && model.Longitude != null)
                {
                    wonders = await Task.Run(() =>
                    {
                        if (_wonders.Count <= WonderAppConstants.DefaultMaxNumberOfWonders)
                        {
                            return(_wonders.ToList());
                        }

                        var usersPosition = GeographyHelper.ConvertLatLonToDbGeography(model.Longitude.Value, model.Latitude.Value);

                        var popularWonders   = GetPopularWonders(WonderAppConstants.DefaultNumberOfWondersToTake);
                        var randomWonders    = GetRandomWonders(WonderAppConstants.DefaultNumberOfWondersToTake);
                        var oneMileWonders   = GetNearestWonders(usersPosition, from: 0, to: 1);
                        var threeMileWonders = GetNearestWonders(usersPosition, from: 1, to: 3);

                        var results = oneMileWonders.Union(threeMileWonders).Union(popularWonders).Union(randomWonders);
                        results     = results.OrderBy(x => Guid.NewGuid());

                        return(results.ToList());
                    });
                }
                else
                {
                    wonders = await Task.Run(() =>
                    {
                        var popularWonders = GetPopularWonders(WonderAppConstants.DefaultNumberOfWondersToTake * 2);
                        var randomWonders  = GetRandomWonders(WonderAppConstants.DefaultNumberOfWondersToTake * 2);

                        var results = popularWonders.Union(randomWonders);
                        results     = results.OrderBy(x => Guid.NewGuid());

                        return(Mapper.Map <List <DealModel> >(results));
                    });
                }

                return(Request.CreateResponse(HttpStatusCode.OK, wonders));
            }
            catch (Exception ex)
            {
                return(Request.CreateErrorResponse(HttpStatusCode.InternalServerError, ex));
            }
        }