#!/usr/bin/env python
# coding=utf-8

import os
import stat
import argparse
import shutil
import sys
import ConfigParser
from AreteSlave.modules.Daemon import Daemon

try:
    import warnings

    with warnings.catch_warnings():
        warnings.simplefilter("ignore", DeprecationWarning)
        import paramiko

    import base64
    has_ssh_support = True
except:
    has_ssh_support = False

def load_authorized_keys(filename):
    # Prevent using this file if others can write to it
    mode = os.stat(filename).st_mode
    unwanted_bits = stat.S_IWGRP | stat.S_IWOTH # unwanted_bits = -----w--w-
    if mode & unwanted_bits:
        print >> sys.stderr, "Authorized keys file has wrong permissions. For security reasons group and other users cannot have write permissions."
        sys.exit(1)

    try:
        with open(filename, 'r') as f:
            lines = f.readlines()

            # take second column of every line, decode it and use as a rsa key
            return map(lambda x: paramiko.RSAKey(data=base64.decodestring(x.split()[1])), lines)
    except:
        print >> sys.stderr, "Cannot load authorized keys file"
        sys.exit(1)

def load_host_key(filename):
    # Prevent using this file if others can read/write to it
    mode = os.stat(filename).st_mode
    unwanted_bits = stat.S_IRWXG | stat.S_IRWXO # unwanted_bits = ----rwxrwx
    if mode & unwanted_bits:
        print >> sys.stderr, "Host key file has wrong permissions. For security reasons group and other users cannot access this file."
        sys.exit(1)

    return paramiko.RSAKey(filename=filename)

if __name__ == "__main__":
    parser = argparse.ArgumentParser(prog='arete-slave')
    
    parser.add_argument('-c', '--config', help="use config file", required=False, type=str)
    parser.add_argument('-p', '--port', help="use port other than 4567", required=False, type=int)
    parser.add_argument('-d', '--database', help="use database file other than 'aretes.db'", required=False, type=str)
    parser.add_argument('-l', '--log', help="use log file other than 'aretes.log'", required=False, type=str)
    parser.add_argument('-w', '--workdir', help="set working directory", required=False, type=str)
    parser.add_argument('-v', '--verbose', help="print everything to stderr too", required=False, action='store_true')
    parser.add_argument('-n', '--new', help="delete current database and log", required=False, action='store_true')
    parser.add_argument('--clean', help="delete temporary file directory", required=False, action='store_true')
    parser.add_argument('-s', '--ssh', help="use ssh to authorize connections", required=False, action='store_true')
    parser.add_argument('--authorized-keys', help="path to authorized keys file", required=False, type=str)
    parser.add_argument('--host-key', help="path to host's private key file", required=False, type=str)

    args = parser.parse_args()

    # defaults
    port = 4567
    database = 'aretes.db'
    log = 'aretes.log'
    default_workdir = '/tmp/arete-slave-'
    workdir = default_workdir + str(port)
    verbose = False
    new = False
    clean = False
    ssh = False

    # config
    if args.config:
        config = ConfigParser.SafeConfigParser()
        check = config.read(args.config)

        def relative(filename):
            return os.sep.join(os.path.abspath(args.config).split(os.sep)[:-1]) + os.sep + filename

        if check and config.has_section('Arete'):
            if config.has_option('Arete', 'port'):
                port = config.getint('Arete', 'port')
                workdir = default_workdir + str(port)
            if config.has_option('Arete', 'database'):
                database = relative(config.get('Arete', 'database'))
            if config.has_option('Arete', 'log'):
                log = relative(config.get('Arete', 'log'))
            if config.has_option('Arete', 'workdir'):
                workdir = relative(config.get('Arete', 'workdir'))
            if config.has_option('Arete', 'verbose'):
                verbose = config.getboolean('Arete', 'verbose')
            if config.has_option('Arete', 'new'):
                new = config.getboolean('Arete', 'new')
            if config.has_option('Arete', 'clean'):
                clean = config.getboolean('Arete', 'clean')
            if config.has_option('Arete', 'ssh'):
                ssh = config.getboolean('Arete', 'ssh')
            if config.has_option('Arete', 'authorized_keys'):
                authorized_keys = relative(config.get('Arete', 'authorized_keys'))
            if config.has_option('Arete', 'host_key'):
                host_key = relative(config.get('Arete', 'host_key'))
        else:
            print >> sys.stderr, "Invalid config file."
            config.get

    # arguments
    if args.port != None:
        port = args.port
        workdir = default_workdir + str(port)
    if args.database != None:
        database = args.database
    if args.log != None:
        log = args.log
    if args.workdir != None:
        workdir = args.workdir
    if args.verbose:
        verbose = True
    if args.new:
        new = True
    if args.clean:
        clean = True
    if args.ssh:
        ssh = True
    if args.authorized_keys != None:
        authorized_keys = args.authorized_keys
    if args.host_key != None:
        host_key = args.host_key

    if clean:
        if os.path.isdir(workdir):
            shutil.rmtree(workdir)
    if new:
        if os.path.isfile(database):
            os.remove(database)
        if os.path.isfile(log):
            os.remove(log)

    if ssh:
        if (not has_ssh_support):
            print >> sys.stderr, "In order to use ssh you must install paramiko library."
            sys.exit(1)

        if (authorized_keys is None) or (host_key is None):
            print >> sys.stderr, "In order to use ssh you must provide --authorized-keys and --host-key arguments"
            sys.exit(1)

        host_key = load_host_key(host_key)
        authorized_keys = load_authorized_keys(authorized_keys)
        daemon = Daemon(port=port, database=database, log=log, workdir=workdir, verbose=verbose, ssh=True, authorized_keys=authorized_keys, host_key=host_key)

    else:
        daemon = Daemon(port=port, database=database, log=log, workdir=workdir, verbose=verbose, ssh=False)

    daemon.run()
