public List<ProximalExperienceServiceModel> FollowFeedSortByDistance(string suserid, string slatitude, string slongitude, string sessionToken, int sessionId, string sskipthroughId = "")
        {
            // Data options and disabling deferred loading are speed enhancements.
            DataLoadOptions dataLoadOptions = new DataLoadOptions();
            dataLoadOptions.LoadWith<RestaurantSearch>(RestaurantSearch => RestaurantSearch.CosLatCosLong);
            dataLoadOptions.LoadWith<RestaurantSearch>(RestaurantSearch => RestaurantSearch.CosLatSinLong);
            dataLoadOptions.LoadWith<RestaurantSearch>(RestaurantSearch => RestaurantSearch.SinLat);
            dataLoadOptions.LoadWith<Experience>(Experience => Experience.User);
            dataLoadOptions.LoadWith<Experience>(Experience => Experience.Restaurant);
            dataLoadOptions.LoadWith<Restaurant>(Restaurant => Restaurant.Address);
            dataLoadOptions.LoadWith<Restaurant>(Restaurant => Restaurant.RestaurantStatistics);
            dataLoadOptions.LoadWith<User>(User => User.Emails);

            dc.LoadOptions = dataLoadOptions;
            dc.DeferredLoadingEnabled = false;

            Coordinates coords = Coordinates.FromStrings(slatitude, slongitude);
            CalculateDistance cd = new CalculateDistance(coords.Latitude, coords.Longitude);
            int userId;
            int skipthroughId = -1;

            if (!int.TryParse(suserid, out userId))
                throw new WebFaultException(System.Net.HttpStatusCode.NotFound);

            Guard.Session(sessionManager, sessionId, sessionToken, userId);

            if (!string.IsNullOrWhiteSpace(sskipthroughId))
            {
                if (!int.TryParse(sskipthroughId, out skipthroughId))
                    throw new WebFaultException(System.Net.HttpStatusCode.NotFound);
            }

            var experienceQuery = from f in dc.UserFollows
                                  join e in dc.Experiences on f.FolloweeId equals e.UserId
                                  where e.Deleted == false
                                  && f.FollowerId == userId
                                  join rs in dc.RestaurantSearches on e.RestaurantId equals rs.RestaurantId
                                  orderby rs.RestaurantId ascending
                                  select new { e, rs };

            List<ProximalExperienceServiceModel> sortedList = new List<ProximalExperienceServiceModel>();
            foreach (var enrs in experienceQuery)
            {
                double nearness = cd.NearnessToPoint((double)enrs.rs.CosLatCosLong,
                                                     (double)enrs.rs.CosLatSinLong,
                                                     (double)enrs.rs.SinLat);

                sortedList.Add(new ProximalExperienceServiceModel(enrs.e, Math.Acos(Math.Min(1, Math.Max(-1, nearness))) * 3959));

            }

            sortedList.Sort(delegate(ProximalExperienceServiceModel x, ProximalExperienceServiceModel y)
            {
                return x.Distance.CompareTo(y.Distance);
            });

            if (skipthroughId != -1)
            {
                int skipToIndex = sortedList.FindIndex(e => e.ExperienceID == skipthroughId);
                sortedList.RemoveRange(0, skipToIndex + 1);
            }

            return sortedList.Take(EXPERIENCE_COUNT).ToList();
        }
        public List<RestaurantFollowServiceModel> UserRestaurantFollowsSortByDistance(string suserid, string slatitude, string slongitude, string sessionToken, int sessionId, string sskipthroughId = "")
        {
            // Data options and disabling deferred loading are speed enhancements.
            DataLoadOptions dataLoadOptions = new DataLoadOptions();
            dataLoadOptions.LoadWith<RestaurantSearch>(RestaurantSearch => RestaurantSearch.CosLatCosLong);
            dataLoadOptions.LoadWith<RestaurantSearch>(RestaurantSearch => RestaurantSearch.CosLatSinLong);
            dataLoadOptions.LoadWith<RestaurantSearch>(RestaurantSearch => RestaurantSearch.SinLat);
            dataLoadOptions.LoadWith<RestaurantFollow>(RestaurantFollow => RestaurantFollow.Restaurant);
            dataLoadOptions.LoadWith<RestaurantFollow>(RestaurantFollow => RestaurantFollow.User1);
            dataLoadOptions.LoadWith<Restaurant>(Restaurant => Restaurant.Address);
            dataLoadOptions.LoadWith<Restaurant>(Restaurant => Restaurant.RestaurantStatistics);

            dc.LoadOptions = dataLoadOptions;
            dc.DeferredLoadingEnabled = false;

            Guard.Session(sessionManager, sessionId, sessionToken);

            Coordinates coords = Coordinates.FromStrings(slatitude, slongitude);
            CalculateDistance cd = new CalculateDistance(coords.Latitude, coords.Longitude);
            int userId;
            int skipthroughId = -1;

            if (!int.TryParse(suserid, out userId))
                throw new WebFaultException(System.Net.HttpStatusCode.NotFound);

            if (!string.IsNullOrWhiteSpace(sskipthroughId))
            {
                if (!int.TryParse(sskipthroughId, out skipthroughId))
                    throw new WebFaultException(System.Net.HttpStatusCode.NotFound);
            }

            var restaurantFollowQuery = from rf in dc.RestaurantFollows
                                        where rf.FollowerId == userId
                                        join rs in dc.RestaurantSearches on rf.RestaurantId equals rs.RestaurantId
                                        orderby rs.RestaurantId ascending
                                        select new { rs, rf };

            List<RestaurantFollowServiceModel> sortedList = new List<RestaurantFollowServiceModel>();
            foreach (var rsnrf in restaurantFollowQuery)
            {
                double nearness = cd.NearnessToPoint( (double)rsnrf.rs.CosLatCosLong,
                                                      (double)rsnrf.rs.CosLatSinLong,
                                                      (double)rsnrf.rs.SinLat);

                User user = null;

                if (rsnrf.rf.FolloweeId > 0)
                {
                    var userQuery = from u in dc.Users
                                    where u.Id == rsnrf.rf.FolloweeId
                                    select u;

                    if (userQuery.Count() == 1)
                    {
                        user = userQuery.First();
                    }
                }

                sortedList.Add(new RestaurantFollowServiceModel(rsnrf.rf, user, Math.Acos(Math.Min(1, Math.Max(-1, nearness))) * 3959));

            }

            sortedList.Sort(delegate(RestaurantFollowServiceModel x, RestaurantFollowServiceModel y)
            {
                return x.Distance.CompareTo(y.Distance);
            });

            if (skipthroughId != -1)
            {
                int skipToIndex = sortedList.FindIndex(e => e.Id == skipthroughId);
                sortedList.RemoveRange(0, skipToIndex + 1);
            }

            return sortedList.Take(RESTAURANTFOLLOW_COUNT).ToList();
        }
        public List<ExperienceServiceModel> FollowFeedSortByCreationDate(string suserid, string slatitude, string slongitude, string sessionToken, int sessionId, string sskipthroughId = "")
        {
            // Data options and disabling deferred loading are speed enhancements.
            DataLoadOptions dataLoadOptions = new DataLoadOptions();
            dataLoadOptions.LoadWith<Experience>(Experience => Experience.User);
            dataLoadOptions.LoadWith<Experience>(Experience => Experience.Restaurant);
            dataLoadOptions.LoadWith<Restaurant>(Restaurant => Restaurant.Address);
            dataLoadOptions.LoadWith<User>(User => User.Emails);

            dc.LoadOptions = dataLoadOptions;
            dc.DeferredLoadingEnabled = false;

            int userId;
            int skipthroughId = -1;
            Coordinates coords = null;
            CalculateDistance cd = null;

            if (!int.TryParse(suserid, out userId))
                throw new WebFaultException(System.Net.HttpStatusCode.NotFound);

            Guard.Session(sessionManager, sessionId, sessionToken, userId);

            if (!string.IsNullOrWhiteSpace(sskipthroughId))
            {
                if (!int.TryParse(sskipthroughId, out skipthroughId))
                    throw new WebFaultException(System.Net.HttpStatusCode.BadRequest);
            }

            if (!String.IsNullOrWhiteSpace(slatitude))
            {
                coords = Coordinates.FromStrings(slatitude, slongitude);
                cd = new CalculateDistance(coords.Latitude, coords.Longitude);
            }
            else if (!String.IsNullOrWhiteSpace(slongitude))
            {
                throw new WebFaultException(System.Net.HttpStatusCode.BadRequest);
            }

            IQueryable<Experience> experienceQuery = from f in dc.UserFollows
                                                     join e in dc.Experiences on f.FolloweeId equals e.UserId
                                                     where f.FollowerId == userId
                                                     && e.Deleted == false
                                                     orderby e.Id descending
                                                     select e;

            if (skipthroughId != -1)
            {
                experienceQuery = experienceQuery.Where(experience => experience.Id < skipthroughId);
            }

            experienceQuery = experienceQuery.Take(EXPERIENCE_COUNT);

            List<ExperienceServiceModel> experiences = new List<ExperienceServiceModel>();
            foreach (Experience ltsExperience in experienceQuery)
            {
                ExperienceServiceModel serviceModel = null;

                if (cd != null)
                {
                    double distance = cd.ToPoint(ltsExperience.Restaurant.Address.Latitude, ltsExperience.Restaurant.Address.Longitude);
                    serviceModel = new ProximalExperienceServiceModel(ltsExperience, distance);
                }
                else
                {
                    serviceModel = new ExperienceServiceModel(ltsExperience);
                }

                experiences.Add(serviceModel);
            }

            return experiences;
        }
        public List<RestaurantSearchServiceModel> RestaurantSearch(string slatitude, string slongitude, string sessionToken, int sessionId, string name = null, string spage = "0")
        {
            // Data options and disabling deferred loading are speed enhancements.
            DataLoadOptions dataLoadOptions = new DataLoadOptions();
            dataLoadOptions.LoadWith<RestaurantSearch>(RestaurantSearch => RestaurantSearch.CosLatCosLong);
            dataLoadOptions.LoadWith<RestaurantSearch>(RestaurantSearch => RestaurantSearch.CosLatSinLong);
            dataLoadOptions.LoadWith<RestaurantSearch>(RestaurantSearch => RestaurantSearch.SinLat);
            dataLoadOptions.LoadWith<RestaurantSearch>(RestaurantSearch => RestaurantSearch.Restaurant);
            dataLoadOptions.LoadWith<Restaurant>(Restaurant => Restaurant.Address);
            dataLoadOptions.LoadWith<Restaurant>(Restaurant => Restaurant.RestaurantStatistics);
            dc.LoadOptions = dataLoadOptions;
            dc.DeferredLoadingEnabled = false;

            Guard.Session(sessionManager, sessionId, sessionToken);

            Coordinates coords;
            if (!String.IsNullOrEmpty(slatitude) && !String.IsNullOrEmpty(slongitude))
                coords = Coordinates.FromStrings(slatitude, slongitude);
            else
                coords = new Coordinates() { Latitude = 33.77901, Longitude = -84.38430 }; // vortex midtown

            int takeCount = RESTRAUNT_COUNT;
            int page = String.IsNullOrEmpty(spage) ? 0 : int.Parse(spage);
            int skipCount = takeCount * page;

            IQueryable<RestaurantSearch> query;

            if (!String.IsNullOrWhiteSpace(name))
            {
                string compactName = NameSearch.CompactName(name);
                query = from r in dc.RestaurantSearches
                        where r.CompactName.Contains(compactName)
                        select r;
            }
            else
            {
                query = from r in dc.RestaurantSearches
                        select r;
            }

            CalculateDistance cd = new CalculateDistance(coords.Latitude, coords.Longitude);

            List<Tuple<double, RestaurantSearch>> sortedList = new List<Tuple<double, RestaurantSearch>>();
            foreach (RestaurantSearch r in query)
            {
                double d = cd.NearnessToPoint((double)r.CosLatCosLong,
                                              (double)r.CosLatSinLong,
                                              (double)r.SinLat);
                sortedList.Add(Tuple.Create(d, r));
            }

            sortedList.Sort(delegate(Tuple<double, RestaurantSearch> x, Tuple<double, RestaurantSearch> y)
            {
                return y.Item1.CompareTo(x.Item1);
            });

            List<RestaurantSearchServiceModel> restaurantModels = new List<RestaurantSearchServiceModel>(50);
            foreach (Tuple<double, RestaurantSearch> tuple in sortedList.Skip(skipCount).Take(takeCount))
            {
                double d = cd.ToPoint(tuple.Item2.Restaurant.Address.Latitude, tuple.Item2.Restaurant.Address.Longitude);
                restaurantModels.Add(new RestaurantSearchServiceModel(tuple.Item2.Restaurant, d));
            }

            return restaurantModels;
        }