#! /usr/bin/env python2.5


def get_data_path():
    import os.path

    home = os.environ.get('HOME', '/')
    xdg_data_home = os.environ.get('XDG_DATA_HOME',
            os.path.join(home, '.local', 'share'))

    synoptic_path = os.path.join(xdg_data_home, "synoptic")
    if os.path.isdir(synoptic_path):
        return synoptic_path
    else:
        os.makedirs(synoptic_path)
        return synoptic_path


class Log:
    """file-like for writes with auto flush after each write
    to ensure that everything is logged, even during an
    unexpected exit."""

    def __init__(self, f):
        self.f = f

    def write(self, s):
        self.f.write(s)
        self.f.flush()

    def flush(self):
        self.f.flush()


def main():
    from optparse import OptionParser

    import os
    import sys

    mydir = get_data_path()

    description = ("An AJAXy information/note manager * "
            "To start a new database file, simply pick a file name and start "
            "synoptic with it. That file will be created and will contain your "
            "set of notes.")

    parser = OptionParser(description=description,
            usage="%prog [options] dbfile")
    parser.add_option(
            "-p", "--port", default=7331, type="int",
            help="Listen port", metavar="PORT")
    parser.add_option(
            "-d", "--daemon", action="store_true",
            help="Go to background after startup")
    parser.add_option(
            "-e", "--dbecho", action="store_true",
            help="Echo database queries")
    parser.add_option(
            "--start-empty", action="store_true",
            help="Start with an empty database, if creating")
    parser.add_option(
            "--browser", default="default",
            help="Type of web browser to launch (or 'none')")
    parser.add_option(
            "-b", "--bind-address", default=None,
            help="Allow remote connection")
    parser.add_option(
            "-a", "--allow-ip",
            help="Allow a given set of hosts and or networks "
            "(CIDR notation), separated by commas", metavar="NETWORK")
    parser.add_option(
            "--pidfile", dest="pidfile",
            default=os.path.join(mydir, "synoptic.pid"),
            help="PID file for daemonization", metavar="PIDFILE")
    parser.add_option(
            "-l", "--logfile", dest="logfile",
            default=os.path.join(mydir, "synoptic.log"),
            help="Log file for daemonization", metavar="LOGFILE")

    options, args = parser.parse_args()

    allowed_networks = []
    if options.allow_ip is not None:
        from ipaddr import IPNetwork
        for net_str in options.allow_ip.split(","):
            if net_str:
                allowed_networks.append(IPNetwork(net_str))

    from synoptic import Application
    real_app = app = Application(allowed_networks=allowed_networks)

    if len(args) != 1:
        parser.print_help()
        sys.exit(1)

    dbname = args[0]

    exists = os.access(dbname, os.F_OK)

    from synoptic import DBSessionInjector
    app = dbinj = DBSessionInjector(
            app, "sqlite:///%s" % args[0], exists,
            echo=options.dbecho)

    from synoptic import ErrorMiddleware
    app = ErrorMiddleware(app)

    if not exists and not options.start_empty:
        from synoptic import import_file, get_static_file
        import_file(dbinj.sessionmaker(),
                get_static_file("initial-content.txt")[0])

    from paste.httpserver import WSGIServer, WSGIHandler
    host = options.bind_address or "127.0.0.1"
    server = WSGIServer(app, (host, options.port), WSGIHandler)

    url = "http://%s:%d/" % (host, options.port)
    print "serving at %s..." % url

    quit_flag = [False]

    def quit_func():
        quit_flag[0] = True

    real_app.set_quit_func(quit_func)

    if options.daemon:
        # do the UNIX double-fork magic, see Stevens' "Advanced
        # Programming in the UNIX Environment" for details (ISBN 0201563177)
        try:
            pid = os.fork()
            if pid > 0:
                # exit first parent
                sys.exit(0)
        except OSError, e:
            print >>sys.stderr, "fork #1 failed: %d (%s)" % (e.errno, e.strerror)
            sys.exit(1)

        # decouple from parent environment
        os.setsid()
        os.umask(0)

        # do second fork
        try:
            pid = os.fork()
            if pid > 0:
                # exit from second parent, print eventual PID before
                #print "Daemon PID %d" % pid
                open(options.pidfile, 'w').write("%d" % pid)
                sys.exit(0)
        except OSError, e:
            print >>sys.stderr, "fork #2 failed: %d (%s)" % (e.errno, e.strerror)
            sys.exit(1)

        sys.stdout = sys.stderr = Log(open(options.logfile, 'a+'))

        sys.stderr.write("starting synoptic with pid %d\n" % os.getpid())

    browser = options.browser.lower()
    if browser != "none":
        def start_browser():
            import webbrowser
            if browser == "default":
                browser_ctlr = webbrowser.get()
            else:
                browser_ctlr = webbrowser.get(browser)
            browser_ctlr.open(url)

        from thread import start_new_thread
        start_new_thread(start_browser, ())

    while not quit_flag[0]:
        server.handle_request()
    print>>sys.stderr, "quitting..."

if __name__ == "__main__":
    main()
