# etmRC.py
import sys, os, os.path, codecs, locale
has_etmrc = False
from dateutil.tz import * 
import datetime
from platform import system
platform = system()

if platform in ('Windows', 'Microsoft'):
    windoz = True
else:
    windoz = False

d_gui_encoding = locale.getdefaultlocale()[1]
d_file_encoding = locale.getdefaultlocale()[1]
d_term_encoding = locale.getdefaultlocale()[1]

rc = []
added = []
msg = []
error = []
warn = []
fatal = False
warning = False
set_ed = False
set_tz = False
tracing_level = 0
zone_msg = ''

zonelist = [
    'Africa/Cairo',
    'Africa/Casablanca',
    'Africa/Johannesburg',
    'Africa/Mogadishu',
    'Africa/Nairobi',
    'America/Belize',
    'America/Buenos_Aires',
    'America/Edmonton',
    'America/Mexico_City',
    'America/Monterrey',
    'America/Montreal',
    'America/Toronto',
    'America/Vancouver',
    'America/Winnipeg',
    'Asia/Baghdad',
    'Asia/Bahrain',
    'Asia/Calcutta',
    'Asia/Damascus',
    'Asia/Dubai',
    'Asia/Hong_Kong',
    'Asia/Istanbul',
    'Asia/Jakarta',
    'Asia/Jerusalem',
    'Asia/Katmandu',
    'Asia/Kuwait',
    'Asia/Macao',
    'Asia/Pyongyang',
    'Asia/Saigon',
    'Asia/Seoul',
    'Asia/Shanghai',
    'Asia/Singapore',
    'Asia/Tehran',
    'Asia/Tokyo',
    'Asia/Vladivostok',
    'Atlantic/Azores',
    'Atlantic/Bermuda',
    'Atlantic/Reykjavik',
    'Australia/Sydney',
    'Europe/Amsterdam',
    'Europe/Berlin',
    'Europe/Lisbon',
    'Europe/London',
    'Europe/Madrid',
    'Europe/Minsk',
    'Europe/Monaco',
    'Europe/Moscow',
    'Europe/Oslo',
    'Europe/Paris',
    'Europe/Prague',
    'Europe/Rome',
    'Europe/Stockholm',
    'Europe/Vienna',
    'Pacific/Auckland',
    'Pacific/Fiji',
    'Pacific/Samoa',
    'Pacific/Tahiti',
    'Turkey',
    'US/Alaska',
    'US/Aleutian',
    'US/Arizona',
    'US/Central',
    'US/East-Indiana',
    'US/Eastern',
    'US/Hawaii',
    'US/Indiana-Starke',
    'US/Michigan',
    'US/Mountain',
    'US/Pacific',
    ]


search_path = os.getenv('PATH').split(os.pathsep)
cwd = os.getcwd()
homedir = os.path.expanduser("~")
etmrc_maybe = os.path.join(cwd, 'rc')
if os.path.isfile(etmrc_maybe):
    etmrc = etmrc_maybe
    etmdir = cwd
    etmdata = cwd
    export = os.path.join(etmdir, 'export')
else:
    etmdir = os.path.join(homedir, ".etm")
    etmrc = os.path.join(homedir, ".etm", "rc")

if sys.platform == 'darwin':
    mac = True
    d_bgcolor = 'GRAY70'
    d_selectcolor = [64, 208, 64, 48]
    d_busycolor = [64, 208, 64]
    d_basefont = 12
    d_htmlfont = 8
    d_htmlprintfont = 5
    d_calfont = 0
    d_width = 560 
    d_height = 360
    d_statusfontadj = 0
    d_listfontadj = 0
    d_datefontadj = 0
else:
    mac = False
    d_bgcolor = 'GRAY85'
    d_selectcolor = [160, 255, 144, 128]
    d_busycolor = [0, 160, 0]
    d_basefont = 8
    d_htmlfont = 4
    d_htmlprintfont = 5
    d_calfont = 8
    d_width = 640
    d_height = 360
    d_statusfontadj = 0
    d_listfontadj = 0
    d_datefontadj = 0

# default colors for the command line interface
d_attrs = {
    'event'         : 'green',
    'reminder'      : 'gray',
    'action'        : 'yellow',
    'task_pastdue'  : 'red',
    'task_today'    : 'magenta',
    'task_soon'     : 'blue',
    'task'          : 'black',
    'task_undated'  : 'black',
    'task_waiting'  : 'gray',
    'task_beginby'  : 'blue',
    'task_finished' : 'gray',
    'note'          : 'yellow',
    'header_0'      : 'red',
    'header_1'      : 'green',
    'header_2'      : 'magenta',
    'header_3'      : 'blue',
    'detail'        : 'gray',
}


