#!/usr/bin/env python

### screentimelock: utility for locking GNU screen to avoid distractions
### version 0.1
###
### Steven J. Murdoch <http://www.cl.cam.ac.uk/~sjm217/>
###
### Installation
### ------------
###  Set the LOCKPRG environment variable to be the path to
###  screentimelock. Alternatively, if you are using the bash shell,
###  create an alias to screen by adding the following line to your
###  .bashrc configuration file:
###       alias screen='LOCKPRG=$HOME/local/bin/timelock screen'
### 
### Usage
### -----
###  To activate the lock press Ctrl-A X
###  To deactivate the lock early, open a new terminal and run "screen -d -r"
###
### Configuration
### -------------
###
###  To modify the maximum locking time (default 1 hour) or the frequency of
###  notifications (default 5 minutes), edit the variables in the "Configuration
###  parameters" section below.
###
### License
### -------
### Copyright (c) 2008, Steven J. Murdoch
### All rights reserved.
###
### Redistribution and use in source and binary forms, with or without
### modification, are permitted provided that the following conditions
### are met:
###
###    * Redistributions of source code must retain the above
###      copyright notice, this list of conditions and the following
###      disclaimer.
###    * Redistributions in binary form must reproduce the above
###      copyright notice, this list of conditions and the following
###      disclaimer in the documentation and/or other materials
###      provided with the distribution.
###    * Neither the name of the copyright holders nor the names of
###      its contributors may be used to endorse or promote products
###      derived from this software without specific prior written
###      permission.
###
### THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
### CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
### INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
### MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
### DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
### BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
### EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
### TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
### DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
### ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
### TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
### THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
### SUCH DAMAGE.

### ========================
### Configuration parameters
###
### Wait until current time % LOCK_PERIOD == 0, then exit
### Every NOTIFY_PERIOD, report time remaining

## Maximum lock time (minutes)
LOCK_PERIOD = 60
## Time between notifications (minutes)
NOTIFY_PERIOD = 5

## Time to sleep between checks (seconds)
SLEEP_PERIOD = 30

### =========================

import time

def get_periods():
    '''Return local time (as a time struct), time in minutes,
       time in notification periods, and time in locking periods'''

    ## Current time
    t = time.localtime()

    ## Current time in minutes
    now = t.tm_min + t.tm_hour*60

    return t, now, int(now / NOTIFY_PERIOD), int(now / LOCK_PERIOD)

def main():
    ## When was last notification output
    last_notify_period = None

    ## Period number when locked
    _, _, _, when_locked = get_periods()

    ## Loop until LOCK_PERIOD expires
    while True:
        t, now, notify_period, lock_period = get_periods()
        if lock_period != when_locked:
            ## Exit trigger reached
            print "Unlocking..."
            break
        elif last_notify_period != notify_period:
            ## First time round or notify trigger reached
            print "Time is %s, unlocking in %s minute(s)"%(
                time.strftime("%H:%M:%S", t),
                LOCK_PERIOD - (now % LOCK_PERIOD))
            ## Record time so notification not output too often
            last_notify_period = notify_period

        ## Sleep until next potential trigger
        time.sleep(SLEEP_PERIOD)

if __name__=="__main__":
    main()
