#!/usr/bin/env python
# -*- coding: utf-8 -*-

# This file is part of the  X2Go Project - http://www.x2go.org
# Copyright (C) 2011-2013 by Oleksandr Shneyder <oleksandr.shneyder@obviously-nice.de>
# Copyright (C) 2011-2013 by Heinz-Markus Graesing <heinz-m.graesing@obviously-nice.de>
# Copyright (C) 2012-2013 by Mike Gabriel <mike.gabriel@das-netzwerkteam.de>
#
# X2Go Session Broker is free software; you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# X2Go Session Broker is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program; if not, write to the
# Free Software Foundation, Inc.,
# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.

import os
import sys
import argparse
import socket
import logging
import thread

try:
    import x2gobroker.defaults
except ImportError:
    sys.path.insert(0, os.path.join(os.getcwd(), '..'))
    import x2gobroker.defaults

from x2gobroker import __VERSION__
from x2gobroker import __AUTHOR__
from x2gobroker.loggers import logger_broker, logger_access, logger_error, tornado_log_request

# raise log level to DEBUG if requested...
if x2gobroker.defaults.X2GOBROKER_DEBUG and not x2gobroker.defaults.X2GOBROKER_TESTSUITE:
    logger_broker.setLevel(logging.DEBUG)
    logger_access.setLevel(logging.DEBUG)
    logger_error.setLevel(logging.DEBUG)

logger_broker.info('X2Go Session Broker ({version}), written by {author}'.format(version=__VERSION__, author=__AUTHOR__))
logger_broker.info('Setting up the broker\'s environment...')
logger_broker.info('  X2GOBROKER_DEBUG: {value}'.format(value=x2gobroker.defaults.X2GOBROKER_DEBUG))
logger_broker.info('  X2GOBROKER_CONFIG: {value}'.format(value=x2gobroker.defaults.X2GOBROKER_CONFIG))
logger_broker.info('  X2GOBROKER_AGENT_CMD: {value}'.format(value=x2gobroker.defaults.X2GOBROKER_AGENT_CMD))
logger_broker.info('  X2GOBROKER_AUTHSERVICE_SOCKET: {value}'.format(value=x2gobroker.defaults.X2GOBROKER_AUTHSERVICE_SOCKET))
logger_broker.info('  X2GOBROKER_DEFAULT_BACKEND: {value}'.format(value=x2gobroker.defaults.X2GOBROKER_DEFAULT_BACKEND))
logger_broker.info('  X2GOBROKER_SSL_CERTFILE: {value}'.format(value=x2gobroker.defaults.X2GOBROKER_SSL_CERTFILE))
logger_broker.info('  X2GOBROKER_SSL_KEYFILE: {value}'.format(value=x2gobroker.defaults.X2GOBROKER_SSL_KEYFILE))

# check effective UID the broker runs as and complain appropriately...
if x2gobroker.defaults.X2GOBROKER_USER != x2gobroker.defaults.X2GOBROKER_DAEMON_USER and os.geteuid() != 0:
    logger_broker.warn('X2Go Session Broker has been started interactively by user {username}, better run as user {daemon_username}.'.format(username=x2gobroker.defaults.X2GOBROKER_USER, daemon_username=x2gobroker.defaults.X2GOBROKER_DAEMON_USER))
    logger_broker.info('Automatically switching to DEBUG mode due to interactive launch of this application.')
elif x2gobroker.defaults.X2GOBROKER_DAEMON_USER != 'root' and os.geteuid() == 0:
    logger_broker.warn('X2Go Session Broker should not be run as root, better run as user {daemon_username}.'.format(daemon_username=x2gobroker.defaults.X2GOBROKER_DAEMON_USER))
elif os.geteuid() == 0:
    logger_broker.warn('X2Go Session Broker should not be run as root, better run as non-privileged user')