def get_localtz(zones=zonelist):
    linfo = gettz()
    now  = datetime.datetime.now(tzlocal())
    name = now.tzname()
    zone = None
    possible = []
    # try the zone list first unless windows system
    if not windoz:
        for z in zones:
            abbr = now.strftime("%Z")
            zinfo = gettz(z)
            if zinfo == linfo:
                possible.append((z, abbr))
                break
    if not possible:
        for z in zones:
            zinfo = gettz(z)
            if zinfo.utcoffset(now) == linfo.utcoffset(now):
                abbr = now.astimezone(zinfo).strftime("%Z")
                possible.append((z, abbr))
    if not possible:
        # the local zone needs to be added to timezones 
        possible = [('none', '')]
    return(possible)

def PathSearch(filename):
    for path in search_path:
        candidate = os.path.join(path,filename)
        if os.path.os.path.isfile(candidate):
            return os.path.abspath(candidate)
    return ''

def check(var):
    global rc, added
    name = var[0]
    defining_code = var[1]
    description = "\n### ".join(var[2:])
    if description:
        rc.append("\n### %s" % description)
    if name in globals():
        if type(globals()[name]) == str:
            if globals()[name] != "":
                s = "%s = '''%s'''" % (name, globals()[name])
                # print "not empty: %s = %s" % (name, globals()[name])
            else:
                s = "%s = ''" % (name)
        else:
            s = "%s = %s" % (name, globals()[name])
        rc.append(s)
    else:
        res = ''
        if type(defining_code) == str:
            try:
                exec "res = %s" % defining_code
            except:
                exec "res = '%s'" % defining_code
        elif type(defining_code) in [tuple, list]:
            exec "res = (%s)" % repr(defining_code)
        else:
            exec "res = %s" % defining_code
        globals()[name] = res
        if globals()[name] != "not set":
            # print "Adding: %s" % name
            if type(res) == str:
                if res != "":
                    s = "%s = '''%s'''" % (name, res)
                else:
                    s = "%s = ''" % (name)
            elif type(res) in [tuple, list]:
                s = "%s = %s" % (name, repr(res))
            else:
                s = "%s = %s" % (name, res)
            added.append(s)
            rc.append(s)

def set_timezone_list():
    global rc, added, set_tz, timezones, zone_msg
    # move the local zone to the top of the list
    zone_msg = ''
    if set_tz:
        return None
    else:
        set_tz = True
    comment = ""
    zones = zonelist
    if auto_set_timezone:
        possible = get_localtz()
        psbl = [z[0] for z in possible]
        if not psbl or len(psbl) == 0:
            # not identified
            s = """
    Your local time zone could not be identified. 
            """
        elif len(psbl) == 1:
            if psbl[0] == 'none':
                s = """
    Your local time zone could not be found among those listed
    in 'timezones' in '%s'. You will need either to insert your
    local time zone in this list or add time zone information
    manually in the items you create.
                """ % etmrc
            else:
                s = """
    Your local time zone, '%s', was found in 'timezones'.
                """ % psbl[0]
        elif len(psbl) > 1:
            s = """
    several possibile values for your local time zone were identified
    in 'timezones' based on the time offset from utc:
        %s 
    if your local time zone is missing you should edit 

        %s 

    add it to the entry for 'timezones' and, optionally, remove any 
    entries that you do not need.
            """ % ('\n    '.join(psbl), etmrc)
        zone_msg = """\
Automatically setting the local time zone ('auto_set_timezone = True')
%s
        """ % s
    rc.append("%stimezones = %s" % (comment, zones))
    added.append("%stimezones = %s" % (comment, zones))

    return None

def set_timezones():
    if not set_tz:
        set_timezone_list()
    return "not set"

def set_etmrc():
    global has_etmrc
    if os.path.isfile(etmrc):
        has_etmrc = True
    return etmrc

def check_etmdir():
    if not os.path.isdir(etmdir):
        os.mkdir(etmdir)
        print("""
Created '%s' to hold etm system files.
\n""" % (etmdir))
    return os.path.isdir(etmdir)

def check_etmdata():
    if not os.path.isdir(etmdata):
        os.mkdir(etmdata)
        print("""
Created '%s' to hold project files.
Users of earlier versions of etm will need either to move their
project files to this subdirectory or to correct the entry for
etmdata in '%s'.\n""" % (etmdata, etmrc))
    return os.path.isdir(etmdata)

