private string BuildDateTimeDescription(Meeting meeting)
        {
            string date;

            if (meeting.Recurrence != null)
            {
                date = DateTimeUtils.BuildRecurrentDate(meeting.Recurrence);
            }
            else
            {
                DateTime dateTime;

                if (meeting.IsAllDay)
                {
                    dateTime = meeting.Start.DateTime;
                }
                else
                {
                    dateTime = meeting.Start.ToLocalTime();
                }

                date = string.Format("{0:dd MMM yyyy}", dateTime);
            }

            string time = meeting.IsAllDay ?
                GetString("AllDayPart") :
                string.Format(GetString("FromToPart"),
                                meeting.Start.ToLocalTime(),
                                meeting.End.ToLocalTime());

            return $"{date} {time}";
        }
        protected override async void OnNavigatedTo(object parameter)
        {
            _meeting = JSON.Deserialize<Meeting>(parameter);

            var items = await GetAllTimeCandidates(_meeting);
            SetTimeSlotProperties(items);

            Items = new ObservableCollection<MeetingTimeCandidate>(items);
            OnPropertyChanged(() => Items);
        }
        public static string BuildRecurrentDate(Meeting.EventRecurrence recurrence)
        {
            var pattern = recurrence.Pattern;

            string date = ResMan.GetString("OccursPart");

            switch (pattern.Type.ToLower())
            {
                case OData.Daily:
                    date += string.Format(ResMan.GetString("DailyPart"), pattern.Interval);
                    break;

                case OData.Weekly:
                    date += ResMan.GetString("EveryPart");
                    string dayFmt = ResMan.GetString("WeeklyPartFirst");

                    var localDayNames = CultureInfo.CurrentCulture.DateTimeFormat.DayNames;
                    var daysOfWeek = pattern.DaysOfWeek;
                    int numDays = daysOfWeek.Count;

                    for (int i = 0; i < numDays; ++i)
                    {
                        if (i > 0)
                        {
                            dayFmt = (i == numDays - 1) ?
                                    ResMan.GetString("WeeklyPartLast") :
                                    ResMan.GetString("WeeklyPartNext");
                        }

                        int dayIndex = GetDayOfWeekIndexInternal(daysOfWeek[i]);
                        date += string.Format(dayFmt, localDayNames[dayIndex]);
                    }
                    break;

                case OData.AbsoluteMonthly:
                    date += string.Format(ResMan.GetString("AbsMonthlyPart"),
                                            pattern.DayOfMonth,
                                            pattern.Interval);
                    break;

                case OData.RelativeMonthly:
                    date += string.Format(ResMan.GetString("RelMonthlyPart"),
                                           ApiOrdinalToLocalOrdinal(pattern.Index),
                                           GetDayOfWeekLocalized(pattern.DaysOfWeek[0]),
                                           pattern.Interval);
                    break;

                case OData.AbsoluteYearly:
                    {
                        var localMonths = CultureInfo.CurrentCulture.DateTimeFormat.MonthNames;

                        date += string.Format(ResMan.GetString("AbsYearlyPart"),
                                                pattern.Interval,
                                                localMonths[pattern.Month - 1],
                                                pattern.DayOfMonth);
                    }
                    break;

                case OData.RelativeYearly:
                    {
                        var localMonths = CultureInfo.CurrentCulture.DateTimeFormat.MonthNames;

                        date += string.Format(ResMan.GetString("RelYearlyPart"),
                                                pattern.Interval,
                                                ApiOrdinalToLocalOrdinal(pattern.Index),
                                                GetDayOfWeekLocalized(pattern.DaysOfWeek[0]),
                                                localMonths[pattern.Month - 1]);
                    }
                    break;
            }

            date += string.Format(ResMan.GetString("EffectivePart"),
                                           ToDateOnlyString(recurrence.Range.StartDate));

            switch (recurrence.Range.Type.ToLower())
            {
                case OData.NoEnd:
                    break;
                case OData.EndDate:

                    date += string.Format(ResMan.GetString("UntilPart"),
                                           ToDateOnlyString(recurrence.Range.EndDate));
                    break;
                case OData.Numbered:
                    DateTimeOffset endDate = CalculateEndDate(recurrence);
                    date += string.Format(ResMan.GetString("UntilPart"),
                                           ToDateOnlyString(endDate));
                    break;
            }

            return date;
        }
        public async Task<Meeting> UpdateEvent(Meeting meeting)
        {
            string uri = EventsFolder + meeting.Id;

            return await GetHttpHelper().PatchItemAsync<Meeting>(uri, meeting);
        }
        private static DateTimeOffset CalculateEndDate(Meeting.EventRecurrence recurrence)
        {
            DateTimeOffset date = DateTimeOffset.Parse(recurrence.Range.StartDate);

            int rangeValue = (recurrence.Range.NumberOfOccurrences - 1) * recurrence.Pattern.Interval;

            switch (recurrence.Pattern.Type.ToLower())
            {
                case OData.Daily:
                    date = date.AddDays(rangeValue);
                    break;

                case OData.Weekly:
                    int occurrences = recurrence.Range.NumberOfOccurrences / recurrence.Pattern.DaysOfWeek.Count;
                    date = date.AddDays(CalculateDayDiff(date, recurrence.Pattern.DaysOfWeek));
                    date = date.AddDays(7 * (occurrences - 1) * recurrence.Pattern.Interval);
                    break;

                case OData.AbsoluteMonthly:
                case OData.RelativeMonthly:
                    date = date.AddMonths(rangeValue);
                    break;

                case OData.AbsoluteYearly:
                case OData.RelativeYearly:
                    date = date.AddYears(rangeValue);
                    break;
            }

            return date;
        }
 private void AddTimeStamp(StringBuilder sb, Meeting meeting)
 {
     // Use CreatedDateTime as an additional condition, but give it a little offset
     sb.Append(" and ");
     sb.Append("CreatedDateTime").Append(" gt ");
     var createdDateTime = meeting.CreatedDateTime.DateTime - TimeSpan.FromMinutes(1);
     sb.Append(DateTimeUtils.DateToFullApiUtcString(createdDateTime));
 }
        public async Task<Meeting> CreateEvent(Meeting meeting)
        {
            string uri = EventsFolder;

            return await GetHttpHelper().PostItemAsync<Meeting>(uri, meeting);
        }
        private string BuildInvitationsUri(Meeting meeting)
        {
            StringBuilder sb = new StringBuilder("MailFolders");
            sb.Append(meeting.IsOrganizer ? "/SentItems/" : "/Inbox/");
            sb.Append(Messages);
            sb.Append("?$filter=");

            BuildFilter(sb, meeting);

            return sb.ToString();
        }
 private void BuildFilter(StringBuilder sb, Meeting meeting)
 {
     sb.AppendFormat("Subject eq '{0}'", meeting.Subject);
     AddTimeStamp(sb, meeting);
 }
        public async Task<EventMessage> CreateInvitationResponse(Meeting meeting, string action)
        {
            var invite = await GetEventInvitation(meeting);

            if (invite == null)
            {
                return null;
            }

            string responseUri = BuildResponseUri(invite.Id, action);

            var reply = await GetHttpHelper().PostItemAsync<EventMessage>(responseUri);

            return reply;
        }
        private async Task<EventMessage> GetEventInvitation(Meeting meeting)
        {
            string uri = BuildInvitationsUri(meeting);

            var invites = await GetHttpHelper().GetItemsAsync<EventMessage>(uri);

            // Put most recent invite on top
            var orderedInvites = invites.OrderByDescending(x => x.CreatedDateTime);

            return orderedInvites.FirstOrDefault(x => x.Type.EqualsCaseInsensitive("#microsoft.graph.eventMessage"));
        }
        private MeetingTimes BuildRequestBody(Meeting meeting)
        {
            var result = new MeetingTimes
            {
                MeetingDuration = "PT30M",
                Attendees = new List<MeetingTimes.Attendee>(),
                TimeConstraint = new TimeConstraint
                {
                    Timeslots = new List<MeetingTimeSlot>()
                },
                LocationConstraint = new LocationConstraint()
                {
                    IsRequired = false,
                    Locations = new List<Location>()
                },
                MaxCandidates = 20,
            };

            foreach (var a in meeting.Attendees ?? Enumerable.Empty<Attendee>())
            {
                if (meeting.Organizer == null || !a.EmailAddress.IsEqualTo(meeting.Organizer.EmailAddress))
                {
                    result.Attendees.Add(new MeetingTimes.Attendee
                    {
                        EmailAddress = a.EmailAddress
                    });
                }
            }

            var date = meeting.Start.DateTime;

            // From 8AM to 6PM local time
            var start = new DateTime(date.Year, date.Month, date.Day, 8, 0, 0, DateTimeKind.Local);
            var end = new DateTime(date.Year, date.Month, date.Day, 18, 0, 0, DateTimeKind.Local);

            start = start.ToUniversalTime();
            end = end.ToUniversalTime();

            var timeSlot = new MeetingTimeSlot
            {
                Start = new MeetingTimeSlot.TimeDescriptor
                {
                    Date = start.DateToApiString(),
                    Time = start.TimeOfDay.ToString(),
                    TimeZone = "UTC"
                },
                End = new MeetingTimeSlot.TimeDescriptor
                {
                    Date = end.DateToApiString(),
                    Time = end.TimeOfDay.ToString(),
                    TimeZone = "UTC"
                }
            };

            result.TimeConstraint.Timeslots.Add(timeSlot);

            if (!string.IsNullOrEmpty(meeting.Location.DisplayName))
            {
                result.LocationConstraint.Locations.Add(new Location
                {
                    DisplayName = meeting.Location.DisplayName
                });
            }

            return result;
        }
        public async Task<IEnumerable<MeetingTimeCandidate>> FindMeetingTimes(Meeting meeting)
        {
            var body = BuildRequestBody(meeting);
            string uri = "https://graph.microsoft.com/beta/me/findmeetingtimes";

            var candidates = await GetHttpHelper().PostItemAsync<MeetingTimes, MeetingTimeCandidatesResult>(uri, body);

            if (candidates == null || candidates.MeetingTimeSlots == null)
            {
                return Enumerable.Empty<MeetingTimeCandidate>();
            }

            return candidates.MeetingTimeSlots;
        }
        private void RecurrenceUpdated(Meeting.EventRecurrence recurrence)
        {
            Meeting.Recurrence = recurrence;
            OnPropertyChanged(() => IsSerial);

            BuildRecurrentDate();
        }
        private void SetDefaultTimes(Meeting meeting)
        {
            meeting.Start = new ZonedDateTime
            {
                DateTime = GetDefaultStartTime(),
                TimeZone = "UTC"
            };

            meeting.End = new ZonedDateTime
            {
                DateTime = GetDefaultStartTime() + TimeSpan.FromMinutes(30),
                TimeZone = "UTC"
            };
        }
        private Meeting CreateNewMeeting()
        {
            var meeting = new Meeting
            {
                Start = new ZonedDateTime(),
                End = new ZonedDateTime(),
                Body = new Body
                {
                    ContentType = "text"
                },
                Attendees = new List<Attendee>(),
                Location = new Location(),
            };

            SetDefaultTimes(meeting);

            return meeting;
        }