/// <summary>
        /// Either finds address that is the same as address provided in database
        /// or creates new one, adds it to db context and then to provided announcement.
        /// </summary>
        /// <param name="announcementModel"></param>
        /// <param name="context"></param>
        /// <returns></returns>
        public static async Task <int> CreateAddressForAnnouncement(SaveAnnouncemenModel announcementModel, Announcement announcement, AppDbContext context)
        {
            // Check if provided address already exists in database.
            Address newAddress = new Address();
            Address dbAddress  = await context.Addresses
                                 .Where(a => a.Country == announcementModel.Country)
                                 .Where(a => a.Region == announcementModel.Region)
                                 .Where(a => a.City == announcementModel.City)
                                 .Where(a => a.Street == announcementModel.Street)
                                 .Where(a => a.StreetNumber == announcementModel.StreetNumber)
                                 .SingleOrDefaultAsync();

            if (dbAddress != null)
            {
                newAddress = dbAddress;
            }
            else
            {
                // Create new address object if it does not exists.
                newAddress = new Address()
                {
                    Country      = StringExtensions.FirstLettersToUpperCase(announcementModel.Country),
                    Region       = StringExtensions.FirstLettersToUpperCase(announcementModel.Region),
                    City         = StringExtensions.FirstLettersToUpperCase(announcementModel.City),
                    Street       = StringExtensions.FirstLettersToUpperCase(announcementModel.Street),
                    StreetNumber = StringExtensions.FirstLettersToUpperCase(announcementModel.StreetNumber),
                };
                // Add address to context
                await context.Addresses.AddAsync(newAddress);
            }
            announcement.Address = newAddress;
            return(0);
        }
        /// <summary>
        /// Creates schedule items and relations to them. Schedule items are not
        /// created if similar to those provided in view model are in database.
        /// Then just simple relations with existing ones are created. Note that changes
        /// need to be saved to persist.
        /// </summary>
        /// <param name="announcementModel"></param>
        /// <param name="announcement"></param>
        /// <param name="context"></param>
        /// <returns></returns>
        public static async Task <int> CreateScheduleItemsForAnnoucement(SaveAnnouncemenModel announcementModel, Announcement announcement, AppDbContext context)
        {
            // Get schedule items that already exist in database or create new ones if the does not.
            List <ScheduleItem> dbScheduleItems  = new List <ScheduleItem>();
            List <ScheduleItem> newScheduleItems = new List <ScheduleItem>();

            foreach (ScheduleItemModel scheduleItem in announcementModel.ScheduleItems)
            {
                ScheduleItem dbScheduleItem = await context.ScheduleItems
                                              .Where(si => si.MaxReservations == scheduleItem.MaxReservations)
                                              .Where(si => si.From == scheduleItem.From)
                                              .Where(si => si.To == scheduleItem.To)
                                              .SingleOrDefaultAsync();

                if (dbScheduleItem != null)
                {
                    dbScheduleItems.Add(dbScheduleItem);
                }
                else
                {
                    newScheduleItems.Add(new ScheduleItem()
                    {
                        From            = (byte)scheduleItem.From,
                        To              = (byte)scheduleItem.To,
                        MaxReservations = (int)scheduleItem.MaxReservations,
                    });
                }
            }
            // Add new schedule items to context.
            await context.ScheduleItems.AddRangeAsync(newScheduleItems);

            // Create relations between announcement and schedule items.
            List <AnnouncementToSchedule> announcementToSchedule = new List <AnnouncementToSchedule>();

            foreach (ScheduleItem scheduleItem in dbScheduleItems)
            {
                announcementToSchedule.Add(new AnnouncementToSchedule()
                {
                    Announcement = announcement,
                    ScheduleItem = scheduleItem,
                });
            }
            foreach (ScheduleItem scheduleItem in newScheduleItems)
            {
                announcementToSchedule.Add(new AnnouncementToSchedule()
                {
                    Announcement = announcement,
                    ScheduleItem = scheduleItem,
                });
            }
            // Add created relations to context.
            await context.AnnouncementToSchedules.AddRangeAsync(announcementToSchedule);

            return(0);
        }
        /// <summary>
        /// Creates payments and relations between provided announcement and
        /// payments created or these stored in database that are the same as
        /// payments given in view model. Note that context changes have to be saved
        /// to persist.
        /// </summary>
        /// <param name="announcementModel"></param>
        /// <param name="announcement"></param>
        /// <param name="context"></param>
        /// <returns></returns>
        public static async Task <int> CreatePaymentsForAnnoucement(SaveAnnouncemenModel announcementModel, Announcement announcement, AppDbContext context)
        {
            // Check if payments defined in view model exist in database.
            List <PaymentMethod> newPayments = new List <PaymentMethod>();
            List <PaymentMethod> dbPayments  = new List <PaymentMethod>();

            foreach (ContactPaymentItem item in announcementModel.Payments)
            {
                PaymentMethod dbPayment = await context.PaymentMethods
                                          .Where(pm => pm.Type == item.Type)
                                          .Where(pm => pm.Data == item.Value)
                                          .SingleOrDefaultAsync();

                // If such payment was found in database add it to list
                // else create new one.
                if (dbPayment != null)
                {
                    dbPayments.Add(dbPayment);
                }
                else
                {
                    newPayments.Add(new PaymentMethod()
                    {
                        Data = item.Value,
                        Type = (byte)item.Type,
                    });
                }
            }
            // Add new payments to context.
            await context.PaymentMethods.AddRangeAsync(newPayments);

            // Create list of relations.
            List <AnnouncementToPayment> announcementToPayments = new List <AnnouncementToPayment>();

            foreach (PaymentMethod payment in dbPayments)
            {
                announcementToPayments.Add(new AnnouncementToPayment()
                {
                    Announcement  = announcement,
                    PaymentMethod = payment,
                });
            }
            foreach (PaymentMethod payment in newPayments)
            {
                announcementToPayments.Add(new AnnouncementToPayment()
                {
                    Announcement  = announcement,
                    PaymentMethod = payment,
                });
            }
            // Add relations to context.
            await context.AnnouncementToPayments.AddRangeAsync(announcementToPayments);

            return(0);
        }
        /// <summary>
        /// Creates contacts and relations between provided announcement and
        /// contacts created or these stored in database that are the same as
        /// contacts given in view model. Note that context changes have to be saved
        /// to persist.
        /// </summary>
        /// <param name="announcementModel"></param>
        /// <param name="announcement"></param>
        /// <param name="context"></param>
        /// <returns></returns>
        public static async Task <int> CreateContactsForAnnoucement(SaveAnnouncemenModel announcementModel, Announcement announcement, AppDbContext context)
        {
            // Check if contacts defined in view model exist in database.
            List <AdditionalContact> newContacts = new List <AdditionalContact>();
            List <AdditionalContact> dbContacts  = new List <AdditionalContact>();

            foreach (ContactPaymentItem item in announcementModel.Contacts)
            {
                AdditionalContact dbContact = await context.AdditionalContacts
                                              .Where(ac => ac.Type == item.Type)
                                              .Where(ac => ac.Data == item.Value)
                                              .SingleOrDefaultAsync();

                // If such contact was found in database add it to list
                // else create new one.
                if (dbContact != null)
                {
                    dbContacts.Add(dbContact);
                }
                else
                {
                    newContacts.Add(new AdditionalContact()
                    {
                        Data = item.Value,
                        Type = (byte)item.Type,
                    });
                }
            }
            // Add new contacts to context.
            await context.AdditionalContacts.AddRangeAsync(newContacts);

            // Create list of relations.
            List <AnnouncementToContact> announcementToContacts = new List <AnnouncementToContact>();

            foreach (AdditionalContact contact in dbContacts)
            {
                announcementToContacts.Add(new AnnouncementToContact()
                {
                    Announcement      = announcement,
                    AdditionalContact = contact,
                });
            }
            foreach (AdditionalContact contact in newContacts)
            {
                announcementToContacts.Add(new AnnouncementToContact()
                {
                    Announcement      = announcement,
                    AdditionalContact = contact,
                });
            }
            // Add relations to contaxt.
            await context.AnnouncementToContacts.AddRangeAsync(announcementToContacts);

            return(0);
        }