#!/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 objx.cli      import CLI
from objx.errors   import Errors, errors
from objx.event    import Event
from objx.help     import TXT
from objx.log      import Logging
from objx.main     import cmnd, init, scan
from objx.parse    import parse
from objx.persist  import skel
from objx.run      import Cfg


from objx import modules
from objx import user


Cfg.version = "91"


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()
