import thread
import time
import sys
import math

class Alarm(object):
    """alarm instance

        this beeps every 0.5 seconds
    """

    snooze_interval = 9 * 60
    ring_interval = 0.5
    
    _alarm_on = True # make the clock run, but don't ring
    _alarm_time = False
    _ring = False
    _snooze = False
    _kill = False
    
    def set(self, hours, minutes, seconds=0):
        """set alarm to <hours>:<minutes>:<seconds>"""
        print 'setting alarm at %r' % ((hours, minutes, seconds),)
        self._alarm_time = (hours, minutes, seconds)

    def switch_alarm_state(self):
        self._alarm_on = not self._alarm_on

    def go(self):
        self._ring = True
        self._snooze = False

    def stop(self):
        self._ring = False
        self._snooze = False

    def snooze(self):
        self._snooze = time.time()

    def quit(self):
        self._kill = True

    def ring(self):
        sys.stdout.write('ring\n\a')
        sys.stdout.flush()

    def run(self):
        thread.start_new_thread(self.eventloop, ())
        self.timeloop()

    def timeloop(self):
        print 'entering timeloop'
        try:
            while 1:
                if self._kill:
                    return
                currtime = time.time()
                if (self._snooze and 
                        self._snooze < (currtime - self.snooze_interval)):
                    self._snooze = False
                timetuple = time.localtime()[3:6]
                if self._alarm_time == timetuple:
                    self._ring = True
                    self._snooze = False
                if self._alarm_on and self._ring and not self._snooze:
                    self.ring()
                self.print_status()
                time.sleep(self.ring_interval)
        except:
            exc, e, tb = sys.exc_info()
            print 'Exception:', exc, e

    def eventloop(self):
        while 1:
            print 'going to block a bit here...'
            char = sys.stdin.read(1)
            print 'char received:', char
            if char in ' ':
                self.snooze()
            elif char == 'q':
                self.quit()
            elif char == 'o':
                # hmmm... do we spot useless accessors here? :|
                self.switch_alarm_state()

    def print_status(self):
        print time.strftime('%H:%M:%S')
        print 'self._alarm_on:', self._alarm_on
        print 'self._ring:', self._ring
        print 'self._snooze:', self._snooze
        if self._alarm_on and self._ring and not self._snooze:
            print 'alarm!'

__alarm__ = Alarm()

def alarm_in(secs, alarm=__alarm__):
    """start the alarm in <secs> seconds"""
    print 'alarm in %s seconds' % secs
    def _switch(self):
        self.quit()
    __alarm__.swith_alarm_state = _switch
    hours = int(math.floor(secs / 3600))
    if hours > 24:
        print 'can\'t set alarms > 24 hours, sorry...'
        return
    mins = int(math.floor((secs - (hours * 3600)) / 60))
    secs = int(math.floor(secs % 60))
    currtime = list(time.localtime()[3:6])
    secs = currtime[2] + secs
    if secs > 60:
        mins += 1
        secs -= 60
    mins = currtime[1] + mins
    if mins > 60:
        hours += 1
        mins -= 60
    hours = currtime[0] + hours
    if hours > 24:
        hours -= 24
    __alarm__.set(hours, mins, secs)
    alarm.run()

def alarm_at(hours, mins, secs=0, alarm=__alarm__):
    """start the alarm at hours:mins:secs"""
    print 'alarm at %s:%s:%s' % (hours, mins, secs)
    __alarm__.set(int(hours), int(mins), int(secs))
    __alarm__.run()

if __name__ == '__main__':
    def usage():
        print ('usage: %s <seconds> *or* %s <hours>:<minutes>[:<seconds>]' %
                    (sys.argv[1], sys.argv[1]))
        print
        print ' the first form will start an alarm in <seconds> seconds, '
        print ' the second will make the program function as an alarm clock,'
        print ' ringing every day at <hours>:<minutes>:<seconds>.'
    if len(sys.argv) != 2:
        usage()
        sys.exit()
    arg = sys.argv[1]
    try:
        seconds = int(arg)
    except ValueError:
        chunks = arg.split(':')
        if len(chunks) not in [2,3]:
            usage()
            sys.exit()
        hours = chunks[0]
        mins = chunks[1]
        secs = 0
        if len(chunks) == 3:
            secs = chunks[2]
        alarm_at(hours, mins, secs)
    else:
        alarm_in(seconds)

