"""Helpers when inside an instance context.
"""
import os
import sys
import transaction
from zope.app.appsetup import database, config
from zope.app.publication.zopepublication import ZopePublication
from zope.app.wsgi import config as wsgi_config
from waeup.kofa.app import University

#: The name under which any artificially created University instance
#: will be put into the root folder
APP_NAME = 'stress_app'

IMPORTERS = {
    'faculties.csv': 'facultyprocessor',
    'departments.csv': 'departmentprocessor',
    'courses.csv': 'courseprocessor',
    'certificates.csv': 'certificateprocessor',
    'certificatecourses.csv': 'certificatecourseprocessor',
    'applicantcontainers.csv': 'applicants container processor',
    'applicants.csv': 'applicantprocessor',
    }

def configure(instance_path=''):
    config_file = os.path.join(
        instance_path, 'parts', 'etc', 'site.zcml')
    print "WAEUP.STRESS: configuring ZODB from %s" % (
        config_file,)
    context = config(config_file)
    return context

def open_zodb(instance_path=''):
    """Open a ZODB and configure it using a site.zcml file.

    If `instance_path` is not given, we assume to be in the root of
    some Zope instance and compute relative paths to
    'parts/etc/site.zcml' and 'var/filestorage/Data.fs'.

    If `instance_path` is given, these paths are os.path.joined with
    it.

    Returns a tuple containing a database object, an open connection
    to this DB and the root folder.
    """
    zope_conf = os.path.join(
        instance_path, 'parts', 'etc', 'zope.conf')
    config_file = os.path.join(
        instance_path, 'parts', 'etc', 'site.zcml')
    print "WAEUP.STRESS: opening ZODB"
    zodb_file = os.path.join(
        instance_path, 'var', 'filestorage', 'Data.fs')

    print "WAEUP.STRESS: configuring ZODB from %s" % (
        zope_conf)

    db = wsgi_config(zope_conf)

    # The way to configure a ZODB if only a single ZODB has to be set up.
    #context = config(config_file)
    #db = database(zodb_file)

    conn = db.open()
    root = conn.root()
    root_folder = root.get(ZopePublication.root_name, None)
    return db, conn, root_folder

def close_zodb(db):
    print "WAEUP.STRESS: closing ZODB"
    transaction.commit() # make sure changes are saved
    db.close()
    return

def zodb(func):
    """A decorator that does a ZODB setup and calls the decorated
    function with the ZODB root folder as first argument.
    """
    def wrapped(*args, **kw):
        instance_path = kw.get('instance_path', '')
        db, conn, root_folder = open_zodb(instance_path)
        try:
            func(root_folder, *args, **kw)
        finally:
            close_zodb(db)
    return wrapped

@zodb
def create_app(root_folder):
    """Create a University instance named 'stress_app' in ZODB.

    The `root_folder` arg is injected by the decorator and represents
    the root folder of an opened, writable ZODB.
    """
    root_folder[APP_NAME] = University()
    print "WAEUP.STRESS.SCRIPTS: created '%s' in root folder." % APP_NAME
    return

@zodb
def import_files(root_folder, *args):
    from zope.component.hooks import setSite
    from zope.component import getUtility
    from waeup.kofa.interfaces import IBatchProcessor
    setSite(root_folder[APP_NAME])
    for path in args:
        if not os.path.isfile(path):
            print "WAEUP.STRESS.SCRIPTS: no such file: %s" % path
            continue
        basename = os.path.basename(path)
        util_name = IMPORTERS.get(basename, None)
        if util_name is None:
            print "WAEUP.STRESS.SCRIPTS: not a valid import filename: %s" % (
                basename)
            print "  valid names: %s" % IMPORTERS.keys()
            continue
        util = getUtility(IBatchProcessor, name=util_name)
        for line in open(path, 'rb'):
            break
        headerfields = line.strip().split(',')
        print "WAEUP.STRESS.SCRIPTS: importing %s" % os.path.basename(path)
        results = util.doImport(path, headerfields)
        print "WAEUP.STRESS.SCRIPTS: import done."
    return

def main(cmd, *args, **kw):
    if cmd == 'install_app':
        configure()
        create_app()
        return
    elif cmd == 'import_csv':
        configure()
        create_app()
        import_files(*args)
        return

if __name__ == '__main__':
    cmd = sys.argv[1]
    args = []
    if len(sys.argv) > 2:
        args = sys.argv[2:]
    main(cmd, *args)
