#!/usr/bin/python

import urllib, urllib2
import sys
import re
import os
import subprocess
import getpass
import xmlrpclib
from hashlib import md5
from pkg_resources import parse_version
from find_git_repository import *

GIT_HOST = 'api.djangy.com'
API_HOST = 'api.djangy.com'
VERSION = '0.4'

CONFIG_PATH = '%s/.djangy' % os.environ['HOME']

COMMANDS = [
    'create',
    'syncdb',
    'migrate',
    'logs'
]

def check_for_update():
    client = xmlrpclib.ServerProxy("http://pypi.python.org/pypi")
    version = client.package_releases("Djangy")[0]
    if parse_version(version) > parse_version(VERSION):
        print ""
        print "There is an updated version of djangy available.  Run easy_install -U Djangy to update."
        print ""

def validate_email(email):
    if re.match('^.+\\@(\\[?)[a-zA-Z0-9\\-\\.]+\\.([a-zA-Z]{2,3}|[0-9]{1,3})(\\]?)$', email) != None:
        return True
    return False

def validate_pubkey(pubkey_path):
    if os.path.exists(pubkey_path):
        return True
    return False

def request(command, email = None, hashed_password = None, pubkey = None, app_name = None, args = ' '):
    if not command in COMMANDS:
        print 'Invalid command.'
        sys.exit(1)
    data = {}
    if app_name: data['application_name'] = app_name
    if email: data['email'] = email
    if args: data['args'] = args
    if pubkey: data['pubkey'] = pubkey
    if hashed_password: data['hashed_password'] = hashed_password
    url_values = urllib.urlencode(data)
    req = urllib2.Request('http://%s/%s' % (API_HOST,command), url_values)
    response = urllib2.urlopen(req)
    return response.read()

def get_application_name():
    if '-a' in sys.argv:
        try:
            return sys.argv[sys.argv.index('-a') + 1]
        except:
            pass
    print 'Please enter your application name: ',
    app_name = sys.stdin.readline().strip('\n')
    print ''
    return app_name

def get_email():
    print 'Enter your email address: ',
    email = sys.stdin.readline().strip('\n')
    if not validate_email(email):
        print 'Invalid email, please try again.'
        sys.exit(1)
    return email
    print ''

def get_password(email):
    password = md5('%s:%s' % (email, getpass.getpass('Please enter your password: '))).hexdigest()
    print ''
    return password

def ask_for_credentials():
    email = get_email()
    hashed_password = get_password(email)
    # write to the config file
    f = open(CONFIG_PATH, 'w')
    f.write('%s\n%s' % (email, hashed_password))
    f.close()
    return (email, hashed_password)
    
def get_credentials():
    if os.path.exists(CONFIG_PATH):
        data = [d.strip('\n') for d in open(CONFIG_PATH).readlines()]
        if len(data) != 2:
            return ask_for_credentials()
        email = data[0]
        if not validate_email(email):
            return ask_for_credentials()
        password = data[1]
        return (email, password)
    return ask_for_credentials()

def get_pubkey():
    # try to find public key path
    pubkey_path = None
    if os.path.exists('%s/.ssh/id_rsa.pub' % os.environ['HOME']):
        pubkey_path = '%s/.ssh/id_rsa.pub' % os.environ['HOME']
        print 'Using %s as your public key...' % pubkey_path
    else:
        print 'Please enter the path to your public key: ',
        pubkey_path = sys.stdin.readline()
    try:
        validate_pubkey(pubkey_path)
    except:
        print 'Invalid public key.'
        sys.exit(1)
    print ''
    return open(pubkey_path).read()

def format_and_list(list, when_empty=''):
    if len(list) > 0:
        if len(list) == 1:
            return list[0]
        else:
            return (', '.join(list[:-1]) + ' and ' + list[-1])
    else:
        return when_empty

def singular_plural(n, singular, plural):
    if n > 1:
        return plural
    else:
        return singular

def main():
    command = ''
    try:
        command = sys.argv[1]
    except:
        pass

    if command in COMMANDS:
        try:
            git_repo_root = find_git_repository(os.getcwd())
            print 'Using git repository %s' % git_repo_root
            print ''
            # Go to the root directory of the repository so that any files
            # we create are stored at the root level.
            os.chdir(git_repo_root)
        except GitRepositoryNotFoundException as e:
            print 'Please run "djangy %s" from within a valid git repository.' % command
            sys.exit(1)

        app_name = get_application_name()
        if command == 'create':
            if len(app_name) > 15 or len(app_name) < 5:
                print 'Your application name must be at least 5 and at most 15 characters long.'
                sys.exit(1)
        email, password = get_credentials()
        if command == 'create':
            pubkey = get_pubkey()
            files_created = []
            if not os.path.exists("djangy.config"):
                f = open("djangy.config", "w")
                f.write("[application]\nrootdir=%s\n" % os.path.basename(os.path.abspath(git_repo_root)))
                f.close()
                files_created.append('djangy.config')
            if not os.path.exists("djangy.eggs"):
                f = open("djangy.eggs", "w")
                f.write("Django\nSouth\n")
                f.close()
                files_created.append('djangy.eggs')
            if len(files_created) > 0:
                n = len(files_created)
                print "We've created the %s %s in %s" \
                    % (singular_plural(n, "file", "files"), format_and_list(files_created), git_repo_root)
                print "Feel free to edit %s and be sure to \"git add\" and \"git commit\" %s.\n" \
                    % (singular_plural(n, "this file", "these files"), singular_plural(n, "it", "them"))
            print request(command, app_name = app_name, email = email, hashed_password = password, pubkey = pubkey)
            # Add the "djangy" remote
            subprocess.call(['git remote add djangy git@%s:%s.git > /dev/null 2>&1' % (GIT_HOST, app_name)], shell=True)
        elif command == 'migrate':
            args = ' '.join(sys.argv[2:])
            print request(command, app_name = app_name, email = email, hashed_password = password, args = args)
        else:
            print request(command, app_name = app_name, email = email, hashed_password = password)
    elif command == '--help':
        print """djangy: djangy.com django hosting service client application

djangy create
  
  Create a new djangy application.  Current directory must be a git
  repository containing a django application, with settings.py at the root
  level.

The following commands must be called from inside a git repository which
has already been initialized as a djangy application via "djangy create":

djangy syncdb

  Create tables for django models in the application's database hosted on
  djangy.com.  This runs "python manage.py syncdb" on djangy's server.

djangy migrate [args...]

  Apply South migrations to update the schema of your application's database
  hosted on djangy.com when you modify your django models.  This runs
  "python manage.py migrate [args...]" on djangy's server.

djangy logs

  View the last 100 lines of your application's access.log, error.log, and
  django.log.

For more information, please visit:  http://www.djangy.com/docs/
Please contact support@djangy.com if you need help.
"""
    else:
        print 'djangy {--help | create | syncdb | migrate [args...] | logs}'
        sys.exit(1)

if __name__ == '__main__':
    check_for_update()
    main()