def check_dir(p, d, s):
    fp = os.path.join(p,d)
    if fp and not os.path.isdir(fp):
        os.mkdir(fp)
        print("""
Created '%s' to use as the default location for %s files.
\n""" % (d, s))
    return os.path.isdir(fp)


def check_export():
    if not os.path.isdir(export):
        os.mkdir(export)
        print("""
Created '%s' to hold exported files.
This location is specified by the entry for export in '%s'.\n""" % (export,etmrc))
    return os.path.isdir(export)

def check_file(file):
    if not os.path.isfile(file):
        fo = open(file, 'w')
        fo.write("")
        fo.close()
        print("""
Created '%s'.
\n""" % (file))
    return os.path.isfile(file)

def set_editor_settings():
    global rc, added, set_ed, editor
    chooselater = ['choose later', '', '', '']
    comment = ""
    selected = []
    unselected = []
    if set_ed:
        return None
    else:
        set_ed = True
    if mac:
        options = {
            'bbedit' : [
                "editcmd = '''%(e)s +%(n)s -w --new-window %(f)s'''",
            ],
            'edit' : [
                "editcmd = '''%(e)s +%(n)s -w --new-window %(f)s'''",
            ],
            'mate' : [
                "editcmd = '''%(e)s -l %(n)s -w %(f)s'''",
            ],
            'vim' : [
                "editcmd = '''%(e)s -g -p -f +%(n)s %(f)s'''",
            ],
        }
        for name in ['bbedit','mate', 'vim', 'edit']:
            editor = PathSearch(name)
            # select the first that works and comment out the others
            if editor:
                if comment != "# ":
                    selected = (editor,
                        options[name][0])
                else:
                    unselected.append(name)
                rc.append("%seditor = '''%s'''" % (comment, editor))
                added.append("%seditor = '''%s'''" % (comment, editor))
                rc.append("%s%s" % (comment, options[name][0]))
                added.append("%s%s" % (comment, options[name][0]))
                comment = "# "
    else: # not mac
        options = {
            'gvim' : [
                "editcmd = '''%(e)s -f +%(n)s %(f)s'''",
            ],
            'emacs' : [
                "editcmd = '''%(e)s +%(n)s %(f)s'''",
            ]
        }
        for name in ['gvim','emacs']:
            editor = PathSearch(name)
            # select the first that works and comment out the others
            if editor:
                if comment != "# ":
                    selected = (editor,
                        options[name][0])
                else:
                    unselected.append(name)
                rc.append("%seditor = '''%s'''" % (comment, editor))
                added.append("%seditor = '''%s'''" % (comment, editor))
                rc.append("%s%s" % (comment, options[name][0]))
                added.append("%s%s" % (comment, options[name][0]))
                comment = "# "
    if selected == []:
        rc.append("editor = ''")
        rc.append("editcmd = ''")
        print("""
        You will need to specify values for:

            editor
            editcmd

        in %s.\n""" % etmrc)
    else:
        print("""
Project files will be located in the directory

    etmdata = '%s'

The following settings were made for your external editor:

    editor = '%s'
    editcmd = '%s'

Edit %s if you wish to make changes.\n""" % (etmdata,
        selected[0], selected[1], etmrc))
        if len(unselected) > 0:
            print("""\
Comparable settings were also made for

    %s

but were commented out. \n""" % ", ".join(unselected))
    return None

def set_editor():
    if not set_ed:
        set_editor_settings()
    return "not set"

def set_editcmd():
    if not set_ed:
        set_editor_settings()
    return "not set"

def trace(func):
    global tracing_level
    if enable_tracing:
        def callf(*args, **kwargs):
            global tracing_level
            tracing_log.write("%sCalling %s: %s, %s\n" %
                ('    '*tracing_level, func.__name__, args, kwargs))
            tracing_level += 1
            r = func(*args, **kwargs)
            tracing_level -= 1
            tracing_log.write("%s%s returned %s\n" % ('    '*tracing_level, func.__name__, r))
            return(r)
        return(callf)
    else:
        return(func)

def make_etmrc():
    fo = open("%s" % etmrc,'w')
    fo.write("""\
### Configuration settings for etm (Event and Task Manager)
###
### etm's current default settings will be written to '~/.etm/rc' if
### this file doesn't already exist. This means you can always restore
### the default settings by either removing or renaming ~/.etm/rc.
### Further, if you would like to restore some but not all of the default
### settings, simply erase the settings you want restored and the next
### time e.py is run, your ~/.etm/rc will be recreated
### with your settings together with the default settings for the ones
### you erased.
###\n""")
    for line in rc:
        fo.write("%s\n" % line)
    fo.close()

