public void AddFeatured(Building building, List<DateTime> days)
        {
            var tzi = TimeZoneInfo.FindSystemTimeZoneById("Mountain Standard Time");
            var today = DateTime.UtcNow.AddHours(tzi.GetUtcOffset(DateTime.Now).Hours);

            //make sure the featured days are scheduled to exactly midnight
            //of the day they've been purchased.
            for (int i = 0; i < days.Count; i++)
                days[i] = days[i].Date.AddHours(-tzi.GetUtcOffset(days[i].Date).Hours);

            using (var context = new RentlerContext())
            {
                foreach (var item in days)
                {
                    context.FeaturedListings.Add(new FeaturedListing
                    {
                        BuildingId = building.BuildingId,
                        ScheduledDate = item,
                        Zip = building.Zip
                    });
                }

                context.SaveChanges();
            }
        }
        public override void ExecuteOnComplete(Order order)
        {
            var tzi = TimeZoneInfo.FindSystemTimeZoneById("Mountain Standard Time");
            var today = DateTime.UtcNow.AddHours(tzi.GetUtcOffset(DateTime.Now).Hours);

            var featuredDate = DateTime.Parse(
                this.Item.ProductOption, null,
                System.Globalization.DateTimeStyles.AssumeUniversal);

            //make sure the featured day is scheduled to exactly midnight.
            featuredDate = featuredDate.Date.AddHours(-tzi.GetUtcOffset(featuredDate.Date).Hours);

            using(var context = new RentlerContext())
            {
                var building = context.Buildings.FirstOrDefault(b => b.BuildingId == order.BuildingId);

                if(building == null)
                    throw new ArgumentNullException("Building");

                context.FeaturedListings.Add(new FeaturedListing
                {
                    BuildingId = building.BuildingId,
                    ScheduledDate = featuredDate,
                    Zip = building.Zip
                });

                context.SaveChanges();
            }
        }
        public Status<string[]> GetOrderedPhotoIds(long buildingId)
        {
            var identity = CustomAuthentication.GetIdentity();

            if (!identity.IsAuthenticated)
                return Status.UnAuthorized<string[]>();

            if (buildingId == 0)
                return Status.ValidationError<string[]>(null, "buildingId", "buildingId cannot be empty");

            using (RentlerContext context = new RentlerContext())
            {
                try
                {
                    var building = (from b in context.Buildings.Include("Photos")
                                    where b.BuildingId == buildingId
                                    select b).SingleOrDefault();

                    if(building == null)
                        return Status.NotFound<string[]>();

                    var photoIds = building.Photos
                        .OrderBy(p => p.SortOrder)
                        .Select(p => p.PhotoId.ToString())
                        .ToArray();

                    return Status.OK<string[]>(photoIds);
                }
                catch (Exception ex)
                {
                    return Status.Error<string[]>(ex.Message, null);
                }
            }
        }
        public Status<bool> RemovePhoto(string username, Guid photoId)
        {
            if (string.IsNullOrWhiteSpace(username))
                return Status.ValidationError<bool>(false, "username", "User not authenticated");

            using (RentlerContext context = new RentlerContext())
            {
                try
                {
                    var building = (from p in context.Photos
                                        .Include("Building.Photos")
                                    where p.PhotoId == photoId &&
                                    p.Building.User.Username == username
                                    select p.Building).SingleOrDefault();

                    if (building == null)
                        return Status.NotFound<bool>();

                    var photo = building.Photos.SingleOrDefault(p => p.PhotoId == photoId);

                    if (photo == null)
                        return Status.NotFound<bool>();

                    context.Photos.Remove(photo);

                    // primary photo is being removed
                    if (building.PrimaryPhotoId == photoId)
                    {
                        // get new primary photo (next in line)
                        var nextPhoto = (from p in building.Photos
                                         where p.PhotoId != photoId
                                         orderby p.SortOrder
                                         select p).FirstOrDefault();

                        // if there isn't one then it doesn't matter
                        if (nextPhoto == null)
                        {
                            building.PrimaryPhotoId = null;
                            building.PrimaryPhotoExtension = null;
                        }
                        else
                        {
                            building.PrimaryPhotoId = nextPhoto.PhotoId;
                            building.PrimaryPhotoExtension = nextPhoto.Extension;
                        }
                    }

                    context.SaveChanges();

                    InvalidateCache(building.BuildingId);

                    return Status.OK<bool>(true);
                }
                catch (Exception ex)
                {
                    return Status.Error<bool>(ex.Message, false);
                }
            }
        }
        public UserCreditCard CreateCreditCardForUser(UserCreditCard card)
        {
            card = manager.CreateCustomerCard(card);

            if(card == null)
                return null;

            using(var context = new RentlerContext())
            {
                context.UserCreditCards.Add(card);
                context.SaveChanges();
            }

            return card;
        }
        public Status<UserCreditCard> AddUserCreditCard(string username, UserCreditCard card)
        {
            if (string.IsNullOrWhiteSpace(username))
                return Status.ValidationError<UserCreditCard>(null, "username", "The username is required");

            if (card == null)
                return Status.ValidationError<UserCreditCard>(null, "card", "card is null");

            card.CreatedBy = "orderadapter";
            card.CreateDate = DateTime.UtcNow;

            // validate the contactinfo
            var cardValidation = Status.Validatate<UserCreditCard>(card);
            if (cardValidation.StatusCode != 200)
                return Status.ValidationError<UserCreditCard>(card, "", "credit card is not valid");

            card.AccountReference = Guid.NewGuid();

            card = manager.CreateCustomerCard(card);

            if (card == null)
                return Status.Error("Problem creating card on payment service.", card);

            using (RentlerContext context = new RentlerContext())
            {
                try
                {
                    var user = (from u in context.Users
                                where u.IsDeleted == false &&
                                u.Username == username
                                select u).SingleOrDefault();

                    user.UserCreditCards.Add(card);
                    context.SaveChanges();

                    return Status.OK<UserCreditCard>(card);
                }
                catch (Exception ex)
                {
                    return Status.Error<UserCreditCard>(ex.Message, card);
                }
            }
        }
        public override void ExecuteOnComplete(Order order)
        {
            using (var context = new RentlerContext())
            {
                // get local date, to timestamp when the building was prioritized (so we can turn it off after 30 days)
                TimeZoneInfo mstTZ = TimeZoneInfo.FindSystemTimeZoneById("Mountain Standard Time");
                DateTime dateLocal = TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, mstTZ);

                var building = context.Buildings.FirstOrDefault(b => b.BuildingId == order.BuildingId);

                if (building == null)
                    throw new ArgumentNullException("Building");

                building.HasPriority = true;
                building.DatePrioritized = dateLocal;

                context.SaveChanges();
            }
        }
        public Status<List<FeaturedListing>> GetFeaturedDates()
        {
            using (var context = new RentlerContext())
            {
                var tzi = TimeZoneInfo.FindSystemTimeZoneById("Mountain Standard Time");
                var today = DateTime.UtcNow.AddHours(tzi.GetUtcOffset(DateTime.Now).Hours);
                today = today.Date.ToUniversalTime().AddHours(-tzi.GetUtcOffset(today).Hours);

                var dates = (from f in context.FeaturedListings
                             where f.ScheduledDate >= today
                             select f).ToList();

                return Status.OK(dates);
            }
        }
        public Status<UserInterest> GetUserInterestWithApplication(string username, int userInterestId)
        {
            if (string.IsNullOrWhiteSpace(username))
                return Status.ValidationError<UserInterest>(null, "username", "The username is required");

            using (RentlerContext context = new RentlerContext())
            {
                try
                {
                    var lead = (from i in context.UserInterests.Include("User.UserApplication")
                                where i.Building.User.Username == username && i.UserInterestId == userInterestId
                                select i).SingleOrDefault();

                    if (lead == null)
                        return Status.NotFound<UserInterest>();

                    return Status.OK(lead);
                }
                catch (Exception ex)
                {
                    // log exception
                    return Status.Error<UserInterest>("System was unable to get lead", null);
                }
            }
        }
        public Status<Building> CreateProperty(Building building)
        {
            var identity = CustomAuthentication.GetIdentity();

            if (!identity.IsAuthenticated)
                return Status.UnAuthorized<Building>();

            if (building == null)
                return Status.ValidationError<Building>(null, "building", "building is null");

            //get the lat/lng location of the building
            Geocode(building);

            using (RentlerContext context = new RentlerContext())
            {
                try
                {
                    building.UserId = identity.UserId;

                    // set defaults
                    building.CreateDateUtc = DateTime.UtcNow;
                    building.CreatedBy = "propertyadapter.createproperty";

                    context.Buildings.Add(building);
                    context.SaveChanges();

                    return Status.OK<Building>(building);
                }
                catch (Exception ex)
                {
                    // TODO: log exception

                    return Status.Error<Building>("An unexpected error occurred so the property was not created. Contact Rentler Support for assistance.", building);
                }
            }
        }
        /// <summary>
        /// Takes care of storing the user's credit card information.
        /// If it is a new card, it will create a new entry in the payment system
        /// and in our own storage. If it is just an update (e.g. the user changing their
        /// address information), it will act accordingly.
        /// </summary>
        /// <param name="card">The user's credit card.</param>
        public void UpdateCreditCardForUser(UserCreditCard card)
        {
            card = manager.UpdateCustomerCard(card);

            if(card.UserCreditCardId == 0)
                CreateCreditCardForUser(card);
            else
            {
                UserCreditCard toUpdate = null;

                using(var context = new RentlerContext())
                {
                    toUpdate = (from u in context.UserCreditCards
                                where u.UserId == card.UserId &&
                                      u.UserCreditCardId == card.UserCreditCardId
                                select u).SingleOrDefault();

                    if(toUpdate == null)
                        throw new ArgumentNullException();

                    toUpdate.Alias = card.Alias;
                    toUpdate.AccountReference = card.AccountReference;
                    toUpdate.CardName = card.CardName;
                    toUpdate.CardNumber = card.CardNumber;
                    toUpdate.ExpirationMonth = card.ExpirationMonth;
                    toUpdate.ExpirationYear = card.ExpirationYear;
                    toUpdate.Address1 = card.Address1;
                    toUpdate.Address2 = card.Address2;
                    toUpdate.City = card.City;
                    toUpdate.Email = card.Email;
                    toUpdate.FirstName = card.FirstName;
                    toUpdate.LastName = card.LastName;
                    toUpdate.Phone = card.Phone;
                    toUpdate.State = card.State;
                    toUpdate.Zip = card.Zip;
                    toUpdate.IsDeleted = card.IsDeleted;

                    context.SaveChanges();
                }
            }
        }
 /// <summary>
 /// Get a user's bank account information.
 /// </summary>
 /// <param name="userId">The user's id.</param>
 /// <param name="userBankId">The unique id of the user's bank info.</param>
 /// <returns>A UserCreditCard.</returns>
 public List<UserCreditCard> GetUserCreditCards(int userId)
 {
     using(var context = new RentlerContext())
         return (from u in context.UserCreditCards
                 where u.UserId == userId
                 select u).ToList();
 }
 /// <summary>
 ///	Gets all of the user's bank accounts.
 /// </summary>
 /// <param name="userId">The user's id.</param>
 /// <returns>A List of the user's bank accounts.</returns>
 public UserBank GetUserBank(int userId, int userBankId)
 {
     using(var context = new RentlerContext())
         return (from u in context.UserBanks
                 where u.UserBankId == userBankId && u.UserId == userId
                 select u).SingleOrDefault();
 }
        public Status<List<UserInterest>> GetLeadsForProperty(long buildingId, string username)
        {
            if (string.IsNullOrWhiteSpace(username))
                return Status.ValidationError<List<UserInterest>>(null, "username", "The username is required");

            using(var context = new RentlerContext())
            {
                var leads = (from ui in context.UserInterests.Include("User")
                             where ui.BuildingId == buildingId &&
                             ui.Building.User.Username == username &&
                             ui.ApplicationSubmitted
                             select ui).ToList();

                return Status.OK<List<UserInterest>>(leads);
            }
        }
        /// <summary>
        /// Gets basic building information for use with creating
        /// a new property within the application.
        /// </summary>
        /// <param name="username">The username of the user to generate
        /// property information from.</param>
        /// <returns>
        /// A building with pre-populated information based on the user.
        /// </returns>
        public Status<Building> GetInfoForNewProperty(string username)
        {
            if (string.IsNullOrWhiteSpace(username))
                return Status.ValidationError<Building>(null, "username", "The username is required");

            using (var context = new RentlerContext())
            {
                // get the user contact info
                var user = (from i in context.Users.Include("ContactInfos")
                            where i.Username.ToLower() == username.ToLower() &&
                            !i.IsDeleted
                            select i).FirstOrDefault();

                if (user == null)
                    return Status.NotFound<Building>();

                Building b = new Building();
                b.User = user;
                b.BuildingAmenities = new List<BuildingAmenity>();
                b.CustomAmenities = new List<CustomAmenity>();

                // Give them a contact info to work with
                if (user.ContactInfos.Count < 1)
                    b.ContactInfo = new ContactInfo();
                else
                    b.ContactInfo = user.ContactInfos.First();

                return Status.OK<Building>(b);
            }
        }
        public Status<bool> DeleteUserInterest(string username, int userInterestId)
        {
            if (string.IsNullOrWhiteSpace(username))
                return Status.ValidationError<bool>(false, "username", "The username is required");

            using (RentlerContext context = new RentlerContext())
            {
                try
                {
                    var lead = (from i in context.UserInterests
                                where i.Building.User.Username == username && i.UserInterestId == userInterestId
                                select i).SingleOrDefault();

                    if (lead == null)
                        return Status.NotFound<bool>();

                    context.UserInterests.Remove(lead);
                    context.SaveChanges();

                    return Status.OK(true);
                }
                catch (Exception ex)
                {
                    // TODO: log exception
                    return Status.Error<bool>("System was unable to remove the lead", false);
                }
            }
        }
        /// <summary>
        /// Removed the requested building
        /// </summary>
        /// <param name="buildingId">building identifier</param>
        /// <param name="username">owner of the building</param>
        /// <returns>
        /// status indicating whether building was successfully removed
        /// </returns>
        public Status<bool> DeleteBuilding(long buildingId, string username)
        {
            if (buildingId == 0)
                return Status.ValidationError<bool>(false, "buildingId", "buildingId is required");

            if (string.IsNullOrWhiteSpace(username))
                return Status.ValidationError<bool>(false, "username", "username is required");

            using (var context = new RentlerContext())
            {
                var building = (from b in context.Buildings.Include("User")
                                where b.IsDeleted == false &&
                                b.BuildingId == buildingId &&
                                b.User.Username == username
                                select b).SingleOrDefault();

                if (building == null)
                    return Status.NotFound<bool>();

                // soft delete building
                building.IsDeleted = true;

                try
                {
                    context.SaveChanges();

                    InvalidateCache(building.BuildingId);

                    return Status.OK<bool>(true);
                }
                catch (Exception ex)
                {
                    return Status.Error<bool>(
                        ex.Message,
                        false
                    );
                }
            }
        }
        /// <summary>
        /// Deactivate the building
        /// </summary>
        /// <param name="buildingId">building identifier</param>
        /// <param name="username">owning user identifier</param>
        /// <returns>
        /// status with the deactivated building
        /// </returns>
        public Status<Building> DeactivateBuilding(long buildingId, string username)
        {
            if (string.IsNullOrWhiteSpace(username))
                return Status.ValidationError<Building>(null, "username", "username is required");

            using (var context = new RentlerContext())
            {
                Building building = GetBuilding(context, buildingId);
                if (building == null)
                    return Status.NotFound<Building>();
                if (building.User.Username.ToLower() != username.ToLower())
                    return Status.NotFound<Building>();
                return DeactivateBuilding(context, building);
            }
        }
        /// <summary>
        /// Deactivates the building.
        /// </summary>
        /// <param name="buildingId">The building id.</param>
        /// <param name="apiKey">The API key.</param>
        /// <returns></returns>
        public Status<Building> DeactivateBuilding(long buildingId, Guid apiKey)
        {
            // validate the api key if it exists
            if (apiKey != null)
            {
                var valKey = this.authAdapter.ValidateApiKey(apiKey);
                if (valKey.StatusCode != 200)
                    return Status.UnAuthorized<Building>();
            }

            // get the building
            using (var context = new RentlerContext())
            {
                Building building = GetBuilding(context, buildingId);
                return DeactivateBuilding(context, building);
            }
        }
        public Status<Photo[]> GetPhotos(string username, long buildingId)
        {
            if (string.IsNullOrWhiteSpace(username))
                return Status.ValidationError<Photo[]>(null, "username", "The username is required");

            using (RentlerContext context = new RentlerContext(false))
            {
                try
                {
                    var isValid = (from b in context.Buildings
                                   where b.User.IsDeleted == false && b.User.Username == username &&
                                   b.IsDeleted == false && b.BuildingId == buildingId
                                   select b).Any();

                    if (!isValid)
                        return Status.NotFound<Photo[]>();

                    var photos = from p in context.Photos
                                 where p.BuildingId == buildingId
                                 orderby p.SortOrder
                                 select p;

                    return Status.OK<Photo[]>(photos.ToArray());
                }
                catch (Exception ex)
                {
                    return Status.Error<Photo[]>(ex.Message, null);
                }
            }
        }
        /// <summary>
        /// Pseudo-randomly selects up to three featured 
        /// items that match a list of zip codes.
        /// </summary>
        /// <param name="zips">A list of zip codes to use to select featured items by location.</param>
        /// <returns>A list of of up to three featured items.</returns>
        public Status<List<BuildingPreview>> GetFeatured(string[] zips)
        {
            var items = new List<BuildingPreviewTemp>();

            var tzi = TimeZoneInfo.FindSystemTimeZoneById("Mountain Standard Time");
            var today = DateTime.UtcNow.AddHours(tzi.GetUtcOffset(DateTime.Now).Hours);

            //offset the time forward so we have the correct time in UTC
            //for the date to point to midnight LOCAL to the Time Zone.
            //For example, 4/23/2012 MST is midnight; in UTC with
            //Daylight Saving Time, it is 6:00am.
            today = today.Date.ToUniversalTime().AddHours(-tzi.GetUtcOffset(today).Hours);

            //let's grab us some featured stuff.
            using (var context = new RentlerContext())
                items = context.FeaturedListings
                    .Include("Building")
                    .Where(f => f.ScheduledDate == today &&
                                f.Building.IsActive &&
                                !f.Building.IsDeleted &&
                                !f.Building.IsRemovedByAdmin)
                    .Select(f => new BuildingPreviewTemp
                    {
                        Address1 = f.Building.Address1,
                        Bathrooms = f.Building.Bathrooms.Value,
                        Bedrooms = f.Building.Bedrooms.Value,
                        City = f.Building.City,
                        IsActive = f.Building.IsActive,
                        IsFeatured = true,
                        IsRemovedByAdmin = f.Building.IsRemovedByAdmin,
                        Price = f.Building.Price,
                        PrimaryPhotoExtension = f.Building.PrimaryPhotoExtension,
                        BuildingId = f.Building.BuildingId,
                        PrimaryPhotoId = f.Building.PrimaryPhotoId,
                        RibbonId = f.Building.RibbonId,
                        State = f.Building.State,
                        Title = f.Building.Title,
                        Zip = f.Building.Zip,
                        Latitude = f.Building.Latitude,
                        Longitude = f.Building.Longitude
                    }).ToList();

            //no featured today? just return.
            if (items.Count == 0)
                return Status.OK(new List<BuildingPreview>());

            var results = new List<BuildingPreviewTemp>();

            //no location data? just return three, randomly.
            if (zips.Length == 0)
                results = items.Shuffle().Take(3).ToList<BuildingPreviewTemp>();
            else
                //find any featured items that match the location, then
                //shuffle and take up to three, randomly
                results = items.Where(i => zips.Contains(i.Zip))
                               .Shuffle().Take(3).ToList<BuildingPreviewTemp>();

            /*
                If we haven't found any, then we need to find the closest location
                that has some featured items.
            */

            //none in the zips we have? try to find the closest zip that has any
            if (results.Count == 0)
            {
                var zi = zipAdapter.GetZipInfo(items.Select(i => i.Zip).ToArray());

                int take = 3;
                float lat, lng = 0;

                //use the average lat/lng of the
                //results we have to get a target.
                lat = zi.Average(z => z.Latitude);
                lng = zi.Average(z => z.Longitude);

                //calculate distance from our target
                //to the other featured items, order them closest-to-farthest
                var rank = items
                    .Select(i => new KeyValuePair<double, BuildingPreviewTemp>(
                        GetDistance(lat, lng, i.Latitude, i.Longitude), i))
                    .OrderBy(i => i.Key)
                    .Select(t => t.Value)
                    .Take(take).ToList();

                results.AddRange(rank);
            }

            /*
                okay, from this point, if we have less than three, we need to get
                three if we can by expanding the net.
            */

            //first, if we don't have enough to work with,
            //don't bother. Otherwise, get a target.
            if (items.Count >= 3 && results.Count < 3)
            {
                //ignore any items we already have
                items.RemoveAll(i => results.Any(r => r.BuildingId == i.BuildingId));

                int take = 3 - results.Count;
                float lat, lng = 0;

                //use the average lat/lng of the
                //results we have to get a target.
                lat = results.Average(r => r.Latitude);
                lng = results.Average(r => r.Longitude);

                //calculate distance from our target to the other
                //featured items, ordered closest-to-farthest
                var rank = items
                    .Select(i => new KeyValuePair<double, BuildingPreviewTemp>(
                        GetDistance(lat, lng, i.Latitude, i.Longitude), i))
                    .OrderBy(i => i.Key).ToList();

                //and take up to whatever we need (up to 2)
                results.AddRange(rank.Select(r => r.Value).Take(take));
            }

            return Status.OK(results.ToList<BuildingPreview>());
        }
        /// <summary>
        /// Gets the property for checkout.
        /// </summary>
        /// <param name="username">The username.</param>
        /// <param name="buildingId">The building id.</param>
        /// <returns></returns>
        public Status<Building> GetPropertyForCheckout(string username, long buildingId)
        {
            // add it
            using (RentlerContext context = new RentlerContext(false))
            {
                try
                {
                    var user = (from u in context.Users
                                       .Include("Buildings")
                                       .Include("UserCreditCards")
                                where u.IsDeleted == false &&
                                u.Username == username
                                select u).FirstOrDefault();

                    if (user == null)
                        return Status.NotFound<Building>();

                    var building = context.Buildings.Find(buildingId);

                    if (building == null)
                        return Status.NotFound<Building>();

                    return Status.OK<Building>(building);
                }
                catch (Exception ex)
                {
                    return Status.Error<Building>(ex.Message, null);
                }
            }
        }
        List<ZipInfoPreview> GetZips()
        {
            var zips = new List<ZipInfoPreview>();

            //L1
            var cache = HttpContext.Current.Cache;
            zips = cache[CacheKeys.ZIP_INFOS] as List<ZipInfoPreview>;
            if (zips != null)
                return zips;

            //L2
            //try to get from redis

            //leave this connection as is; it is rarely hit, thanks to the L1 cache,
            //and zip infos should be loaded as fast as possible, since it is vital for search.
            var connection = ConnectionGateway.Current.GetWriteConnection();
            var zipTask = connection.Strings.Get(App.RedisDatabase, CacheKeys.ZIP_INFOS);
            var result = connection.Wait(zipTask);

            if (result != null && result.Length > 0)
            {
                using (var stream = new MemoryStream(result))
                    zips = Serializer.Deserialize<List<ZipInfoPreview>>(stream);

                //add to L1
                cache[CacheKeys.ZIP_INFOS] = zips;

                return zips;
            }

            using (var context = new RentlerContext())
            {
                //get from db
                zips = (from z in context.ZipInfos
                        select new ZipInfoPreview
                        {
                            ZipCode = z.ZipCode,
                            FriendlyName = (z.City + " " + z.CityAliasName + " " + z.StateCode).ToLower(),
                            StateCode = z.StateCode.ToLower(),
                            Latitude = z.Latitude,
                            Longitude = z.Longitude
                        }).ToList();
            }

            //add to L2
            var con = ConnectionGateway.Current.GetWriteConnection();
            con.Strings.Set(App.RedisDatabase, CacheKeys.ZIP_INFOS, zips.ToBinaryArray());

            //add to L1
            cache[CacheKeys.ZIP_INFOS] = zips;

            return zips;
        }
 /// <summary>
 /// Gets the building used for basic building controls.
 /// </summary>
 /// <param name="context">The context.</param>
 /// <param name="buildingId">The building id.</param>
 /// <returns></returns>
 private Building GetBuilding(RentlerContext context, long buildingId)
 {
     return (from b in context.Buildings.Include("User")
             where b.IsDeleted == false &&
             b.BuildingId == buildingId
             select b).SingleOrDefault();
 }
 /// <summary>
 /// Get a user's credit card information.
 /// </summary>
 /// <param name="userId">The user's id.</param>
 /// <param name="userCardId">The unique id of the user's credit card info.</param>
 /// <returns>A UserCreditCard.</returns>
 public UserCreditCard GetUserCreditCard(int userId, int userCardId)
 {
     using(var context = new RentlerContext())
         return (from u in context.UserCreditCards
                 where u.UserCreditCardId == userCardId && u.UserId == userId
                 select u).SingleOrDefault();
 }
        /// <summary>
        /// Gets the property listing info.
        /// </summary>
        /// <param name="buildingId">The building id.</param>
        /// <param name="username">The username.</param>
        /// <returns></returns>
        public Status<Building> GetPropertyListingInfo(long buildingId, string username)
        {
            if (string.IsNullOrWhiteSpace(username))
                return Status.ValidationError<Building>(null, "username", "The username is required");

            using (var context = new RentlerContext(false))
            {
                try
                {
                    var building = (from b in context.Buildings
                                        .Include("BuildingAmenities")
                                        .Include("CustomAmenities")
                                        .Include("User.ContactInfos")
                                        .Include("ContactInfo")
                                    where b.IsDeleted == false &&
                                    b.BuildingId == buildingId &&
                                    b.User.IsDeleted == false &&
                                    b.User.Username == username
                                    select b).SingleOrDefault();

                    // invalid building id
                    if (building == null)
                        return Status.NotFound<Building>();

                    return Status.OK<Building>(building);
                }
                catch (Exception ex)
                {
                    return Status.Error<Building>(ex.Message, null);
                }
            }
        }
        /// <summary>
        /// Takes care of storing the user's bank account information.
        /// If it is a new card, it will create a new entry in the payment system
        /// and in our own storage. If it is just an update (e.g. the user changing their
        /// address information), it will act accordingly.
        /// </summary>
        /// <param name="bank">The user's bank account.</param>
        public void UpdateBankForUser(UserBank bank)
        {
            bank = manager.UpdateCustomerBank(bank);

            if(bank.UserBankId == 0)
                CreateBankForUser(bank);
            else
            {
                using(var context = new RentlerContext())
                {
                    var toUpdate = (from u in context.UserBanks
                                    where u.UserId == bank.UserId &&
                                    u.UserBankId == bank.UserBankId
                                    select u).SingleOrDefault();

                    if(toUpdate == null)
                        throw new ArgumentNullException();

                    toUpdate.AccountName = bank.AccountName;
                    toUpdate.AccountNumber = bank.AccountNumber;
                    toUpdate.AccountType = bank.AccountType;
                    toUpdate.PayerAlias = bank.PayerAlias;
                    toUpdate.PayeeAlias = bank.PayeeAlias;
                    toUpdate.RoutingNumber = bank.RoutingNumber;
                    toUpdate.Address1 = bank.Address1;
                    toUpdate.Address2 = bank.Address2;
                    toUpdate.City = bank.City;
                    toUpdate.Email = bank.Email;
                    toUpdate.FirstName = bank.FirstName;
                    toUpdate.LastName = bank.LastName;
                    toUpdate.Phone = bank.Phone;
                    toUpdate.State = bank.State;
                    toUpdate.Zip = bank.Zip;
                    toUpdate.IsDeleted = bank.IsDeleted;

                    context.SaveChanges();
                }
            }
        }
        /// <summary>
        /// Gets the property that includes all of the temporary ordering
        /// information that is associated.
        /// </summary>
        /// <param name="buildingId">The building id.</param>
        /// <param name="username">The username.</param>
        /// <returns>
        /// A building with all the temporary ordering information.
        /// </returns>
        public Status<Building> GetPropertyPromoteInfo(long buildingId, string username)
        {
            if (string.IsNullOrWhiteSpace(username))
                return Status.ValidationError<Building>(null, "username", "The username is required");

            using (var context = new RentlerContext(false))
            {
                try
                {
                    var building = (from b in context.Buildings
                                        .Include("TemporaryOrder.OrderItems")
                                    where b.IsDeleted == false &&
                                    b.BuildingId == buildingId &&
                                    b.User.IsDeleted == false &&
                                    b.User.Username == username
                                    select b).SingleOrDefault();

                    // invalid building id
                    if (building == null)
                        return Status.NotFound<Building>();

                    // see if temporary order is still valid
                    if (building.TemporaryOrder != null)
                    {
                        bool hasChanges = false;

                        // we only care about featured date order items
                        var featuredOrderItems = building.TemporaryOrder.OrderItems.Where(i => i.ProductId == "featureddate");
                        if (featuredOrderItems != null)
                        {
                            for (int i = 0; i < featuredOrderItems.Count(); ++i)
                            {
                                var orderItem = featuredOrderItems.ElementAt(i);

                                // get date as is in db
                                DateTime featureUtc = DateTime.Parse(orderItem.ProductOption);
                                if (featureUtc.Date < DateTime.UtcNow.Date)
                                {
                                    // if the featured date has passed its invalid so remove it
                                    context.OrderItems.Remove(orderItem);
                                    --i;
                                    hasChanges = true;
                                }
                            }
                        }

                        if (building.TemporaryOrder.OrderItems.Count == 0)
                        {
                            context.Orders.Remove(building.TemporaryOrder);
                            // redundant but its here just in case we get a messed
                            // up temporary order with no order items
                            hasChanges = true;
                        }

                        if (hasChanges)
                            context.SaveChanges();
                    }

                    return Status.OK<Building>(building);
                }
                catch (Exception ex)
                {
                    return Status.Error<Building>(ex.Message, null);
                }
            }
        }
        /// <summary>
        /// Get Property by its Id and owner's username
        /// </summary>
        /// <param name="buildingId">the Id of the property</param>
        /// <param name="username">the username of the property owner</param>
        /// <returns>
        /// the property
        /// </returns>
        public Status<Building> GetPropertyForManagement(long buildingId, string username)
        {
            if (string.IsNullOrWhiteSpace(username))
                return Status.ValidationError<Building>(null, "username", "The username is required");

            using (var context = new RentlerContext())
            {
                if (!context.Users.Any(u => u.IsDeleted == false && u.Username == username))
                    return Status.NotFound<Building>();

                var building = (from b in context.Buildings.Include("Leads.User.UserApplication")
                                where b.BuildingId == buildingId &&
                                b.User.Username == username &&
                                b.IsDeleted == false
                                select b).SingleOrDefault();

                if (building == null)
                    return Status.NotFound<Building>();

                return Status.OK<Building>(building);
            }
        }
        /// <summary>
        /// Creates the building.
        /// </summary>
        /// <param name="username">The username.</param>
        /// <param name="building">The building.</param>
        /// <returns></returns>
        public Status<Building> CreateBuilding(string username, Building building)
        {
            // validate the input
            if (string.IsNullOrWhiteSpace(username))
                return Status.ValidationError<Building>(null, "username", "username is required");
            if (building == null)
                return Status.ValidationError<Building>(null, "building", "building is null");

            // validate the building
            var validation = Status.Validatate<Building>(building);
            if (validation.StatusCode != 200)
                return validation;

            // normalize standard amenities
            if (building.BuildingAmenities != null)
            {
                var amenities = building.BuildingAmenities.Distinct().ToList();
                for (int x = 0; x < amenities.Count; ++x)
                {
                    if (!Amenities.Current.IsValidAmenity(amenities[x].AmenityId))
                    {
                        amenities.RemoveAt(x);
                        --x;
                    }
                }
                building.BuildingAmenities = amenities;
            }

            // normalize custom amenities
            if (building.CustomAmenities != null)
            {
                var custom = building.CustomAmenities.Distinct().ToList();
                // pascal case custom amenities
                for (int x = 0; x < custom.Count; ++x)
                {
                    if (string.IsNullOrEmpty(custom[x].Name))
                    {
                        custom.RemoveAt(x);
                        --x;
                        continue;
                    }
                    custom[x].Name = char.ToUpper(custom[x].Name[0]) + custom[x].Name.Substring(1);
                }
                building.CustomAmenities = custom;
            }

            //get the lat/lng location of the building
            Geocode(building);

            // add it
            using (RentlerContext context = new RentlerContext())
            {
                var user = (from u in context.Users.Include("ContactInfos")
                            where u.Username == username && !u.IsDeleted
                            select u).FirstOrDefault();

                if (user == null)
                    return Status.ValidationError<Building>(null, "username", "User doesn't exist");

                // try to make one
                if (building.ContactInfo == null)
                    return Status.ValidationError<Building>(null, "contactinfo", "No contact information specified");

                // validate the contactinfo
                var contactValidation = Status.Validatate<ContactInfo>(building.ContactInfo);
                if (contactValidation.StatusCode != 200)
                    return Status.ValidationError<Building>(null, "contactinfo", "The contact information is not valid");

                // if the contactinfoid isn't set
                if (building.ContactInfoId == 0)
                {
                    // add it
                    ContactInfo finalContact = building.ContactInfo;
                    user.ContactInfos.Add(finalContact);
                    context.SaveChanges();

                    // add it to the building
                    building.ContactInfoId = finalContact.ContactInfoId;
                }
                else
                {
                    var contact = user.ContactInfos.Where(u => u.ContactInfoId == building.ContactInfoId).FirstOrDefault();
                    if (contact == null)
                        return Status.ValidationError<Building>(null, "contactinfoid", "ContactInfoId is invalid");

                    // update the contact info
                    contact.CompanyName = building.ContactInfo.CompanyName;
                    contact.ContactInfoTypeCode = building.ContactInfo.ContactInfoTypeCode;
                    contact.Email = building.ContactInfo.Email;
                    contact.Name = building.ContactInfo.Name;
                    contact.PhoneNumber = building.ContactInfo.PhoneNumber;
                    contact.ShowEmailAddress = building.ContactInfo.ShowEmailAddress;
                    contact.ShowPhoneNumber = building.ContactInfo.ShowPhoneNumber;
                }

                // don't allow them to pass complex object. We handled it above.
                building.ContactInfo = null;

                // set defaults
                building.CreateDateUtc = DateTime.UtcNow;
                building.CreatedBy = "propertyadapter";
                building.UpdateDateUtc = DateTime.UtcNow;
                building.UpdatedBy = "propertyadapter";

                user.Buildings.Add(building);

                try
                {
                    context.SaveChanges();
                }
                catch (Exception e)
                {
                    // log exception
                    return Status.Error<Building>(
                        "An unexpected error occurred while trying to save the listing information. Contact Rentler support for assistance.",
                        building
                    );
                }

                return Status.OK<Building>(building);
            }
        }