public async Task <IActionResult> Index(PhysicianSpecialization specialization, DateTime startDate, AppointmentType appointmentType)
        {
            var model = new AddAppointmentViewModel
            {
                FreeTerms = new List <Appointment>()
            };

            if (startDate < DateTime.Now)
            {
                return(View(model));
            }

            try
            {
                var builder = new StringBuilder("Appointments/free/?");
                var query   = HttpUtility.ParseQueryString(string.Empty);
                query["specialization"] = specialization.ToString();
                query["startDate"]      = startDate.ToString("MM.dd.yyyy"); // little hack
                query["type"]           = appointmentType.ToString();
                builder.Append(query.ToString());

                model.FreeTerms = await _client.SendRequestAsync <List <Appointment> >(HttpMethod.Get, builder.ToString());

                return(View(model));
            }
            catch (HttpRequestException)
            {
                ModelState.AddModelError("TryAgain", _localizer["TryAgain"]);
                return(View(model));
            }
        }
        public async Task <ActionResult <IEnumerable <Appointment> > > GetFreeTerms(
            [FromQuery] PhysicianSpecialization specialization,
            [FromQuery] DateTime startDate,
            [FromQuery] AppointmentType type)
        {
            // Get all physicians with the required specialization
            var physicians = await _context.Physicians
                             .Where(p => p.Specialization == specialization)
                             .ToListAsync();

            // TODO: change this
            // By default, search for free appointments in the 2 days span from the start date
            TimeSpan defaultDateSpan = new TimeSpan(2, 0, 0, 0);
            DateTime endDate         = startDate.Add(defaultDateSpan);

            // TODO: allow setting appointment span for each physician separately
            TimeSpan defaultAppointmentTimeSpan = new TimeSpan(0, 30, 0);

            var freeAppointments = new List <Appointment>();

            foreach (var physician in physicians)
            {
                // TODO: allow setting working hours for each physician separately

                // Get physician's appointments sorted by date
                var appointments = await _context.Appointments
                                   .Where(a => a.PhysicianId == physician.Id)
                                   .Where(a => a.Time >= startDate)
                                   .Where(a => a.Time <= endDate)
                                   .OrderBy(a => a.Time)
                                   .ToListAsync();

                // iterate ovet days in selected timespan
                for (DateTime day = startDate; day < endDate; day = day.AddDays(1))
                {
                    // iterate over potential appointment hours in current day
                    for (DateTime appointmentTime = day.AddHours(8); appointmentTime < day.AddHours(16); appointmentTime += defaultAppointmentTimeSpan)
                    {
                        if (appointments.Count == 0)
                        {
                            // current appointmentTime is free
                            freeAppointments.Add(new Appointment
                            {
                                Physician   = physician,
                                PhysicianId = physician.Id,
                                Time        = appointmentTime,
                                Type        = type
                            });
                        }
                        else
                        {
                            DateTime closestAppointmentTime = appointments.ElementAt(0).Time;
                            if (
                                (appointmentTime < closestAppointmentTime && appointmentTime + defaultAppointmentTimeSpan > closestAppointmentTime) ||
                                (appointmentTime >= closestAppointmentTime))
                            {
                                // current appointmentTime is taken
                                appointments.RemoveAt(0);
                            }
                            else
                            {
                                // current appointmentTime is free
                                freeAppointments.Add(new Appointment
                                {
                                    Physician   = physician,
                                    PhysicianId = physician.Id,
                                    Time        = appointmentTime,
                                    Type        = type
                                });
                            }
                        }
                    }
                }
            }
            return(freeAppointments);
        }