#!/usr/bin/env python3
# This file is placed in the Public Domain.
# pylint: disable=C0413,W0212,E0401


"main"


import getpass
import os
import pathlib
import pwd
import readline
import sys
import termios
import time


sys.path.insert(0, os.getcwd())


from objr.cli      import CLI
from objr.errors   import Errors, errors
from objr.event    import Event
from objr.help     import TXT
from objr.log      import Logging
from objr.main     import cmnd, init, scan
from objr.parse    import parse
from objr.persist  import skel
from objr.run      import Cfg


from objr import modules
from objr import user


Cfg.version = "141"


if os.path.exists("mods"):
    import mods as MODS
else:
    MODS = None


class Console(CLI):

    "Console"

    def announce(self, txt):
        "disable announce."

    def callback(self, evt):
        "wait for callback."
        CLI.callback(self, evt)
        evt.wait()

    def poll(self):
        "poll console and create event."
        evt = Event()
        evt.txt = input("> ")
        evt.type = "command"
        return evt



def daemon(pidfile, verbose=False):
    "switch to background."
    pid = os.fork()
    if pid != 0:
        os._exit(0)
    os.setsid()
    pid2 = os.fork()
    if pid2 != 0:
        os._exit(0)
    if not verbose:
        with open('/dev/null', 'r', encoding="utf-8") as sis:
            os.dup2(sis.fileno(), sys.stdin.fileno())
        with open('/dev/null', 'a+', encoding="utf-8") as sos:
            os.dup2(sos.fileno(), sys.stdout.fileno())
        with open('/dev/null', 'a+', encoding="utf-8") as ses:
            os.dup2(ses.fileno(), sys.stderr.fileno())
    os.umask(0)
    os.chdir("/")
    if os.path.exists(pidfile):
        os.unlink(pidfile)
    path = pathlib.Path(pidfile)
    path.parent.mkdir(parents=True, exist_ok=True)
    with open(pidfile, "w", encoding="utf-8") as fds:
        fds.write(str(os.getpid()))


def modnames():
    "list all modules."
    return sorted({x for x in dir(modules) + dir(user) + dir(MODS) if not x.startswith("__")})


def privileges(username):
    "drop privileges."
    pwnam = pwd.getpwnam(username)
    os.setgid(pwnam.pw_gid)
    os.setuid(pwnam.pw_uid)


def wrap(func):
    "reset terminal."
    old3 = None
    try:
        old3 = termios.tcgetattr(sys.stdin.fileno())
    except termios.error:
        pass
    try:
        func()
    except (KeyboardInterrupt, EOFError):
        print("")
    finally:
        if old3:
            termios.tcsetattr(sys.stdin.fileno(), termios.TCSADRAIN, old3)


def wrapped():
    "wrap main."
    wrap(main)
    errors()


def main():
    "main"
    readline.redisplay()
    skel()
    parse(Cfg, " ".join(sys.argv[1:]))
    Cfg.dis = Cfg.sets.dis
    Cfg.mod += "," + ",".join(modnames())
    if "h" in Cfg.opts:
        print(TXT)
        return
    if "v" in Cfg.opts:
        dte = " ".join(time.ctime(time.time()).replace("  ", " ").split()[1:])
        modiess = ",".join([x.upper() for x in modnames()])
        print(f'{dte} {Cfg.name.upper()} {Cfg.opts.upper()} {modiess}'.replace("  ", " "))
    wait = False
    if "d" in Cfg.opts:
        Cfg.user = getpass.getuser()
        CLI.out = Errors.out = Logging.out = None
        daemon(Cfg.pidfile, "-v" in sys.argv)
        privileges(Cfg.user)
        modstr = "," + ",".join(modnames())
        init(modules, modstr)
        init(user, modstr)
        wait = True
    elif "c" in Cfg.opts:
        csl = Console(print)
        if "i" in Cfg.opts:
            init(modules, Cfg.mod, Cfg.dis)
            init(user, Cfg.mod, Cfg.dis)
            init(MODS, Cfg.mod, Cfg.dis)
        csl.start()
        wait = True
    scan(modules, Cfg.mod, Cfg.dis)
    scan(user, Cfg.mod, Cfg.dis)
    scan(MODS, Cfg.mod, Cfg.dis)
    if Cfg.otxt:
        cmnd(Cfg.otxt, print)
    if wait or "w" in Cfg.opts:
        while 1:
            time.sleep(1.0)


if __name__ == "__main__":
    wrapped()
