#!/usr/bin/env python

import sys, yaml, os, getpass
from bombardier_core.static_data import OK, SERVER_CONFIG_FILE
from bombardier_core.Cipher import Cipher
from commands import getstatusoutput as gso

USAGE  = ["usage:  %prog [-u] [-k KEY_PATH]",
          '',
          "KEY_PATH := The path to the id_dsa.pub file for ssh key-sharing.",
          "            Defaults to /root/.ssh/id_dsa.pub",
         ]

def ask_yes_no(prompt):
    result = ''
    while result == '':
        instr = raw_input(prompt)
        if len(instr) == 0:
            result = True
        if instr.lower()[0] == 'y':
            result = True
        elif instr.lower()[0] == 'n':
            result = False
    return result

def get_server_home():
    try:
        config_data = yaml.load(open(SERVER_CONFIG_FILE).read())
    except:
        print "Cannot read server_home from %s" % SERVER_CONFIG_FILE
        sys.exit(1)
    server_home = config_data.get("server_home")
    if not os.path.isdir(server_home):
        print "server_home not set in %s" % SERVER_CONFIG_FILE
        sys.exit(1)
    return server_home

def find_latest(file_list):
    version_numbers = []
    file_list = [x.split('-')[1].split('.tar.gz')[0] for x in file_list]
    file_list = [int(x) for x in file_list]
    return max(file_list)

def upgrade(version):
    server_home = get_server_home()
    if not version:
        version = "alpha"
    else:
        print "That version is not supported. Please choose 'alpha'."
        sys.exit(1)

    file_types = ["core", "cli", "server"]
    cmd = "curl https://launchpad.net/bombardier"
    status, output = gso(cmd)
    matcher = re.compile('\<a href=\"(http:\/\/launchpad\.net\/bombardier\/1\.00\/%s\/\+download\/.*)\"\>' % version)
    url_list = matcher.findall(output)
    print "Preparing to download and install the following:"
    print '\n> '.join(url_list)
    if ask_yes_no("Proceed? [y/n]") == False:
        print "Aborted."
        sys.exit(1)
    working_dir = tempfile.mkdtemp()
    for url in url_list:
        os.chdir(working_dir)
        print "downloading %s..." % url
        status = os.system("curl -O %s" % url)
        if status != OK:
            print "Error downloading %s... Giving up." % url
            sys.exit(1)

    directory_list = []
    for url in url_list:
        file_name = url.split('/')[-1]
        if "client" not in url:
            print "unpacking..."
            status = os.system("tar -xzvf %s" % file_name)
            if status != OK:
                print "Error unpacking %s... Giving up." % file_name
                print "You can look at the file in %s" % working_dir
                sys.exit(1)
            directory = file_name.split('.tar.gz')[0]
            directory_list.append(directory)
        else:
            status = os.system("mv %s %s/dist" % (file_name, server_home))
            if status != OK:
                print "Error putting %s in the server home (%s)..." % (file_name, server_home)
                print "You can look at the file in %s" % working_dir
                sys.exit(1)

    for directory in directory_list:
        print "installing..."
        os.chdir(directory)
        #status = os.system("%s setup.py install" % sys.executable)
        status = OK
        if status != OK:
            print "Error installing %s... Giving up." % file_name
            print "You can look at the file in %s" % working_dir
            sys.exit(1)

def set_password():
    server_home = get_server_home()
    test_decrypt_file = os.path.join(server_home, 'admin',
                                     'encryption_validation.yml')
    if os.path.isfile(test_decrypt_file):
        return

    print "\nYou will need to set your configuration key as part of the setup process."
    print "This key will be used to encrypt sensitive configuration items."
    password_1 = 'abc123'
    password_2 = 'def456'
    while password_1 != password_2:
        password_1 = getpass.getpass("Please enter your configuration key: ")
        password_2 = getpass.getpass("Please re-enter your configuration key: ")
        if password_1 != password_2:
            print "%%%% Configuration keys do not match. Please try again."

    lazy_dog = "the_quick_brown_fox_jumped_over_the_lazy_dog\n"
    cipher = Cipher(password_1)
    enc_lazy = cipher.encrypt_string(lazy_dog)
    enc_dict = { "enc_test" : enc_lazy }
    open( test_decrypt_file, 'w' ).write(yaml.dump( enc_dict ))

def copy_dsa_key(root_pub_key_path, server_home):
    admin_dir = os.path.join(server_home, "admin")
    if not root_pub_key_path:
        home_directory = os.environ.get("HOME")
        root_pub_key_path = os.path.join(home_directory, ".ssh", "id_dsa.pub")
    if not os.path.isfile(root_pub_key_path):
        print "%%%% ABORTING: %s does not exist. " % root_pub_key_path
        print "   Please create it with ssh-keygen -t dsa"
        sys.exit(1)
    prompt = "Using the one in root's home directory..."
    os.system("cp -f %s %s" % (root_pub_key_path, admin_dir))
    return

def create_if_needed(path):
    if not os.path.isdir(path):
        status = os.system("mkdir -p %s" % path)
        if status != OK:
            print "%%%% ABORTING: Unable to create path %s"
            sys.exit(1)

def create_directory_structure(server_home):
    print "\nCreating directory structure in %s..." % server_home
    create_if_needed(os.path.join(server_home, "admin"))
    create_if_needed(os.path.join(server_home, "dist"))
    create_if_needed(os.path.join(server_home, "cmdb"))
    create_if_needed(os.path.join(server_home, "status"))
    create_if_needed(os.path.join(server_home, "repos"))
    create_if_needed(os.path.join(server_home, "package"))
    create_if_needed(os.path.join(server_home, "machine"))
    create_if_needed(os.path.join(server_home, "bom"))
    create_if_needed(os.path.join(server_home, "include"))

def run_cmd(cmd):
    status = os.system(cmd)
    if status != OK:
        print "%%%% ABORTING: Unable to run %s" % cmd
        sys.exit(1)

def init(server_home, key_path):
    if not server_home:
        server_home = '/var/deploy'
    
    prompt = "Perform initial Bombardier Server environment setup in %s? (y/n): "
    result = ask_yes_no(prompt % server_home)
    if result == True: 
        create_directory_structure(server_home)
        copy_dsa_key(key_path, server_home)
        print "Writing configuration to /etc/bombardier.yml..."
        config_data = {"server_home": server_home}
        open("/etc/bombardier.yml", 'w').write(yaml.dump(config_data))
    else:
        print "Aborted."
        sys.exit(1)
    set_password()
    print "\n\nBasic server setup complete."
    print "Now configure your web server according to the instructions"
    print "in your documentation."

if __name__ == "__main__":
    import optparse
    parser = optparse.OptionParser('\n'.join(USAGE))
    parser.add_option("-s", "--server_home", dest="server_home",
                      help="specify the server home directory")
    parser.add_option("-v", "--version", dest="version",
                      help="branch to download")
    parser.add_option("-k", "--key-path", dest="key_path",
                      help="path to your public SSH key")

    (options, commands) = parser.parse_args()

    if len(commands) != 1:
        print "CMD: %s" % ' '.join(sys.argv)
        print "This command requires a command argument"
        parser.print_help()
        sys.exit(1)
    command = args[0]
    if command == "init":
        init(options.server_home, options.key_path)
    elif command == "upgrade":
        upgrade(options.version)
    elif command == "set_password":
        set_password()
    else:
        print "CMD: %s" % ' '.join(sys.argv)
        print "Unknown command: %s" % command
        parser.print_help()
        sys.exit(1)