variables = [
    ['gui_encoding', '"%s"' % d_gui_encoding, 
        'The default encodings for the etm graphic user interface, for',
        'reading and writing etm_data files and for writing to the terminal',
        'window. The following defaults should work for most users:',
        '    gui_encoding = "%s" '   % d_gui_encoding,
        '    file_encoding = "%s" '  % d_file_encoding,
        '    term_encoding = "%s" '  % d_term_encoding],
    ['file_encoding', '"%s"' % d_file_encoding, ''],
    ['term_encoding', '"%s"' % d_term_encoding, ''],
    ['etmUser', '""', 
        'If given, automatically append "@U <etmUser>" when saving items.'],
    ['etmdata', "%s" % os.path.join(etmdir,"data"),
        'The directory in which project files will be stored.'],
    ['etmActions', "",
        'If given, the relative path from "etmda" to the directory for the',
        'user action files.'],
    ['etmEvents', "",
        'If given, the relative path from "etmda" to the directory for the',
        'user event files.'],
    ['etmReminders', "",
        'If given, the relative path from "etmda" to the directory for the',
        'user reminder files.'],
    ['etmTasks', "",
        'If given, the relative path from "etmda" to the directory for the',
        'user task files.'],
    ['etmDone', "",
        'If given, the relative path from "etmda" to the directory for',
        'logging user repeated task completions.'],
    ['etmNotes', "",
        'If given, the relative path from "etmda" to the directory for the',
        'user note files.'],
    ['export', "%s" % os.path.join(etmdir, "export"),
        'The directory in which exported exported iCal/vCal and CSV',
        'files will be stored.'],
    ['contextsFile', "%s" % os.path.join(etmdir, "contexts.txt"),
        'The path to the file in which default contexts will be stored.',
        'This is a plain text file with one context per line.'],
    ['limitContextsSelection', False,
        'If true, the selection list for contexts will be limited to those',
        'listed in "contextsFile". Otherwise, contexts used in other data', 
        'items will also be displayed.'],
    ['keywordsFile', "%s" % os.path.join(etmdir, "keywords.txt"),
        'The path to the file in which default keywords will be stored.',
        'This is a plain text file with one keyword per line.'],
    ['limitKeywordsSelection', False,
        'If true, the selection list for keywords will be limited to those',
        'listed in "keywordsFile". Otherwise, keywords used in other data', 
        'items will also be displayed.'],
    ['auto_set_timezone', True,
        'If true, the system (local) time zone will be automatically',
        'appended to new items. If false, time zone information will',
        'need to be entered manually.'],
    ['timezones', 'set_timezones()', 
        'The list of available time zones. Elements can be added to',
        'or removed from this list as necessary.'],
    ['due_hour', 12,
        'Due hour and minute set the implicit time that tasks are due',
        'on their due dates. Noon, which is the default, corresponds to',
        'most expectations. E.g, a task that is due at noon on November',
        '30 in New York (12:00 EST), would also be due on November 30',
        'in London (17:00 11/30 GMT) and Honolulu (7:00 11/30 HST),',
        'but would be due on December 1 on the other side of the',
        'international date line in Tokyo (2:00 12/1 JST) and Singapore',
        '(1:00 12/1 SGT).'],
    ['due_minute', 0, ''],
    ['inc', 60,
        'The interval in seconds between alert updates'],
    ['rotate_action', True,
        'If true, new action files will be created each month in the',
        'format "<current month number>-ACTION.txt".', 
        'Otherwise static files in the format "ACTION.txt" will be',
        'used.'],
    ['rotate_done', True,
        'If true, new done files will be created each month in the',
        'format "<current month number>-DONE.txt".', 
        'Otherwise static files in the format "DONE.txt" will be',
        'used.'],
    ['rotate_event', True,
        'If true, new event files will be created each month in the',
        'format "<current month number>-EVENT.txt".', 
        'Otherwise static files in the format "EVENT.txt" will be',
        'used.'],
    ['rotate_note', True,
        'If true, new note files will be created each month in the',
        'format "<current month number>-NOTE.txt".', 
        'Otherwise static files in the format "NOTE.txt" will be',
        'used.'],
    ['rotate_reminder', True,
        'If true, new reminder files will be created each month in the',
        'format "<current month number>-REMINDER.txt".', 
        'Otherwise static files in the format "REMINDER.txt" will be',
        'used.'],
    ['rotate_task', True,
        'If true, new task files will be created each month in the',
        'format "<current month number>-TASK.txt".', 
        'Otherwise static files in the format "TASK.txt" will be',
        'used.'],
    ['action', '"actns"',
        'The root for action data files. By default new action entries will be saved to',
        '"<current month number>-ACTION.txt" if rotate_action is true',
        'and otherwise to "ACTION.txt".'],
    ['done', '"done"',
        'The root for finished copies of repeating tasks. By default new events',
        'will be saved to "<current month number>-DONE.txt" if rotate_done is true',
        'and otherwise to "DONE.txt".'],
    ['event', '"evnts"',
        'The root for event data files. By default new events will be saved to',
        '"<current month number>-EVENT.txt" if rotate_event is true',
        'and otherwise to "EVENT.txt".'],
    ['note', '"notes"',
        'The root for note data files. By default new note entries will be saved to',
        '"<current month number>-NOTE.txt" if rotate_files is true',
        'and otherwise to "NOTE.txt".'],
    ['reminder', '"rmdrs"',
        'The root for reminder data files. By default new note entries will be saved to',
        '"<current month number>-REMINDER.txt" if rotate_reminder is true',
        'and otherwise to "REMINDER.txt".'],
    ['task', '"tasks"',
        'The root for task data files. By default new tasks will be saved to',
        '"<current month number>-TASK.txt" if rotate_task is true',
        'and otherwise to "TASK.txt".'],
    ['action_interval', 10,
        'If positive, an alert will be sounded every action_interval',
        'minutes while the action timer is running.'],
    ['numbaks', 3,
        'The number of backups of data files to keep'],
    ['context', None,
        'The default context for new events and tasks'],
    ['keyword', None,
        'The default keyword for new events and tasks'],
    ['editor', '"%s" % set_editor()',
        'Edit settings',
        'editor:  the full path to the external editor',
        'editcmd: the command for editing an old task, event or action',
        'using the following SUBSTITUTIONS:',
        '   %(e)s -> editor',
        '   %(n)s -> the line number to edit',
        '   %(f)s -> the file name'     ],
    ['editcmd', '"%s" % set_editcmd()', ''],
    ['alertcmd', '''''',
        'The command to run when alerts are triggered with these replacements:',
        '   %(t)s -> thetimeis <current time>',
        '   %(T)s -> <current time>',
        '   %(m)s -> the text of the alert message',
        'If left blank, the default, then an internal alert will be displayed.'],
    ['extent', 30,
        'New events with a starttime but no endtime will, by default,',
        'have an endtime equal to this number of minutes after starttime',
        'when displaying busy and free times'],
    ['increment', 1,
        'When aggregating times for events and action entries, if',
        'the actual number of minutes is m and the increment is i, then',
        'the number of minutes added will be ceil(m/i)*i. E.g. if m=20',
        'and i=15, then ceil(20.0/15.0)*15 = 30 minutes will be added.'],
    ['hours_minutes', False,
        'Display time spent in time reports using hours and minutes (True)',
        'or hours rounded up to the nearest tenth (False).'],
    ['ledger_include', "1010",
        "Four digit string of the form CDKI where C, D, K and I are",
        "integers. Subtotal by category if C is positive and in an order",
        "corresponding to C. Subtotal by date if D is positive and in an",
        "order corresponding to D. Subtotal by keywords to a depth",
        "corresponding to the value of K if positive. E.g., if K is 2,",
        "and there is an item with keyword 'a:b:c', then subtotals",
        "corresponding to 'a' and 'a:b' would be formed."],
    ['use_ampm', True,
        'Display time using 12 hour, AM/PM format (True) or 24 hour format',
        '(False)'],
    ['sundayfirst', True,
        'Make Sunday the first day of the week if true (True)'],
    ['opening', "8:00a",
        'The opening or earliest time to consider, by default, in displaying ',
        'unscheduled periods'],
    ['closing', "5:00p",
        'The closing or latest time to consider, by default, in displaying ',
        'unscheduled periods'],
    ['busy_include', "1010",
        "Four digit string of the form bBfF where b, B, f and F are",
        "either 0 or 1. Include busy time bars if b = 1; include busy",
        "times if B = 1; include free time bars if f = 1; include free",
        "times if F = 1."],
    ['minimum', 30,
        'The minimum number of minutes for an free (unscheduled) period to',
        'be displayed'],
    ['wrap', 15,
        'The number of minutes before and after busy periods to omit',
        'in computing free periods'],
    ['busychar', '*',
        'The character used to indicate busy periods'],
    ['freechar', '-',
        'The character used to indicate free periods'],
    ['conflictchar', '#',
        'The character used to indicate a more than one event',
        'scheduled for the same time period'],
    ['charMinute', 12,
        'The number of minutes expressed by one character in busy/free time',
        'bars. It must be true that 60 % charMinute = 0. Recommended choices', 
        'are 10, 12 or 15. Using the default, 12, the time bar for 8am - 8pm',
        'would be 12*(60/12) = 60 characters wide. Using 10, the same 12',
        'hour time bar would be 12*(60/10) = 72 characters wide.'],
    ['main_history', [
        '-g d -o fnr', '-g c -o fnr', '-g k -o fnr',
        '-g d -o afnru', '-g c -o afnru', '-g k -o afnru',
        '-g d -o abfnruw', '-g c -o abfnruw', '-g k -o abfnruw',
        ], 
        'A list of option strings to include in the history list for',
        'agenda view.'],
    ['item_history', ['set items for this list in "item_history"'], 
        'A list of option strings to include in the history list for',
        'item view.'],
    ['busy_history', ['set items for this list in "busy_history"'], 
        'A list of option strings to include in the history list for',
        'busy/free view.'],
    ['data_history', ['set items for this list in "data_history"'], 
        'A list of option strings to include in the history list for',
        'data view.'],
    ['ledger_history', ['set items for this list in "ledger_history"'], 
        'A list of option strings to include in the history list for',
        'ledger view.'],
    ['actn_tmpl', ['set items for this list in "actn_tmpl"'],
        'Templates',
        'Items in these lists appear in the relevant drop-down list after',
        'pressing TAB. E.g., items in the "actn_tmpl" list would appear',
        'when entering options for an action. Abbreviation expansion is',
        'supported in all templates so that if the relevant template list',
        'contains an expression in the form "X:Y" where "X" is an,',
        'abbreviation containing only letters and numbers and "Y" is an',
        'arbitrary replacement string, then entering X and pressing TAB',
        'would result in X being replaced by Y.',
        '',
        'A list of templates for new actions.'],
    ['evnt_tmpl', ['set items for this list in "evnt_tmpl"'],
        'A list of templates for new events.'],
    ['task_tmpl', ['set items for this list in "task_tmpl"'],
        'A list of templates for new tasks.'],
    ['note_tmpl', ['set items for this list in "note_tmpl"'],
        'A list of templates for new notes.'],
    ['rmdr_tmpl', ['set items for this list in "rmdr_tmpl"'],
        'A list of templates for new reminders.'],
    ['proj_tmpl', ['set items for this list in "proj_tmpl"'],
        'A list of templates for new projects.'],
    ['weekday_fmt', '%a, %b %d',
        'The format to use for the date when grouping by date using the' 'following directives: ',
        '%a:  Locale\'s abbreviated weekday name.',
        '%A:  Locale\'s full weekday name.',
        '%b:  Locale\'s abbreviated month name.',
        '%B:  Locale\'s full month name.',
        '%c:  Locale\'s appropriate date and time representation.',
        '%d:  Day of the month as a decimal number [01,31].',
        '%H:  Hour (24-hour clock) as a decimal number [00,23].',
        '%I:  Hour (12-hour clock) as a decimal number [01,12].',
        '%j:  Day of the year as a decimal number [001,366].',
        '%m:  Month as a decimal number [01,12].',
        '%M:  Minute as a decimal number [00,59].',
        '%p:  Locale\'s equivalent of either AM or PM.',
        '%S:  Second as a decimal number [00,61].',
        '%U:  Week number of the year (Sunday as the first day of the week) as a',
        '     decimal number [00,53]. All days in a new year preceding the first',
        '     first Sunday are considered to be in week 0.',
        '%w:  Weekday as a decimal number [0(Sunday),6].',
        '%W:  Week number of the year (Monday as the first day of the week) as a',
        '     decimal number [00,53]. All days in a new year preceding the first',
        '     Monday are considered to be in week 0.',
        '%x:  Locale\'s appropriate date representation.',
        '%X:  Locale\'s appropriate time representation.',
        '%y:  Year without century as a decimal number [00,99].',
        '%Y:  Year with century as a decimal number.',
        '%Z:  Time zone name (no characters if no time zone exists).',
        '%%:  A literal "%" character.'],
    ['week_begin', 6,
        'The first day of the week. Monday = 0, Sunday = 6.'],
    ['basefontsize', d_basefont, 
        'The base font size'],
    ['htmlfont', d_htmlfont, 
        'The starting html font size'],
    ['htmlprintfont', d_htmlprintfont, 
        'The starting html printing font size'],
    ['calfontsize', d_calfont, 
        'The calendar font size. Ignored if set equal to 0.'],
    ['statusfontadj', d_statusfontadj, 
        'The adjustment for the status bar font'],
    ['listfontadj', d_listfontadj, 
        'The adjustment for the item list font'],
    ['datefontadj', d_datefontadj, 
        'The adjustment for the date (title) font'],
    ['first_column', 90, 
        'The widths of the first and second columns in the gui list view'],
    ['second_column', 70, ''],
    ['detail_bgcolor', d_bgcolor, 
            'The background color for the detail (information) bar',
            'in the etm wx gui'],
    ['detail_fgcolor', 'Black', 
            'The foreground color for the detail (information) bar',
            'in the etm wx gui'],
    ['entry_fgcolor', 'Black', 
            'The foreground color for the entry bar',
            'in the etm wx gui'],
    ['entry_bgcolor', 'White', 
            'The background color for the entry bar',
            'in the etm wx gui'],
    ['main_bgcolor', 'White', 
            'The background color for the main window and the entry bar',
            'in the etm wx gui'],
    ['main_fgcolor', 'Black', 
            'The default foreground color for the main window',
            'in the etm wx gui'],
    ['busycolor', d_busycolor, 
            'The background color for busy bars in the busy panel'],
    ['selectcolor', d_selectcolor, 
            'The background color for selected days in the calendar',
            'panel'],
    ['cal_pastcolor', '#FFCCCC',
        'The background color to use for past years in the',
        '12 month calendar'],
    ['cal_currentcolor', '#FFFFCC',
        'The background color to use for the current year in the',
        '12 month calendar'],
    ['cal_futurecolor', '#99CCFF',
        'The background color to use for future years in the',
        '12 month calendar'],
    ['event_color', '''%s''' % d_attrs['event'],
        'The colors for the command line (terminal) interface. Only',
        'the following colors are available: "black", "blue", "cyan",',
        '"gray", "green", "magenta", "red", "white" and "yellow"'],
    ['reminder_color', '''%s''' % d_attrs['reminder'], ''],
    ['action_color', '''%s'''   % d_attrs['action'], ''],
    ['task_pastdue_color', '''%s''' % d_attrs['task_pastdue'], ''],
    ['task_today_color', '''%s''' % d_attrs['task_today'], ''],
    ['task_soon_color', '''%s''' % d_attrs['task_soon'], ''],
    ['task_color', '''%s''' % d_attrs['task'], ''],
    ['task_undated_color', '''%s''' % d_attrs['task_undated'], ''],
    ['task_waiting_color', '''%s''' % d_attrs['task_waiting'], ''],
    ['task_beginby_color', '''%s''' % d_attrs['task_beginby'], ''],
    ['task_finished_color', '''%s''' % d_attrs['task_finished'], ''],
    ['note_color', '''%s''' % d_attrs['note'], ''],
    ['header_0_color', '''%s''' % d_attrs['header_0'], ''],
    ['header_1_color', '''%s''' % d_attrs['header_1'], ''],
    ['header_2_color', '''%s''' % d_attrs['header_2'], ''],
    ['header_3_color', '''%s''' % d_attrs['header_3'], ''],
    ['detail_color', '''%s''' % d_attrs['detail'], ''],
    ['Main', '"main"',
        'Language customizations:',
        'The word to use in the agenda view title bar.',],
    ['Item', '"item"',
        'The word to use in the item view title bar.'],
    ['Busy', '"busy"',
        'The word to use in the busy view title bar.'],
    ['Data', '"data"',
        'The word to use in the data view title bar.'],
    ['Ledger', '"ledger"',
        'The word to use in the time ledger title bar.'],
    ['Options', '"options"',
        'The word to use in the prompt for options.'],
    ['NoDueDate', '"Without a due date"',
        'The group title for items without a due date.'],
    ['Quit', '"Quit"',
        'The word to use for quit in the command line.'],
    ['Help', '"Help"',
        'The word to use for help in the command line.'],
    ['minutes', 'minutes from now',
        'In alerts, the string to append for more than one minute'],
    ['minute', 'minute from now',
        'In alerts, the string for exactly one minute'],
    ['rightnow', '',
        'In alerts, the string to use for this instant'],
    ['thetimeis', '"The time is"',
        'The prefix for the spoken time'],
    ['location', ['Chapel Hill', 'NC'],
        'The USNO location for sun/moon data. Either a US city-state',
        '2-tuple such as [\'Chapel Hill\', \'NC\'] or',
        'a placename-longitude-latitude 7-tuple such as ',
        '[\'Home\', \'W\', 79, 0, \'N\', 35, 54]',
    ],
    ['weatherlocation', 'USNC0105&u=f',
    'The yahoo weather location code and temperature scale for your area.',
    'Go to http://weather.yahoo.com/, enter your location and hit return.',
    'When the weather page for your location opens, choose view source ',
    '(under the View menu), search for \'forecastrss\' and copy the ',
    'location code that follows \'p=\', e.g., for',
    '       ...forecastrss?p=USNC0120&u=f',
    'the location code would be \'USNC0120&u=f\'. Note: the \'&u=f\'',
    'gives fahrenheit readings while \'&u=c\' would give celcius/centigrade.'],
    ['rising', 'rising', 'Phrase for the barometric pressure is increasing'],
    ['constant', 'steady', 'Phrase for the barometric pressure is constant'],
    ['falling', 'falling', 'Phrase for the barometric pressure is decreasing'],
    ['chill', 'feels like', 'Phrase for the wind chill temperature'],
    ['weather', 'Weather for', 'Phase for weather header'],
    ['current_conditions', 'Current conditions', 'Phrase for current conditions'],
    ['forecast', 'Forecast', 'Phrase for forecast'],
    ]

