# etmRC.py
# encoding: utf-8
import sys, os, os.path, codecs, locale, re
has_etmrc = False
from dateutil.tz import * 
import datetime
import shutil, fnmatch 

from dateutil.rrule import *
from dateutil.parser import parse
from dateutil.relativedelta import *

from platform import system
platform = system()

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

# set enable_tracing = True in ~/.etm/rc to enable tracing
enable_tracing = False

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

d_file_encoding = 'UTF8'
file_encoding = d_file_encoding 

(yr,mn,dy) = tuple(map(int, datetime.datetime.now().strftime("%Y,%m,%d").split(',')))
d_year_beg = 1
d_year_end = 5

rc = []
added = []
msg = []
error = []
warn = []
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, "etmrc")
if os.path.isfile(etmrc_maybe):
    oldrc = None
    etmrc = etmrc_maybe
    etmdir = d_etmdir = cwd
    d_etmdata = cwd
    export = d_export = cwd
else:
    oldrc = os.path.join(homedir, ".etm", "rc")
    etmrc = os.path.join(homedir, ".etm", "etmrc")
    etmdir = d_etmdir = os.path.join(homedir, ".etm")
    d_etmdata = os.path.join(etmdir, "etmdata")
    export = d_export = os.path.join(etmdir, "export")

if windoz:
    # hack to keep windoz from treating, e.g. '\n' in '\etmdata\notes' 
    # as a newline character instead of a path separator
    d_etmActions = os.path.join(etmdir, "etmdata", "MONTHLY")
    d_etmEvents  = os.path.join(etmdir, "etmdata", "MONTHLY")
    d_etmTasks   = os.path.join(etmdir, "etmdata", "MONTHLY")
    d_etmNotes   = os.path.join(etmdir, "etmdata", "MONTHLY")
    abbreviations = os.path.join(etmdir, "ABBREVIATIONS.TXT")

else:
    d_etmActions = os.path.join(etmdir, "etmdata", "monthly")
    d_etmEvents  = os.path.join(etmdir, "etmdata", "monthly")
    d_etmTasks   = os.path.join(etmdir, "etmdata", "monthly")
    d_etmNotes   = os.path.join(etmdir, "etmdata", "monthly")
    abbreviations = os.path.join(etmdir, "abbreviations.txt")
if sys.platform == 'darwin':
    mac = True
    d_fgcolor = 'BLACK'
    d_bgcolor = 'WHITE'
    d_selectcolor = [56, 139, 32, 48]
    d_busycolor = [56, 139, 32]
    d_basefont = 12
    d_busyfont = 10
    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_fgcolor = 'BLACK'
    d_bgcolor = 'WHITE'
    d_selectcolor = [160, 255, 144, 128]
    d_busycolor = [0, 160, 0]
    d_basefont = 9
    d_busyfont = 7
    d_htmlfont = 5
    d_htmlprintfont = 6
    d_calfont = 9
    d_width = 640
    d_height = 360
    d_statusfontadj = 0
    d_listfontadj = 0
    d_datefontadj = 0

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

d_guicolors = {
    'allday'   : ( 60, 179, 113),
    'reminder' : (205, 105, 201),
    'action'   : (  0, 139, 139),
    'event'    : ( 46, 139,  87),
    'pastdue'  : (176,  23,  31),
    'waiting'  : (250, 128, 114),
    'task'     : ( 65, 105, 225),
    'undated'  : (100, 149, 237),
    'begin'    : (132, 112, 255),
    'finished' : (141, 182, 205),
    'note'     : ( 48, 128,  20),
    'details'  : (110, 110, 110),
    'header_1' : (  0,   0, 128),
    'header_2' : (  0,   0, 205),
    'header_3' : (  0,   0, 255),
    }

