#!/usr/bin/python3


"""
Module containing functions to launch the rest api web server with
desired user configurations
"""

import argparse
import sys
import logging

import bottle

from rest_api.api import user_files
from rest_api.api import sync_files
from rest_api.api import user_files_api_v0
from rest_api.api import job_manager
from rest_api.api import instrument_info
from rest_api.api import access_anywhere
from rest_api.api import workflow

from rest_api import products


def main(args=None):
    """
    Main launch point for the rest api
    Parses command line arguments and launches the web server
    """
    if args is None:
        args = parse_args(sys.argv[1:])

    log_level = logging.DEBUG if args.verbose else logging.INFO
    logging.basicConfig(filename='/var/log/py-user.log',level=log_level)
    log = logging.getLogger(__name__)

    product_specific = products.product_specific(args.model)
    config = {
        'rest_api.product_specific': product_specific,
        'user_files.base_dir': args.userdir,
        'user_files.upload_dir': args.uploads,
        'user_files.reports_dir': args.reports,
        'rest_api.db_file': args.job_db_file,
        'rest-api.jobs_dir': args.jobs_dir,
    }

    app = create_app(config)
    log.debug('## main.create_app done')

    product_specific.startup_side_effect(
        args.job_db_file,
        args.reports,
        args.procedures,
        args.jobs_dir,
    )

    log.debug('## main.product_specific.startup_side_effect done')

    app.run(
        host='0.0.0.0',
        server='paste',
        port=args.port,
        debug=args.verbose,
        reloader=args.verbose,
        protocol_version="HTTP/1.1"
    )


def parse_args(args):
    """
    Parses command line arguments
    """
    parser = get_argparser()
    args = parser.parse_args(args)
    return args


def get_argparser():
    """
    Sets up the commmand line argument parser

    Returns:
        parser (ArgumentParser): initilaized object configured with arguments to parse
    """
    parser = argparse.ArgumentParser()
    parser.add_argument('-d',
                        '--userdir',
                        default='.',
                        help='Base directory to serve files from')
    parser.add_argument('-p',
                        '--port',
                        default=80,
                        type=int,
                        help='HTTP server listen port')
    parser.add_argument('-u',
                        '--uploads',
                        default='.',
                        help='Directory where uploaded files should be saved')
    parser.add_argument('-v',
                        '--verbose',
                        action='store_true',
                        help='Enable verbose debug output')
    parser.add_argument('--job_db_file',
                        default='./jobs.db', # Should probably be elsewhere /var/db for example?
                        help='path to the job manager database file')
    parser.add_argument('--model',
                        default='off-target',
                        choices=products.products.PRODUCT_STR_TO_MODULE_STR,
                        help='model type for the instrument')
    parser.add_argument('--reports',
                        default='./job-manager/',
                        help='path to the default base directory where reports are created')
    parser.add_argument('--procedures',
                        default='./job-manager/test-procedures/',
                        help='path to the base directory where test procedures are stored')
    parser.add_argument('--jobs_dir',
                        default='./job-manager',
                        help='path to the directory where job files are stored')

    return parser


def create_app(config):
    """Function to create the bottle application and merge in routes from
    the user files api and the job manager api

    Returns:
        app (Bottle instance): the bottle web application to run
    """
    app = bottle.Bottle()

    job_manager.app.config.update(config)
    access_anywhere.app.config.update(config)
    instrument_info.app.config.update(config)
    user_files.user_files.config.update(config)
    user_files_api_v0.user_files.config.update(config)
    sync_files.user_files.config.update(config)
    app.config.update(config)
    workflow.app.config.update(config)

    app.merge(job_manager.app)
    app.merge(user_files.user_files)
    app.merge(sync_files.user_files)
    app.merge(user_files_api_v0.user_files)
    app.merge(instrument_info.app)
    app.merge(access_anywhere.app)
    app.merge(workflow.app)

    app.add_hook('after_request', add_connection_header)

    app.error(422)(job_manager.api.handle_unprocessable_entity)

    return app


def add_connection_header():
    """
    Re-transmits any received 'Connection' headers.
    Only necessary for the mobile app.
    """
    connection = bottle.request.get_header('Connection')
    if connection:
        bottle.response.set_header('Connection', connection)


if __name__ == '__main__':
    main()
