"""
@author Stephen Jackson <scj7t4@mst.edu>

This file generates the crontab that is used to record all the shows.
"""

from datetime import *
import json
import sys
import os

from unidecode import unidecode

from settings import Settings

settings = Settings()

def safename(s):
    """
    Strips the string s of all the non-alphanumeric characters.
    """
    cleaned_string = unidecode(s)
    return ''.join(e.encode('utf-8') for e in cleaned_string if e.isalnum())

def add_leaders(show):
    """
    Adds extra buffer to the show so the entirey of the show is captured.
    """
    # Increase the duration to add the leadin and leadout
    show['duration'] += settings.LEADIN.total_seconds() 
    show['duration'] += settings.LEADOUT.total_seconds()

    # Adjust the start time
    time_format = "%H:%M:%S"
    start_time = datetime.strptime(show['start_time'],time_format)
    orig_time = start_time.time()
    start_time -= settings.LEADIN
    new_time = start_time.time()

    if orig_time < new_time:
        # The date wrapped and we need to adjust for the new day.
        show['start_day'] -= 1
        if show['start_day'] == 0:
            show['start_day'] = 7
            
    # Store the adjusted time
    show['start_time'] = str(start_time.time())
    
    return show

def show_to_crontab(show): 
    """
    Given a show (as a dictionary) create a crontab entry for that show.
    
    expected keys:
    start_time
    duration (in seconds)
    title
    start_day (as ISO weekday 1-7)
    
    The % are escaped because those are a special character to cron.
    """
    time_format = "%H:%M:%S"
    start_time = datetime.strptime(show['start_time'],time_format)
    cronline = "{min} {hour} {dom} {mon} {dow} root {command}"
    file = "{target}{show}/{show}-\%Y-\%m-\%d".format(target=settings.RECORDINGDIR,
        show=safename(show['title']))
        
    script = "webstreamd-record"
    rd = {
        'script': script, 
        'file': file,
        'stream': settings.STREAMURL,
        'duration': int(show['duration']/60.0)
        }
    recorder_cmd = "{script} {file} {duration} {stream}"
    
    cmd = recorder_cmd.format(**rd)
    cd = {
        'min': start_time.minute,
        'hour': start_time.hour,
        'dom': '*',
        'mon': '*',
        'dow': show['start_day'] % 7, # Converts from python to Crontab
        'command': cmd
        }
    return cronline.format(**cd)

def generate_crontab(js):
    """
    Generates the schedule crontab, which lists all the moments
    that recording should start.
    
    Takes a list of dictionaries. See show_to_crontab for the required keys.
    """
    print """\
# This the AUTOGENERATED recording schedule for webstreamd
# Generated {}
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
""".format(datetime.today())
    for show in js:
        print show_to_crontab(show)

def main():
    """
    Loads the schedule.json as specified by the config file.
    
    If no config file is given as a commandline argument, uses the
    default config file (Settings.DEFAULTCONFIG).
    """
    if len(sys.argv) == 2:
        conf_file = sys.argv[1]
    elif len(sys.argv) == 1:
        conf_file = Settings.DEFAULTCONFIG
    else:
        print "Format: {} [CONFIG_FILE]".format(sys.argv[0])
        exit(1)
    settings.load_config(conf_file)
    fp = open(settings.SCHEDULE)
    js = json.load(fp)
    fp.close()
    js = [ add_leaders(x) for x in js ]
    generate_crontab(js)

if __name__ == "__main__":
    main()
