"Commands for the TurboGears command line tool."
import optparse
import sys
import os
import glob
import pkg_resources

sys.path.insert(0, os.getcwd())

import turbogears
from turbogears.command import quickstart

no_connection_param = set(["help", "list"])
no_model_param = set(["help"])

class CommandWithDB(object):
    "Base class for commands that need to use the database"
    config = None
    
    def __init__(self, version):
        pass
        
    def find_config(self):
        """Chooses the config file, trying to guess whether this is a
        development or installed project."""
        if not self.config:
            if os.path.exists("setup.py"):
                self.config = "dev.cfg"
            else:
                self.config = "prod.cfg"
        
        if os.path.exists(self.config):
            import cherrypy
            cherrypy.config.update(file=self.config)
            self.dburi = cherrypy.config.get("sqlobject.dburi")
        else:
            self.dburi = None
            
    def get_model(self):
        "Looks to see if model.py still exists."
        import setuptools
        candidates = setuptools.find_packages()
        if candidates:
            candidate = candidates[0]
            if os.path.exists("%s/model.py" % candidate):
                package = __import__(candidate, {}, {}, ["model"])
                return package.model
        return None

class SQL(CommandWithDB):
    """Wrapper command for sqlobject-admin.
    
    This automatically supplies sqlobject-admin with the database that
    is found in the config file. Will also supply the model module as
    appropriate."""
    
    def __init__(self, version):
        if len(sys.argv) == 1 or sys.argv[1][0] == "-":
            parser = optparse.OptionParser(
                usage="%prog sql [turbogears options] [sqlobject command] " \
                      "[sqlobject options]\n" \
                      "HINT: '%prog sql help' will list the sqlobject " \
                      "commands",
                version="%prog " + version)
            parser.add_option("-c", "--config", help="config file", 
                              dest="config")
            (options, args) = parser.parse_args(sys.argv[1:3])
            
            if not options.config:
                parser.error("Please provide a valid option or sqlobject command.")
            self.config = options.config
            # get rid of our config option
            if not args:
                del sys.argv[1:3]
            else:
                del sys.argv[1]
                
        self.find_config()
    
    def run(self):
        "Executes the sqlobject-admin code."
        sqlobjcommand = sys.argv[1]
        
        if sqlobjcommand not in no_connection_param:
            if not self.dburi:
                print """Database URI not specified in the config file (%s).
    Please be sure it's on the command line.""" % self.config
            else:
                print "Using database URI %s" % self.dburi
                sys.argv.insert(2, self.dburi)
                sys.argv.insert(2, "-c")
        
        if sqlobjcommand not in no_model_param:
            eggname = glob.glob("*.egg-info")
            if not eggname or not \
                os.path.exists(os.path.join(eggname[0], "sqlobject.txt")):
                eggname = self.fix_egginfo(eggname)
            eggname = eggname[0].replace(".egg-info", "")
            if not "." in sys.path:
                sys.path.append(".")
                pkg_resources.working_set.add_entry(".")
            sys.argv.insert(2, eggname)
            sys.argv.insert(2, "--egg")
            
        from sqlobject.manager import command
        command.the_runner.run(sys.argv)
        
    def fix_egginfo(self, eggname):
        print """
This project seems incomplete. In order to use the sqlobject commands
without manually specifying a model, there needs to be an 
egg-info directory with an appropriate sqlobject.txt file.

I can fix this automatically. Would you like me to?
"""
        dofix = raw_input("Enter [y] or n: ")
        if not dofix or dofix.lower()[0] == 'y':
            oldargs = sys.argv
            sys.argv = ["setup.py", "egg_info"]
            import imp
            imp.load_module("setup", *imp.find_module("setup", ["."]))
            sys.argv = oldargs

            import setuptools
            package = setuptools.find_packages()[0]
            eggname = glob.glob("*.egg-info")
            sqlobjectmeta = open(os.path.join(eggname[0], "sqlobject.txt"), "w")
            sqlobjectmeta.write("""db_module=%(package)s.model
history_dir=$base/%(package)s/sqlobject-history
""" % dict(package=package))
        else:
            sys.exit(0)
        return eggname

        
class Shell(CommandWithDB):
    """Convenient version of the Python interactive shell.
    This shell attempts to locate your configuration file and model module
    so that it can import everything from your model and make it available
    in the Python shell namespace."""
    
    def run(self):
        "Run the shell"
        self.find_config()
        
        mod = self.get_model()
        if mod:
            locals = mod.__dict__
        else:
            locals = dict(__name__="tg-admin")
        try:
            # try to use IPython if possible
            import IPython
            shell = IPython.Shell.IPShell(user_ns=locals)
            shell.mainloop()
        except ImportError:
            import code
            code.interact(local=locals)
        
commands = {
    "quickstart" : ("Create a new TurboGears project", quickstart.quickstart),
    "sql" : ("Run the SQLObject manager", SQL),
    "shell" : ("Start a Python prompt with your database available", Shell),
}

def main():
    "Main command runner. Manages the primary command line arguments."
    if len(sys.argv) == 1 or sys.argv[1] == "--help-commands" or \
        sys.argv[1] == "--help" or not commands.has_key(sys.argv[1]):
        print """
TurboGears %s command line interface

Usage: %s [command] [options]

Available commands:""" % (turbogears.__version__, sys.argv[0])
        longest = max([len(key) for key in commands.keys()])
        format = "%" + str(longest) + "s  %s"
        commandlist = commands.keys()
        commandlist.sort()
        for key in commandlist:
            print format % (key, commands[key][0])
        sys.exit(0)
    commandname = sys.argv[1]
    del sys.argv[1]
    command = commands[commandname][1](turbogears.__version__)
    command.run()
    