#!/usr/bin/python
import os
import sys

home = os.environ.get("CUMIN_HOME", os.path.normpath("/usr/share/cumin"))
sys.path.append(os.path.join(home, "python"))

from cumin import *
from cumin.config import *
from cumin.util import *
from parsley.loggingex import PipeLogThread
from psycopg2 import OperationalError
from cumin.admin import SchemaVersion, SchemaMissing
from cumin.errors import CuminErrors

def restore_IO():
    sys.stderr = sys.__stderr__
    sys.stdout = sys.__stdout__

def set_aviary_configs(cumin, values):
    cumin.aviary_job_servers = values.aviary_job_servers
    cumin.aviary_query_servers = values.aviary_query_servers
    cumin.aviary_key = values.aviary_key
    cumin.aviary_cert = values.aviary_cert
    cumin.aviary_root_cert = values.aviary_root_cert
    cumin.aviary_domain_verify = values.aviary_domain_verify

    # For development use.  Default is False.  Undocumented.
    cumin.aviary_suds_logs = values.aviary_suds_logs

def set_wallaby_configs(cumin, values, brokers):
    if values.wallaby_broker == "":
        cumin.wallaby_broker = brokers[0]
    else:
        if values.wallaby_broker == "None":
            values.wallaby_broker = None
        cumin.wallaby_broker = values.wallaby_broker
    # Let 0 indicate "no timeout", since the timeout
    # value is an int in the config and None can't be
    # specified
    cumin.wallaby_refresh = values.wallaby_refresh
    if cumin.wallaby_refresh == 0:
        cumin.wallaby_refresh = None
    
def adjust_return(passed_init, ret):
    # Shift non-zer0 return codes left 1 bit
    # and OR in whether or not init passed
    if ret != 0:
        ret = ret << 1 | passed_init
    return ret

def main():
    passed_init = 1
    return_code = CuminErrors.NO_ERROR

    # Do our own simple option check so we can redirect IO early
    # without worrying about other options or the behavior of optParse
    opts = check_for_options(["--section", "--daemon"], sys.argv[1:])
    if type(opts["--section"]) is str:
        section_name = opts["--section"]
    else:
        section_name = "web"

    # If the --daemon option has been set, redirect stderr and stdio through
    # pipes.  Launch a thread to read those pipes and direct the content to
    # files with rollover control. 
    pipeThread = None
    if opts["--daemon"]:
        try:
            cumin_home = os.environ.get("CUMIN_HOME", os.path.normpath("/usr/share/cumin"))
            err_file = os.path.join(cumin_home, "log", section_name+".stderr")
            out_file = os.path.join(cumin_home, "log", section_name+".stdout")
 
           # Open pipes and redirect
            err_r, err_w = os.pipe()
            out_r, out_w = os.pipe()
            pipeThread = PipeLogThread(descriptors=[err_r, out_r],
                                       paths=[err_file, out_file],
                                       call_on_fail=restore_IO)
            pipeThread.start()
            sys.stderr = os.fdopen(err_w, "w", 0)
            sys.stdout = os.fdopen(out_w, "w", 0)
        except:
            restore_IO()
            print_exc()
            pipeThread = None

    # Use ArgError to jump to the finally block and exit 
    class ArgError(Exception):
        pass

    try:
        cumin = None

        setup_initial_logging()

        parser = CuminOptionParser()

        # Add additional parameters for web
        parser.add_option("--host")
        parser.add_option("--port", type=int)
        parser.add_option("--section", default="web")
        parser.add_option("--daemon", action="store_true", default=False)

        # Get options
        opts, args = parser.parse_args()

        # --section controls which section is read from the config file
        # If a section other than "web" is specified, require it to exist
        config = CuminWebConfig(opts.section, strict_section = opts.section != "web")

        # There might be other sections returned from config.parse() but
        # currently we don't care about them...
        values = getattr(config.parse(), opts.section)

        # Use the config values as defaults for unspecified options
        apply_defaults(values, opts)

        setup_operational_logging(opts, 
                                  values.log_max_mb,
                                  values.log_max_archives)

        if len(args) != 0:
            log.error("Extra arguments:" + "".join([" "+arg for arg in args]))
            raise ArgError

        broker_uris = [x.strip() for x in opts.brokers.split(",")]
        authmech = [x.strip() for x in values.auth.split(";")]
        cumin = Cumin(config.get_home(), broker_uris, opts.database, 
                      opts.host, opts.port, values.persona, authmech)

        if type(values.sasl_mech_list) == str:
            cumin.sasl_mech_list = values.sasl_mech_list.upper()

        set_aviary_configs(cumin, values)
        set_wallaby_configs(cumin, values, broker_uris)

        cumin.debug = opts.debug
        cumin.user = values.user
        cumin.update_interval = values.update_interval
        cumin.max_qmf_table_sort = values.max_qmf_table_sort

        cumin.fast_view_attributes = [x.strip() for x in values.fast_view_attributes.split(',')]

        # set default values for form inputs
        cumin.set_form_defaults(values.request_memory,
                                values.request_memory_vm,
                                values.request_disk,
                                values.request_disk_vm)

        cumin.check()
        cumin.init()

        if not opts.init_only and not return_code:
            passed_init = 0

            cumin.start()
            while True:
                # print_threads()
                sleep(1)
                if not cumin.server_alive():
                    print "web server has stopped, exiting..."
                    log.error("Web server process has stopped")
                    return_code = CuminErrors.WEB_SERVER_ERROR
                    break

    except KeyboardInterrupt:
        log.info("Received SIGINT")
        pass

    except SystemExit:
        if "--help" not in sys.argv:
            log.error("Error in options")
            return_code = CuminErrors.PARSE_ERROR

    except ArgError:
        return_code = CuminErrors.PARSE_ERROR

    except OperationalError:
        # Failed to talk to the database on check()
        log.info("Run 'cumin-database check' as root for more information.")
        return_code = CuminErrors.DATABASE_ERROR

    except SchemaMissing:
        log.info("Run 'cumin-admin create-schema' as root")
        return_code = CuminErrors.SCHEMA_ERROR

    except SchemaVersion:
        log.info("Run 'cumin-admin upgrade-schema' as root")
        return_code = CuminErrors.SCHEMA_VER_ERROR

    except:
        print_exc()
        return_code = CuminErrors.UNHANDLED_ERROR

    if cumin:
        cumin.stop()
    if pipeThread:
        pipeThread.stop()
    logging.shutdown()
    return adjust_return(passed_init, return_code)

if __name__ == "__main__":
    try:
        sys.exit(main())
    except KeyboardInterrupt:
        sys.exit(0)