holidays = """us holidays 
* Martin Luther King Day @d 2010-01-18 @r y @M 1 @w MO(3)
* Valentine's Day @d 2010-02-14 @r y @M 2 @m 14
* President's Day @c holiday @d 2010-02-15 @M 2 @r y @w MO(3)
* Daylight saving time begins @d 2010-03-14 @z US/Eastern @r y @M 3 @w SU(2)
* St Patrick's Day @d 2010-03-17 @r y @M 3 @m 17
* Easter @r l @+ (2011-04-24, 2012-04-08, 2013-03-31, 2014-04-20, 2015-04-05, 2016-03-27)
* Mother's Day @d 2010-05-09 @r y @M 5 @w SU(2)
* Memorial Day @d 2010-05-31 @r y @M 5 @w MO(-1)
* Father's Day @d 2010-06-20 @r y @M 6 @w SU(3)
* Independence Day @d 2010-07-04 @r y @M 7 @m 4
* Labor Day @d 2010-09-06 @r y @M 9 @w MO(1)
* Daylight saving time ends @d 2010-11-01 @r y @M 11 @w SU(1)
* Thanksgiving @d 2010-11-26 @r y @M 11 @w TH(4)
* Christmas @d 2010-12-25 @r y @M 12 @m 25""".split('\n')

examples = """etm examples @u !30!
! etm examples @n The file 'examples.text' contains this note
and other examples of etm usage. This temporary file can be removed
whenever convenient.
* Sunday afternoon and evening event @d !U! @r w @w SU @s 4:00p @e +4:00 @l home
* Friday morning meeting @d !F! @r w @w FR @s 8:00a @e +1:00 @l Bean and Barrel
* Tuesday early morning event @d !T! @r w @w TU @s 8:00a @e +1:30 @l club @a (30, 15)
* Tuesday/Thursday morning and afternoon events @d !T! @r w @w (TU, TH) @s (10:05a, 2:50p) @e +1:15 @a (10, 2) @l 10.113
* Thursday noon event @d !h! @r w @i 2 @w TH @s 12:00p @e +1:15 @a (10, 2) @l 10.113
* Friday night event @d !F! @r w @w FR @s 7:00p @e +2:00 @l Lumina Theater
* Alert test @d !0! @s !s! @a (15, 5, 0)
* Monday, Wednesday, Friday late afternoon event @d !W! @r w @w (MO, WE, FR) @s 5p @e +1h @l club
- Take out trash @d !H! @l home @r w @w TH @o s
- Water house plants @d !-5! @r d @i 4 @o r @f (!0!) @l home @n finished today when one day past due, should be due again !4!.
- borrow tools from Ed @d !a! @l home @n This task and 'pick up' are both prerequisites for 'fix'. 
+ pick up door hardware @c errands @d !a! @l home @n This task and 'borrow' are both prerequisites for 'fix'. 
-- fix door @c home @d !a! @l home @n Both 'borrow' and 'pick up' are prerequisites for this task. Finish each of the prerequisites by selecting it, pressing 'f' and then Shift-Return and note the change in color (status) of this task when both of it's prerequisites have been completed. 
--- return tools to Ed @l home @d !a! @n The three tasks 'borrow', 'pick up' and 'fix' are all prerequisites for this task. Finish all the prerequisites and note the change in color (status) of this task.
- Promote etm @d !14! @b 14 @g http://freshmeat.net/projects/etm/ @n Fourteen days after installing etm you should be ready to rave about it. Press 'g' with this note selected to visit Freshmeat where you can comment upon and vote 'thumbs up' for etm.""".split('\n')


try:
    from os.path import relpath
except ImportError: # python < 2.6
    from os.path import curdir, abspath, sep, commonprefix, pardir, join
    def relpath(path, start=curdir):
        """Return a relative version of a path"""
        if not path:
            raise ValueError("no path specified")
        start_list = abspath(start).split(sep)
        path_list = abspath(path).split(sep)
        # Work out how much of the filepath is shared by start and path.
        i = len(commonprefix([start_list, path_list]))
        rel_list = [pardir] * (len(start_list)-i) + path_list[i:]
        if not rel_list:
            return curdir
        return join(*rel_list)

