import os
import getopt
import sys
import errno
import time
import re

class Conf(object):
    def __init__(self, args):
        self.args=args
        ### SET PROGRAM DEFAULTS
        self.cnf = {
                'um2':  os.path.expanduser('~/umenu2'),
                'conf': os.path.expanduser('~/umenu2/conf'),
                'prog': os.path.expanduser('~/umenu2/prog'),
                'menu': os.path.expanduser('~/umenu2/menu'),
                'diag': False,
                'term': False,
                'nobanner': False,
                'license': False,
                'icons': False,
                }

        ### THESE CONFIG SETTINGS ARE DIRECTORY LOCATIONS
        self.locations=[
                'um2',
                'conf',
                'menu',
                'prog',
                ]
        self.bootstrap(args)




    def bootstrap(self, args):
        """
        Use ~/.umenurc to find the conf directory. Use the conf
        directory to find everything else. Then override 
        everything from the conf directory according to 
        command line args. During the process, substitute
        anything like :::um2:::, and fix anything like
        /home/richard/umenu2/conf/../prog with
        os.path.abspath()
        """

        ### .umenurc HAS ONE JOB: DEFINE THE CONF DIR
        ### POSSIBLY OVERRIDE CONF FROM ~/.umenurc
        fntemp = os.path.expanduser('~' + '/.umenurc')
        try:
            f = open(fntemp, 'r')
        except OSError as exc:
            if exc.errno == errno.ENOENT and not os.path.isfile(fntemp):
                pass
            else:
                s='ERROR: {} file.'
                print(s.format(fntemp))
                raise
        else:
            ### SET self.cnf['conf'] TO .umenurc's VALUE
            s = f.readline().strip()
            f.close()
            s = re.sub('^conf\s*', '', s)
            if re.match('^=', s):
                s = re.sub('^=\s*', '', s)
                self.cnf['conf'] = os.path.expanduser(s)

        ### PARSE CMD LINE ARGS, SAVE FOR LATER
        tmpcnf=self.parse_args()

        ### CHANGE CONFIG DIR IF ARG SAYS TO
        if 'conf' in tmpcnf:
            self.cnf['conf'] = os.path.expanduser(tmpcnf['conf'])

        ### GET CONFIGURATION FROM CONF DIR
        self.parse_conf_dir()
        self.substitute_dirs()

        ### CMD LINE ARGS OVERRIDE ALL ELSE
        for key in tmpcnf:
            self.cnf[key] = tmpcnf[key]

        ### FIX FUNKY PATHS
        for key in self.locations:
            self.cnf[key] = os.path.abspath(self.cnf[key])




    def substitute_dirs(self):
        done = False
        tries = 0
        while not done:
            done = True
            tries += 1
            for key in self.locations:
                s = self.cnf[key]
                for key2 in self.locations:
                    srchfraze = ':::' + key2 + ':::'
                    s2 = re.sub(srchfraze, self.cnf[key2], s)
                    if s2 != s:
                        s = s2
                        done = False
                self.cnf[key] = s
            if tries > 15:  ### Magic number, more than high enough
                print('\nInfinite loop in Conf.substitute_dirs.')
                self.showall()
                print('Aborting!\n')
                sys.exit(1)







    def showall(self):
        print('########## ALL CONF BELOW ##########')
        for key in sorted(self.cnf.keys()):
            """
            Python formatting plays all sorts of stupid
            games with values of bools, changing them
            to 1 and 0, so I kludged to make them
            appear as True and False.
            """
            val = self.cnf[key]
            thetype = type(val)
            if thetype == bool:
                if val:
                    val = 'True'
                else:
                    val = 'False'

            s='{:>10} : {:<30} {}'
            s=s.format( key, val,thetype)
            print(s)
        print('########## ALL CONF ABOVE ##########')

    def parse_conf_dir(self):
        """
        Be sure to later include security cleansing for
        all these filename->contents pairs.
        """
        for fil in os.listdir(self.cnf['conf']):
            if fil == 'conf':      ### Don't process conf file in conf dir
                continue           ### For simplicity, such double-indirection
                                   ### is disallowd

            filpath = '{}/{}'.format(self.cnf['conf'], fil)
            lines = []
            f = open(filpath, 'r')
            val = f.readline().strip()
            f.close()
            if fil == 'menu' or fil == 'prog':
                val = os.path.expanduser(val)

            if val.strip().lower() == 't':
                self.cnf[fil] = True
            elif val.strip().lower() == 'f':
                self.cnf[fil] = False
            else:
                self.cnf[fil] = val

        

    def parse_args(self):
        tmpcnf={'conf': self.cnf['conf']}
        args = self.args
        del(args[0])
        (optlist, arglist) = getopt.getopt(args, 'tdbhlic:');

        for tup in optlist:
            if tup[0] == '-h':
                self.usage()
                sys.exit(0)
            elif tup[0] == '-l':
                from UmenuLicense import License
                lic = License()
                lic.reveal()
                sys.exit(0)
            elif tup[0] == '-d':
                if tup[1]:
                    s='Option error: Option {} takes no value, you put value {}!'
                    print(s.format(tup[0], tup[1]))
                    sys.exit(1)
                else:
                    tmpcnf['diag'] = True
            elif tup[0] == '-t':
                if tup[1]:
                    s='Option error: Option {} takes no value, you put value {}!'
                    print(s.format(tup[0], tup[1]))
                    sys.exit(1)
                else:
                    tmpcnf['term'] = True

            elif tup[0] == '-l':
                if tup[1]:
                    s='Option error: Option {} takes no value, you put value {}!'
                    print(s.format(tup[0], tup[1]))
                    sys.exit(1)
                else:
                    tmpcnf['license'] = True
            elif tup[0] == '-i':
                if tup[1]:
                    s='Option error: Option {} takes no value, you put value {}!'
                    print(s.format(tup[0], tup[1]))
                    sys.exit(1)
                else:
                    tmpcnf['icons'] = True
            elif tup[0] == '-c':
                if tup[1]:
                    tmpcnf['conf'] = os.path.expanduser(tup[1])
                else:
                    s='Option error: Option {} must have directory value!'
                    print(s.format(tup[0]))
                    sys.exit(1)
        if len(arglist) != 1:
            print('Argument error: Must have exactly one non-dash argument, at end.')
            print('It must contain the desired menu string.')
            print('Aborting.\n')
            sys.exit(1)
        else:
            self.cnf['rootmnu'] = arglist[0]
            self.cnf['curmnu'] = arglist[0]
        return(tmpcnf)


    def usage(self):
        s="""
        Usage: ./umenu.py [options] <rootmenustring>
         where <rootmenustring> is an existing menu or submenu.
        
        Options:
           -t
              Terminate after call to program, which is
              useful when UMENU is used as a "start menu"
           -d
              Run UMENU in diagnostic mode.
           -h
              Prints usage.
           -l
              Prints license information then terminates.
                Best viewed with ./umenu.py -l | less
           -c <confdir>
              Use <confdir> as the configuration directory
        
        Within UMENU: press a key on the menu to run a command or submenu, press ";"
        to refresh current menu and screen, or press = to escape to the root menu.
        """
        slist=s.split('\n')
        for line in slist:
            line = re.sub('^        ', '', line)
            print(line)

