#!/usr/bin/python

import os, sys, socket, optparse
import snake.treedb, snake.ksdb
import snake.log, snake.config
from DocXMLRPCServer import DocXMLRPCServer

api_version = 1

def version():
    '''Return the API version that this server supports.'''
    return api_version

def setup_option_parser():
    parser=optparse.OptionParser()
    parser.add_option("-d", "--debug",
                action="store_true", dest="debug", default=False,
                help="Output noisy debugging info")
    parser.add_option("-q", "--quiet",action="store_true",dest="quiet",
                default=False,
                help="Surpress output")
    parser.add_option("-v", "--verbose",
                action="count", dest="verbosity", default=0,
                help="Output extra information")
    parser.add_option("-c", "--config", 
                action="store", dest="conffile", default=snake.config.DEFAULT_CONFIGFILE,
                help="Override default configuration file")
    parser.add_option("-n", "--hostname",
                action="store", dest="hostname", default=snake.config.DEFAULT_HOSTNAME,
                help="Set hostname to be used for URL construction (default: %default)")
    parser.add_option("-l", "--listen",
                action="store", dest="listen", default=snake.config.DEFAULT_IPADDR,
                help="Set IP address/hostname to be bound (default: %default)")
    parser.add_option("-p", "--port",
                action="store", dest="port", default=snake.config.DEFAULT_PORT,
                help="Bind service to specified port (default: %default)")
    parser.add_option("-f", "--foreground",
                action="store_true", dest="fg", default=False,
                help="Run in the foreground")
    parser.add_option("-z", "--zeroconf-off",
                action="store_const", dest="zeroconf", default=None, const="no",
                help="Disable zeroconf service advertisment")
    return parser

if __name__ == "__main__":

    # Parse commandline options
    parser = setup_option_parser()
    (opt,args) = parser.parse_args()

    # Set up logging
    if opt.debug:
        opt.verbosity = snake.log.DEBUG
    if opt.quiet:
        opt.verbosity = snake.log.QUIET

    log = snake.log.setup_logger(opt.verbosity)

    # Load 'server' configuration from snake.conf
    if os.access(opt.conffile, os.R_OK):
        # ensure opt.conffile is an absolute path
        if opt.conffile[0] != "/":
            opt.conffile = os.path.join(os.environ["PWD"], opt.conffile)
        log.debug("Loading configuration from %s" % opt.conffile)
        config = snake.config.getconfig("server", opt.conffile)
    else:
        print >> sys.stderr, "Error reading config file: %s" % opt.conffile
        sys.exit(1)

    # With config file loaded and logger setup, add a file logger
    snake.log.add_file_log(config["logfile"])

    # Override configfile options from commandline options
    for i in ('port','hostname','listen','zeroconf'):
        a = getattr(opt,i,None)
        if a:
            log.debug("Overriding config['%s']: %s->%s" % (i,config[i],a))
            config[i] = a

    # Are we backgrounding?
    if not opt.fg:
        if os.fork():
            '''parent'''
            sys.exit()
        else:
            '''child'''
            log.debug("Backgrounding snake-server")
            snake.log.detach_console()

    # Setup xmlrpc server
    try:
        server = DocXMLRPCServer((config["listen"], int(config["port"])))
    except socket.error, (errno, msg):
        log.error("Socket error: %s" % msg)
        sys.exit(1)

    # zeroconf advertisement
    if config['zeroconf'] == 'yes':
        try:
            import snake.zeroconf
        except ImportError:
            log.error("Avahi/DBus python bindings not available")

        try:
            log.info("Enabling Avahi service advertisment")
            avahi_server = snake.zeroconf.AvahiServer()
            avahi_server.advertise(config['hostname'], config['port'])
        except Exception, e:
            log.error("Failed to enable Avahi/DBus service discovery")
            log.debug(e)
    else:
        log.info("Avahi service advertisment disabled")

    # register functions
    server.register_function(snake.treedb.dicttrees,'tree.list')
    server.register_function(snake.treedb.removetree,'tree.remove')
    server.register_function(snake.treedb.add,'uri.add')
    server.register_function(snake.treedb.removeuri,'uri.remove')
    # FIXME: add check function (like snake-tree)
    server.register_function(snake.ksdb.listkickstarts,'kickstart.list')
    server.register_function(snake.ksdb.write_data,'kickstart.add')
    server.register_function(snake.ksdb.remove,'kickstart.remove')
    server.register_function(snake.ksdb.generate,'kickstart.generate')
    server.register_function(snake.ksdb.rename,'kickstart.rename')
    server.register_function(snake.ksdb.describe,'kickstart.describe')
    # Let us introspect, friend.
    server.register_function(version,'snake.version')
    server.register_introspection_functions()

    log.info("Listening for XMLRPC requests on http://%s:%s/" % (config["listen"],config["port"]))
    try:
        server.serve_forever()
    except KeyboardInterrupt:
        print "Exiting on keyboard interrupt."
