List<IStore> IStoreRetriever.GetAllStoresInRadius(double latitude, double longitude, double radius)
        {
            using (UndeadEarthDataContext dataContext = new UndeadEarthDataContext(_connectionString))
            {
                dataContext.ReadUncommited();

                Tuple<double, double> north = _distanceCalculator.GetNorthernPoint(latitude, longitude, radius);
                Tuple<double, double> south = _distanceCalculator.GetSouthernPoint(latitude, longitude, radius);
                Tuple<double, double> east = _distanceCalculator.GetEasternPoint(latitude, longitude, radius);
                Tuple<double, double> west = _distanceCalculator.GetWesternPoint(latitude, longitude, radius);

                List<IStore> stores = dataContext.StoreDtos.Where(c => (double)c.Latitude < north.Item1 && (double)c.Latitude > south.Item1
                                                                && (double)c.Longitude < east.Item2 && (double)c.Longitude > west.Item2)
                                                                .Cast<IStore>().ToList();

                List<IStore> storesToRemove = new List<IStore>();

                foreach (IStore store in stores)
                {
                    if (_distanceCalculator.CalculateMiles(latitude, longitude, store.Latitude, store.Longitude) > radius)
                    {
                        storesToRemove.Add(store);
                    }
                }

                stores.RemoveAll(c => storesToRemove.Contains(c));

                return stores;
            }
        }
        List<IZombiePack> IZombiePackRetriever.GetAllZombiePacksInRadius(double latitude, double longitude, double radius)
        {
            using (UndeadEarthDataContext dataContext = new UndeadEarthDataContext(_connectionString))
            {
                dataContext.ReadUncommited();

                Tuple<double, double> north = _distanceCalculator.GetNorthernPoint(latitude, longitude, radius);
                Tuple<double, double> south = _distanceCalculator.GetSouthernPoint(latitude, longitude, radius);
                Tuple<double, double> east = _distanceCalculator.GetEasternPoint(latitude, longitude, radius);
                Tuple<double, double> west = _distanceCalculator.GetWesternPoint(latitude, longitude, radius);

                List<IZombiePack> zombiePacks = dataContext.ZombiePackDtos.Where(c => (double)c.Latitude < north.Item1 && (double)c.Latitude > south.Item1
                                                                && (double)c.Longitude < east.Item2 && (double)c.Longitude > west.Item2)
                                                                .Cast<IZombiePack>().ToList();

                List<IZombiePack> zombiePacksToRemove = new List<IZombiePack>();

                foreach (IZombiePack zombiePack in zombiePacks)
                {
                    if (_distanceCalculator.CalculateMiles(latitude, longitude, zombiePack.Latitude, zombiePack.Longitude) > radius)
                    {
                        zombiePacksToRemove.Add(zombiePack);
                    }
                }

                zombiePacks.RemoveAll(c => zombiePacksToRemove.Contains(c));

                return zombiePacks;
            }
        }
 List<KeyValuePair<Guid, int>> IHotZoneRetriever.GetRemainingZombiePacksInHotZones(Guid userId)
 {
     using (UndeadEarthDataContext dataContext = new UndeadEarthDataContext(_connectionString))
     {
         return GetCountsForHotZonesLeft(userId, null, dataContext).ToList();
     }
 }
        List<IHotZone> IHotZoneRetriever.GetAllHotZones()
        {
            using (UndeadEarthDataContext dataContext = new UndeadEarthDataContext(_connectionString))
            {
                dataContext.ReadUncommited();

                return dataContext.HotZoneDtos.Cast<IHotZone>().ToList();
            }
        }
        List<IStore> IStoreRetriever.GetAllStoresByHotZoneId(Guid hotZoneId)
        {
            using (UndeadEarthDataContext dataContext = new UndeadEarthDataContext(_connectionString))
            {
                dataContext.ReadUncommited();

                return dataContext.StoreDtos.Where(s => s.HotZoneId == hotZoneId).Cast<IStore>().ToList();
            }
        }
        List<IItem> IStoreRetriever.GetItems(Guid storeId)
        {
            using (UndeadEarthDataContext dataContext = new UndeadEarthDataContext(_connectionString))
            {
                dataContext.ReadUncommited();

                return dataContext.ItemDtos.Cast<IItem>().ToList();
            }
        }
        bool IStoreRetriever.StoreExists(double latitude, double longitude)
        {
            using (UndeadEarthDataContext dataContext = new UndeadEarthDataContext(_connectionString))
            {
                dataContext.ReadUncommited();

                return dataContext.StoreDtos.Any(c => (double)c.Latitude == latitude && (double)c.Longitude == longitude);
            }
        }
        bool IHotZoneRetriever.HotZoneExists(Guid hotZoneId)
        {
            using (UndeadEarthDataContext dataContext = new UndeadEarthDataContext(_connectionString))
            {
                dataContext.ReadUncommited();

                return dataContext.HotZoneDtos.Any(s => s.Id == hotZoneId);
            }
        }
        bool IZombiePackRetriever.ZombiePackExists(Guid zombiePackId)
        {
            using (UndeadEarthDataContext dataContext = new UndeadEarthDataContext(_connectionString))
            {
                dataContext.ReadUncommited();

                return dataContext.ZombiePackDtos.Any(c => c.Id == zombiePackId);
            }
        }
        bool IHotZoneRetriever.IsStartingHotZone(Guid hotZoneId)
        {
            using (UndeadEarthDataContext dataContext = new UndeadEarthDataContext(_connectionString))
            {
                dataContext.ReadUncommited();

                return dataContext.HotZoneDtos.Any(h => h.CanStartHere == true && h.Id == hotZoneId);
            }
        }
        IUser IUserRetriever.GetUserById(Guid userId)
        {
            using (UndeadEarthDataContext dataContext = new UndeadEarthDataContext(_connectionString))
            {
                dataContext.ReadUncommited();

                return dataContext.GetUserById(userId);
            }
        }
        Guid IZombiePackRetriever.GetHotZoneByZombiePackId(Guid zombiePackId)
        {
            using (UndeadEarthDataContext dataContext = new UndeadEarthDataContext(_connectionString))
            {
                dataContext.ReadUncommited();

                return dataContext.ZombiePackDtos.Single(c => c.Id == zombiePackId).HotZoneId;
            }
        }
        IZombiePack IZombiePackRetriever.GetZombiePackById(Guid id)
        {
            using (UndeadEarthDataContext dataContext = new UndeadEarthDataContext(_connectionString))
            {
                dataContext.ReadUncommited();

                return dataContext.ZombiePackDtos.SingleOrDefault(c => c.Id == id);
            }
        }
        bool IItemRetriever.ItemExists(Guid itemId)
        {
            using (UndeadEarthDataContext dataContext = new UndeadEarthDataContext(_connectionString))
            {
                dataContext.ReadUncommited();

                return dataContext.ItemExists(itemId);
            }
        }
        bool ISafeHouseRetriever.SafeHouseExists(Guid safeHouseId)
        {
            using (UndeadEarthDataContext dataContext = new UndeadEarthDataContext(_connectionString))
            {
                dataContext.ReadUncommited();

                return dataContext.SafeHouseDtos.Any(c => c.Id == safeHouseId);
            }
        }
        IItem IItemRetriever.GetItemById(Guid itemId)
        {
            using (UndeadEarthDataContext dataContext = new UndeadEarthDataContext(_connectionString))
            {
                dataContext.ReadUncommited();

                return dataContext.GetItemById(itemId);
            }
        }
        bool IUserRetriever.UserExists(Guid userId)
        {
            using (UndeadEarthDataContext dataContext = new UndeadEarthDataContext(_connectionString))
            {
                dataContext.ReadUncommited();

                return dataContext.UserExists(userId);
            }
        }
        List<KeyValuePair<Guid, string>> IHotZoneRetriever.GetStartingHotZones()
        {
            using (UndeadEarthDataContext dataContext = new UndeadEarthDataContext(_connectionString))
            {
                dataContext.ReadUncommited();

                return dataContext.HotZoneDtos.Where(h => h.CanStartHere == true).Select(s => new KeyValuePair<Guid, string>(s.Id, s.Name)).ToList();
            }
        }
        List<IZombiePack> IZombiePackRetriever.GetAllZombiePacksInHotZone(Guid hotZoneId)
        {
            using (UndeadEarthDataContext dataContext = new UndeadEarthDataContext(_connectionString))
            {
                dataContext.ReadUncommited();

                return dataContext.ZombiePackDtos.Where(c => c.HotZoneId == hotZoneId).Cast<IZombiePack>().ToList();
            }
        }
        bool ISafeHouseRetriever.SafeHouseHasItem(Guid itemId, Guid userId)
        {
            using (UndeadEarthDataContext dataContext = new UndeadEarthDataContext(_connectionString))
            {
                dataContext.ReadUncommited();

                return dataContext.SafeHouseItemDtos.Any(c => c.ItemId == itemId
                                                            && c.UserId == userId);
            }
        }
        Guid? IUserRetriever.GetLastVisitedHotZone(Guid userId)
        {
            using (UndeadEarthDataContext dataContext = new UndeadEarthDataContext(_connectionString))
            {
                dataContext.ReadUncommited();

                UserDto user = dataContext.GetUserById(userId);
                return user.LastVisitedHotZoneId;
            }
        }
        int IUserRetriever.GetCurrentMoney(Guid userId)
        {
            using (UndeadEarthDataContext dataContext = new UndeadEarthDataContext(_connectionString))
            {
                dataContext.ReadUncommited();

                IUser user = dataContext.GetUserById(userId);
                return user.Money;
            }
        }
        List<IItem> IItemRetriever.GetAllBelowPrice(int price)
        {
            using (UndeadEarthDataContext dataContext = new UndeadEarthDataContext(_connectionString))
            {
                dataContext.ReadUncommited();

                return dataContext.ItemDtos
                                  .Where(i => i.Price <= price)
                                  .Cast<IItem>()
                                  .ToList();
            }
        }
        List<IItem> IUserItemRetriever.GetUserItems(Guid userId)
        {
            using (UndeadEarthDataContext dataContext = new UndeadEarthDataContext(_connectionString))
            {
                dataContext.ReadUncommited();

                List<IItem> items = (from userItems in dataContext.UserItemDtos
                                     join item in dataContext.ItemDtos
                                     on userItems.ItemId equals item.Id
                                     where userItems.UserId == userId
                                     select item).Cast<IItem>().ToList();

                return items;
            }
        }
        List<IItem> ISafeHouseRetriever.GetItems(Guid userId)
        {
            using (UndeadEarthDataContext dataContext = new UndeadEarthDataContext(_connectionString))
            {
                dataContext.ReadUncommited();

                var items = (from safeHouseItem in dataContext.SafeHouseItemDtos
                             join item in dataContext.ItemDtos
                             on safeHouseItem.ItemId equals item.Id
                             where safeHouseItem.UserId == userId
                             select item);

                return items.Cast<IItem>().ToList(); ;
            }
        }
        int IHotZoneRetriever.ZombiePacksLeft(Guid userId, Guid hotZoneId)
        {
            using (UndeadEarthDataContext dataContext = new UndeadEarthDataContext(_connectionString))
            {
                List<KeyValuePair<Guid, int>> result = GetCountsForHotZonesLeft(userId, hotZoneId, dataContext);

                if (result.Count == 0)
                {
                    return 0;
                }
                else
                {
                    return result.First().Value;
                }

            }
        }
        Tuple<int, DateTime> IUserRetriever.GetLastSavedEnergy(Guid userId)
        {
            using (UndeadEarthDataContext dataContext = new UndeadEarthDataContext(_connectionString))
            {
                dataContext.ReadUncommited();
                var dto = dataContext.UserDtos.SingleOrDefault(s => s.Id == userId);
                if (dto != null)
                {
                    if (dto.LastEnergy == null)
                    {
                        return null;
                    }

                    if (dto.LastEnergyDate == null)
                    {
                        dto.LastEnergyDate = DateTime.Now;
                    }

                    return new Tuple<int, DateTime>(dto.LastEnergy.Value, dto.LastEnergyDate.Value);
                }
            }

            return null;
        }
        int IUserRetriever.GetEnergyForDifficultyCalculation(Guid userId)
        {
            using (UndeadEarthDataContext dataContext = new UndeadEarthDataContext(_connectionString))
            {
                dataContext.ReadUncommited();

                UserDto user = dataContext.GetUserById(userId);
                return user.BaseLineEnergy;
            }
        }
        bool IUserRetriever.FacebookUserExists(long facebookUserId)
        {
            if (facebookUserId == 0)
            {
                throw new InvalidOperationException("Facebook UserId cannot be 0.");
            }

            using (UndeadEarthDataContext dataContext = new UndeadEarthDataContext(_connectionString))
            {
                UserDto userDto = dataContext.GetUserByFacebookUserId(facebookUserId);  
                return userDto != null;
            }
        }
        void IUserSaver.InsertUser(Guid userId, long facebookUserId, string name, Guid startingLocation, int baseAttackPower, int baseEnergy)
        {
            if(facebookUserId == 0)
            {
                throw new InvalidOperationException("Facebook UserId cannot be 0.");
            }

            using (UndeadEarthDataContext dataContext = new UndeadEarthDataContext(_connectionString))
            {
                UserDto userDto = dataContext.GetUserByFacebookUserId(facebookUserId);
                if(userDto != null)
                {
                    throw new InvalidOperationException("User already exists.");
                }

                userDto = new UserDto
                {
                    Id = userId,
                    FacebookUserId = facebookUserId,
                    ZoneId = startingLocation,
                    CurrentBaseAttack = baseAttackPower,
                    CurrentBaseEnergy = baseEnergy,
                    LastVisitedHotZoneId = startingLocation,
                    BaseLineAttackPower = baseAttackPower,
                    BaseLineEnergy = baseEnergy,
                    DisplayName = name,
                    Level = 1,
                    Email = string.Empty,
                    LocationId = startingLocation,
                    Money = 0,
                    PossibleItemAmount = 5
                };

                dataContext.UserDtos.InsertOnSubmit(userDto);
                dataContext.SubmitChanges();
            }
        }