#!/usr/bin/python3.2

import argparse, os
from bugz.bugzilla import BugzillaProxy
from gentoopm.portagepm.atom import PortageAtom, InvalidAtomStringError

WORKDIR='/var/lib/at'

class ATJob:
    states = 'new', 'prepared'
    stored = 'url', 'bugid', 'packages', 'state', 'summary'

    def __init__(self, tag, workdir=WORKDIR, create=False):
        if not tag:
            raise ValueError("tag must not be empty")
        self.workdir=os.path.join(workdir, str(tag))
        if not os.path.exists(self.workdir):
            if not create:
                raise ValueError("workdir %s does not exist" % self.workdir)
            os.makedirs(self.workdir)

        self.tag = tag
        for k in self.stored:
            self.__dict__[k] = None
        self.read()

    def read(self):
        for k in self.stored:
            d = None
            try:
                f = open(os.path.join(self.workdir, k), 'r')
                d = f.read()
                f.close()
            except IOError:
                pass
            if d and d.count('\n'):
                d = d.split('\n')[:-1]
            self.__dict__[k] = d
    
    def write(self):
        for k in self.stored:
            d = self.__dict__.get(k, None)
            if type(d) == type([]):
                d = '\n'.join(d) + '\n'
            fn = os.path.join(self.workdir, k)
            if not d:
                if os.path.exists(fn):
                    os.unlink(fn)
            else:
                f = open(fn, 'w')
                f.write(d)
                f.close()

    def __str__(self):
        return '[%s][%s] %s' % (self.state, self.tag, self.summary) + \
            ''.join(map(lambda s: '\n\t%s' % s, self.packages))

    def listjobs(workdir=WORKDIR):
        if not os.path.exists(workdir):
            return []
        else:
            return os.listdir(workdir)

def atlist(**args):
    for j in ATJob.listjobs():
        print(ATJob(j))

def default_input(s, default=None):
    return input('%s [%s]: ' % (s, default)) or default

def fetch_bug(bugid):
    bp = BugzillaProxy('https://bugs.gentoo.org/xmlrpc.cgi')
    res = bp.Bug.get({'ids': int(bugid)})['bugs']
    if len(res) != 1:
        raise RuntimeError('bug id not unique')
    return res[0]
    
def create(tag, workdir, **args):
    job = ATJob(tag, workdir=workdir, create=True)
    if job.state:
        raise RuntimeError('job already exists in state %s' % job.state)
    job.bugid = default_input('bug id', job.bugid or job.tag)
    if job.bugid.isdigit():
        job.bug = fetch_bug(job.bugid)
        job.summary = default_input('summary', job.bug['summary'])
        job.url = default_input('url', job.url or 'https://bugs.gentoo.org/%s' % job.bugid)
        job.packages = []
        for fragment in job.bug['summary'].split():
            try:
                job.packages.append(PortageAtom(fragment))
            except ValueError:
                pass
            except InvalidAtomStringError:
                pass
        job.packages = list(map(str, (filter(lambda a: a.complete, job.packages))))
    else:
        job.summary = default_input('summary', None)
        job.url = default_input('url', job.url or 'https://bugs.gentoo.org/%s' % job.bugid)
    job.state = 'created'
    job.write()

def prepare(tag, workdir, **args):
    job = ATJob(tag, workdir)
    if job.state != 'created':
        raise RuntimeError('job already exists in state %s' % job.state)

    if os.system('emerge -pv %s' % ' '.join(job.packages)):
        os.system('emerge -v --autounmask-write --autounmask-keep-masks %s' \
            % ' '.join(job.packages))
        os.system('dispatch-conf')
    if os.system('emerge -pv %s' % ' '.join(job.packages)):
        print('failed to set keywords and useflags')
        return
    job.state = 'prepared'
    job.write()
        
if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='arch testing',
        formatter_class=argparse.ArgumentDefaultsHelpFormatter)
    parser.add_argument('--workdir', default=WORKDIR,
        help='topdir for all operations')

    subparsers = parser.add_subparsers(help='actions')

    parser_list = subparsers.add_parser('list', 
        help='list existing jobs',
        formatter_class=argparse.ArgumentDefaultsHelpFormatter)
    parser_list.set_defaults(func=atlist)

    parser_create = subparsers.add_parser('create',
        help='create create job',
        formatter_class=argparse.ArgumentDefaultsHelpFormatter)
    parser_create.add_argument('tag', help='job name')
    parser_create.set_defaults(func=create)

    parser_prepare = subparsers.add_parser('prepare',
        help='prepare',
        formatter_class=argparse.ArgumentDefaultsHelpFormatter)
    parser_prepare.add_argument('tag', help='job name')
    parser_prepare.set_defaults(func=prepare)
    
    """
    parser_rip.add_argument('--force', action='store_true', default=False,
        help='force file operations')
    parser_rip.add_argument('--cdrom', default=CDROM,
        help='optical device')
    parser_rip.add_argument('--paranoia', default='-z',
        help='cdparanoia cmdline options')
    parser_rip.add_argument('--flac', default=FLAC,
        help='flac cmdline options')
    parser_rip.add_argument('--tracks', default='1-',
        help='tracks range to rip (cdparanoia -B style)')
    parser_rip.add_argument('--discid', default=None,
        help='Pass freedb disc id')
    parser_rip.add_argument('--askmeta', action='store_true', default=False,
        help='Run subcommand meta in extra terminal')
    parser_rip.add_argument('--eject', action='store_true', default=False,
        help='Eject media after operation')"""

    args = parser.parse_args()

    args.func(**dict(args._get_kwargs()))