def checkRotating():
    """
        Check and, if necessary, update rotating files. Return a hash with
        keys in the item types [action, note, event, task] giving the full path 
        to the current rotating file for the item type.
    """
    currentHash = {}
    thisyear, thismonth, month_name = datetime.datetime.today().strftime(
            "%Y,%m,%B").split(',')
    for n, (t, d) in rotate.items():
        if d:
            if not os.path.isdir(d):
                os.makedirs(d)
            curdir = os.path.join(d, thisyear, thismonth)
            if not os.path.isdir(curdir):
                os.makedirs(curdir)
            curfile = os.path.join(curdir, "%s.text" % t)
            curstr = "%s file for %s %s" % (n, month_name, thisyear)
        else:
            # we're not using rotating files
            if not os.path.isdir(etmdata):
                os.makedirs(etmdata)
            curfile = os.path.join(etmdata, "%s.text" % t)
            curstr = "%s file" % n
        if not os.path.isfile(curfile):
            fo = codecs.open(curfile, 'w', file_encoding)
            fo.write("%s\n" % curstr)
            fo.close()
        currentHash[n] = curfile
    return(currentHash)

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

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_examples():
    txtfile = os.path.join(etmdata, 'etm-examples.text')
    date_regex = re.compile(r'\!(\-?\d+)\!')
    start_regex = re.compile(r'\!s\!')
    weekday_regex = re.compile(r'\!([a-z]{3})\!')
    nextday_regex = re.compile(r'\!([mtwhfau])\!')
    lastday_regex = re.compile(r'\!([MTWHFAU])\!')
    etmdir_regex = re.compile(r'etmdir\s*=')
    etmdata_regex = re.compile(r'etmdata\s*=')
    etmActions_regex = re.compile(r'etmActions\s*=')
    etmEvents_regex = re.compile(r'etmEvents\s*=')
    etmNotes_regex = re.compile(r'etmNotes\s*=')
    etmTasks_regex = re.compile(r'etmTasks\s*=')
    export_regex = re.compile(r'export\s*=')

    oneday = datetime.timedelta(days=1)
    today = datetime.date.today()
    now = datetime.datetime.now()
    hr, min, sec = (now.strftime("%H,%M,%S")).split(",")

    # added to current time, this will produce an even quarter hour at least 
    # 15 minutes from now. Used to test alerts. 
    min = 15-int(min)%15 + 15
    sec = int(sec)

    starttime = (now + relativedelta(minutes=+min,seconds=-sec)).strftime("%I:%M%p")

    monday = parse('mon') # the date of the next monday on or after today
    nextday = {}
    nextday['m'] = monday               # match !m!
    nextday['t'] = monday + oneday      # match !t!
    nextday['w'] = monday + 2*oneday    # match !w!
    nextday['h'] = monday + 3*oneday    # match !h!
    nextday['f'] = monday + 4*oneday    # match !f!
    nextday['a'] = monday + 5*oneday    # match !a!
    nextday['u'] = monday + 6*oneday    # match !u!

    MONDAY = monday - 7*oneday # the last monday before today
    lastday = {}
    lastday['M'] = MONDAY               # match !M!
    lastday['T'] = MONDAY + oneday      # match !T!
    lastday['W'] = MONDAY + 2*oneday    # match !W!
    lastday['H'] = MONDAY + 3*oneday    # match !H!
    lastday['F'] = MONDAY + 4*oneday    # match !F!
    lastday['A'] = MONDAY + 5*oneday    # match !A!
    lastday['U'] = MONDAY + 6*oneday    # match !U!

    lines = examples
    p_line = lines[0]
    for i in range(len(lines)):
        s = lines[i]
        s = start_regex.sub(starttime, s)
        m = date_regex.search(s)
        r = date_regex.finditer(s)
        t = list(s)
        for m in r:
            d = m.expand('today + \\1 * oneday')
            d = eval(d)
            d = d.strftime("%Y-%m-%d")
            ms = m.start()
            me = m.end()
            t[ms] = d
            for j in range(ms+1, me):
                t[j] = ''
            lines[i] = ''.join(t)
        # w = weekday_regex.search(s)
        x = weekday_regex.finditer(s)
        for w in x:
            d = w.expand('parse("\\1")')
            d = eval(d)
            d = d.strftime("%Y-%m-%d")
            ws = w.start()
            we = w.end()
            t[ws] = d
            for j in range(ws+1, we):
                t[j] = ''
            lines[i] = ''.join(t)
        y = nextday_regex.finditer(s)
        for w in y:
            k = w.expand("\\1")
            d = nextday[k]
            d = d.strftime("%Y-%m-%d")
            ws = w.start()
            we = w.end()
            t[ws] = d
            for j in range(ws+1, we):
                t[j] = ''
            lines[i] = ''.join(t)
        z = lastday_regex.finditer(s)
        for w in z:
            k = w.expand("\\1")
            d = lastday[k]
            d = d.strftime("%Y-%m-%d")
            ws = w.start()
            we = w.end()
            t[ws] = d
            for j in range(ws+1, we):
                t[j] = ''
            lines[i] = ''.join(t)
    fo = codecs.open(txtfile, 'w', file_encoding)
    fo.writelines("\n".join(lines))
    fo.close()
    print "Created '%s'" % txtfile

