#!/usr/bin/env python
"""
Command line tool for initializing Burlap-structured Django projects.

e.g.

    burlap skel --name=myproject
"""

import argparse
import os
import sys

#sys.path.insert(0, os.path.normpath(os.path.join(os.path.realpath(__file__), '../..')))

import burlap
import burlap.common

fabfile_template = os.path.join(
    os.path.dirname(burlap.__file__),
    'templates',
    'burlap_fabfile.template.py')

ACTIONS = (
    SKEL,
    CREATE_MIGRATION,
    MIGRATE,
) = (
    'skel',
    'create_migration',
    'migrate',
)

def md(d):
    if os.path.isdir(d):
        return
    os.makedirs(d)

if __name__ == "__main__":
    parser = argparse.ArgumentParser(
        description=('Initialize a Burlap structured project.'),
    )
    parser.add_argument(
        'action',
        type=str,
        nargs='*',
        help='skel=creates project skeleton')
    parser.add_argument(
        '--initial',
        action='store_true',
        default=False,
        dest='initial',
        help='Generate the initial migration.')
    parser.add_argument(
        '--auto',
        action='store_true',
        default=False,
        dest='auto',
        help='Attempt to automatically generate a migration.')
    parser.add_argument(
        '--empty',
        action='store_true',
        default=False,
        dest='empty',
        help='Make a blank migration.')
    parser.add_argument(
        '--name',
        type=str,
        dest='project_name',
        help='project name')
    parser.add_argument(
        '--pip-requirements',
        type=str,
        default='Django,Fabric',
        dest='pip_requirements',
        help='The default Python packages to install.')
    parser.add_argument(
        '--roles',
        type=str,
        default='dev,prod',
        dest='roles',
        help='The default roles to populate.')
    args = parser.parse_args()

    print 'args.action:',args.action

    if args.action[0] == CREATE_MIGRATION:
        burlap.common.AppHandler(args.action[1]).create_migration(initial=args.initial)
    elif args.action[0] == MIGRATE:
        burlap.common.AppHandler(args.action[1]).migrate()
    elif args.action[0] == SKEL:
        assert args.project_name, 'Specify project name.'
        site_name = args.project_name + '_site'
        
        default_roles = [_ for _ in args.roles.split(',') if _.strip()]
        
        print 'Creating folders...'
        md('roles/all')
        for _role in default_roles:
            md('roles/%s' % _role)
        md('src')
        md('media')
        md('static')
        
        print 'Creating roles...'
        open('roles/all/settings.yaml', 'w')\
            .write('''# This is the name of the Django app that contains the global settings for your site.
app_name: {site_name}

# This is the name of the Apache site that will host your Django app.
default_site: {site_name}

# This the template used to retrieving your Django app settings.
settings_module: '%(app_name)s.settings'
'''.format(project_name=args.project_name, site_name=site_name))
        for _role in default_roles:
            open('roles/%s/settings.yaml' % _role, 'w')\
                .write('''# Settings for {role}.
inherits: all

# Set this to the domain/IP of your {role} server(s).
# For now, let's assume we'll do most development locally...
hosts: ['localhost']

# This is the base directory where all files will be installed once deployed.
# For development, we'll just make this the CWD.
remote_app_dir_template: "."
'''.format(project_name=args.project_name, site_name=site_name, role=_role))
        
        default_packages = args.pip_requirements.split(',')
        
        open('roles/all/pip-requirements.txt', 'w').write('\n'.join(default_packages))
        
        content = open(fabfile_template, 'r').read()
        content = content.format(project_name=args.project_name)
        open('fabfile.py', 'w').write(content)
        
        print 'Initializing local development virtual environment...'
        os.system('virtualenv --no-site-packages .env')
        for package in default_packages:
            os.system('. ./.env/bin/activate; pip install %s; deactivate' % package)
        
        print 'Initializing Django project...'
        if not os.path.isdir('src/%s' % site_name):
            print 'Initializing base django project...'
            os.system('. ./.env/bin/activate; django-admin.py startproject %s src; deactivate' \
                % (site_name,))
            _settings_fn = 'src/%s_site/settings.py' % args.project_name
            _content = open(_settings_fn, 'r').read()
            _sites = '''SITE_{name_upper} = "{name_lower}"
SITES = (
    SITE_{name_upper},
)
'''.format(
    name_upper=args.project_name.upper(),
    name_lower=args.project_name.lower(),
)
            _top = []
            for _role in default_roles:
                _top.append("ROLE_%s = '%s'" % (_role.upper(), _role.lower()))
            _top.append('ROLES = (')
            for _role in default_roles:
                _top.append("    ROLE_%s," % (_role.upper(),))
            _top.append(')')
            _index = _content.find('"""\n\n')+4
            _bottom = '''
PROJECT_DIR = os.path.abspath(os.path.join(os.path.split(__file__)[0], '..', '..'))

STATIC_ROOT = os.path.join(PROJECT_DIR, 'static')

MEDIA_ROOT = os.path.join(PROJECT_DIR, 'media')
MEDIA_URL = '/media/'

STATICFILES_FINDERS = (
    'django.contrib.staticfiles.finders.FileSystemFinder',
    'django.contrib.staticfiles.finders.AppDirectoriesFinder',
)
TEMPLATE_LOADERS = (
    'django.template.loaders.filesystem.Loader',
    'django.template.loaders.app_directories.Loader',
)
TEMPLATE_DIRS = (
    '%s/src/{app_name}/templates' % PROJECT_DIR
)
ADMIN_TITLE = '{app_name_title}'
ADMIN_TITLE_SIMPLE = '{app_name_simple}'

'''.format(
    app_name=args.project_name,
    app_name_title=args.project_name.title() + ' Administration',
    app_name_simple=args.project_name.title())
            open(_settings_fn, 'w').write(_content[:_index]+_sites+('\n'.join(_top))+_content[_index:]+_bottom)

        print 'Creating Django helper scripts...'
        open('src/manage', 'w').write('''#!/bin/bash
# Helper script for ensuring we use the Python binary in our local
# virtual environment when calling management commands.
# Otherwise, we'd have to always run `. ../.env/bin/activate`, which can be
# annoying.
# Be sue to run `fab <role> pip.init` first in order to setup
# the target role's Python virtual environment.
DIR=`dirname $0`;
cd $DIR;
../.env/bin/python manage.py $@''')
        open('src/runserver', 'w').write('''#!/bin/bash
# Helper script for running the local dev server, ensuring
# our virtual environment is used.
#set -e
#script_dir=`dirname $0`
#cd $script_dir
if [ -z "$PORT" ]; then
    export PORT=8111
fi
if [ -z "$ROLE" ]; then
    export ROLE=dev
fi
. ~/.bash_aliases
./manage runserver localhost:$PORT''')
        open('src/shell', 'w').write('''#!/bin/bash
# Creates a local PIP-aware shell.
#set -e
if [ $_ == $0 ]
then
    echo "Please source this script. Do not execute."
    exit 1
fi
#script_dir=`dirname $0`
#cd $script_dir
. .env/bin/activate
PS1="\u@\h:\W(fab)\$ "''')
        open('shell', 'w').write('''#!/bin/bash
# Creates a local PIP-aware shell.
#set -e
if [ $_ == $0 ]
then
    echo "Please source this script. Do not execute."
    exit 1
fi
#script_dir=`dirname $0`
#cd $script_dir
. ../.env/bin/activate
PS1="\u@\h:\W(virt)\$ "''')
        open('.gitignore', 'w').write('''.env
.project
.pydevproject
.settings
.pip_cache
.tarball_cache
.manifests
''')
        os.system('chmod +x shell')
        os.system('chmod +x src/shell')
        os.system('chmod +x src/manage')
        os.system('chmod +x src/runserver')

        # Create the primary app for containing models/urls/views.
        if not os.path.isdir('src/%s' % args.project_name):
            os.system('cd src; ./manage startapp %s' % (args.project_name,))
            
        os.system('cd src; ./manage syncdb')
        
        print '='*80
        print
        print 'Skeleton created for project %s!' % (args.project_name.title(),)
        print
        print '''Some introductory notes:
        
    * The term "role" will be used to denote different server environments. e.g. The "prod" role will refer to production while the "dev" role will refer to development.
    * There's a global settings file located at roles/all/settings.yaml. Additionally, each role has its own settings file, located at roles/<role>/settings.yaml, that inherits from the global settings.
    * You can run fabric commands for each role using shell comands of the form `fab <role> <command>`. e.g. To do a full deployment to production, you'd run `fab prod deploy1`.
    * The fabfile.py has been pre-populated with some sample commands for performing deployments, but it can be customized however you like.
    * Modify the file `src/{site_name}/settings.py` to contain your database connection parameters and other custom parameters. Use os.environ.get('ROLE') to specify settings for different roles.
    * If you database server requires configuration, update the appropriate role settings.yaml file and then run `fab <role> db.configure. Only PostgreSQL and MySQL are currently supported.
    * Add your custom models to src/{project_name}/models.py and/or create other custom apps using `src/manage startapp <myapp>`.
    * Initialize your new project's local development database by running `fab dev db.create:post_process=1`.
    * Run the script `src/runserver` to start the local Django dev server.
        '''.format(project_name=args.project_name, site_name=site_name)
    else:
        raise NotImplementedError, 'Unknown action: %s' % (action[0])