#!/usr/bin/env python

import argparse
import fileinput
import getpass
import os
import re
import sys

from docker import client
from subprocess import check_output

def replace_line(file,search,replace):
    for line in fileinput.input(file, inplace=1):
        if search in line:
            line = replace+"\n"
        sys.stdout.write(line)

def check_process(process):
    print process,"is already running..."
    restart_process = 1
    while 1:
        choice=raw_input("Would you like to restart "+process+"? [Y]")
        if choice == "":
            break
        try:
            if choice in ["Y", "y", "Yes", "yes", "YES"]:
                break
            elif choice in ["N", "n", "No", "no", "NO"]:
                restart_process = 0 
                break
            else:
                print choice, "is not Yes or No"
        except:
            print choice, "is not Yes or No"
    return restart_process

def start(args):

    # !! TODO check for wharf container, if exists kill
    # !! TODO build new wharf container, tag it, and start it

    # defaults
    WHARF_CONTAINER_PORT = 80
    WHARF_HOST_PORT = 80
    WHARF_IP_ADDRESS = "0.0.0.0"
    MAIL_SERVER = "smtp.gmail.com"
    MAIL_PORT = 465
    MAIL_USE_TLS = False
    MAIL_USE_SSL = True
    MAIL_USERNAME = "gmail_email_address"
    MAIL_PASSWORD = "gmail_password"
    DOCKER_PORT = 4243
    REDIS_PORT = 6379
    REDIS_BIND_ADDRESS = "127.0.0.1"
    DOCKER_BIND_ADDRESS = "0.0.0.0"
    DOCKER_HOST = "localhost"
    DOMAIN = "localhost"
    REDIS_HOST = "localhost"
    SERVICES_FOLDER = "/wharf/services/"
    UPLOAD_FOLDER = "/wharf/tmp/"
    SECRET_KEY = "EckNi2Fluincawd+"
    SECURITY_PASSWORD_SALT = "S)1<P3_~$XF}DI=#"
    SQLALCHEMY_DATABASE_URI = "sqlite:////tmp/db.sqlite"
    DEFAULT_MAIL_SENDER = "dockerwharf@gmail.com"
    UNIX_DOCKER_PATH = "unix:///var/run/docker.sock"

    if args.config:
        print "interactive config"
        # interactive configuration
        while 1:
            choice=raw_input("Enter port for the Wharf container:["+str(WHARF_CONTAINER_PORT)+"]")
            if choice == "":
                break
            try:
                int(choice)
                if int(choice) < 0 or int(choice) > 65535:
                    print choice, "is not a valid range"
                else:
                    WHARF_CONTAINER_PORT = int(choice)
                    break
            except ValueError:
                print choice, "is not a valid port"
        while 1:
            choice=raw_input("Enter port for the Wharf host:["+str(WHARF_HOST_PORT)+"]")
            if choice == "":
                break
            try:
                int(choice)
                if int(choice) < 0 or int(choice) > 65535:
                    print choice, "is not a valid range"
                else:
                    WHARF_HOST_PORT = int(choice)
                    break
            except ValueError:
                print choice, "is not a valid port"
        while 1:
            choice=raw_input("Enter ip address of the Wharf host:["+str(WHARF_IP_ADDRESS)+"]")
            choice = re.findall(r'(?:[\d]{1,3})\.(?:[\d]{1,3})\.(?:[\d]{1,3})\.(?:[\d]{1,3})',choice)
            if choice:
                WHARF_IP_ADDRESS = choice
                break
            else:
                print choice, "is not a valid ip address"
        while 1:
            choice=raw_input("Enter SMTP mail server:["+str(MAIL_SERVER)+"]")
            # !! TODO
            #    parse mail host 
            if choice != "":
                MAIL_SERVER = choice
            break
        while 1:
            choice=raw_input("Enter port for the mail server:["+str(MAIL_PORT)+"]")
            if choice == "":
                break
            try:
                int(choice)
                if int(choice) < 0 or int(choice) > 65535:
                    print choice, "is not a valid range"
                else:
                    MAIL_PORT = int(choice)
                    break
            except ValueError:
                print choice, "is not a valid port"
        while 1:
            choice=raw_input("Use TLS?:["+str(MAIL_USE_TLS)+"]")
            if choice == "":
                break
            try:
                if choice == "True" or choice == "False":
                    MAIL_USE_TLS = bool(choice)
                    break
                else:
                    print choice, "is not True or False"
            except:
                print choice, "is not True or False"
        while 1:
            choice=raw_input("Use SSL?:["+str(MAIL_USE_SSL)+"]")
            if choice == "":
                break
            try:
                if choice == "True" or choice == "False":
                    MAIL_USE_SSL = bool(choice)
                    break
                else:
                    print choice, "is not True or False"
            except:
                print choice, "is not True or False"
        while 1:
            choice=raw_input("Enter mail username:["+str(MAIL_USERNAME)+"]")
            if choice != "":
                MAIL_USERNAME = choice
            break
        while 1:
            choice=getpass.getpass("Enter mail password:["+str(MAIL_PASSWORD)+"]")
            if choice != "":
                MAIL_PASSWORD = choice
            break
        while 1:
            choice=raw_input("Enter port for docker:["+str(DOCKER_PORT)+"]")
            if choice == "":
                break
            try:
                int(choice)
                if int(choice) < 0 or int(choice) > 65535:
                    print choice, "is not a valid range"
                else:
                    DOCKER_PORT = int(choice)
                    break
            except ValueError:
                print choice, "is not a valid port"
        while 1:
            choice=raw_input("Enter port for redis:["+str(REDIS_PORT)+"]")
            if choice == "":
                break
            try:
                int(choice)
                if int(choice) < 0 or int(choice) > 65535:
                    print choice, "is not a valid range"
                else:
                    REDIS_PORT = int(choice)
                    break
            except ValueError:
                print choice, "is not a valid port"
        while 1:
            choice=raw_input("Enter bind address for redis server:["+str(REDIS_BIND_ADDRESS)+"]")
            choice = re.findall(r'(?:[\d]{1,3})\.(?:[\d]{1,3})\.(?:[\d]{1,3})\.(?:[\d]{1,3})',choice)
            if choice != "":
                REDIS_BIND_ADDRESS = choice
                break
            else:
                print choice, "is not a valid ip address"
        while 1:
            choice=raw_input("Enter docker hostname:["+str(DOCKER_HOST)+"]")
            if choice != "":
                DOCKER_HOST = choice
            break
        while 1:
            choice=raw_input("Enter domain:["+str(DOMAIN)+"]")
            if choice != "":
                DOMAIN = choice
            break
        while 1:
            choice=raw_input("Enter redis hostname:["+str(REDIS_HOST)+"]")
            if choice != "":
                REDIS_HOST = choice
            break
        while 1:
            choice=raw_input("Enter path for services:["+str(SERVICES_FOLDER)+"]")
            # !! TODO verify a valid path
            if choice != "":
                SERVICES_FOLDER = choice
            break
        while 1:
            choice=raw_input("Enter path for uploads:["+str(UPLOAD_FOLDER)+"]")
            # !! TODO verify a valid path
            if choice != "":
                UPLOAD_FOLDER = choice
            break
        while 1:
            choice=getpass.getpass("Enter secret key:["+str(SECRET_KEY)+"]")
            if choice != "":
                SECRET_KEY = choice
            break
        while 1:
            choice=getpass.getpass("Enter password salt:["+str(SECURITY_PASSWORD_SALT)+"]")
            if choice != "":
                SECURITY_PASSWORD_SALT = choice
            break
        while 1:
            choice=raw_input("Enter database URI:["+str(SQLALCHEMY_DATABASE_URI)+"]")
            if choice != "":
                SQLALCHEMY_DATABASE_URI = choice
            break
        while 1:
            choice=raw_input("Enter mail sender:["+str(DEFAULT_MAIL_SENDER)+"]")
            if choice != "":
                DEFAULT_MAIL_SENDER = choice
            break
        while 1:
            choice=raw_input("Enter unix docker path:["+str(UNIX_DOCKER_PATH)+"]")
            if choice != "":
                UNIX_DOCKER_PATH = choice
            break
    else:
        print "no interactive config"
        # look for pre-existing configuration file
        if args.file:
            print args.file
            # check that file exists
        else:
            print "use default file location"
    
    print "writing configuration settings..."

    # !! TODO determine wharf root directory

    # write out mail settings
    try:
        with open('wharf/email_config/email.py', 'w') as f:
            f.write("MAIL_SERVER = '"+str(MAIL_SERVER)+"'\n")
            f.write("MAIL_PORT = "+str(MAIL_PORT)+"\n")
            f.write("MAIL_USE_TLS = "+str(MAIL_USE_TLS)+"\n")
            f.write("MAIL_USE_SSL = "+str(MAIL_USE_SSL)+"\n")
            f.write("MAIL_USERNAME = '"+str(MAIL_USERNAME)+"'\n")
            f.write("MAIL_PASSWORD = '"+str(MAIL_PASSWORD)+"'\n")
    except:
        # !! TODO make this location more robust
        print "unable to write to 'wharf/email_config/email.py',"
        print "perhaps the directory is in the wrong location?"
        sys.exit()

    # write out remaining settings
    replace_line("wharf/__init__.py", "DEFAULT_MAIL_SENDER =",
                 "DEFAULT_MAIL_SENDER = '"+str(DEFAULT_MAIL_SENDER)+"'")
    replace_line("wharf/__init__.py", "DOCKER_HOST =",
                 "DOCKER_HOST = '"+str(DOCKER_HOST)+"'")
    replace_line("wharf/__init__.py", "DOMAIN =","DOMAIN = '"+str(DOMAIN)+"'")
    replace_line("wharf/__init__.py", "REDIS_HOST =",
                 "REDIS_HOST = '"+str(REDIS_HOST)+"'")
    replace_line("wharf/__init__.py", "REDIS_PORT =",
                 "REDIS_PORT = "+str(REDIS_PORT))
    replace_line("wharf/__init__.py", "SECRET_KEY =",
                 "SECRET_KEY = '"+str(SECRET_KEY)+"'")
    replace_line("wharf/__init__.py", "SECURITY_PASSWORD_SALT =",
                 "SECURITY_PASSWORD_SALT = '"+str(SECURITY_PASSWORD_SALT)+"'")
    replace_line("wharf/__init__.py", "SERVICES_FOLDER =",
                 "SERVICES_FOLDER = '"+str(SERVICES_FOLDER)+"'")
    replace_line("wharf/__init__.py", "SQLALCHEMY_DATABASE_URI =",
                 "SQLALCHEMY_DATABASE_URI = '"+str(SQLALCHEMY_DATABASE_URI)+"'")
    replace_line("wharf/__init__.py", "UPLOAD_FOLDER =",
                 "UPLOAD_FOLDER = '"+str(UPLOAD_FOLDER)+"'")
    replace_line("Dockerfile", "EXPOSE ",
                 "EXPOSE "+str(WHARF_CONTAINER_PORT))

    # !! TODO requires sudo
    replace_line("/etc/redis/redis.conf", "port ",
                 "port "+str(REDIS_PORT))
    replace_line("/etc/redis/redis.conf", "bind ",
                 "bind "+str(REDIS_BIND_ADDRESS))

    if args.test:
        print "don't run wharf"
    else:
        print "run wharf"
    if args.verbose:
        print "be verbose!"
    else:
        print "be quiet!"

    redis_running = check_output("ps -A | grep redis | wc -l", shell=True)
    docker_running = check_output("ps -A | grep docker | wc -l", shell=True)
    redis_running = (redis_running.split())[0]
    docker_running = (docker_running.split())[0]
    if int(redis_running):
        restart_redis = check_process("redis-server")
        if restart_redis:
            running = check_output("service redis-server restart", shell=True) 
    else:
        running = check_output("service redis-server restart", shell=True) 
    cmd = "docker -H=tcp://"+DOCKER_BIND_ADDRESS+":"+str(DOCKER_PORT)+" -H="+UNIX_DOCKER_PATH+" -d &"
    if int(docker_running):
        restart_docker = check_process("docker")
        if restart_docker:
            # stop docker
            try:
                os.system("service docker stop")
                pid = check_output("ps -A | grep docker | awk '{ print $1 }'", shell=True)
                os.system("kill -9 "+str(pid))
            except:
                pass 

            # start docker
            os.system(cmd) 
    else:
        # stop docker
        try:
            os.system("service docker stop")
            pid = check_output("ps -A | grep docker | awk '{ print $1 }'", shell=True)
            os.system("kill -9 "+str(pid))
        except:
            pass

        # start docker
        os.system(cmd) 

    print "starting docker..."
    print "starting redis..."
    print "starting wharf..."
    print "all services up, browse to http://"+str(DOCKER_HOST)+":"+str(WHARF_HOST_PORT)
    return

def restart(args):
    stop(args)
    start(args)
    return

def stop(args):
    print args.action
    # kill wharf container
    if args.verbose:
        print "be verbose!"
    else:
        print "be quiet!"
    if args.test:
        print "nothing to do in testing mode!"
    return

def main():
    parser = argparse.ArgumentParser()

    parser.add_argument('-c', '--config',
                        help="interactive configuration",
                        action="store_true", default=False)
    parser.add_argument('-f', '--file',
                        help="path to configuration file", default='wharf.conf')
    parser.add_argument('-t', '--test',
                        help="does not actually start wharf, just tests the \
                              configuration",
                        action="store_true", default=False)
    parser.add_argument('-v', '--verbose',
                        help="increase output verbosity",
                        action="store_true", default=False)
    parser.add_argument('action', choices={'start', 'stop', 'restart'},
                        help="starts/restart/stops required services for \
                              wharf, default: start",
                        nargs='?', default='start')
    args = parser.parse_args()

    if args.action == 'start':
        start(args)
    elif args.action == 'restart':
        restart(args)
    elif args.action == 'stop':
        stop(args)

if __name__ == '__main__':
    main() 