def make_holidays():
    holidayfile = os.path.join(etmdata, 'usholidays.text')
    if not os.path.isfile(holidayfile):
        fo = codecs.open(holidayfile, 'w', file_encoding)
        fo.writelines("\n".join(holidays))
        fo.close()
        print "Created '%s'" % holidayfile

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 and zinfo == linfo:
                possible.append((z, abbr))
                break
    if not possible:
        for z in zones:
            zinfo = gettz(z)
            if zinfo and 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] != "":
                if windoz:
                    s = "%s = r'''%s'''" % (name, globals()[name])
                else:
                    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 != "":
                    if windoz:
                        s = "%s = r'''%s'''" % (name, res)
                    else:
                        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 = """Attempting to set the local time zone %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, has_etmrc

def check_newinstall():
    has_oldrc = False
    if oldrc and os.path.isfile(oldrc):
        has_oldrc = True
    has_etmrc = False
    if os.path.isfile(etmrc):
        has_etmrc = True
    if not has_etmrc:
        # this is the first install of 800+
        if has_oldrc:
            # there is an old rc file => this is an upgrade
            # get old data
            print "reading old configuration file: '%s'" % oldrc
            oldrc_fo = codecs.open(oldrc, 'r', file_encoding)
            string = "\n".join(oldrc_fo.readlines())
            oldrc_fo.close()
            exec(string)
            paths = []
            try:
                if etmActions:
                    paths.append(etmActions)
            except:
                print "    etmActions not defined - skipping update"
            try:
                if etmEvents:
                    paths.append(etmEvents)
            except:
                print "    etmEvents not defined - skipping update"
            try:
                if etmNotes:
                    paths.append(etmNotes)
            except:
                print "    etmNotes not defined - skipping update"
            try:
                if etmTasks:
                    paths.append(etmTasks)
            except:
                print "    etmTasks not defined - skipping update"
            try:
                paths.append(etmdata)
            except:
                print "    etmdata not defined - skipping update"
                etmdata = d_etmdata
                check_etmdata()
            if len(paths) > 0:
                common_prefix = os.path.commonprefix(paths)
                pattern='[!.]*.txt'
                filelist = []
                print "paths", paths
                for d in paths:
                    if d:
                        for path, subdirs, names in os.walk(d, followlinks=True):
                            for name in names:
                                if fnmatch.fnmatch(name, pattern):
                                    full_path = os.path.join(path,name)
                                    rel_path = relpath(full_path, common_prefix)
                                    tup = (full_path, rel_path)
                                    filelist.append(tup)
                print "Copying %s old *.txt files from\n  %s\nto\n  %s" % \
                        (len(filelist), etmdata, d_etmdata)
                for oldpath, newfile in filelist:
                    newpath = os.path.join(d_etmdata, newfile)
                    dirname = os.path.dirname(newpath)
                    if not os.path.isdir(dirname):
                        os.makedirs(dirname)
                    if os.path.isfile(newpath):
                        print "    skipping %s\n      %s already exists" % (
                                oldpath,
                                newpath
                                )
                    else:
                        print "    copying %s\n      to %s" % (oldpath, newpath)
                        shutil.copyfile(oldpath, newpath)
                # we need now to run old2new on d_etmdata
                walkdir(d_etmdata)
    return(has_oldrc, has_etmrc)

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

def check_etmdata():
    try:
        etmdata
    except:
        etmdata = d_etmdata
    if not os.path.isdir(etmdata):
        os.makedirs(etmdata)
        print("""Created '%s' to hold project files.""" % etmdata)
    return os.path.isdir(etmdata)

def check_dir(p, d, s):
    if d:
        try:
            if not os.path.isdir(d):
                os.makedirs(d)
                print("""\
            Created '%s' to use as the default location for %s files.""" % (d, s))
            return os.path.isdir(d)
        except:
                print("""
            Error: could not create '%s' for %s files.
            \n""" % (d, s))

def check_export():
    if not os.path.isdir(export):
        os.makedirs(export)
        print("""Created '%s' to hold exported files.""" % export)
    return os.path.isdir(export)

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

def set_editor_settings(term=False):
    if term:
        editor = "term_editor"
        editcmd = "term_editcmd"
    else:
        editor = "editor"
        editcmd = "editcmd"

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

            %s
            %s

        in %s.\n""" % (editor, editcmd, etmrc))
    else:
        print("""
The following settings were made for your external editor:

    %s = '%s'
    %s = '%s'

Edit %s if you wish to make changes.\n""" % (
        editor, selected[0], editcmd, 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(term):
    if not set_ed:
        set_editor_settings(term)
    return "not set"

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

def make_xlat(d):
    adict = d
    rx = re.compile('|'.join(adict))
    def one_xlat(match):
        return adict[match.group(0)]
    def xlat(text):
        return rx.sub(one_xlat, text)
    return xlat

def walkdir(path):
    global numfiles, numlines, numchanges
    encoding = d_file_encoding 
    numfiles = 0
    numlines = 0
    numchanges = 0
    amper = re.compile(r'^&')
    under = re.compile(r'^(_+)')
    period = re.compile(r'^(\.+)')
    # to remove any any white space following '@e +'
    extent = re.compile(r'@e \+\s+')
    sdict = {
        '@l(?=\s*\()' : '@+', # include list
        '@x' : '@-', # exclude list
        '@p' : '@e +', # action period -> +extent
            }
    translate = make_xlat(sdict)
    print "Updating old data files to new format and changing the extension from *.txt to *.text"
    for path, subdirs, names in os.walk(path):
        for name in names:
            level = 1
            if fnmatch.fnmatch(name, '[!.]*.txt'):
                changed = False
                f = os.path.join(path,name)
                sf = f[len(path)+1:]
                newf = "%s.text" % os.path.splitext(f)[0]
                if os.path.isfile(newf):
                    print "    Skipping %s\n      %s already exists" % (
                            f, newf)
                    continue
                numfiles += 1
                # use the relative path as the key
                fo = codecs.open(f, 'r', file_encoding)
                lines = fo.readlines()
                fo.close()
                changes = []
                for i in range(len(lines)):
                    numlines += 1
                    old_line = lines[i].rstrip()
                    if not old_line:
                        continue
                    new_line = translate(old_line)
                    new_line = extent.sub('@e +', new_line)
                    new_line = amper.sub('*', new_line)     # old rem -> event
                    m = under.match(new_line)
                    if m:
                        new_line = under.sub('+'*len(m.group(0)), new_line)
                    m = period.match(new_line)
                    if m:
                        new_line = period.sub('-'*len(m.group(0)), new_line)
                    if new_line != old_line:
                        numchanges += 1
                        changes.append("    line %s: " % i)
                        changes.append("        '%s'" % old_line)
                        changes.append("     => '%s'" % new_line) 
                        lines[i] = "%s\n" % new_line
                        changed = True
                if changed:
                    print "  Made the following changes in '%s':" % f
                    for l in changes:
                        print l
                    fo = codecs.open(f, 'w', file_encoding)
                    fo.writelines(lines)
                    fo.close()
                shutil.move(f, newf)
                print "  '%s' => '%s'" % (f, newf)

    if numchanges:
        print("Made %s changes in %s lines from %s files" % 
                (numchanges, numlines, numfiles))
    else:
        print("No changes were needed in %s lines from %s files." 
                % (numlines, numfiles))


def make_etmrc():
    fo = codecs.open(etmrc, 'w', file_encoding)
    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.decode(file_encoding))
    fo.close()
    print "Created '%s'" % etmrc

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:',
        '    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.'],
    ['etmdir', "%s" % d_etmdir,
        'The directory in which configuration files will be stored.'],
    ['etmdata', "%s" % d_etmdata,
        'The directory in which project files will be stored.'],
    ['etmActions', "%s" % d_etmActions,
        'Directories for monthly files',
        'If a directory (full path) is given and not equal to "", the directory',
        'will be used for monthy files. E.g., if etmActions = ETMACTIONS, then',
        'in August 2011, the directories and file',
        '             ETMACTIONS/2011/08/actns.text                 ',
        'will be created, if necessary, as the default file for actions',
        'created during the month and this process would repeat in subsequent',
        'months. If, on the other hand, etmActions = "", then the file',
        '             ETMDATA/actns.text                           ',
        'would be used as the (permanent) default for actions.  ',
        '',
        'The directory for monthy user action files.'],
    ['etmEvents',  "%s" % d_etmEvents,
        'The directory for monthly user event files.'],
    ['etmTasks',  "%s" % d_etmTasks,
        'The directory for monthly user task files.'],
    ['etmNotes',  "%s" % d_etmNotes,
        'The directory for monthly user note files.'],
    ['export', "%s" % d_export,
        'The directory in which exported exported iCal/vCal and CSV',
        'files will be stored.'],
    ['abbreviationsFile', "%s" % abbreviations,
        'The path to the file in which abbreviations will be stored.',
        'This is a plain text file with one abbreviation per line',
        'in the format "X|Y" where X is an alpha-numeric string without',
        'spaces (the abbreviation) and Y is the replacement string.',
        'occurrences of ":X:" will then be replaced by "Y", e.g., if',
        'abbreviations.txt contains the line "chtc|Chapel Hill Tennis Club"',
        'then ":chtc:" in an item would become "Chapel Hill Tennis Club".'],
    ['contextsFile', "%s" % os.path.join(d_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.'],
    ['addFileContexts', True,
        'If true, the selection list for contexts will include those from',
        'data files as well as those from "contextsFile".'],
    ['keywordsFile', "%s" % os.path.join(d_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.'],
    ['addFileKeywords', True,
        'If true, the selection list for keywords will include those from',
        'data files as well as those from "keywordsFile".'],
    ['locationsFile', "%s" % os.path.join(d_etmdir, "locations.txt"),
        'The path to the file in which default locations will be stored.',
        'This is a plain text file with one location per line.'],
    ['addFileLocations', True,
        'If true, the selection list for locations will include those from',
        'data files as well as those from "locationsFile".'],
    ['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, ''],
    ['actions', '"actns"',
        'The root for action data files. By default new actions will be',
        'saved to "<etmActions>/<current year>/<current month>-ACTIONS.text"'],
    ['events', '"evnts"',
        'The root for event data files. By default new events will be',
        ' saved to "<etmEvents>/<current year>/<current month>-EVENTS.text"'],
    ['notes', '"notes"',
        'The root for note data files. By default new notes will be',
        ' saved to "<etmNotes>/<current year>/<current month>-NOTES.text"'],
    ['tasks', '"tasks"',
        'The root for task data files. By default new tasks will be',
        ' saved to "<etmTasks>/<current year>/<current month>-TASKS.text"'],
    ['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()', ''],
    ['term_editor', '"%s" % set_editor(True)',
        'Terminal Edit settings',
        'term_editor:  the full path to the external editor to use in the',
        'terminal with the command line interface'
        'term_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'     ],
    ['term_editcmd', '"%s" % set_editcmd(True)', ''],
    ['show_nums', True, 
        'Show item numbers by default in the interactive command line',
        'interface. These nubers can be used to modify items.'],
    ['use_colors', True, 
        'Use colors by default in the interactive command line interface.'],
    ['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.'],
    ['action_interval', 6,
        'If positive, an alert will be sounded every action_interval',
        'minutes while the action timer is running.' ],
    ['increment', 1,
        'When using the timer for action entries, record times rounded up',
        'to this number of minutes.  E.g. if the timer shows 20 minutes when',
        'stopped and increment = 6, then 24 minutes will recorded as the',
        'extent of the action.'],
    ['display_totals_fmt', 2,
        'Display time totals using (1) hours and tenths, (2) hours and',
        'minutes or (3) minutes.'],
    ['file_totals_fmt', 2,
        'Display time totals using (1) hours and tenths, (2) hours and',
        'minutes or (3) minutes.'],
    ['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:00am',
        'The opening or earliest time to consider, by default, in displaying ',
        'free periods'],
    ['closing', '5:00pm',
        'The closing or latest time to consider, by default, in displaying ',
        'free periods'],
    ['include', "Bfc",
        "String containing one or more characters from b, B, f, F and c.",
        "Include B)usy time bars, b)usy times, F)ree time bars, f)free times",
        "c)onflict times."],
    ['minimum', 30,
        'The minimum number of minutes for a free block of time 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'],
    ['slotsize', 12,
        'The number of minutes expressed by one character in busy/free time',
        'bars. It must be true that 60 % slotsize = 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.'],
    ['display_shortcuts', ['o -g ((y,m,d),)', 'o -g (c, (y,m,d), T) -T -d 0', 'o -g F',], 
        'A list of at most 10 strings for quickly setting options for',
        'outline and busy views. Begin option strings with an "o"',
        'for outline view and a "b" for busy view. The items ',
        'from this list are bound to the hotkeys 0, ..., 9. E.g., if', 
        'the first item begins with "o" then pressing "0" would open ',
        'outline view with the first item inserted.',
        ],
    #  ['google_password', '',
        #  'Google Calendar sync options. To get the information you need for',
        #  'these options, login to your Google Calendar account and click ',
        #  'on the menu button to the right of the calendar under "My Calendars"',
        #  'that you would like to sync. Then, from the drop down menu, select',
        #  '"Calendar Settings". Near the bottom of the page that opens, you',
        #  'will see a line with "Calendar Address", colored links for "XML",',
        #  '"ICAL" and "HTML" and then your Google Calendar Id to the right.',
        #  'Enter your password, the Calendar ID and the "ICAL" url below.',
        #  '(Hint: You can Control-Click on "ICAL" to copy the address to your',
        #  'clipboard and then paste it below.)',
        #  '',
        #  'Your Google Calendar password. If this is left empty, you will be',
        #  'prompted for your password when you sync.'],
    #  ['google_calendarid', '',
        #  'Your Google Calendar ID.'],
    #  ['google_icalurl', '',
        #  'Your Google ICAL url.'],
    ['item_templates', ['set items for this list in "item_templates"'],
        'Option Templates',
        'Items in these lists appear in the relevant drop-down list after',
        'pressing CTRL-TAB. I.e, items in the "item_templates" list when', 
        'entering options for an action, event, note or task and items in',
        '"display_templates" list when entering options for outline or busy',
        'views. The selection list is limited to those items which match',
        'the last display option or the last item field, if possible, and',
        'otherwise the entire entry. E.g., entering "@r" when setting the',
        'options for an event and pressing CTRL-TAB would display those', 
        'entries from "item_tmplates" that begin with "@r". Alternatively',
        'entering "* tennis" and pressing CTRL-TAB would display those',
        'entries from "item_templates that begin with "* tennis". Note that',
        'making a selection from the list would replace the entire match',
        'with the selection.',
        '',
        'A list of templates for actions, events, notes and tasks options.'],
    ['display_templates', ['set items for this list in "display_templates"'],
        'A list of option templates for outline and busy view options.',
        'Option settings from the current session are appended to this',
        'list.' ],
    ['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.'],
    ['year_beg', d_year_beg,
        'Data period',
        'All occurrences of non-repeating items and all occurrences of', 
        'repeating items with dates within the interval determined by', 
        'year_beg and year_end are available in all views. For repeating', 
        'items without dates in the interval, the first occurrence after', 
        'this interval and the last occurrence before this interval are also', 
        'available.'
        '',
        'Positive integer. Process items beginning with January 1 of the year',
        'that is this number of years BEFORE the current year. Default: %s' % \
        d_year_beg],
    ['year_end', d_year_end,
        'Positive integer. Process items ending with December 31 of the year',
        'that is this number of years AFTER the current year. Default: %s' % \
        d_year_end],
    ['basefontsize', d_basefont, 
        'The base font size'],
    ['busyfontsize', d_busyfont, 
        'The font size for the hour numbers in the busy panel'],
    ['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'],
    ['fgcolor', d_fgcolor, 
            'The background color for the etm wx gui'],
    ['bgcolor', d_bgcolor, 
            'The background color for 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'],
    ['gui_allday',  d_guicolors['allday'],
        'The colors for the gui outline panel and html fonts. Each must be',
        'given as a tuple of (r,g,b) integers.',
        '',
        'The color for all day events.'],
    ['gui_reminder',  d_guicolors['reminder'], 
        'The color for reminders (events with zero extent).'],
    ['gui_action',  d_guicolors['action'], 
        'The color for actions.'],
    ['gui_event',  d_guicolors['event'], 
        'The color for events.'],
    ['gui_pastdue',  d_guicolors['pastdue'], 
        'The color for pastdue tasks.'],
    ['gui_waiting',  d_guicolors['waiting'], 
        'The color for tasks with unfinished prerequisites.'],
    ['gui_undated',  d_guicolors['undated'], 
        'The color for undated tasks.'],
    ['gui_begin',  d_guicolors['begin'], 
        'The color for task begin by notices.'],
    ['gui_finished',  d_guicolors['finished'], 
        'The color for finished tasks.'],
    ['gui_task',  d_guicolors['task'], 
        'The color for dated tasks which are neither finished, pastdue nor',
        'have unfinished prerequisites.'],
    ['gui_note',  d_guicolors['note'], 
        'The color for notes.'],
    ['gui_details',  d_guicolors['details'], 
        'The color for details (displayed in the html report window).'],
    ['gui_header1',  d_guicolors['header_1'], 
        'The color for level 1, 4, 7, .., headers.'],
    ['gui_header2',  d_guicolors['header_2'], 
        'The color for level 2, 5, 8, .., headers.'],
    ['gui_header3',  d_guicolors['header_3'], 
        'The color for level 3, 6, 9, .., headers.'],
    ['event_color',  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"',
        '',],
    ['allday_event_color', '''%s''' % d_attrs['allday'], ''],
    ['reminder_color', '''%s''' % d_attrs['reminder'], ''],
    ['action_color', '''%s'''   % d_attrs['action'], ''],
    ['task_pastdue_color', '''%s''' % d_attrs['task_pastdue'], ''],
    ['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_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'], ''],
    ['F1Help', '"F1: help"',
        'Language customizations:',
        'The prompt to use for F1 help in the status bar.'],
    ['nextalert', 'next alert:',
        'The label for the time of the next alert in the status bar'],
    ['minutes_msg', 'begins %s minutes from now',
        'In alerts, the message for warnings more than one minute early.',
        '"%s" will be replaced by the number of minutes.'],
    ['oneminute_msg', 'begins one minute from now',
        'In alerts, the message for warnings exactly one minute early.'],
    ['rightnow_msg', 'begins now',
        'In alerts, the message for warnings at the starting time.'],
    ['thetimeis', '"The time is"',
        'The prefix for the spoken time'],
    ['early_warning', '"minute warning"',
        'The label for item early warnings in the alert queue'],
    ['event_beginning', '"event begins"',
        'The label for item starting times in the alert queue'],
    ['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
check_etmdir()
check_export()
has_oldrc, has_etmrc = check_newinstall()
newuser = not (has_oldrc or has_etmrc)
upgrade = has_oldrc and not has_etmrc
etmrc, has_etmrc = set_etmrc()

if has_etmrc:
    etmrc_fo = codecs.open(etmrc, 'r', file_encoding)
    string = "\n".join(etmrc_fo.readlines())
    etmrc_fo.close()
    exec(string)

for variable in variables:
    check(variable)

rotate = {}
for n, f, d in [
    ('Actions', actions, etmActions), 
    ('actions', actions, etmActions), 
    ('events', events, etmEvents), 
    ('notes', notes, etmNotes), 
    ('tasks', tasks, etmTasks)]:
    rotate[n] = (f, d)

check_file(abbreviationsFile)
check_file(contextsFile)
check_file(keywordsFile)
check_file(locationsFile)

check_etmdata()
checkRotating()

if newuser:
    make_examples()
    make_holidays()
if upgrade:
    make_holidays()

check_dir(etmdata, etmActions, actions)
check_dir(etmdata, etmEvents, events)
check_dir(etmdata, etmTasks, tasks)
check_dir(etmdata, etmNotes, notes)

# show_ptitle = True
# show_ptitle = False
possible_timezones = get_localtz(timezones)

if len(added) > 0:
    #  print "len(added) > 0: has_etmrc", etmrc, has ecmrc
    if has_etmrc:
        import shutil
        shutil.copyfile(etmrc, "%s.bak" % etmrc)
        make_etmrc()
        etmrc_fo = codecs.open(etmrc, 'r', file_encoding)
        string = "\n".join(etmrc_fo.readlines())
        etmrc_fo.close()
        exec(string)
        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()

    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!
"""