#!/bin/env python
import sys, os

import sqlalchemy as sa
from sqlalchemy import orm

from tagit.db import open_db

# Need to `import tagit.plugin` rather than `from tagit.plugin import actions`
# so that changes to tagit.plugin.actions are reflected here after we load
# plugins. Most changes should just be mutations of the set, but it's
# conceivable a plugin might want to change the variable itself for some reason.
import tagit.plugin
from tagit.plugin import option_parser as op
from tagit.plugin import (errprint, fatal, fatal_lines, 
                          load_plugin, load_config_file)

import tagit.builtin            # apply builtin "plugins"

# Helpers
def parse_args():
    op.disable_interspersed_args()
    
    op.add_option('-s', '--source', dest='source', metavar='SOURCE',
                  help='Load database from SOURCE. '
                  "Defaults to the TAGIT_DB envar, then to `.tagit.db'.")
    
    op.add_option('-l', '--load', dest='plugins', action='append', 
                  metavar='PLUGIN', default=[],
                  help='Load plugin PLUGIN.')
    
    op.add_option('-c', '--config', dest='config', action='append',
                  metavar='FILE', default=[],
                  help='Load configuration from FILE.')
    
    (options, args) = op.parse_args()
    
    try: cmd = args.pop(0)
    except IndexError:
        fatal("No action supplied!")
    
    return (options, cmd, args)


def configure(options):
    config_files = list(reversed(options.config))
    
    env_config = os.environ.get('TAGIT_CONFIG')
    if env_config: 
        config_files.append(env_config)
    
    home_dir = os.environ.get('HOME')
    if home_dir:
        rc_file = os.sep.join([home_dir, '.tagit', 'config'])
        if os.access(rc_file, os.R_OK):
            config_files.append(rc_file)
    
    for f in config_files:
        load_config_file(options, f)


def get_action(cmd):
    actions = tagit.plugin.actions
    action = actions.get(cmd)
    
    if not action:
        actions = [a for a in actions.values() if a.name.startswith(cmd)]
        
        if len(actions) == 1:
            action = actions[0]
        elif not actions:
            fatal("Unknown action: %r" % cmd)
        else:
            fatal("Multiple actions match %r: %s\n" %
                  (cmd, ', '.join(act.name for act in acts)))
    
    return action


def main():
    (options, cmd, args) = parse_args()
    
    # Load config files
    configure(options)
    
    # Load plugins
    for name in options.plugins:
        if not load_plugin(name):
            fatal("Could not load plugin %r" % name)
    
    # Find the database source
    source = options.source
    if not source:
        source = os.getenv('TAGIT_DB', '.tagit.db')
        if not os.access(source, os.F_OK):
            fatal("No database given, and default file '%s' "
                  "does not exist; exiting" % source)
    
    # Determine the action
    action = get_action(cmd)
    (options, args) = action.option_parser.parse_args(args)
    
    # Perform the action
    open_db(source)
    action.hooks(options)
    action.perform(options, args)


if __name__ == "__main__":
    try: main()
    except KeyboardInterrupt: 
        raise SystemExit(130)