# main
# set enable_tracing = True in ~/.etm/rc to enable tracing
enable_tracing = False
etmrc = set_etmrc()
if has_etmrc:
    etmrc_fo = open(etmrc, 'r')
    exec(etmrc_fo)
    etmrc_fo.close()

for variable in variables:
    check(variable)

# This is more trouble than it's worth. Removed for 692, 2011-01-03
#  try:
    #  if sys.stdout.encoding.lower() != encoding.lower():
        #  try to reset stdout to the encoding specified in etmrc
        #  try:
            #  old_stdout = sys.stdout
            #  old_encoding = sys.stdout.encoding
            #  codec = codecs.lookup(encoding)
            #  new_stdout = codec[-1](sys.stdout)
            #  new_encoding = new_stdout.encoding
            #  sys.stdout = new_stdout
            #  print("""\
    #  Warning. The encoding of sys.stdout, '%s', does not match the setting
    #  for 'encoding' in ~/.etm/rc, '%s'. Using '%s'.""" % 
            #  (sys.stdout.encoding.lower(), encoding.lower(), new_encoding))
        #  except:
            #  print("""\
    #  Error. Output using encoding '%s' is not supported by your terminal.
    #  Please correct the setting for 'encoding' in ~/.etm/etmrc.
    #  Using encoding '%s' instead.
    #  """ % (encoding, sys.stdout.encoding))
            #  sys.stdout = old_stdout
