private async Task ResetReminders(AccountDataItem account, CancellationToken token)
        {
            if (account == null)
            {
                return;
            }

            ClearReminders(account.LocalAccountId, token);

            token.ThrowIfCancellationRequested();

            var semesterId = account.CurrentSemesterId;

            if (semesterId == Guid.Empty)
            {
                return;
            }

            DateTime todayAsUtc = DateTime.SpecifyKind(DateTime.Today, DateTimeKind.Utc);

            ViewItemTaskOrEvent[] itemsDueTodayOrGreater;
            ViewItemSchedule[]    allSchedules;

            try
            {
                ScheduleViewItemsGroup viewModelSchedule = await ScheduleViewItemsGroup.LoadAsync(account.LocalAccountId, semesterId, trackChanges : true, includeWeightCategories : false);

                AgendaViewItemsGroup viewModel = await AgendaViewItemsGroup.LoadAsync(account.LocalAccountId, viewModelSchedule.Semester, DateTime.SpecifyKind(todayAsUtc, DateTimeKind.Local), trackChanges : true);

                // Data we need to load and hold are...
                // - Items due today or greater
                // - All schedules
                // We don't need to worry about holding a lock though, if the collections change and that breaks us, that's fine,
                // that implies that the data has been changed anyways and another ResetReminders will come in.
                // Therefore we should also expect to get some exceptions here.

                allSchedules           = viewModelSchedule.Classes.SelectMany(i => i.Schedules).ToArray();
                itemsDueTodayOrGreater = viewModel.Items.Where(i => i.Date.Date >= DateTime.SpecifyKind(todayAsUtc, DateTimeKind.Local)).ToArray();
            }
            catch
            {
                // Semester wasn't found or other misc error
                return;
            }

            // Since we're no longer inside the lock and we're using a view group that tracks changes, any properties we access on the view items could change at any time.
            // Therefore we need to take that into consideration and be careful about what we do.

            if (account.RemindersDayBefore)
            {
                Dictionary <DateTime, List <ViewItemTaskOrEvent> > groupedByDay = new Dictionary <DateTime, List <ViewItemTaskOrEvent> >();

                DateTime tomorrow = DateTime.SpecifyKind(todayAsUtc.AddDays(1), DateTimeKind.Local);

                //select all incomplete tasks/events that is due on tomorrow or later
                foreach (ViewItemTaskOrEvent h in itemsDueTodayOrGreater.Where(i => i.Date.Date >= tomorrow))
                {
                    token.ThrowIfCancellationRequested();

                    var hDate = h.Date.Date;

                    if (!groupedByDay.TryGetValue(hDate, out List <ViewItemTaskOrEvent> group))
                    {
                        group = new List <ViewItemTaskOrEvent>();
                        groupedByDay[hDate] = group;
                    }

                    group.Add(h);
                }

                foreach (var pair in groupedByDay)
                {
                    token.ThrowIfCancellationRequested();

                    DateTime dueOn = pair.Key;
                    List <ViewItemTaskOrEvent> items = pair.Value;

                    DateTime reminderTime = GetDayBeforeReminderTime(dueOn.AddDays(-1), account, allSchedules);

                    if (!IsTimeOkay(reminderTime))
                    {
                        continue;
                    }


                    ViewItemTaskOrEvent[] tasks  = items.Where(i => i.Type == TaskOrEventType.Task).ToArray();
                    ViewItemTaskOrEvent[] events = items.Where(i => i.Type == TaskOrEventType.Event).ToArray();


                    if (tasks.Length > 0)
                    {
                        XmlDocument xml = GenerateToastReminder(
                            tasks.Length == 1 ? "You have 1 item due tomorrow" : "You have " + tasks.Length + " items due tomorrow",
                            GetItemLineText(tasks[0]),
                            tasks.Length >= 2 ? GetItemLineText(tasks[1]) : null,
#pragma warning disable 0612
                            new QueryStringHelper()
#pragma warning restore 0612
                            .SetLocalAccountId(account.LocalAccountId)
                            .SetAction("DayBeforeHomeworkReminder")
                            .ToString()
                            );

                        string remoteId = null;
                        if (account.IsOnlineAccount)
                        {
                            int hashedItems = string.Join(";", tasks.Select(i => i.Identifier)).GetHashCode();
                            remoteId = $"PP_DayBeforeHomeworks_{account.AccountId}_{hashedItems}";
                        }

                        Schedule(
                            GenerateScheduledToastNotification(
                                xml,
                                reminderTime,
                                GetId(account), //id's don't need to be unique
                                remoteId)
                            );
                    }

                    if (events.Length > 0)
                    {
                        XmlDocument xml = GenerateToastReminder(
                            events.Length == 1 ? "You have 1 event tomorrow" : "You have " + events.Length + " events tomorrow",
                            GetItemLineText(events[0]),
                            events.Length >= 2 ? GetItemLineText(events[1]) : null,
#pragma warning disable 0612
                            new QueryStringHelper()
#pragma warning restore 0612
                            .SetLocalAccountId(account.LocalAccountId)
                            .SetAction("DayBeforeExamReminder")
                            .ToString()
                            );

                        string remoteId = null;
                        if (account.IsOnlineAccount)
                        {
                            int hashedItems = string.Join(";", events.Select(i => i.Identifier)).GetHashCode();
                            remoteId = $"PP_DayBeforeExams_{account.AccountId}_{hashedItems}";
                        }

                        Schedule(
                            GenerateScheduledToastNotification(
                                xml,
                                reminderTime,
                                GetId(account),
                                remoteId));
                    }
                }
            }

            if (account.RemindersDayOf)
            {
                foreach (ViewItemTaskOrEvent h in itemsDueTodayOrGreater)
                {
                    token.ThrowIfCancellationRequested();
                    bool hasClassTime = false;

                    DateTime reminderTime = GetDayOfReminderTime(h, ref hasClassTime);

                    if (!IsTimeOkay(reminderTime))
                    {
                        continue;
                    }

                    string subtitle = GetClassName(h) + " - ";

                    if (h.Type == TaskOrEventType.Task)
                    {
                        subtitle += "due ";
                    }

                    if (hasClassTime)
                    {
                        subtitle += "in one hour";
                    }

                    else
                    {
                        subtitle += "today";
                    }

                    XmlDocument xml = GenerateToastReminder(
                        TrimString(h.Name, 200),
                        subtitle,
                        TrimString(h.Details, 200),
                        ArgumentsHelper.CreateArgumentsForView(h, account.LocalAccountId).SerializeToString()
                        );

                    string remoteId = null;
                    if (account.IsOnlineAccount)
                    {
                        remoteId = $"PP_DayOf_{account.AccountId}_{h.Identifier}";
                    }

                    Schedule(
                        GenerateScheduledToastNotification(
                            xml,
                            reminderTime,
                            GetId(account),
                            remoteId));
                }
            }
        }
            public RemoteViews GetViewAt(int position)
            {
                try
                {
                    object item = _items[position];

                    if (item is DateTime)
                    {
                        var dateHeaderView = new RemoteViews(_context.PackageName, Resource.Layout.WidgetAgendaDateListItem);
                        dateHeaderView.SetTextViewText(Resource.Id.WidgetAgendaDateHeaderTextView, ToFriendlyDate((DateTime)item, _now));

                        return(dateHeaderView);
                    }

                    if (item is string)
                    {
                        // String represents "Nothing due!", etc
                        var emptyView = new RemoteViews(_context.PackageName, Resource.Layout.WidgetAgendaEmptyListItem);
                        emptyView.SetTextViewText(Resource.Id.WidgetAgendaEmptyListItemTextView, item as string);

                        return(emptyView);
                    }

                    var task = item as BaseViewItemHomeworkExam;
                    var c    = task.GetClassOrNull();
                    if (c == null)
                    {
                        var emptyView = new RemoteViews(_context.PackageName, Resource.Layout.WidgetAgendaEmptyListItem);
                        return(emptyView);
                    }

                    RemoteViews taskView = new RemoteViews(_context.PackageName, Resource.Layout.WidgetAgendaTaskListItem);
                    taskView.SetTextViewText(Resource.Id.WidgetAgendaTaskTextView, task.Name);
                    taskView.SetInt(Resource.Id.WidgetAgendaTaskColorBar, "setBackgroundColor", ColorTools.GetColor(c.Color));

                    Intent taskIntent = new Intent()
                                        .SetAction(Intent.ActionView)
                                        .SetData(Android.Net.Uri.Parse("powerplanner:?" + ArgumentsHelper.CreateArgumentsForView(task, _localAccountId).SerializeToString()));
                    taskView.SetOnClickFillInIntent(Resource.Id.WidgetAgendaTaskListItem, taskIntent);

                    return(taskView);
                }
                catch (Exception ex)
                {
                    // Out of range exception can be expected since the items list can change while we're working
                    if (!(ex is ArgumentOutOfRangeException))
                    {
                        TelemetryExtension.Current?.TrackException(ex);
                    }

                    var emptyView = new RemoteViews(_context.PackageName, Resource.Layout.WidgetAgendaEmptyListItem);
                    return(emptyView);
                }
            }