# parse-in potential command line options
cmdline_args = None
if __name__ == "__main__":
    import setproctitle
    setproctitle.setproctitle(os.path.basename(sys.argv[0]))

    daemon_options = [
        {'args':['-C','--config-file'], 'default': None, 'metavar': 'CONFIG_FILE', 'help': 'Specify a special configuration file name, default is: {default}'.format(default=x2gobroker.defaults.X2GOBROKER_CONFIG), },
        {'args':['-b', '--bind'], 'default': '127.0.0.1:8080', 'metavar': 'BIND_ADDRESS', 'help': 'The [address:]port that the web.py http-engine shall bind to (default: 127.0.0.1:8080)', },
        {'args':['-d','--debug'], 'default': False, 'action': 'store_true', 'help': 'enable debugging code; also: allow testing in web browser (make http\'s POST method available as GET method, as well)', },
    ]
    p = argparse.ArgumentParser(description='X2Go Session Broker (Standalone Daemon)',\
                                formatter_class=argparse.RawDescriptionHelpFormatter, \
                                add_help=True, argument_default=None)
    p_daemon = p.add_argument_group('standalone-daemon arguments')

    for (p_group, opts) in ( (p_daemon, daemon_options), ):
        for opt in opts:
            args = opt['args']
            del opt['args']
            p_group.add_argument(*args, **opt)

    cmdline_args = p.parse_args()

    if cmdline_args.config_file is not None:
        x2gobroker.defaults.X2GOBROKER_CONFIG = cmdline_args.config_file

    # override X2GOBROKER_DEBUG=0 in os.environ with the command line switch
    if cmdline_args.debug:
        x2gobroker.defaults.X2GOBROKER_DEBUG = cmdline_args.debug

    # some people just give the port but prepend a colon, webpy does not like this, so we strip if off
    cmdline_args.bind = cmdline_args.bind.lstrip('*')
    cmdline_args.bind = cmdline_args.bind.lstrip(':')

    if ':' in cmdline_args.bind:
        bind_address, bind_port = cmdline_args.bind.split(':')[0:2]
        bind_port = int(bind_port)
    else:
        bind_address = None
        bind_port = int(cmdline_args.bind)

# import classes serving the different web.py URLs
import x2gobroker.web.plain
import x2gobroker.web.uccs
#import x2gobroker.web.json
#import x2gobroker.web.html
import x2gobroker.web.extras

# define the web.py URLs
urls = ( ('/plain/(.*)', x2gobroker.web.plain.X2GoBrokerWeb,),
         ('/uccs/[a-zA-Z]*(/*)$', x2gobroker.web.uccs.X2GoBrokerWeb,),
         ('/uccs/(.*)/api/([0-9])(/*)$', x2gobroker.web.uccs.X2GoBrokerWebAPI,),
         ('/pubkeys(/*)$', x2gobroker.web.extras.X2GoBrokerPubKeyService,),
       )

settings = {
    'log_function': tornado_log_request,
}

# run the web.py standalone daemon...
if __name__ == "__main__":
    import tornado.web
    import tornado.httpserver
    import tornado.ioloop
    application = tornado.web.Application(urls, **settings)
    try:
        if x2gobroker.defaults.X2GOBROKER_SSL_CERTFILE and x2gobroker.defaults.X2GOBROKER_SSL_KEYFILE:
            # switch on https:// mode
            http_server = tornado.httpserver.HTTPServer(application,
                                                        ssl_options={
                                                            "certfile": x2gobroker.defaults.X2GOBROKER_SSL_CERTFILE,
                                                            "keyfile": x2gobroker.defaults.X2GOBROKER_SSL_KEYFILE,
                                                        },
            )
        else:
            # run without https
            http_server = tornado.httpserver.HTTPServer(application)
        http_server.listen(bind_port, address=bind_address)
        tornado.ioloop.IOLoop.instance().start()
    except socket.error, e:
        print (e)
else:
    import tornado.wsgi
    import wsgilog
    _tornado_application = tornado.wsgi.WSGIApplication(urls, **settings)

    def _application(environ, start_response):

        # some WSGI implementations do not like the SCRIPT_NAME env var
        if 'SCRIPT_NAME' in environ:
            del environ['SCRIPT_NAME']

        # make sure the httpd server's environment is set as os.environ
        for key in environ.keys():
            if key.startswith('X2GOBROKER_'):
                os.environ.update({ key: environ[key] })
        reload(x2gobroker.defaults)

        return _tornado_application(environ, start_response)

    application = wsgilog.WsgiLog(_application, tohtml=True, tofile=True, tostream=False, toprint=False, file='/var/log/x2gobroker/wsgi.log', )