#  except:
    #  pass

check_etmdir()
check_etmdata()
check_export()
check_file(contextsFile)
check_file(keywordsFile)
check_dir(etmdata, etmActions, action)
check_dir(etmdata, etmEvents, event)
check_dir(etmdata, etmReminders, reminder)
check_dir(etmdata, etmTasks, task)
check_dir(etmdata, etmDone, done)
check_dir(etmdata, etmNotes, note)

if fatal:
    sys.exit()

# show_ptitle = True
show_ptitle = False

tracing_log = None
if enable_tracing:
    tracinglog = os.path.join(etmdir, 'tracing.log')
    tracing_log = open(tracinglog, "w", True)
    print "Tracing enabled. Writing to '%s'." % tracinglog

if len(added) > 0:
    if has_etmrc:
        import shutil
        shutil.copyfile(etmrc, "%s.bak" % etmrc)
        make_etmrc()
        etmrc_fo = open(etmrc, 'r')
        exec(etmrc_fo)
        etmrc_fo.close()
        print """\
IMPORTANT: Your configuration file

    %s

has as been copied to

    %s.bak

and a new configuration file which incorporates your settings together
with

    %s

has been saved as

    %s \n""" % (etmrc, etmrc, "\n    ".join(added), etmrc)

    else:
        make_etmrc()
        print("""\
A new configuration file with default settings has been saved as

    %s \n""" % etmrc)

    if zone_msg:
        print "%s" % zone_msg


    print """\
Please remember to vote for etm at <http://freshmeat.net/projects/etm/>
and to send your comments to <daniel.graham@duke.edu>. Continuing
improvement depends upon your feedback.

Thanks for using etm!
"""
    if warning:
        sys.exit()