#! /usr/bin/python

import pygration
import pygration.config
import pygration.history
import pygration.migration
import pygration.migrator
import sqlalchemy
import optparse
import os
import os.path
import sys
import types


PATH_HELP = "path to the pygration directory"
NOOP_HELP = "show what will be done without actually doing it"
VERBOSE_HELP = "print extra output to the screen"

USAGE = """
    pygrate [options] <command>

Commands:
    show <migration>              Show the status of a migration
    add <migration>               Run the expansion phase, add to the DB
    simdrop <migration>           Simulate the drop phase (move elements)
    drop <migration>              Run the contraction phase, drop from the DB
    rollback_add <migration>      Rollback the add phase of the migration
    rollback_simdrop <migration>  Rollback the simdrop phase of the migration
    ff                            Runs all the phases over each step in the migration

Migration:
    The filename (without extension) of the migration you want to run
    """

DEFAULT_PATH = '.'


def run_main():
    parser = optparse.OptionParser( usage=USAGE )
    parser.add_option("-p", "--path", help=PATH_HELP)
    parser.add_option("-e", "--env")
    parser.add_option("-n", "--noop", dest="noop", action="store_true"
            , default=False, help=NOOP_HELP)
    parser.add_option( "-v", "--verbose", dest="verbose", action="store_true"
            , default=True, help=VERBOSE_HELP)

    opts, args = parser.parse_args()

    if len(args) < 1:
        parser.error("Too few arguments - must specify a command")
        exit(1)

    command = args[0]
    
    cmds_req_migration = ['show', 'add', 'simdrop', 'drop'
            , 'rollback_add', 'rollback_simdrop']
    cmds_no_migration = ['ff']

    if command in cmds_req_migration:
        if len(args) < 2:
            parser.error("Too few arguments - '%s' requires a migration" \
                    " to be specified" % command)
            exit(1)
        elif len(args) == 2:
            migration = args[1]
        else:
            parser.error("Too many arguments")
            exit(1)
    elif command in cmds_no_migration:
        if len(args) > 1:
            parser.error("Too many arguments")
            exit(1)
    else:
        parser.error("Unknown command '%s'" % command)
        exit(1)

    path = DEFAULT_PATH
    if opts.path:
        path = opts.path

    # Put the path 
    sys.path.insert(0, os.path.abspath(path))

    if opts.verbose:
        print "Migration Directory = '%s'" % path

    # Config Loading Section #
    config_path = os.path.join(path, 'conf.d')
    conf_files = os.listdir(config_path)
    try:
        config_selection = pygration.config.select(conf_files, opts.env)
    except pygration.config.UnknownDBError, e:
        print "There is no configuration for %s" % opts.env
        print "Available configurations are: %s" % e.choices
        exit(1)
    except pygration.config.UnspecifiedDBError, e:
        print "You must specify a db when more than one are available."
        print 'Available dbs are: %s' % e.choices
        exit(1)

    config_selection = os.path.join(config_path, config_selection)
    print "Config File = '%s'" % config_selection
    conf = pygration.config.load(config_selection)
    if opts.verbose:
        print "Config Options = %s" % conf

    # Open SQLAlchemy DB Engine
    session = pygration.db.open(conf.connection,
                                conf.drivername,
                                conf.schema,
                                conf.username,
                                conf.password,
                                conf.host,
                                conf.port,
                                conf.database,
                                conf.query
                               )

    # Create the file loader
    if conf.binary is not None:
        file_loader = pygration.db.FileLoader(conf.binary, conf.binary_args
                , conf.opts)
    else:
        file_loader = None

    # MigrationSet #
    migration_set = pygration.migration.load(path)

    # History Section #
    history = pygration.history.load(session)

    # Create Migrator objects #
    if opts.noop:
        migrator_db = pygration.migrator.NoopDB()
    else:
        migrator_db = pygration.migrator.LiveDB(session, file_loader)
    migrator = pygration.migrator.Migrator(migrator_db
            , migration_set, history)

    if command in ['show']:
        migrator.show(migration)
    elif command in ['add', 'simdrop', 'drop']:
        migrator.migrate(command, migration)
    elif command in ['rollback_add', 'rollback_simdrop']:
        migrator.rollback(command[9:], migration)
    elif command in ['ff']:
        migrator.fastforward()
    else:
        print "Unknown migrator command"


if ( __name__ == "__main__" ):
    run_main()

