I'm currently working on an alarm clock with multiple (re-occuring) alarms.
I'm using a raspberry pi with Microsoft IoT installed and UWP (C#) for the layout and underlying algorithms.
The problem I'm running into is retrieving the next alarm time.
Pseudo code:
Select nextAlarm()
For all alarms a
if (((a.time >= now.time AND a.repeatDay == now.DayOfWeek)
OR a.repeatDay > now.DayOfWeek) AND a.dateTime < currentAlarm.dateTime)
currentAlarm = a;
However this will take O(n) time for every alarm and the function a.repeatDay > now.DayOfWeek isn't a trivial function (if the current day is Wednesday and the next alarm is on Monday, the function doesn't work).
What I'm asking is how can I store the alarms in such a way that above function works (and preferably faster than O(n)) or how I can store the repeat days that said problem is solved.
Currently using SQLite.net-pcl package
Alarm and RepeatDay class:
public class Alarm
{
[PrimaryKey, AutoIncrement]
public long Id { get; set; }
[NotNull]
public string Name { get; set; }
[NotNull]
public DateTime Time { get; set; }
[NotNull]
public int Repeat { get; set; }
public Alarm(string name, DateTime time, RepeatWeek repeat)
{
this.Name = name;
this.Time = time;
this.Repeat = repeat;
}
}
public class RepeatWeek
{
int repeat = 0;
public static implicit operator int(RepeatWeek w)
{
return w.repeat;
}
public void setDay(DayOfWeek w)
{
repeat |= 1 << (int)w;
}
public void removeDay(DayOfWeek w)
{
repeat &= ~(1 << (int)w);
}
public DayOfWeek getNext(DayOfWeek d, bool inclToday = false)
{
throw new NotImplementedException();
return DayOfWeek.Monday; //Needs work
}
}
I've tried my hand to implement GetNextDay. It then becomes a simple matter to implement Alarm.GetNext, and an even simpler LINQ query takes care of your requirement. I left some of it for you to implement so you can say you did it.
public class Alarm
{
public long Id { get; set; }
public string Name { get; set; }
public DateTime Time { get; set; }
public int Repeat { get; set; }
public Alarm(string name, DateTime time, RepeatWeek repeat)
{
this.Name = name;
this.Time = time;
this.Repeat = repeat;
}
public DateTime GetNext()
{
var includeToday = true;
if (DateTime.Now.TimeOfDay > Time.TimeOfDay)
{
includeToday = false;
}
var repeat = new RepeatWeek(Repeat);
var nextDayOfWeek = repeat.GetNextDay(includeToday);
return MergeDayOfWeekAndTime(nextDayOfWeek, Time);
}
private DateTime MergeDayOfWeekAndTime(DayOfWeek? nextDayOfWeek, DateTime Time)
{
//Left as exercise to the reader.
throw new NotImplementedException();
}
}
public class RepeatWeek
{
int Repeat;
public RepeatWeek(int repeat = 0)
{
Repeat = repeat;
}
public static implicit operator int(RepeatWeek w)
{
return w.Repeat;
}
public void setDay(DayOfWeek w)
{
Repeat |= 1 << (int)w;
}
public void removeDay(DayOfWeek w)
{
Repeat &= ~(1 << (int)w);
}
public static DayOfWeek FollowingDayOfWeek(DayOfWeek day)
{
if (day == DayOfWeek.Saturday)
{
return DayOfWeek.Sunday;
}
else
{
return day + 1;
}
}
public DayOfWeek? GetNextDay(bool inclToday = false)
{
var inspect = DateTime.Now.DayOfWeek;
if (!inclToday)
{
inspect = FollowingDayOfWeek(inspect);
}
for (int i = 0; i < 7; i++)
{
if ((Repeat & (1 << (int)inspect)) > 0) return inspect;
inspect = FollowingDayOfWeek(inspect);
}
return null;
}
}
[TestClass]
public class MyTestClass
{
[TestMethod]
public void GetNextDayOfWeek()
{
var repeat = new RepeatWeek();
repeat.setDay(DayOfWeek.Monday);
repeat.setDay(DayOfWeek.Tuesday);
var expected = DayOfWeek.Monday;
if (DateTime.Now.DayOfWeek == DayOfWeek.Monday)
{
expected = DayOfWeek.Tuesday;
}
var actual = repeat.GetNextDay();
Assert.AreEqual(expected, actual);
}
[TestMethod]
public void GetNextAlarm()
{
//Populate this yourself.
var alarms = new List<Alarm>();
var nextAlarm = alarms.Select(a => a.GetNext()).OrderBy(a => a.Ticks).FirstOrDefault();
}
}