Index: trunk/Cocoa/Pester/Source/PSAlarms.m
===================================================================
--- trunk/Cocoa/Pester/Source/PSAlarms.m	(revision 26)
+++ trunk/Cocoa/Pester/Source/PSAlarms.m	(revision 28)
@@ -11,4 +11,5 @@
 
 NSString * const PSAlarmsDidChangeNotification = @"PSAlarmsDidChangeNotification";
+NSString * const PSAlarmsNextAlarmDidChangeNotification = @"PSAlarmsNextAlarmDidChangeNotification";
 
 static NSString * const PSPendingAlarms = @"Pester pending alarms"; // NSUserDefaults key
@@ -16,10 +17,17 @@
 static PSAlarms *PSAlarmsAllAlarms = nil;
 
+@interface PSAlarms (Private)
+
+- (void)_updateNextAlarm;
+
+@end
+
 @implementation PSAlarms
 
-+ (void)setUp; // XXX if you can think of a better name, please be my guest.
++ (void)setUp;
 {
     if (PSAlarmsAllAlarms == nil) {
         PSAlarmsAllAlarms = [[self alloc] init];
+        [PSAlarmsAllAlarms _updateNextAlarm]; // only generate notifications after singleton established
     }
 }
@@ -27,5 +35,26 @@
 + (PSAlarms *)allAlarms;
 {
+    NSAssert(PSAlarmsAllAlarms != nil, @"Attempt to use +[PSAlarms allAlarms] before setup complete");
     return PSAlarmsAllAlarms;
+}
+
+- (void)_updateNextAlarm;
+{
+    NSEnumerator *e;
+    PSAlarm *alarm, *oldNextAlarm = nextAlarm;
+    [nextAlarm release];
+    nextAlarm = nil;
+    // sort alarms so earliest is first
+    [alarms sortUsingSelector: @selector(compare:)];
+    // find first un-expired alarm
+    e = [alarms objectEnumerator];
+    while ( (alarm = [e nextObject]) != nil) {
+        if ([alarm isValid]) {
+            nextAlarm = [alarm retain];
+            break;
+        }
+    }
+    if (oldNextAlarm != nextAlarm)
+        [[NSNotificationCenter defaultCenter] postNotificationName: PSAlarmsNextAlarmDidChangeNotification object: nextAlarm];
 }
 
@@ -33,8 +62,14 @@
 {
     if ( (self = [super init]) != nil) {
+        alarms = [[NSMutableArray alloc] init];
         NS_DURING
-            NSData *alarmData = [[NSUserDefaults standardUserDefaults] dataForKey: PSPendingAlarms];
-            if (alarmData != nil) {
-                alarms = [[NSUnarchiver unarchiveObjectWithData: alarmData] retain];
+            NSArray *alarmsData = [[NSUserDefaults standardUserDefaults] arrayForKey: PSPendingAlarms];
+            NSEnumerator *e = [alarmsData objectEnumerator];
+            NSData *alarmData;
+            PSAlarm *alarm;
+            while ( (alarmData = [e nextObject]) != nil) {
+                alarm = [NSUnarchiver unarchiveObjectWithData: alarmData];
+                if (alarm != nil)
+                    [alarms addObject: alarm];
             }
         NS_HANDLER
@@ -42,5 +77,4 @@
             NSLog(@"An error occurred while attempting to restore the alarm list: %@", localException);
         NS_ENDHANDLER
-        if (alarms == nil) alarms = [[NSMutableArray alloc] init];
         [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(_alarmTimerSet:) name: PSAlarmTimerSetNotification object: nil];
         [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(_alarmTimerExpired:) name: PSAlarmTimerExpiredNotification object: nil];
@@ -51,5 +85,5 @@
 - (void)dealloc;
 {
-    [alarms dealloc];
+    [alarms release];
     [[NSNotificationCenter defaultCenter] removeObserver: self];
     [super dealloc];
@@ -58,11 +92,18 @@
 - (void)_changed;
 {
-    NSData *alarmData;
+    NSMutableArray *alarmsData = [[NSMutableArray alloc] init];
     NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
-    [alarms sortUsingSelector: @selector(compare:)];
-    alarmData = [NSArchiver archivedDataWithRootObject: alarms];
-    [defaults setObject: alarmData forKey: PSPendingAlarms];
+    NSEnumerator *e;
+    PSAlarm *alarm;
+    [self _updateNextAlarm];
+    // NSLog(@"PSAlarms _changed:\n%@", alarms);
+    // archive
+    e = [alarms objectEnumerator];
+    while ( (alarm = [e nextObject]) != nil) {
+        [alarmsData addObject: [NSArchiver archivedDataWithRootObject: alarm]];
+    }
+    [defaults setObject: alarmsData forKey: PSPendingAlarms];
     [defaults synchronize];
-    // NSLog(@"PSAlarms changed: %@", alarms);
+    [alarmsData release];
     [[NSNotificationCenter defaultCenter] postNotificationName: PSAlarmsDidChangeNotification object: self];
 }
@@ -80,4 +121,9 @@
 }
 
+- (PSAlarm *)nextAlarm;
+{
+    return nextAlarm;
+}
+
 - (int)alarmCount;
 {
@@ -92,4 +138,5 @@
 - (void)removeAlarmAtIndex:(int)index;
 {
+    [(PSAlarm *)[alarms objectAtIndex: index] cancel];
     [alarms removeObjectAtIndex: index];
 }
@@ -99,9 +146,11 @@
     NSEnumerator *e = [indices objectEnumerator];
     NSNumber *n;
-    int indexCount = [indices count], i = 0;
+    int indexCount = [indices count], i = 0, alarmIndex;
     int *indexArray = (int *)malloc(indexCount * sizeof(int));
     NS_DURING
         while ( (n = [e nextObject]) != nil) {
-            indexArray[i] = [n intValue];
+            alarmIndex = [n intValue];
+            [(PSAlarm *)[alarms objectAtIndex: alarmIndex] cancel];
+            indexArray[i] = alarmIndex;
             i++;
         }
