# Based on devtools.commands.quickstart.py by TurboGears Team 2008
# Used under the MIT License
#
import pkg_resources
import re
import optparse
from paste.script import command
from paste.script import create_distro
import os, pwd, sys
import stat
import string, random
import readline, getpass

beginning_letter = re.compile(r"^[^a-z]*")
valid_only = re.compile(r"[^a-z0-9_]")

class BazstartCommand(command.Command):
    """Create a new Bazki project.

Create a new Bazki project with this command.

Example usage::

    $ paster bazstart yourproject
    """

    version = pkg_resources.get_distribution('Bazki').version
    tgversion = pkg_resources.get_distribution('turbogears2').version
    max_args = 3
    min_args = 0
    summary = __doc__.splitlines()[0]
    usage = '\n' + __doc__
    group_name = "Bazki"
    name = None
    package = None
    dburl = None
    username = None
    elmname = None
    password = None
    svn_repository = None
    templates = "bazki"
    dry_run = False
    no_input = False
    secret = ''.join(random.choice(string.lowercase) for x in xrange(16))
    bazkitype = 'bazki'
    extra_db = None
    custom_db = None
    remove_db = None
    admin_path = 'Object/User/Admin'
    admin = 'Admin'
    extra_imports = []
    extra_controllers = []
    statics = ['bazki']
    urlprefix = None
    suppress_output = False
    repo = None

    parser = command.Command.standard_parser(quiet=True)
    parser = optparse.OptionParser(
                    usage="%prog quickstart [options] [project name]",
                    version="%prog " + version)
    parser.add_option("-p", "--package",
            help="package name for the code",
            dest="package")
    parser.add_option("-r", "--svn-repository", metavar="REPOS",
            help="create project in given SVN repository",
            dest="svn_repository", default=svn_repository)
    parser.add_option("-d", "--dburl",
            help="specify URL for database used",
            dest="dburl")
    parser.add_option("-u", "--username",
            help="specify username for initial admin user",
            dest="username")
    parser.add_option("-e", "--elmname",
            help="specify element name for inital admin user",
            dest="elmname")
    parser.add_option("-P", "--password",
            help="specify password for initial admin user",
            dest="password")
    parser.add_option(
        "--urlprefix",
        help="specify the public urlprefix for this site",
        dest="urlprefix")
    parser.add_option("--custom-db",
            help="specify a tree of extra custom database yaml files "
                 "(used for tests)",
            dest="custom_db")
    parser.add_option(
        "--remove-db",
        help="specify a path in the initial db to remove (used for tests)",
        dest="remove_db")
    parser.add_option("--dry-run",
            help="dry run (don't actually do anything)",
            action="store_true", dest="dry_run")
    parser.add_option("-q", "--quiet",
            help="suppress output",
            action="store_true", dest="suppress_output")
    parser.add_option("--noinput",
            help="no input (don't ask any questions)",
            action="store_true", dest="no_input")

    def command(self):
        """Quickstarts the new project."""

        for k in self.options.__dict__:
            if self.options.__dict__[k] is not None:
                self.__dict__[k] = self.options.__dict__[k]

        if self.args:
            self.name = self.args[0]

        while not self.name:
            self.name = raw_input("Enter project name: ")

        if self.package is None:
            package = self.name.lower()
            package = beginning_letter.sub("", package)
            package = valid_only.sub("", package)
            if package and self.no_input:
                self.package = package
            else:
                self.package = None
                while not self.package:
                    self.package = raw_input(
                        "Enter package name [%s]: " % package).strip() or package
        if self.dburl is None:
            dburl=('mysql://sql.mit.edu/%s+%s?read_default_file=%s'
                   % (getpass.getuser(), self.package,
                      os.path.expanduser('~/.my.cnf')))
            if self.no_input:
                self.dburl = dburl
            else:
                while not self.dburl:
                    self.dburl = raw_input(
                        "Enter database URL, of the form mysql://hostname/dbname?read_default_file=~/.my.cnf [%s]: " % dburl).strip() or dburl

        if self.username is None:
            username=pwd.getpwuid(os.getuid())[0]
            if self.no_input:
                self.username = username
            else:
                while not self.username:
                    self.username = raw_input(
                        "Enter username for initial admin user [%s]: " % username).strip() or username
        if self.elmname is None:
            elmname=self.username[0].upper()+self.username[1:]
            if self.no_input:
                self.elmname = elmname
            else:
                while not self.elmname:
                    self.elmname = raw_input(
                        "Enter element name for initial admin user [%s]: " % elmname).strip() or elmname
        if self.password is None:
            if self.no_input:
                self.password = ''.join(random.choice(string.lowercase)
                                        for x in xrange(16))
            else:
                while not self.password:
                    self.password = getpass.getpass(
                        "Enter password for initial admin user (visible to anyone with edit access): ")

        if self.urlprefix is None:
            urlprefix = 'http://%s.scripts.mit.edu/%s' % (getpass.getuser(),
                                                          self.package)
            if self.no_input:
                self.urlprefix = urlprefix
            else:
                while not self.urlprefix:
                    self.urlprefix = raw_input(
                        "Enter public URL prefix [%s]: " % urlprefix).strip() or urlprefix

        self.name = pkg_resources.safe_name(self.name)

        env = pkg_resources.Environment()
        if self.name.lower() in env:
            print 'The name "%s" is already in use by' % self.name,
            for dist in env[self.name]:
                print dist
                return

        import imp
        try:
            if imp.find_module(self.package):
                print 'The package name "%s" is already in use' % self.package
                return
        except ImportError:
            pass

        if os.path.exists(self.name):
            print 'A directory called "%s" already exists. Exiting.' % self.name
            return

        command = create_distro.CreateDistroCommand("create")
        cmd_args = []
        for template in self.templates.split():
            cmd_args.append("--template=%s" % template)
        if self.svn_repository:
            cmd_args.append("--svn-repository=%s" % self.svn_repository)
        if self.dry_run:
            cmd_args.append("--simulate")
            cmd_args.append("-q")
        if self.suppress_output:
            cmd_args.append("-q")
        cmd_args.append(self.name)
        cmd_args.append("package=%s" % self.package)
        cmd_args.append("bazversion=%s" % self.version)
        cmd_args.append("tgversion=%s" % self.tgversion)
        cmd_args.append("dburl=%s" % self.dburl)
        cmd_args.append("username=%s" % self.username)
        cmd_args.append("elmname=%s" % self.elmname)
        cmd_args.append("password=%s" % self.password)
        cmd_args.append("secret=%s" % self.secret)
        cmd_args.append("projectroot=%s" % os.path.abspath(self.name))
        cmd_args.append("bazkitype=%s" % self.bazkitype)
        cmd_args.append("admin=%s" % self.admin)
        cmd_args.append("extra_imports=%s"
                        % ';'.join(self.extra_imports))
        cmd_args.append("extra_controllers=%s"
                        % ';'.join(self.extra_controllers))
        cmd_args.append("statics=%s"
                        % ';'.join(self.statics))
        cmd_args.append("urlprefix=%s" % self.urlprefix)
        
        # Sitedir hack
        #
        # To use this hack, put the following at the start of ~/bin/paster:
        ## import site
        ## # sitedir hack
        ## __paster_sitedir__='/mit/xavid/lib/python2.5/site-packages/'
        ## site.addsitedir(__paster_sitedir__)
        
        import __main__
        if hasattr(__main__,'__paster_sitedir__'):
            print >>sys.stderr, "Using sitedir:", __main__.__paster_sitedir__
            sitedir = __main__.__paster_sitedir__
        else:
            sitedir = ''
        cmd_args.append("sitedir=%s" % sitedir)
        
        command.run(cmd_args)

        if not self.dry_run:
            os.chdir(self.name)

            for path in ['precommit.py', 'clear-database.py', 'prod.py',
                         'webroot/dispatch.fcgi']:
                if os.path.exists(path):
                    oldmode = os.stat(path).st_mode
                    os.chmod(path,
                             oldmode | stat.S_IXUSR)
            sys.argv = ["setup.py", "egg_info"]
            import imp
            imp.load_module("setup", *imp.find_module("setup", ["."]))

            # dirty hack to allow "empty" dirs
            for base, path, files in os.walk("./"):
                for file in files:
                    if file == "empty":
                        os.remove(os.path.join(base, file))

            # Create "public" and "bazki" symlinks
            os.symlink(os.path.join('..', self.package, 'public'),
                       os.path.join('webroot','__public'))
            bazlib = os.path.dirname(os.path.dirname(
                os.path.abspath(__file__)))
            for s in self.statics:
                os.symlink(os.path.join(bazlib, s, 'static'),
                           os.path.join('webroot', s))

            # Initialize the database using a subversion import
            from . import bootstrap
            bootstrap.bootstrap(self.name, self.package, self.suppress_output,
                                self.username,self.elmname,self.password,
                                self.bazkitype, self.extra_db,
                                self.custom_db,
                                self.remove_db.split(':') if self.remove_db
                                else [],
                                self.admin_path,
                                self.urlprefix,
                                self.repo)
