"""
/***************************************************************************
 *            Timer.py
 *
 *  Thu May  6 07:31:31 2004
 *  Copyright  2004  Stas Z
 *  stasz@linux.isbeter.nl
 ****************************************************************************/
Timer is part of childsplay, http://childsplay.sf.net, but can be used as a
multi purpose timer/sheduler.
Look at the docstrings and the toplevel test code for possible usages.

# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Library General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
"""

import threading,time,sys

class Worker(threading.Thread):
    """Thread object used and called by Timer""" 
    def __init__(self,delay,func,fargs,loop):
        threading.Thread.__init__(self)
        self.__delay = delay
        self.__func = func
        self.__fargs = fargs
        self.__loop = loop
        self.__do = 1
        import atexit
        atexit.register(self._stop)
                
    def run(self):
        """This overrides the threading.Thread.run method."""
        while self.__do:
            try:
                self.__do = apply(self.__func,self.__fargs)
            except Exception,info:
                print >> sys.stderr,"Timer stopped due to a exception in %s" % self.__func
                print >> sys.stderr, "The exception message is:"
                print >> sys.stderr, info
                self.__do = 0
            time.sleep(self.__delay)
            self.__loop -= 1
            if not self.__loop: self.__do = 0
            
    def _stop(self):
        """Used to stop the thread.
        DON'T call this directly, use Timer.stop()."""
        if self.__do:
            print >> sys.stderr,"Stopping timer..."
            self.__do = 0
            
            
class Timer:
    def __init__(self,delay,func,fargs=(),loop=-1):
        """Timer, a timer object which runs in a seperate thread and calls the
        function 'func' with the arguments 'fargs' after 'delay' seconds for 
        'loop' times.
        'fargs' defaults to (), and 'loop' defaults to -1 which means
        loop forever.
        The timer checks the return value of the called function and will stop
        when the return value is false.
        So you should make sure you return true when you want to continue and false
        on error or when it should stop.        
            
        After construction you must call the start method to actual start 
        the timer.
        The timer register a function in the atexit module to cleanup any threads
        still running when the main application exits.
        Be aware that if your application doesn't exit in a 'normal' way the 
        atexit function might not work. (not normal ways are exceptions that are
        not cached by your app and terminate the program.)        
        """
        self.worker = Worker(delay,func,fargs,loop)
    
    def start(self):
        """Start the timer object."""
        self.worker.start()
                    
    def stop(self):
        """Stop the timer."""
        self.worker._stop()

if __name__ == '__main__':
    def test(*args):
        print "message from test"
        if args: print "args from test",args
        
    t = Timer(1,test,('these are the args',),loop=6)
    print "Start timer (6 times)"
    t.start()
    print "wait 2 seconds"
    time.sleep(2)
    print "and do some stuff in main"
    print "wait another 2 secs"
    time.sleep(2)
    print "and now stop the timer"
    t.stop()
